summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.bp2
-rw-r--r--ApiDocs.bp1
-rw-r--r--ProtoLibraries.bp18
-rw-r--r--StubLibraries.bp10
-rw-r--r--apct-tests/perftests/windowmanager/src/android/wm/RelayoutPerfTest.java4
-rw-r--r--apex/jobscheduler/framework/java/android/app/AlarmManager.java2
-rw-r--r--apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java8
-rw-r--r--apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java30
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java162
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java190
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/JobStore.java2
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/PendingJobQueue.java407
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java5
-rw-r--r--apex/jobscheduler/service/java/com/android/server/tare/DeviceIdleModifier.java2
-rw-r--r--apex/jobscheduler/service/java/com/android/server/tare/ProcessStateModifier.java5
-rw-r--r--apex/jobscheduler/service/java/com/android/server/usage/AppIdleHistory.java41
-rw-r--r--apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java94
-rw-r--r--boot/Android.bp4
-rw-r--r--boot/hiddenapi/hiddenapi-max-target-o.txt41
-rw-r--r--cmds/am/src/com/android/commands/am/Am.java2
-rw-r--r--cmds/am/src/com/android/commands/am/Instrument.java5
-rw-r--r--cmds/app_process/Android.bp2
-rw-r--r--cmds/app_process/app_main.cpp5
-rw-r--r--cmds/idmap2/Android.bp1
-rw-r--r--core/api/current.txt429
-rw-r--r--core/api/module-lib-current.txt68
-rw-r--r--core/api/system-current.txt242
-rw-r--r--core/api/test-current.txt52
-rw-r--r--core/java/Android.bp8
-rw-r--r--core/java/android/accessibilityservice/AccessibilityService.java27
-rw-r--r--core/java/android/accessibilityservice/AccessibilityShortcutInfo.java4
-rw-r--r--core/java/android/accessibilityservice/InputMethod.java6
-rw-r--r--core/java/android/accounts/CantAddAccountActivity.java2
-rw-r--r--core/java/android/accounts/ChooseTypeAndAccountActivity.java2
-rw-r--r--core/java/android/animation/ValueAnimator.java101
-rw-r--r--core/java/android/app/Activity.java29
-rw-r--r--core/java/android/app/ActivityClient.java4
-rw-r--r--core/java/android/app/ActivityManager.java134
-rw-r--r--core/java/android/app/ActivityOptions.java14
-rw-r--r--core/java/android/app/ActivityThread.java67
-rw-r--r--core/java/android/app/AppOpsManager.java2
-rw-r--r--core/java/android/app/ApplicationExitInfo.java62
-rw-r--r--core/java/android/app/ApplicationPackageManager.java26
-rw-r--r--core/java/android/app/ContextImpl.java14
-rw-r--r--core/java/android/app/Dialog.java3
-rw-r--r--core/java/android/app/GameManager.java2
-rw-r--r--core/java/android/app/IActivityClientController.aidl2
-rw-r--r--core/java/android/app/IApplicationThread.aidl1
-rw-r--r--core/java/android/app/ILocaleManager.aidl5
-rw-r--r--core/java/android/app/INotificationManager.aidl2
-rw-r--r--core/java/android/app/Instrumentation.java9
-rw-r--r--core/java/android/app/KeyguardManager.java14
-rw-r--r--core/java/android/app/LoadedApk.java56
-rw-r--r--core/java/android/app/LocaleManager.java28
-rw-r--r--core/java/android/app/Notification.java4
-rw-r--r--core/java/android/app/PictureInPictureParams.java85
-rw-r--r--core/java/android/app/PropertyInvalidatedCache.java71
-rw-r--r--core/java/android/app/StatusBarManager.java58
-rw-r--r--core/java/android/app/SystemServiceRegistry.java13
-rw-r--r--core/java/android/app/TEST_MAPPING19
-rw-r--r--core/java/android/app/TaskInfo.java14
-rw-r--r--core/java/android/app/admin/DevicePolicyDrawableResource.java34
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java854
-rw-r--r--core/java/android/app/admin/DevicePolicyResources.java1246
-rw-r--r--core/java/android/app/admin/DevicePolicyResourcesManager.java528
-rw-r--r--core/java/android/app/admin/DevicePolicyStringResource.java11
-rw-r--r--core/java/android/app/admin/FactoryResetProtectionPolicy.java15
-rw-r--r--core/java/android/app/admin/FullyManagedDeviceProvisioningParams.java45
-rw-r--r--core/java/android/app/admin/IDevicePolicyManager.aidl22
-rw-r--r--core/java/android/app/admin/ParcelableResource.java3
-rw-r--r--core/java/android/app/admin/PreferentialNetworkServiceConfig.java6
-rw-r--r--core/java/android/app/admin/SecurityLog.java18
-rw-r--r--core/java/android/app/admin/SecurityLogTags.logtags4
-rw-r--r--core/java/android/app/cloudsearch/SearchRequest.java39
-rw-r--r--core/java/android/app/cloudsearch/SearchResult.java18
-rw-r--r--core/java/android/app/prediction/AppTargetEvent.java5
-rw-r--r--core/java/android/app/servertransaction/ActivityTransactionItem.java4
-rw-r--r--core/java/android/app/servertransaction/LaunchActivityItem.java7
-rw-r--r--core/java/android/app/servertransaction/StartActivityItem.java4
-rw-r--r--core/java/android/app/trust/ITrustManager.aidl3
-rw-r--r--core/java/android/app/trust/TEST_MAPPING15
-rw-r--r--core/java/android/app/trust/TrustManager.java19
-rw-r--r--core/java/android/app/usage/BroadcastResponseStats.java2
-rw-r--r--core/java/android/app/usage/IUsageStatsManager.aidl8
-rw-r--r--core/java/android/app/usage/UsageStatsManager.java18
-rw-r--r--core/java/android/companion/CompanionDeviceManager.java50
-rw-r--r--core/java/android/companion/virtual/VirtualDeviceParams.java30
-rw-r--r--core/java/android/content/Context.java32
-rw-r--r--core/java/android/content/ContextWrapper.java4
-rw-r--r--core/java/android/content/Intent.java108
-rw-r--r--core/java/android/content/pm/AppSearchShortcutInfo.java2
-rw-r--r--core/java/android/content/pm/ApplicationInfo.java2
-rw-r--r--core/java/android/content/pm/Capability.aidl18
-rw-r--r--core/java/android/content/pm/Capability.java143
-rw-r--r--core/java/android/content/pm/CapabilityParams.aidl18
-rw-r--r--core/java/android/content/pm/CapabilityParams.java215
-rw-r--r--core/java/android/content/pm/CrossProfileApps.java85
-rw-r--r--core/java/android/content/pm/ICrossProfileApps.aidl2
-rw-r--r--core/java/android/content/pm/IPackageInstallerSession.aidl1
-rw-r--r--core/java/android/content/pm/IPackageManager.aidl17
-rw-r--r--core/java/android/content/pm/PackageInfo.java3
-rw-r--r--core/java/android/content/pm/PackageInfoLite.java5
-rw-r--r--core/java/android/content/pm/PackageInstaller.java25
-rw-r--r--core/java/android/content/pm/PackageManager.java97
-rw-r--r--core/java/android/content/pm/PackageParser.java31
-rw-r--r--core/java/android/content/pm/SHORTCUT_OWNERS5
-rw-r--r--core/java/android/content/pm/ShortcutInfo.java131
-rw-r--r--core/java/android/content/pm/Signature.java4
-rw-r--r--core/java/android/content/pm/SigningInfo.java8
-rw-r--r--core/java/android/content/pm/parsing/ApkLite.java20
-rw-r--r--core/java/android/content/pm/parsing/ApkLiteParseUtils.java7
-rw-r--r--core/java/android/content/pm/parsing/FrameworkParsingPackageUtils.java24
-rw-r--r--core/java/android/content/pm/parsing/PackageLite.java18
-rw-r--r--core/java/android/content/res/AssetManager.java7
-rw-r--r--core/java/android/hardware/CameraSessionStats.java11
-rw-r--r--core/java/android/hardware/CameraStreamStats.java23
-rw-r--r--core/java/android/hardware/SyncFence.java20
-rw-r--r--core/java/android/hardware/biometrics/BiometricFingerprintConstants.java29
-rw-r--r--core/java/android/hardware/camera2/CameraCharacteristics.java4
-rw-r--r--core/java/android/hardware/camera2/params/MandatoryStreamCombination.java22
-rw-r--r--core/java/android/hardware/camera2/params/OutputConfiguration.java12
-rw-r--r--core/java/android/hardware/camera2/params/StreamConfigurationMap.java9
-rw-r--r--core/java/android/hardware/fingerprint/FingerprintManager.java13
-rw-r--r--core/java/android/hardware/fingerprint/IFingerprintService.aidl6
-rw-r--r--core/java/android/hardware/fingerprint/IUdfpsOverlayController.aidl9
-rw-r--r--core/java/android/hardware/location/GeofenceHardwareRequestParcelable.java9
-rw-r--r--core/java/android/inputmethodservice/IInputMethodWrapper.java47
-rw-r--r--core/java/android/inputmethodservice/ImsConfigurationTracker.java5
-rw-r--r--core/java/android/inputmethodservice/InkWindow.java78
-rw-r--r--core/java/android/inputmethodservice/InputMethodService.java79
-rw-r--r--core/java/android/inputmethodservice/NavigationBarController.java103
-rw-r--r--core/java/android/inputmethodservice/navigationbar/ButtonDispatcher.java50
-rw-r--r--core/java/android/inputmethodservice/navigationbar/DeadZone.java15
-rw-r--r--core/java/android/inputmethodservice/navigationbar/KeyButtonDrawable.java46
-rw-r--r--core/java/android/inputmethodservice/navigationbar/KeyButtonRipple.java16
-rw-r--r--core/java/android/inputmethodservice/navigationbar/KeyButtonView.java17
-rw-r--r--core/java/android/inputmethodservice/navigationbar/NavigationBarFrame.java2
-rw-r--r--core/java/android/inputmethodservice/navigationbar/NavigationBarInflaterView.java12
-rw-r--r--core/java/android/inputmethodservice/navigationbar/NavigationBarView.java32
-rw-r--r--core/java/android/inputmethodservice/navigationbar/ReverseLinearLayout.java7
-rw-r--r--core/java/android/net/IVpnManager.aidl2
-rw-r--r--core/java/android/net/Ikev2VpnProfile.java26
-rw-r--r--core/java/android/net/NetworkPolicyManager.java20
-rw-r--r--core/java/android/net/SntpClient.java9
-rw-r--r--core/java/android/net/VpnManager.java32
-rw-r--r--core/java/android/net/VpnProfileState.aidl (renamed from packages/SystemUI/src/com/android/systemui/dagger/SysUISubcomponentModule.java)13
-rw-r--r--core/java/android/net/VpnProfileState.java153
-rw-r--r--core/java/android/net/netstats/NetworkStatsDataMigrationUtils.java18
-rw-r--r--core/java/android/nfc/Tag.java10
-rw-r--r--core/java/android/os/BatteryConsumer.java5
-rw-r--r--core/java/android/os/BatteryStats.java79
-rw-r--r--core/java/android/os/BatteryUsageStatsQuery.java12
-rwxr-xr-xcore/java/android/os/Build.java2
-rw-r--r--core/java/android/os/Bundle.java7
-rw-r--r--core/java/android/os/Environment.java10
-rw-r--r--core/java/android/os/ExternalVibration.java10
-rw-r--r--core/java/android/os/IBinder.java5
-rw-r--r--core/java/android/os/IUserManager.aidl2
-rw-r--r--core/java/android/os/IpcDataCache.java385
-rw-r--r--core/java/android/os/ParcelableHolder.java6
-rw-r--r--core/java/android/os/PowerComponents.java4
-rw-r--r--core/java/android/os/Process.java10
-rw-r--r--core/java/android/os/UidBatteryConsumer.java20
-rw-r--r--core/java/android/os/UserManager.java66
-rw-r--r--core/java/android/os/storage/IStorageManager.aidl66
-rw-r--r--core/java/android/os/storage/StorageManager.java53
-rw-r--r--core/java/android/permission/IPermissionController.aidl2
-rw-r--r--core/java/android/permission/IPermissionManager.aidl2
-rw-r--r--core/java/android/permission/PermissionControllerManager.java6
-rw-r--r--core/java/android/permission/PermissionControllerService.java19
-rw-r--r--core/java/android/permission/PermissionManager.java29
-rw-r--r--core/java/android/permission/PermissionUsageHelper.java15
-rw-r--r--core/java/android/provider/DeviceConfig.java21
-rw-r--r--core/java/android/provider/Settings.java33
-rw-r--r--core/java/android/service/ambientcontext/AmbientContextDetectionResult.java34
-rw-r--r--core/java/android/service/ambientcontext/AmbientContextDetectionService.java18
-rw-r--r--core/java/android/service/ambientcontext/AmbientContextDetectionServiceStatus.java23
-rw-r--r--core/java/android/service/autofill/FillEventHistory.java133
-rw-r--r--core/java/android/service/autofill/FillRequest.java30
-rw-r--r--core/java/android/service/displayhash/DisplayHashingService.java3
-rw-r--r--core/java/android/service/dreams/DreamService.java4
-rw-r--r--core/java/android/service/dreams/OWNERS5
-rw-r--r--core/java/android/service/games/GameScreenshotResult.java52
-rw-r--r--core/java/android/service/games/GameSession.java14
-rw-r--r--core/java/android/service/gatekeeper/GateKeeperResponse.java2
-rw-r--r--core/java/android/service/quicksettings/TileService.java34
-rw-r--r--core/java/android/service/trust/GrantTrustResult.aidl19
-rw-r--r--core/java/android/service/trust/GrantTrustResult.java179
-rw-r--r--core/java/android/service/trust/ITrustAgentService.aidl3
-rw-r--r--core/java/android/service/trust/ITrustAgentServiceCallback.aidl4
-rw-r--r--core/java/android/service/trust/TrustAgentService.java106
-rw-r--r--core/java/android/service/voice/AlwaysOnHotwordDetector.java6
-rw-r--r--core/java/android/service/wallpaper/WallpaperService.java8
-rw-r--r--core/java/android/telephony/TelephonyRegistryManager.java203
-rw-r--r--core/java/android/text/PrecomputedText.java40
-rw-r--r--core/java/android/text/StaticLayout.java6
-rw-r--r--core/java/android/util/FeatureFlagUtils.java8
-rw-r--r--core/java/android/util/IconDrawableFactory.java4
-rw-r--r--core/java/android/util/NtpTrustedTime.java111
-rw-r--r--core/java/android/util/TimingsTraceLog.java2
-rw-r--r--core/java/android/view/AccessibilityInteractionController.java3
-rw-r--r--core/java/android/view/ContentRecordingSession.java38
-rw-r--r--core/java/android/view/HandwritingInitiator.java56
-rw-r--r--core/java/android/view/IPinnedTaskListener.aidl2
-rw-r--r--core/java/android/view/IWindow.aidl3
-rw-r--r--core/java/android/view/IWindowManager.aidl5
-rw-r--r--core/java/android/view/IWindowSession.aidl6
-rw-r--r--core/java/android/view/InputWindowHandle.java101
-rw-r--r--core/java/android/view/InsetsController.java31
-rw-r--r--core/java/android/view/MotionEvent.java2
-rw-r--r--core/java/android/view/SurfaceControl.java61
-rw-r--r--core/java/android/view/View.java7
-rw-r--r--core/java/android/view/ViewConfiguration.java1
-rw-r--r--core/java/android/view/ViewRootImpl.java97
-rw-r--r--core/java/android/view/WindowCallbacks.java18
-rw-r--r--core/java/android/view/WindowLayout.java19
-rw-r--r--core/java/android/view/WindowManager.java57
-rw-r--r--core/java/android/view/WindowManagerGlobal.java36
-rw-r--r--core/java/android/view/WindowlessWindowManager.java14
-rw-r--r--core/java/android/view/accessibility/AccessibilityNodeInfo.java32
-rw-r--r--core/java/android/view/autofill/AutofillManager.java20
-rw-r--r--core/java/android/view/inputmethod/InputMethod.java27
-rw-r--r--core/java/android/view/inputmethod/InputMethodManager.java14
-rw-r--r--core/java/android/view/selectiontoolbar/SelectionToolbarManager.java2
-rw-r--r--core/java/android/view/translation/UiTranslationManager.java34
-rw-r--r--core/java/android/view/translation/UiTranslationStateCallback.java111
-rw-r--r--core/java/android/view/translation/ViewTranslationCallback.java2
-rw-r--r--core/java/android/widget/Editor.java10
-rw-r--r--core/java/android/widget/RemoteViews.java8
-rw-r--r--core/java/android/widget/TextView.java135
-rw-r--r--core/java/android/window/ClientWindowFrames.java36
-rw-r--r--core/java/android/window/DisplayWindowPolicyController.java47
-rw-r--r--core/java/android/window/ITaskOrganizerController.aidl2
-rw-r--r--core/java/android/window/OnBackInvokedCallback.java2
-rw-r--r--core/java/android/window/OnBackInvokedDispatcher.java6
-rw-r--r--core/java/android/window/ProxyOnBackInvokedDispatcher.java8
-rw-r--r--core/java/android/window/SplashScreen.java8
-rw-r--r--core/java/android/window/TaskOrganizer.java2
-rw-r--r--core/java/android/window/WindowInfosListener.java11
-rw-r--r--core/java/android/window/WindowOnBackInvokedDispatcher.java50
-rw-r--r--core/java/com/android/internal/app/ChooserActivity.java2
-rw-r--r--core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java16
-rw-r--r--core/java/com/android/internal/app/IntentForwarderActivity.java4
-rw-r--r--core/java/com/android/internal/app/OWNERS3
-rw-r--r--core/java/com/android/internal/app/ResolverActivity.java19
-rw-r--r--core/java/com/android/internal/app/ResolverMultiProfilePagerAdapter.java12
-rw-r--r--core/java/com/android/internal/app/UnlaunchableAppActivity.java4
-rw-r--r--core/java/com/android/internal/graphics/SfVsyncFrameCallbackProvider.java1
-rw-r--r--core/java/com/android/internal/infra/ServiceConnector.java14
-rw-r--r--core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl2
-rw-r--r--core/java/com/android/internal/inputmethod/InputMethodNavButtonFlags.java49
-rw-r--r--core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java4
-rw-r--r--core/java/com/android/internal/jank/FrameTracker.java13
-rw-r--r--core/java/com/android/internal/jank/InteractionJankMonitor.java24
-rw-r--r--core/java/com/android/internal/logging/InstanceId.java98
-rw-r--r--core/java/com/android/internal/logging/InstanceIdSequence.java62
-rw-r--r--core/java/com/android/internal/logging/UiEventLogger.java111
-rw-r--r--core/java/com/android/internal/net/VpnConfig.java7
-rw-r--r--core/java/com/android/internal/notification/SystemNotificationChannels.java2
-rw-r--r--core/java/com/android/internal/os/AudioPowerCalculator.java6
-rw-r--r--core/java/com/android/internal/os/BatteryStatsImpl.java475
-rw-r--r--core/java/com/android/internal/os/BatteryUsageStatsProvider.java7
-rw-r--r--core/java/com/android/internal/os/BluetoothPowerCalculator.java6
-rw-r--r--core/java/com/android/internal/os/CpuPowerCalculator.java4
-rw-r--r--core/java/com/android/internal/os/CustomMeasuredPowerCalculator.java4
-rw-r--r--core/java/com/android/internal/os/GnssPowerCalculator.java5
-rw-r--r--core/java/com/android/internal/os/KernelAllocationStats.java26
-rw-r--r--core/java/com/android/internal/os/MobileRadioPowerCalculator.java8
-rw-r--r--core/java/com/android/internal/os/ScreenPowerCalculator.java13
-rw-r--r--core/java/com/android/internal/os/SensorPowerCalculator.java4
-rw-r--r--core/java/com/android/internal/os/UserPowerCalculator.java6
-rw-r--r--core/java/com/android/internal/os/VideoPowerCalculator.java6
-rw-r--r--core/java/com/android/internal/os/WakelockPowerCalculator.java6
-rw-r--r--core/java/com/android/internal/os/WifiPowerCalculator.java7
-rw-r--r--core/java/com/android/internal/policy/DecorView.java5
-rw-r--r--core/java/com/android/internal/policy/TransitionAnimation.java6
-rw-r--r--core/java/com/android/internal/power/MeasuredEnergyStats.java5
-rw-r--r--core/java/com/android/internal/statusbar/IStatusBar.aidl5
-rw-r--r--core/java/com/android/internal/statusbar/IStatusBarService.aidl9
-rw-r--r--core/java/com/android/internal/telephony/ICarrierPrivilegesCallback.aidl (renamed from core/java/com/android/internal/telephony/ICarrierPrivilegesListener.aidl)3
-rw-r--r--core/java/com/android/internal/telephony/ITelephonyRegistry.aidl10
-rw-r--r--core/java/com/android/internal/util/LatencyTracker.java16
-rw-r--r--core/java/com/android/internal/util/ScreenshotHelper.java71
-rw-r--r--core/java/com/android/internal/view/BaseIWindow.java4
-rw-r--r--core/java/com/android/internal/view/IInputMethod.aidl10
-rw-r--r--core/java/com/android/internal/view/IInputMethodManager.aidl2
-rw-r--r--core/java/com/android/internal/widget/ConversationLayout.java17
-rw-r--r--core/java/com/android/internal/widget/ILockSettings.aidl2
-rw-r--r--core/java/com/android/internal/widget/LockPatternUtils.java95
-rw-r--r--core/java/com/android/internal/widget/LockPatternView.java109
-rw-r--r--core/java/com/android/internal/widget/MessagingGroup.java14
-rw-r--r--core/java/com/android/internal/widget/MessagingLayout.java29
-rw-r--r--core/java/com/android/internal/widget/MessagingLinearLayout.java1
-rw-r--r--core/java/com/android/internal/widget/MessagingMessage.java5
-rw-r--r--core/java/com/android/server/SystemConfig.java53
-rw-r--r--core/jni/Android.bp3
-rw-r--r--core/jni/AndroidRuntime.cpp1
-rw-r--r--core/jni/android_hardware_input_InputWindowHandle.cpp104
-rw-r--r--core/jni/android_util_Process.cpp82
-rw-r--r--core/jni/android_view_SurfaceControl.cpp69
-rw-r--r--core/jni/android_window_WindowInfosListener.cpp70
-rw-r--r--core/jni/com_android_internal_os_KernelAllocationStats.cpp149
-rw-r--r--core/jni/com_android_internal_os_Zygote.cpp2
-rw-r--r--core/jni/com_android_internal_os_ZygoteCommandBuffer.cpp28
-rw-r--r--core/proto/android/os/appbatterystats.proto47
-rw-r--r--core/proto/android/os/batteryusagestats.proto1
-rw-r--r--core/proto/android/os/incident.proto4
-rw-r--r--core/proto/android/server/windowmanagerservice.proto1
-rw-r--r--core/proto/android/service/netstats.proto121
-rw-r--r--core/res/AndroidManifest.xml122
-rw-r--r--core/res/OWNERS4
-rw-r--r--core/res/res/anim-ldrtl/activity_close_enter.xml55
-rw-r--r--core/res/res/anim-ldrtl/activity_close_exit.xml55
-rw-r--r--core/res/res/anim-ldrtl/activity_open_enter.xml53
-rw-r--r--core/res/res/anim-ldrtl/activity_open_exit.xml54
-rw-r--r--core/res/res/drawable-nodpi/stat_sys_adb.xml83
-rw-r--r--core/res/res/drawable/grant_permissions_buttons_bottom.xml23
-rw-r--r--core/res/res/drawable/grant_permissions_buttons_top.xml23
-rw-r--r--core/res/res/layout/log_access_user_consent_dialog_permission.xml86
-rw-r--r--core/res/res/values/attrs.xml4
-rw-r--r--core/res/res/values/attrs_manifest.xml10
-rw-r--r--core/res/res/values/config.xml45
-rw-r--r--core/res/res/values/dimens.xml3
-rw-r--r--core/res/res/values/ids.xml16
-rw-r--r--core/res/res/values/public-final.xml (renamed from core/res/res/values/public.xml)145
-rw-r--r--core/res/res/values/public-staging.xml231
-rw-r--r--core/res/res/values/strings.xml49
-rw-r--r--core/res/res/values/styles.xml38
-rw-r--r--core/res/res/values/symbols.xml9
-rw-r--r--core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerData.java3
-rw-r--r--core/tests/batterystatstests/BatteryUsageStatsProtoTests/src/com/android/internal/os/BatteryUsageStatsPulledTest.java6
-rw-r--r--core/tests/coretests/res/raw/obb_enc_file100_orig1.obbbin275008 -> 0 bytes
-rw-r--r--core/tests/coretests/res/raw/obb_enc_file100_orig3.obbbin298560 -> 0 bytes
-rw-r--r--core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java1
-rw-r--r--core/tests/coretests/src/android/content/pm/CrossProfileAppsTest.java8
-rw-r--r--core/tests/coretests/src/android/graphics/drawable/IconTest.java55
-rw-r--r--core/tests/coretests/src/android/net/SntpClientTest.java3
-rw-r--r--core/tests/coretests/src/android/os/IpcDataCacheTest.java312
-rw-r--r--core/tests/coretests/src/android/os/storage/StorageManagerBaseTest.java26
-rw-r--r--core/tests/coretests/src/android/os/storage/StorageManagerIntegrationTest.java59
-rw-r--r--core/tests/coretests/src/android/view/InsetsControllerTest.java12
-rw-r--r--core/tests/coretests/src/android/view/MotionEventTest.java24
-rw-r--r--core/tests/coretests/src/android/view/stylus/HandwritingInitiatorTest.java6
-rw-r--r--core/tests/coretests/src/android/window/BackNavigationTest.java4
-rw-r--r--core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java23
-rw-r--r--core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java30
-rw-r--r--core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java500
-rw-r--r--core/tests/coretests/src/com/android/internal/os/BatteryStatsSensorTest.java2
-rw-r--r--core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsTest.java75
-rw-r--r--core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java8
-rw-r--r--core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java2
-rw-r--r--core/tests/coretests/src/com/android/internal/widget/LockPatternViewTest.java247
-rw-r--r--core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java47
-rw-r--r--core/tests/mockingcoretests/src/android/util/TimingsTraceLogTest.java14
-rw-r--r--core/tests/utiltests/src/com/android/internal/util/LockPatternUtilsTest.java17
-rw-r--r--data/etc/Android.bp8
-rw-r--r--data/etc/com.android.cellbroadcastreceiver.xml29
-rw-r--r--data/etc/com.android.launcher3.xml1
-rw-r--r--data/etc/com.android.systemui.xml4
-rw-r--r--data/etc/platform.xml2
-rw-r--r--data/etc/privapp-permissions-platform.xml46
-rw-r--r--data/etc/services.core.protolog.json54
-rw-r--r--graphics/java/android/graphics/Rect.java8
-rw-r--r--graphics/java/android/graphics/RuntimeShader.java220
-rw-r--r--graphics/java/android/graphics/Typeface.java2
-rw-r--r--graphics/java/android/graphics/drawable/RippleDrawable.java19
-rw-r--r--graphics/java/android/graphics/fonts/Font.java2
-rw-r--r--graphics/java/android/graphics/text/LineBreakConfig.java106
-rw-r--r--identity/java/android/security/identity/CredentialDataRequest.java28
-rw-r--r--identity/java/android/security/identity/PresentationSession.java3
-rw-r--r--keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java27
-rw-r--r--keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java8
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/common/CommonFoldingFeature.java (renamed from libs/WindowManager/Jetpack/src/androidx/window/common/CommonDisplayFeature.java)121
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/common/DeviceStateManagerFoldingFeatureProducer.java (renamed from libs/WindowManager/Jetpack/src/androidx/window/common/DeviceStateManagerPostureProducer.java)30
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/common/DisplayFeature.java60
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/common/EmptyLifecycleCallbacksAdapter.java55
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/common/ResourceConfigDisplayFeatureProducer.java74
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/common/SettingsDevicePostureProducer.java96
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/common/SettingsDisplayFeatureProducer.java36
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java35
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationAdapter.java18
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationRunner.java30
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java150
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/sidecar/SampleSidecarImpl.java98
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/sidecar/StubSidecar.java2
-rw-r--r--libs/WindowManager/OWNERS3
-rw-r--r--libs/WindowManager/Shell/res/color/letterbox_education_dismiss_button_background_ripple.xml (renamed from packages/SystemUI/res/layout/communal_host_view.xml)12
-rw-r--r--libs/WindowManager/Shell/res/color/tv_pip_menu_close_icon.xml19
-rw-r--r--libs/WindowManager/Shell/res/color/tv_pip_menu_close_icon_bg.xml21
-rw-r--r--libs/WindowManager/Shell/res/drawable/letterbox_education_dismiss_button_background_ripple.xml2
-rw-r--r--libs/WindowManager/Shell/res/values-af/strings_tv.xml1
-rw-r--r--libs/WindowManager/Shell/res/values-am/strings_tv.xml1
-rw-r--r--libs/WindowManager/Shell/res/values-ar/strings_tv.xml1
-rw-r--r--libs/WindowManager/Shell/res/values-as/strings_tv.xml1
-rw-r--r--libs/WindowManager/Shell/res/values-az/strings_tv.xml1
-rw-r--r--libs/WindowManager/Shell/res/values-b+sr+Latn/strings_tv.xml1
-rw-r--r--libs/WindowManager/Shell/res/values-be/strings_tv.xml1
-rw-r--r--libs/WindowManager/Shell/res/values-bg/strings_tv.xml1
-rw-r--r--libs/WindowManager/Shell/res/values-bn/strings_tv.xml1
-rw-r--r--libs/WindowManager/Shell/res/values-bs/strings_tv.xml1
-rw-r--r--libs/WindowManager/Shell/res/values-ca/strings.xml2
-rw-r--r--libs/WindowManager/Shell/res/values-ca/strings_tv.xml1
-rw-r--r--libs/WindowManager/Shell/res/values-cs/strings_tv.xml1
-rw-r--r--libs/WindowManager/Shell/res/values-da/strings_tv.xml1
-rw-r--r--libs/WindowManager/Shell/res/values-de/strings_tv.xml1
-rw-r--r--libs/WindowManager/Shell/res/values-el/strings_tv.xml1
-rw-r--r--libs/WindowManager/Shell/res/values-en-rAU/strings_tv.xml1
-rw-r--r--libs/WindowManager/Shell/res/values-en-rCA/strings_tv.xml1
-rw-r--r--libs/WindowManager/Shell/res/values-en-rGB/strings_tv.xml1
-rw-r--r--libs/WindowManager/Shell/res/values-en-rIN/strings_tv.xml1
-rw-r--r--libs/WindowManager/Shell/res/values-en-rXC/strings_tv.xml1
-rw-r--r--libs/WindowManager/Shell/res/values-es-rUS/strings_tv.xml1
-rw-r--r--libs/WindowManager/Shell/res/values-es/strings_tv.xml1
-rw-r--r--libs/WindowManager/Shell/res/values-et/strings_tv.xml1
-rw-r--r--libs/WindowManager/Shell/res/values-eu/strings_tv.xml1
-rw-r--r--libs/WindowManager/Shell/res/values-fa/strings_tv.xml1
-rw-r--r--libs/WindowManager/Shell/res/values-fi/strings_tv.xml1
-rw-r--r--libs/WindowManager/Shell/res/values-fr-rCA/strings_tv.xml1
-rw-r--r--libs/WindowManager/Shell/res/values-fr/strings_tv.xml1
-rw-r--r--libs/WindowManager/Shell/res/values-gl/strings_tv.xml1
-rw-r--r--libs/WindowManager/Shell/res/values-gu/strings_tv.xml1
-rw-r--r--libs/WindowManager/Shell/res/values-hi/strings_tv.xml1
-rw-r--r--libs/WindowManager/Shell/res/values-hr/strings_tv.xml1
-rw-r--r--libs/WindowManager/Shell/res/values-hu/strings_tv.xml1
-rw-r--r--libs/WindowManager/Shell/res/values-hy/strings_tv.xml1
-rw-r--r--libs/WindowManager/Shell/res/values-in/strings_tv.xml1
-rw-r--r--libs/WindowManager/Shell/res/values-is/strings_tv.xml1
-rw-r--r--libs/WindowManager/Shell/res/values-it/strings_tv.xml1
-rw-r--r--libs/WindowManager/Shell/res/values-iw/strings_tv.xml1
-rw-r--r--libs/WindowManager/Shell/res/values-ja/strings_tv.xml1
-rw-r--r--libs/WindowManager/Shell/res/values-ka/strings_tv.xml1
-rw-r--r--libs/WindowManager/Shell/res/values-kk/strings_tv.xml1
-rw-r--r--libs/WindowManager/Shell/res/values-km/strings_tv.xml1
-rw-r--r--libs/WindowManager/Shell/res/values-kn/strings_tv.xml1
-rw-r--r--libs/WindowManager/Shell/res/values-ko/strings_tv.xml1
-rw-r--r--libs/WindowManager/Shell/res/values-ky/strings_tv.xml1
-rw-r--r--libs/WindowManager/Shell/res/values-land/styles.xml2
-rw-r--r--libs/WindowManager/Shell/res/values-lo/strings_tv.xml1
-rw-r--r--libs/WindowManager/Shell/res/values-lt/strings_tv.xml1
-rw-r--r--libs/WindowManager/Shell/res/values-lv/strings_tv.xml1
-rw-r--r--libs/WindowManager/Shell/res/values-mk/strings_tv.xml1
-rw-r--r--libs/WindowManager/Shell/res/values-ml/strings_tv.xml1
-rw-r--r--libs/WindowManager/Shell/res/values-mn/strings_tv.xml1
-rw-r--r--libs/WindowManager/Shell/res/values-mr/strings_tv.xml1
-rw-r--r--libs/WindowManager/Shell/res/values-ms/strings_tv.xml1
-rw-r--r--libs/WindowManager/Shell/res/values-my/strings_tv.xml1
-rw-r--r--libs/WindowManager/Shell/res/values-nb/strings_tv.xml1
-rw-r--r--libs/WindowManager/Shell/res/values-ne/strings_tv.xml1
-rw-r--r--libs/WindowManager/Shell/res/values-nl/strings_tv.xml1
-rw-r--r--libs/WindowManager/Shell/res/values-or/strings_tv.xml1
-rw-r--r--libs/WindowManager/Shell/res/values-pa/strings_tv.xml1
-rw-r--r--libs/WindowManager/Shell/res/values-pl/strings_tv.xml1
-rw-r--r--libs/WindowManager/Shell/res/values-pt-rBR/strings_tv.xml1
-rw-r--r--libs/WindowManager/Shell/res/values-pt-rPT/strings_tv.xml1
-rw-r--r--libs/WindowManager/Shell/res/values-pt/strings_tv.xml1
-rw-r--r--libs/WindowManager/Shell/res/values-ro/strings_tv.xml1
-rw-r--r--libs/WindowManager/Shell/res/values-ru/strings_tv.xml1
-rw-r--r--libs/WindowManager/Shell/res/values-si/strings_tv.xml1
-rw-r--r--libs/WindowManager/Shell/res/values-sk/strings_tv.xml1
-rw-r--r--libs/WindowManager/Shell/res/values-sl/strings_tv.xml1
-rw-r--r--libs/WindowManager/Shell/res/values-sq/strings_tv.xml1
-rw-r--r--libs/WindowManager/Shell/res/values-sr/strings_tv.xml1
-rw-r--r--libs/WindowManager/Shell/res/values-sv/strings_tv.xml1
-rw-r--r--libs/WindowManager/Shell/res/values-sw/strings_tv.xml1
-rw-r--r--libs/WindowManager/Shell/res/values-ta/strings_tv.xml1
-rw-r--r--libs/WindowManager/Shell/res/values-te/strings_tv.xml1
-rw-r--r--libs/WindowManager/Shell/res/values-television/config.xml10
-rw-r--r--libs/WindowManager/Shell/res/values-television/dimen.xml24
-rw-r--r--libs/WindowManager/Shell/res/values-th/strings_tv.xml1
-rw-r--r--libs/WindowManager/Shell/res/values-tl/strings_tv.xml1
-rw-r--r--libs/WindowManager/Shell/res/values-tr/strings_tv.xml1
-rw-r--r--libs/WindowManager/Shell/res/values-uk/strings_tv.xml1
-rw-r--r--libs/WindowManager/Shell/res/values-ur/strings_tv.xml1
-rw-r--r--libs/WindowManager/Shell/res/values-uz/strings_tv.xml1
-rw-r--r--libs/WindowManager/Shell/res/values-vi/strings_tv.xml1
-rw-r--r--libs/WindowManager/Shell/res/values-zh-rCN/strings_tv.xml1
-rw-r--r--libs/WindowManager/Shell/res/values-zh-rHK/strings_tv.xml1
-rw-r--r--libs/WindowManager/Shell/res/values-zh-rTW/strings_tv.xml1
-rw-r--r--libs/WindowManager/Shell/res/values-zu/strings_tv.xml1
-rw-r--r--libs/WindowManager/Shell/res/values/colors_tv.xml4
-rw-r--r--libs/WindowManager/Shell/res/values/strings_tv.xml5
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/ShellCommandHandlerImpl.java7
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java7
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java39
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/TaskView.java14
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java16
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java29
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BadgedImageView.java4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java26
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java11
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayController.java8
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java35
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java23
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUI.java11
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java25
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduAnimationController.java5
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduDialogLayout.java8
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduWindowManager.java32
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvPipModule.java12
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java27
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java5
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java18
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenTaskListener.java12
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/kidsmode/KidsModeTaskOrganizer.java337
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenTaskListener.java12
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/IPip.aidl5
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PinnedStackListenerForwarder.java13
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java12
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipMenuController.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java187
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java147
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipUtils.java7
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java63
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java35
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDismissTargetHandler.java6
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipInputConsumer.java10
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java8
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java30
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java1
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java6
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchState.java18
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsAlgorithm.java236
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsState.java36
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java285
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipKeepClearAlgorithm.kt741
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuActionButton.java11
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java133
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuView.java117
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipNotificationController.java14
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java49
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java34
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java28
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/StageTaskListener.java14
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java7
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java18
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java35
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/LaunchBubbleFromLockScreen.kt15
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/LaunchBubbleScreen.kt13
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/BaseAppHelper.kt2
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java1
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitWindowManagerTests.java2
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java37
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduDialogLayoutTest.java2
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduWindowManagerTest.java39
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/fullscreen/FullscreenTaskListenerTest.java2
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/kidsmode/KidsModeTaskOrganizerTest.java149
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java6
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/tv/TvPipKeepClearAlgorithmTest.kt469
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageTaskListenerTests.java2
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java82
-rw-r--r--libs/androidfw/Android.bp2
-rw-r--r--libs/hwui/Android.bp5
-rw-r--r--libs/hwui/HardwareBitmapUploader.cpp12
-rw-r--r--libs/hwui/HardwareBitmapUploader.h2
-rw-r--r--libs/hwui/Properties.cpp2
-rw-r--r--libs/hwui/hwui/Bitmap.cpp4
-rw-r--r--libs/hwui/renderthread/DrawFrameTask.cpp1
-rw-r--r--libs/storage/IMountService.cpp39
-rw-r--r--libs/storage/include/storage/IMountService.h6
-rw-r--r--location/java/android/location/GnssExcessPathInfo.java375
-rw-r--r--location/java/android/location/GnssReflectingPlane.java44
-rw-r--r--location/java/android/location/GnssSingleSatCorrection.java395
-rw-r--r--location/java/android/location/LastLocationRequest.java7
-rw-r--r--location/java/android/location/Location.java148
-rw-r--r--location/java/android/location/LocationManager.java3
-rw-r--r--location/java/android/location/LocationRequest.java10
-rw-r--r--media/java/android/media/AudioManager.java19
-rwxr-xr-xmedia/java/android/media/IAudioService.aidl9
-rw-r--r--media/java/android/media/ISpatializerHeadTrackerAvailableCallback.aidl27
-rw-r--r--media/java/android/media/MediaActionSound.java5
-rw-r--r--media/java/android/media/MediaCodec.java20
-rw-r--r--media/java/android/media/MediaFormat.java41
-rw-r--r--media/java/android/media/MediaRoute2Info.java2
-rw-r--r--media/java/android/media/MediaRouter2.java897
-rw-r--r--media/java/android/media/NearbyDevice.java38
-rw-r--r--media/java/android/media/RouteDiscoveryPreference.java5
-rw-r--r--media/java/android/media/Spatializer.java93
-rw-r--r--media/java/android/media/projection/IMediaProjection.aidl13
-rw-r--r--media/java/android/media/projection/MediaProjection.java57
-rw-r--r--media/java/android/media/tv/AdRequest.java6
-rw-r--r--media/java/android/media/tv/AitInfo.java6
-rw-r--r--media/java/android/media/tv/CommandRequest.java31
-rw-r--r--media/java/android/media/tv/CommandResponse.java19
-rw-r--r--media/java/android/media/tv/SectionRequest.java5
-rw-r--r--media/java/android/media/tv/SectionResponse.java10
-rw-r--r--media/java/android/media/tv/StreamEventResponse.java15
-rw-r--r--media/java/android/media/tv/TableRequest.java7
-rw-r--r--media/java/android/media/tv/TableResponse.java7
-rw-r--r--media/java/android/media/tv/TimelineResponse.java5
-rw-r--r--media/java/android/media/tv/TvInputManager.java4
-rw-r--r--media/java/android/media/tv/TvView.java10
-rw-r--r--media/java/android/media/tv/interactive/AppLinkInfo.aidl2
-rw-r--r--media/java/android/media/tv/interactive/AppLinkInfo.java186
-rw-r--r--media/java/android/media/tv/interactive/ITvInteractiveAppClient.aidl4
-rw-r--r--media/java/android/media/tv/interactive/ITvInteractiveAppManager.aidl9
-rw-r--r--media/java/android/media/tv/interactive/ITvInteractiveAppManagerCallback.aidl6
-rw-r--r--media/java/android/media/tv/interactive/ITvInteractiveAppService.aidl3
-rw-r--r--media/java/android/media/tv/interactive/ITvInteractiveAppServiceCallback.aidl2
-rw-r--r--media/java/android/media/tv/interactive/ITvInteractiveAppSession.aidl3
-rw-r--r--media/java/android/media/tv/interactive/ITvInteractiveAppSessionCallback.aidl3
-rwxr-xr-xmedia/java/android/media/tv/interactive/TvInteractiveAppManager.java128
-rwxr-xr-xmedia/java/android/media/tv/interactive/TvInteractiveAppService.java148
-rw-r--r--media/java/android/media/tv/interactive/TvInteractiveAppServiceInfo.aidl (renamed from media/java/android/media/tv/interactive/TvInteractiveAppInfo.aidl)4
-rw-r--r--media/java/android/media/tv/interactive/TvInteractiveAppServiceInfo.java (renamed from media/java/android/media/tv/interactive/TvInteractiveAppInfo.java)34
-rwxr-xr-xmedia/java/android/media/tv/interactive/TvInteractiveAppView.java133
-rw-r--r--media/java/android/media/tv/tuner/Lnb.java10
-rw-r--r--media/java/android/media/tv/tuner/Tuner.java8
-rw-r--r--media/jni/android_media_MediaDrm.cpp14
-rw-r--r--native/android/storage_manager.cpp13
-rw-r--r--packages/BackupRestoreConfirmation/res/values/strings.xml2
-rw-r--r--packages/BackupRestoreConfirmation/src/com/android/backupconfirm/BackupRestoreConfirmation.java30
-rw-r--r--packages/CompanionDeviceManager/res/color/selector.xml1
-rw-r--r--packages/CompanionDeviceManager/res/drawable/btn_negative_multiple_devices.xml26
-rw-r--r--packages/CompanionDeviceManager/res/drawable/btn_negative_top.xml23
-rw-r--r--packages/CompanionDeviceManager/res/drawable/btn_positive_bottom.xml23
-rw-r--r--packages/CompanionDeviceManager/res/drawable/helper_ok_button.xml1
-rw-r--r--packages/CompanionDeviceManager/res/drawable/ic_apps.xml27
-rw-r--r--packages/CompanionDeviceManager/res/drawable/ic_device_other.xml24
-rw-r--r--packages/CompanionDeviceManager/res/drawable/ic_notifications.xml26
-rw-r--r--packages/CompanionDeviceManager/res/drawable/ic_storage.xml26
-rw-r--r--packages/CompanionDeviceManager/res/drawable/ic_watch.xml26
-rw-r--r--packages/CompanionDeviceManager/res/layout/activity_confirmation.xml116
-rw-r--r--packages/CompanionDeviceManager/res/layout/data_transfer_confirmation.xml59
-rw-r--r--packages/CompanionDeviceManager/res/layout/helper_confirmation.xml19
-rw-r--r--packages/CompanionDeviceManager/res/layout/list_item_device.xml20
-rw-r--r--packages/CompanionDeviceManager/res/layout/list_item_permission.xml60
-rw-r--r--packages/CompanionDeviceManager/res/layout/vendor_header.xml7
-rw-r--r--packages/CompanionDeviceManager/res/values-af/strings.xml14
-rw-r--r--packages/CompanionDeviceManager/res/values-am/strings.xml14
-rw-r--r--packages/CompanionDeviceManager/res/values-ar/strings.xml14
-rw-r--r--packages/CompanionDeviceManager/res/values-as/strings.xml14
-rw-r--r--packages/CompanionDeviceManager/res/values-az/strings.xml14
-rw-r--r--packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml14
-rw-r--r--packages/CompanionDeviceManager/res/values-be/strings.xml14
-rw-r--r--packages/CompanionDeviceManager/res/values-bg/strings.xml14
-rw-r--r--packages/CompanionDeviceManager/res/values-bn/strings.xml14
-rw-r--r--packages/CompanionDeviceManager/res/values-bs/strings.xml16
-rw-r--r--packages/CompanionDeviceManager/res/values-ca/strings.xml14
-rw-r--r--packages/CompanionDeviceManager/res/values-cs/strings.xml14
-rw-r--r--packages/CompanionDeviceManager/res/values-da/strings.xml14
-rw-r--r--packages/CompanionDeviceManager/res/values-de/strings.xml14
-rw-r--r--packages/CompanionDeviceManager/res/values-el/strings.xml14
-rw-r--r--packages/CompanionDeviceManager/res/values-en-rAU/strings.xml14
-rw-r--r--packages/CompanionDeviceManager/res/values-en-rCA/strings.xml14
-rw-r--r--packages/CompanionDeviceManager/res/values-en-rGB/strings.xml14
-rw-r--r--packages/CompanionDeviceManager/res/values-en-rIN/strings.xml14
-rw-r--r--packages/CompanionDeviceManager/res/values-en-rXC/strings.xml14
-rw-r--r--packages/CompanionDeviceManager/res/values-es-rUS/strings.xml14
-rw-r--r--packages/CompanionDeviceManager/res/values-es/strings.xml14
-rw-r--r--packages/CompanionDeviceManager/res/values-et/strings.xml14
-rw-r--r--packages/CompanionDeviceManager/res/values-eu/strings.xml14
-rw-r--r--packages/CompanionDeviceManager/res/values-fa/strings.xml14
-rw-r--r--packages/CompanionDeviceManager/res/values-fi/strings.xml14
-rw-r--r--packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml14
-rw-r--r--packages/CompanionDeviceManager/res/values-fr/strings.xml14
-rw-r--r--packages/CompanionDeviceManager/res/values-gl/strings.xml14
-rw-r--r--packages/CompanionDeviceManager/res/values-gu/strings.xml14
-rw-r--r--packages/CompanionDeviceManager/res/values-hi/strings.xml14
-rw-r--r--packages/CompanionDeviceManager/res/values-hr/strings.xml14
-rw-r--r--packages/CompanionDeviceManager/res/values-hu/strings.xml14
-rw-r--r--packages/CompanionDeviceManager/res/values-hy/strings.xml14
-rw-r--r--packages/CompanionDeviceManager/res/values-in/strings.xml14
-rw-r--r--packages/CompanionDeviceManager/res/values-is/strings.xml14
-rw-r--r--packages/CompanionDeviceManager/res/values-it/strings.xml14
-rw-r--r--packages/CompanionDeviceManager/res/values-iw/strings.xml14
-rw-r--r--packages/CompanionDeviceManager/res/values-ja/strings.xml14
-rw-r--r--packages/CompanionDeviceManager/res/values-ka/strings.xml14
-rw-r--r--packages/CompanionDeviceManager/res/values-kk/strings.xml14
-rw-r--r--packages/CompanionDeviceManager/res/values-km/strings.xml14
-rw-r--r--packages/CompanionDeviceManager/res/values-kn/strings.xml14
-rw-r--r--packages/CompanionDeviceManager/res/values-ko/strings.xml14
-rw-r--r--packages/CompanionDeviceManager/res/values-ky/strings.xml14
-rw-r--r--packages/CompanionDeviceManager/res/values-lo/strings.xml14
-rw-r--r--packages/CompanionDeviceManager/res/values-lt/strings.xml14
-rw-r--r--packages/CompanionDeviceManager/res/values-lv/strings.xml14
-rw-r--r--packages/CompanionDeviceManager/res/values-mk/strings.xml14
-rw-r--r--packages/CompanionDeviceManager/res/values-ml/strings.xml14
-rw-r--r--packages/CompanionDeviceManager/res/values-mn/strings.xml14
-rw-r--r--packages/CompanionDeviceManager/res/values-mr/strings.xml14
-rw-r--r--packages/CompanionDeviceManager/res/values-ms/strings.xml14
-rw-r--r--packages/CompanionDeviceManager/res/values-my/strings.xml14
-rw-r--r--packages/CompanionDeviceManager/res/values-nb/strings.xml14
-rw-r--r--packages/CompanionDeviceManager/res/values-ne/strings.xml14
-rw-r--r--packages/CompanionDeviceManager/res/values-night/themes.xml26
-rw-r--r--packages/CompanionDeviceManager/res/values-nl/strings.xml14
-rw-r--r--packages/CompanionDeviceManager/res/values-or/strings.xml14
-rw-r--r--packages/CompanionDeviceManager/res/values-pa/strings.xml14
-rw-r--r--packages/CompanionDeviceManager/res/values-pl/strings.xml14
-rw-r--r--packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml14
-rw-r--r--packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml14
-rw-r--r--packages/CompanionDeviceManager/res/values-pt/strings.xml14
-rw-r--r--packages/CompanionDeviceManager/res/values-ro/strings.xml14
-rw-r--r--packages/CompanionDeviceManager/res/values-ru/strings.xml14
-rw-r--r--packages/CompanionDeviceManager/res/values-si/strings.xml14
-rw-r--r--packages/CompanionDeviceManager/res/values-sk/strings.xml14
-rw-r--r--packages/CompanionDeviceManager/res/values-sl/strings.xml14
-rw-r--r--packages/CompanionDeviceManager/res/values-sq/strings.xml14
-rw-r--r--packages/CompanionDeviceManager/res/values-sr/strings.xml14
-rw-r--r--packages/CompanionDeviceManager/res/values-sv/strings.xml14
-rw-r--r--packages/CompanionDeviceManager/res/values-sw/strings.xml14
-rw-r--r--packages/CompanionDeviceManager/res/values-ta/strings.xml14
-rw-r--r--packages/CompanionDeviceManager/res/values-te/strings.xml14
-rw-r--r--packages/CompanionDeviceManager/res/values-th/strings.xml14
-rw-r--r--packages/CompanionDeviceManager/res/values-tl/strings.xml14
-rw-r--r--packages/CompanionDeviceManager/res/values-tr/strings.xml14
-rw-r--r--packages/CompanionDeviceManager/res/values-uk/strings.xml14
-rw-r--r--packages/CompanionDeviceManager/res/values-ur/strings.xml14
-rw-r--r--packages/CompanionDeviceManager/res/values-uz/strings.xml14
-rw-r--r--packages/CompanionDeviceManager/res/values-vi/strings.xml14
-rw-r--r--packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml14
-rw-r--r--packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml14
-rw-r--r--packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml14
-rw-r--r--packages/CompanionDeviceManager/res/values-zu/strings.xml14
-rw-r--r--packages/CompanionDeviceManager/res/values/strings.xml20
-rw-r--r--packages/CompanionDeviceManager/res/values/styles.xml82
-rw-r--r--packages/CompanionDeviceManager/res/values/themes.xml3
-rw-r--r--packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java152
-rw-r--r--packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java3
-rw-r--r--packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceListAdapter.java28
-rw-r--r--packages/CompanionDeviceManager/src/com/android/companiondevicemanager/PermissionListAdapter.java128
-rw-r--r--packages/CompanionDeviceManager/src/com/android/companiondevicemanager/Utils.java5
-rw-r--r--packages/ConnectivityT/framework-t/Android.bp8
-rw-r--r--packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStats.java10
-rw-r--r--packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStatsManager.java117
-rw-r--r--packages/ConnectivityT/framework-t/src/android/net/ConnectivityFrameworkInitializerTiramisu.java14
-rw-r--r--packages/ConnectivityT/framework-t/src/android/net/EthernetManager.java286
-rw-r--r--packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkUpdateRequest.java75
-rw-r--r--packages/ConnectivityT/framework-t/src/android/net/IEthernetManager.aidl13
-rw-r--r--packages/ConnectivityT/framework-t/src/android/net/IEthernetServiceListener.aidl1
-rw-r--r--packages/ConnectivityT/framework-t/src/android/net/INetworkInterfaceOutcomeReceiver.aidl (renamed from packages/ConnectivityT/framework-t/src/android/net/IEthernetNetworkManagementListener.aidl)6
-rw-r--r--packages/ConnectivityT/framework-t/src/android/net/INetworkStatsService.aidl2
-rw-r--r--packages/ConnectivityT/framework-t/src/android/net/NetworkIdentity.java10
-rw-r--r--packages/ConnectivityT/framework-t/src/android/net/NetworkIdentitySet.java2
-rw-r--r--packages/ConnectivityT/framework-t/src/android/net/NetworkStats.java61
-rw-r--r--packages/ConnectivityT/framework-t/src/android/net/NetworkStatsCollection.java60
-rw-r--r--packages/ConnectivityT/framework-t/src/android/net/NetworkStatsHistory.java16
-rw-r--r--packages/ConnectivityT/framework-t/src/android/net/TrafficStats.java16
-rw-r--r--packages/ConnectivityT/framework-t/src/android/net/netstats/provider/INetworkStatsProviderCallback.aidl3
-rw-r--r--packages/ConnectivityT/framework-t/src/android/net/netstats/provider/NetworkStatsProvider.java6
-rw-r--r--packages/ConnectivityT/service/Android.bp8
-rw-r--r--packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsFactory.java26
-rw-r--r--packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsRecorder.java4
-rw-r--r--packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsService.java41
-rw-r--r--packages/ConnectivityT/tests/unit/java/com/android/server/net/IpConfigStoreTest.java (renamed from services/tests/servicestests/src/com/android/server/net/IpConfigStoreTest.java)19
-rw-r--r--packages/DynamicSystemInstallationService/Android.bp8
-rw-r--r--packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java96
-rw-r--r--packages/DynamicSystemInstallationService/src/com/android/dynsystem/EventLogTags.logtags7
-rw-r--r--packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java127
-rw-r--r--packages/PackageInstaller/res/values-ar/strings.xml2
-rw-r--r--packages/PackageInstaller/res/values-or/strings.xml2
-rw-r--r--packages/PrintSpooler/res/values-it/strings.xml4
-rw-r--r--packages/PrintSpooler/res/values-pt-rPT/strings.xml4
-rw-r--r--packages/SettingsLib/ActivityEmbedding/src/com/android/settingslib/activityembedding/ActivityEmbeddingUtils.java23
-rw-r--r--packages/SettingsLib/FooterPreference/res/layout-v31/preference_footer.xml2
-rw-r--r--packages/SettingsLib/FooterPreference/res/layout/preference_footer.xml2
-rw-r--r--packages/SettingsLib/FooterPreference/src/com/android/settingslib/widget/FooterPreference.java7
-rw-r--r--packages/SettingsLib/SearchWidget/res/values-or/strings.xml2
-rw-r--r--packages/SettingsLib/SettingsTheme/res/color-v31/settingslib_text_color_primary.xml22
-rw-r--r--packages/SettingsLib/SettingsTheme/res/values-v31/styles.xml2
-rw-r--r--packages/SettingsLib/res/drawable/ic_account_circle.xml (renamed from packages/SystemUI/res/drawable/ic_account_circle.xml)0
-rw-r--r--packages/SettingsLib/res/drawable/ic_account_circle_filled.xml (renamed from packages/SystemUI/res/drawable/ic_account_circle_filled.xml)0
-rw-r--r--packages/SettingsLib/res/drawable/ic_add_supervised_user.xml (renamed from packages/SystemUI/res/drawable/ic_add_supervised_user.xml)0
-rw-r--r--packages/SettingsLib/res/drawable/user_avatar_bg.xml (renamed from packages/SystemUI/res/drawable/kg_bg_avatar.xml)2
-rw-r--r--packages/SettingsLib/res/values-af/strings.xml11
-rw-r--r--packages/SettingsLib/res/values-am/strings.xml11
-rw-r--r--packages/SettingsLib/res/values-ar/strings.xml14
-rw-r--r--packages/SettingsLib/res/values-as/strings.xml11
-rw-r--r--packages/SettingsLib/res/values-az/strings.xml11
-rw-r--r--packages/SettingsLib/res/values-b+sr+Latn/strings.xml11
-rw-r--r--packages/SettingsLib/res/values-be/strings.xml14
-rw-r--r--packages/SettingsLib/res/values-bg/strings.xml11
-rw-r--r--packages/SettingsLib/res/values-bn/strings.xml14
-rw-r--r--packages/SettingsLib/res/values-bs/strings.xml11
-rw-r--r--packages/SettingsLib/res/values-ca/strings.xml11
-rw-r--r--packages/SettingsLib/res/values-cs/strings.xml11
-rw-r--r--packages/SettingsLib/res/values-da/strings.xml11
-rw-r--r--packages/SettingsLib/res/values-de/strings.xml13
-rw-r--r--packages/SettingsLib/res/values-el/strings.xml11
-rw-r--r--packages/SettingsLib/res/values-en-rAU/strings.xml13
-rw-r--r--packages/SettingsLib/res/values-en-rCA/strings.xml13
-rw-r--r--packages/SettingsLib/res/values-en-rGB/strings.xml13
-rw-r--r--packages/SettingsLib/res/values-en-rIN/strings.xml13
-rw-r--r--packages/SettingsLib/res/values-en-rXC/strings.xml10
-rw-r--r--packages/SettingsLib/res/values-es-rUS/strings.xml14
-rw-r--r--packages/SettingsLib/res/values-es/strings.xml13
-rw-r--r--packages/SettingsLib/res/values-et/strings.xml11
-rw-r--r--packages/SettingsLib/res/values-eu/strings.xml14
-rw-r--r--packages/SettingsLib/res/values-fa/strings.xml11
-rw-r--r--packages/SettingsLib/res/values-fi/strings.xml11
-rw-r--r--packages/SettingsLib/res/values-fr-rCA/strings.xml14
-rw-r--r--packages/SettingsLib/res/values-fr/strings.xml14
-rw-r--r--packages/SettingsLib/res/values-gl/strings.xml14
-rw-r--r--packages/SettingsLib/res/values-gu/strings.xml11
-rw-r--r--packages/SettingsLib/res/values-hi/strings.xml11
-rw-r--r--packages/SettingsLib/res/values-hr/strings.xml14
-rw-r--r--packages/SettingsLib/res/values-hu/strings.xml11
-rw-r--r--packages/SettingsLib/res/values-hy/strings.xml11
-rw-r--r--packages/SettingsLib/res/values-in/strings.xml11
-rw-r--r--packages/SettingsLib/res/values-is/strings.xml11
-rw-r--r--packages/SettingsLib/res/values-it/strings.xml13
-rw-r--r--packages/SettingsLib/res/values-iw/strings.xml11
-rw-r--r--packages/SettingsLib/res/values-ja/strings.xml11
-rw-r--r--packages/SettingsLib/res/values-ka/strings.xml11
-rw-r--r--packages/SettingsLib/res/values-kk/strings.xml11
-rw-r--r--packages/SettingsLib/res/values-km/strings.xml14
-rw-r--r--packages/SettingsLib/res/values-kn/strings.xml11
-rw-r--r--packages/SettingsLib/res/values-ko/strings.xml11
-rw-r--r--packages/SettingsLib/res/values-ky/strings.xml11
-rw-r--r--packages/SettingsLib/res/values-lo/strings.xml11
-rw-r--r--packages/SettingsLib/res/values-lt/strings.xml11
-rw-r--r--packages/SettingsLib/res/values-lv/strings.xml11
-rw-r--r--packages/SettingsLib/res/values-mk/strings.xml11
-rw-r--r--packages/SettingsLib/res/values-ml/strings.xml11
-rw-r--r--packages/SettingsLib/res/values-mn/strings.xml11
-rw-r--r--packages/SettingsLib/res/values-mr/strings.xml11
-rw-r--r--packages/SettingsLib/res/values-ms/strings.xml11
-rw-r--r--packages/SettingsLib/res/values-my/strings.xml11
-rw-r--r--packages/SettingsLib/res/values-nb/strings.xml11
-rw-r--r--packages/SettingsLib/res/values-ne/strings.xml11
-rw-r--r--packages/SettingsLib/res/values-nl/strings.xml11
-rw-r--r--packages/SettingsLib/res/values-or/strings.xml32
-rw-r--r--packages/SettingsLib/res/values-pa/strings.xml11
-rw-r--r--packages/SettingsLib/res/values-pl/strings.xml11
-rw-r--r--packages/SettingsLib/res/values-pt-rBR/strings.xml11
-rw-r--r--packages/SettingsLib/res/values-pt-rPT/strings.xml13
-rw-r--r--packages/SettingsLib/res/values-pt/strings.xml11
-rw-r--r--packages/SettingsLib/res/values-ro/strings.xml11
-rw-r--r--packages/SettingsLib/res/values-ru/strings.xml11
-rw-r--r--packages/SettingsLib/res/values-si/strings.xml11
-rw-r--r--packages/SettingsLib/res/values-sk/strings.xml11
-rw-r--r--packages/SettingsLib/res/values-sl/strings.xml11
-rw-r--r--packages/SettingsLib/res/values-sq/strings.xml11
-rw-r--r--packages/SettingsLib/res/values-sr/strings.xml11
-rw-r--r--packages/SettingsLib/res/values-sv/strings.xml14
-rw-r--r--packages/SettingsLib/res/values-sw/strings.xml11
-rw-r--r--packages/SettingsLib/res/values-ta/strings.xml11
-rw-r--r--packages/SettingsLib/res/values-te/strings.xml23
-rw-r--r--packages/SettingsLib/res/values-th/strings.xml11
-rw-r--r--packages/SettingsLib/res/values-tl/strings.xml11
-rw-r--r--packages/SettingsLib/res/values-tr/strings.xml11
-rw-r--r--packages/SettingsLib/res/values-uk/strings.xml14
-rw-r--r--packages/SettingsLib/res/values-ur/strings.xml11
-rw-r--r--packages/SettingsLib/res/values-uz/strings.xml11
-rw-r--r--packages/SettingsLib/res/values-v31/styles.xml4
-rw-r--r--packages/SettingsLib/res/values-vi/strings.xml11
-rw-r--r--packages/SettingsLib/res/values-zh-rCN/strings.xml11
-rw-r--r--packages/SettingsLib/res/values-zh-rHK/strings.xml11
-rw-r--r--packages/SettingsLib/res/values-zh-rTW/strings.xml11
-rw-r--r--packages/SettingsLib/res/values-zu/strings.xml11
-rw-r--r--packages/SettingsLib/res/values/colors.xml3
-rw-r--r--packages/SettingsLib/res/values/strings.xml56
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java28
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java61
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/Utils.java15
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java2
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java20
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/LeAudioProfile.java7
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothAdapter.java5
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java8
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/connectivity/ConnectivitySubsystemsRecoveryManager.java18
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/drawable/UserIconDrawable.java4
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java3
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java16
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/users/AvatarPhotoController.java23
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/users/AvatarPickerActivity.java4
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/users/UserCreatingDialog.java12
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/utils/ThreadUtils.java7
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java38
-rw-r--r--packages/SettingsLib/tests/integ/src/com/android/settingslib/users/AvatarPhotoControllerTest.java28
-rw-r--r--packages/SettingsLib/tests/robotests/res/layout/preference_footer.xml36
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothEventManagerTest.java11
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/connectivity/ConnectivitySubsystemsRecoveryManagerTest.java93
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaDeviceTest.java13
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/FooterPreferenceTest.java12
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiUtilsTest.java21
-rw-r--r--packages/SettingsProvider/res/values-or/strings.xml2
-rw-r--r--packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java2
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java2
-rw-r--r--packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java1
-rw-r--r--packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderTest.java2
-rw-r--r--packages/Shell/AndroidManifest.xml11
-rw-r--r--packages/SystemUI/AndroidManifest.xml9
-rw-r--r--packages/SystemUI/TEST_MAPPING25
-rw-r--r--packages/SystemUI/animation/res/values/ids.xml9
-rw-r--r--packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewLaunchAnimatorController.kt50
-rw-r--r--packages/SystemUI/animation/src/com/android/systemui/animation/ViewBoundAnimator.kt328
-rw-r--r--packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt202
-rw-r--r--packages/SystemUI/monet/src/com/android/systemui/monet/Shades.java3
-rw-r--r--packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java4
-rw-r--r--packages/SystemUI/proguard.flags8
-rw-r--r--packages/SystemUI/res-keyguard/drawable/kg_emergency_button_background.xml3
-rw-r--r--packages/SystemUI/res-keyguard/drawable/media_squiggly_progress.xml17
-rw-r--r--packages/SystemUI/res-keyguard/values-it/strings.xml10
-rw-r--r--packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml10
-rw-r--r--packages/SystemUI/res-keyguard/values/dimens.xml3
-rw-r--r--packages/SystemUI/res-keyguard/values/styles.xml5
-rw-r--r--packages/SystemUI/res/color/kg_user_avatar_frame.xml4
-rw-r--r--packages/SystemUI/res/drawable/ic_circular_unchecked.xml2
-rw-r--r--packages/SystemUI/res/drawable/media_output_status_check.xml2
-rw-r--r--packages/SystemUI/res/drawable/media_output_status_failed.xml2
-rw-r--r--packages/SystemUI/res/drawable/media_ttt_undo_background.xml15
-rw-r--r--packages/SystemUI/res/drawable/user_switcher_icon_large.xml6
-rw-r--r--packages/SystemUI/res/layout/clipboard_edit_text_activity.xml1
-rw-r--r--packages/SystemUI/res/layout/clipboard_overlay.xml4
-rw-r--r--packages/SystemUI/res/layout/dream_overlay_complication_clock_date.xml1
-rw-r--r--packages/SystemUI/res/layout/dream_overlay_complication_weather.xml1
-rw-r--r--packages/SystemUI/res/layout/dream_overlay_status_bar_view.xml11
-rw-r--r--packages/SystemUI/res/layout/media_output_dialog.xml2
-rw-r--r--packages/SystemUI/res/layout/media_output_list_item.xml15
-rw-r--r--packages/SystemUI/res/layout/media_session_view.xml109
-rw-r--r--packages/SystemUI/res/layout/ongoing_privacy_chip.xml5
-rw-r--r--packages/SystemUI/res/layout/screenshot_static.xml14
-rw-r--r--packages/SystemUI/res/layout/status_bar_expanded.xml3
-rw-r--r--packages/SystemUI/res/layout/status_bar_notification_section_header.xml4
-rw-r--r--packages/SystemUI/res/layout/system_event_animation_window.xml14
-rw-r--r--packages/SystemUI/res/values-af/strings.xml43
-rw-r--r--packages/SystemUI/res/values-am/strings.xml43
-rw-r--r--packages/SystemUI/res/values-ar/strings.xml52
-rw-r--r--packages/SystemUI/res/values-as/strings.xml43
-rw-r--r--packages/SystemUI/res/values-az/strings.xml51
-rw-r--r--packages/SystemUI/res/values-b+sr+Latn/strings.xml51
-rw-r--r--packages/SystemUI/res/values-be/strings.xml52
-rw-r--r--packages/SystemUI/res/values-bg/strings.xml54
-rw-r--r--packages/SystemUI/res/values-bn/strings.xml43
-rw-r--r--packages/SystemUI/res/values-bs/strings.xml46
-rw-r--r--packages/SystemUI/res/values-ca/strings.xml52
-rw-r--r--packages/SystemUI/res/values-cs/strings.xml52
-rw-r--r--packages/SystemUI/res/values-da/strings.xml52
-rw-r--r--packages/SystemUI/res/values-de/strings.xml54
-rw-r--r--packages/SystemUI/res/values-el/strings.xml52
-rw-r--r--packages/SystemUI/res/values-en-rAU/strings.xml42
-rw-r--r--packages/SystemUI/res/values-en-rCA/strings.xml42
-rw-r--r--packages/SystemUI/res/values-en-rGB/strings.xml42
-rw-r--r--packages/SystemUI/res/values-en-rIN/strings.xml42
-rw-r--r--packages/SystemUI/res/values-en-rXC/strings.xml33
-rw-r--r--packages/SystemUI/res/values-es-rUS/strings.xml52
-rw-r--r--packages/SystemUI/res/values-es/strings.xml52
-rw-r--r--packages/SystemUI/res/values-et/strings.xml52
-rw-r--r--packages/SystemUI/res/values-eu/strings.xml58
-rw-r--r--packages/SystemUI/res/values-fa/strings.xml56
-rw-r--r--packages/SystemUI/res/values-fi/strings.xml54
-rw-r--r--packages/SystemUI/res/values-fr-rCA/strings.xml52
-rw-r--r--packages/SystemUI/res/values-fr/strings.xml52
-rw-r--r--packages/SystemUI/res/values-gl/strings.xml52
-rw-r--r--packages/SystemUI/res/values-gu/strings.xml52
-rw-r--r--packages/SystemUI/res/values-hi/strings.xml52
-rw-r--r--packages/SystemUI/res/values-hr/strings.xml51
-rw-r--r--packages/SystemUI/res/values-hu/strings.xml42
-rw-r--r--packages/SystemUI/res/values-hy/strings.xml52
-rw-r--r--packages/SystemUI/res/values-in/strings.xml52
-rw-r--r--packages/SystemUI/res/values-is/strings.xml52
-rw-r--r--packages/SystemUI/res/values-it/strings.xml62
-rw-r--r--packages/SystemUI/res/values-iw/strings.xml52
-rw-r--r--packages/SystemUI/res/values-ja/strings.xml42
-rw-r--r--packages/SystemUI/res/values-ka/strings.xml43
-rw-r--r--packages/SystemUI/res/values-kk/strings.xml52
-rw-r--r--packages/SystemUI/res/values-km/strings.xml52
-rw-r--r--packages/SystemUI/res/values-kn/strings.xml45
-rw-r--r--packages/SystemUI/res/values-ko/strings.xml52
-rw-r--r--packages/SystemUI/res/values-ky/strings.xml54
-rw-r--r--packages/SystemUI/res/values-land/styles.xml11
-rw-r--r--packages/SystemUI/res/values-lo/strings.xml43
-rw-r--r--packages/SystemUI/res/values-lt/strings.xml43
-rw-r--r--packages/SystemUI/res/values-lv/strings.xml52
-rw-r--r--packages/SystemUI/res/values-mk/strings.xml52
-rw-r--r--packages/SystemUI/res/values-ml/strings.xml43
-rw-r--r--packages/SystemUI/res/values-mn/strings.xml42
-rw-r--r--packages/SystemUI/res/values-mr/strings.xml43
-rw-r--r--packages/SystemUI/res/values-ms/strings.xml52
-rw-r--r--packages/SystemUI/res/values-my/strings.xml54
-rw-r--r--packages/SystemUI/res/values-nb/strings.xml52
-rw-r--r--packages/SystemUI/res/values-ne/strings.xml42
-rw-r--r--packages/SystemUI/res/values-night/colors.xml10
-rw-r--r--packages/SystemUI/res/values-nl/strings.xml62
-rw-r--r--packages/SystemUI/res/values-or/strings.xml45
-rw-r--r--packages/SystemUI/res/values-pa/strings.xml52
-rw-r--r--packages/SystemUI/res/values-pl/strings.xml52
-rw-r--r--packages/SystemUI/res/values-pt-rBR/strings.xml51
-rw-r--r--packages/SystemUI/res/values-pt-rPT/strings.xml66
-rw-r--r--packages/SystemUI/res/values-pt/strings.xml51
-rw-r--r--packages/SystemUI/res/values-ro/strings.xml43
-rw-r--r--packages/SystemUI/res/values-ru/strings.xml52
-rw-r--r--packages/SystemUI/res/values-si/strings.xml52
-rw-r--r--packages/SystemUI/res/values-sk/strings.xml42
-rw-r--r--packages/SystemUI/res/values-sl/strings.xml43
-rw-r--r--packages/SystemUI/res/values-sq/strings.xml52
-rw-r--r--packages/SystemUI/res/values-sr/strings.xml51
-rw-r--r--packages/SystemUI/res/values-sv/strings.xml52
-rw-r--r--packages/SystemUI/res/values-sw/strings.xml52
-rw-r--r--packages/SystemUI/res/values-sw600dp-land/dimens.xml57
-rw-r--r--packages/SystemUI/res/values-sw600dp-port/dimens.xml2
-rw-r--r--packages/SystemUI/res/values-sw720dp-land/dimens.xml5
-rw-r--r--packages/SystemUI/res/values-sw720dp-port/dimens.xml5
-rw-r--r--packages/SystemUI/res/values-ta/strings.xml46
-rw-r--r--packages/SystemUI/res/values-te/strings.xml45
-rw-r--r--packages/SystemUI/res/values-th/strings.xml54
-rw-r--r--packages/SystemUI/res/values-tl/strings.xml52
-rw-r--r--packages/SystemUI/res/values-tr/strings.xml52
-rw-r--r--packages/SystemUI/res/values-uk/strings.xml52
-rw-r--r--packages/SystemUI/res/values-ur/strings.xml43
-rw-r--r--packages/SystemUI/res/values-uz/strings.xml52
-rw-r--r--packages/SystemUI/res/values-vi/strings.xml52
-rw-r--r--packages/SystemUI/res/values-zh-rCN/strings.xml52
-rw-r--r--packages/SystemUI/res/values-zh-rHK/strings.xml52
-rw-r--r--packages/SystemUI/res/values-zh-rTW/strings.xml52
-rw-r--r--packages/SystemUI/res/values-zu/strings.xml43
-rw-r--r--packages/SystemUI/res/values/colors.xml10
-rw-r--r--packages/SystemUI/res/values/config.xml14
-rw-r--r--packages/SystemUI/res/values/dimens.xml58
-rw-r--r--packages/SystemUI/res/values/strings.xml16
-rw-r--r--packages/SystemUI/res/values/styles.xml3
-rw-r--r--packages/SystemUI/res/xml/media_session_collapsed.xml120
-rw-r--r--packages/SystemUI/res/xml/media_session_expanded.xml101
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/dagger/qualifiers/UiBackground.java (renamed from packages/SystemUI/src/com/android/systemui/dagger/qualifiers/UiBackground.java)0
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/flags/Flag.kt46
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/flags/FlagManager.kt4
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/BitmapUtil.java87
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityOptionsCompat.java18
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java13
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java4
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldSharedComponent.kt2
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldSharedModule.kt7
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt2
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/unfold/updates/hinge/HingeSensorAngleProvider.kt16
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/unfold/util/ScopedUnfoldTransitionProgressProvider.kt2
-rw-r--r--packages/SystemUI/src-debug/com/android/systemui/flags/FlagsModule.kt6
-rw-r--r--packages/SystemUI/src/com/android/keyguard/BouncerPanelExpansionCalculator.kt49
-rw-r--r--packages/SystemUI/src/com/android/keyguard/EmergencyButton.java8
-rw-r--r--packages/SystemUI/src/com/android/keyguard/EmergencyButtonController.java4
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java3
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java12
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardMessageArea.java14
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java13
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java9
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java51
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java6
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java11
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java16
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java14
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java29
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java4
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardVisibilityHelper.java16
-rw-r--r--packages/SystemUI/src/com/android/keyguard/LockIconViewController.java19
-rw-r--r--packages/SystemUI/src/com/android/keyguard/NumPadAnimator.java4
-rw-r--r--packages/SystemUI/src/com/android/keyguard/NumPadButton.java12
-rw-r--r--packages/SystemUI/src/com/android/keyguard/NumPadKey.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/LatencyTester.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/Prefs.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/ScreenDecorHwcLayer.kt22
-rw-r--r--packages/SystemUI/src/com/android/systemui/ScreenDecorations.java229
-rw-r--r--packages/SystemUI/src/com/android/systemui/SystemUIApplication.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialView.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt15
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java126
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/broadcast/BroadcastSender.kt132
-rw-r--r--packages/SystemUI/src/com/android/systemui/charging/WirelessChargingAnimation.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java25
-rw-r--r--packages/SystemUI/src/com/android/systemui/clipboardoverlay/DraggableConstraintLayout.java140
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/CommunalHostView.java45
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/CommunalHostViewController.java396
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/CommunalHostViewPositionAlgorithm.java74
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/CommunalSource.java105
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/CommunalSourceMonitor.java158
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/CommunalSourcePrimer.java180
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/CommunalStateController.java125
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/PackageObserver.java101
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/conditions/CommunalSettingCondition.java67
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/dagger/CommunalModule.java125
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/dagger/CommunalViewComponent.java38
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt33
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/management/ControlsEditingActivity.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/management/StructureAdapter.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt12
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt31
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/GlobalModule.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/GlobalRootComponent.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/decor/RoundedCornerResDelegate.kt201
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeLog.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeService.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeSuppressor.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarView.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarViewController.java36
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/SmartSpaceComplication.java45
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationHostViewController.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/complication/DreamClockDateComplication.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/complication/DreamClockTimeComplication.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamClockDateComplicationComponent.java110
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamClockDateComplicationModule.java71
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamClockTimeComplicationComponent.java115
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamClockTimeComplicationModule.java76
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/RegisteredComplicationsModule.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamModule.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/smartspace/DreamsSmartspaceController.kt219
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandler.java39
-rw-r--r--packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebug.java51
-rw-r--r--packages/SystemUI/src/com/android/systemui/flags/Flags.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivity.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java22
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java138
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaData.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaDataFilter.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt9
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaFlags.kt11
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt19
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaHost.kt18
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java23
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaViewController.kt87
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaViewHolder.kt12
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/PlayerSessionViewHolder.kt18
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt17
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/SeekBarObserver.kt35
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/SeekBarViewModel.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/SquigglyProgress.kt184
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java132
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogFactory.kt18
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupDialog.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelper.kt98
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/ChipInfoCommon.kt30
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt103
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipState.kt65
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/ChipStateReceiver.kt56
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt93
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttReceiverUiEventLogger.kt40
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/ChipStateSender.kt351
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSender.kt110
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderUiEventLogger.kt82
-rw-r--r--packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java298
-rw-r--r--packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java89
-rw-r--r--packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationBarEdgePanel.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java36
-rw-r--r--packages/SystemUI/src/com/android/systemui/power/PowerUI.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt13
-rw-r--r--packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogController.kt31
-rw-r--r--packages/SystemUI/src/com/android/systemui/qrcodescanner/controller/QRCodeScannerController.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/FgsManagerController.kt17
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSFragment.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java52
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java45
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/QRCodeScannerTile.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetAdapter.java50
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/DraggableConstraintLayout.java354
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java71
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/SwipeDismissHandler.java237
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/smartspace/SmartspacePrecondition.kt45
-rw-r--r--packages/SystemUI/src/com/android/systemui/smartspace/SmartspaceTargetFilter.kt49
-rw-r--r--packages/SystemUI/src/com/android/systemui/smartspace/dagger/SmartspaceModule.kt72
-rw-r--r--packages/SystemUI/src/com/android/systemui/smartspace/dagger/SmartspaceViewComponent.kt84
-rw-r--r--packages/SystemUI/src/com/android/systemui/smartspace/filters/LockscreenTargetFilter.kt152
-rw-r--r--packages/SystemUI/src/com/android/systemui/smartspace/preconditions/LockscreenPrecondition.kt95
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt139
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/events/StatusEvent.kt36
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventChipAnimationController.kt297
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventCoordinator.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationScheduler.kt259
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java21
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt13
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ActivityLaunchAnimCoordinator.kt95
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/CommunalCoordinator.java82
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.kt180
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java198
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinator.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinator.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/dagger/CoordinatorsModule.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/NotificationGroupManagerLegacy.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilder.kt9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifPanelEventSource.kt128
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDiffer.kt51
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/KeyguardNotificationVisibilityProvider.kt213
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptLogger.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java32
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java21
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java60
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java35
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java155
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java42
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculator.kt261
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java42
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt50
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java24
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java31
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/LSShadeTransitionLogger.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitchController.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotifActivityLaunchEvents.kt39
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotifActivityLaunchEventsModule.java (renamed from core/java/com/android/internal/logging/UiEvent.java)22
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotifPanelEvents.kt39
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotifPanelEventsModule.java30
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java520
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQSContainerController.kt171
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java25
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java39
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java105
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/CentralSurfacesComponent.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/CentralSurfacesStartableModule.java (renamed from packages/SystemUI/src/com/android/systemui/tv/TvSysUIComponentModule.java)16
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java63
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/StatusBarSystemEventAnimator.kt84
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserSwitcherController.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightControllerImpl.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchController.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java89
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputViewController.kt100
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/tv/TvGlobalRootComponent.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/user/UserSwitcherActivity.kt17
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/Utils.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/animation/AnimationUtil.kt41
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/concurrency/SysUIConcurrencyModule.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/service/PackageObserver.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/settings/SettingsProxy.java71
-rw-r--r--packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java14
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/BouncerPanelExpansionCalculatorTest.kt71
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaControllerTest.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java13
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.kt55
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardVisibilityHelperTest.java92
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java60
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java22
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/animation/ViewBoundAnimatorTest.kt277
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt29
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt10
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java121
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/broadcast/BroadcastSenderTest.kt145
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/communal/CommunalHostViewControllerTest.java242
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/communal/CommunalHostViewPositionAlgorithmTest.java44
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/communal/CommunalSettingConditionTest.java119
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/communal/CommunalSourceMonitorTest.java169
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/communal/CommunalSourcePrimerTest.java205
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/communal/CommunalStateControllerTest.java91
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/communal/PackageObserverTest.java77
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlActionCoordinatorImplTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/controls/ui/DetailDialogTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/decor/RoundedCornerResDelegateTest.kt139
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java16
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java13
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java22
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarViewControllerTest.java50
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/dreams/SmartSpaceComplicationTest.java30
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamClockDateComplicationTest.java62
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamClockTimeComplicationTest.java61
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java121
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsDebugTest.kt47
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java29
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/MediaCarouselControllerTest.kt2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt227
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/MediaDataFilterTest.kt5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt35
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt48
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/MediaViewControllerTest.kt55
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/SeekBarObserverTest.kt41
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/SquigglyProgressTest.kt118
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java28
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java90
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java19
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputGroupDialogTest.java19
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelperTest.kt52
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommonTest.kt158
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt74
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttReceiverUiEventLoggerTest.kt30
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSenderTest.kt172
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderUiEventLoggerTest.kt46
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/monet/ColorSchemeTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java9
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogControllerTest.kt92
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java76
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QRCodeScannerTileTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetAdapterTest.java70
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java10
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/smartspace/DreamSmartspaceControllerTest.kt181
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/smartspace/LockscreenPreconditionTest.kt132
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/smartspace/LockscreenTargetFilterTest.kt149
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java13
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt160
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationUiAdjustmentTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorControllerTest.kt15
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ActivityLaunchAnimCoordinatorTest.kt138
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/CommunalCoordinatorTest.java106
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt31
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.java196
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinatorTest.java12
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/KeyguardNotificationVisibilityProviderTest.java440
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java23
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java15
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java8
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java15
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java15
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculatorTest.kt266
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesTest.java12
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java208
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationQSContainerControllerTest.kt238
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java30
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java76
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchControllerTest.kt5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java12
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerTest.kt3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/animation/AnimationUtilTest.kt51
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/mockito/KotlinMockitoHelpers.kt9
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableNotificationInterruptStateProviderImpl.java10
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java10
-rw-r--r--proto/src/camera.proto2
-rw-r--r--proto/src/metrics_constants/metrics_constants.proto6
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java11
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java72
-rw-r--r--services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java9
-rw-r--r--services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java35
-rw-r--r--services/accessibility/java/com/android/server/accessibility/magnification/GesturesObserver.java2
-rw-r--r--services/accessibility/java/com/android/server/accessibility/magnification/MagnificationGesturesObserver.java7
-rw-r--r--services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java10
-rw-r--r--services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java29
-rw-r--r--services/api/current.txt5
-rw-r--r--services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java12
-rw-r--r--services/autofill/java/com/android/server/autofill/Session.java21
-rw-r--r--services/backup/backuplib/java/com/android/server/backup/TransportManager.java54
-rw-r--r--services/backup/java/com/android/server/backup/UserBackupManagerService.java25
-rw-r--r--services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java6
-rw-r--r--services/cloudsearch/java/com/android/server/cloudsearch/CloudSearchManagerService.java59
-rw-r--r--services/cloudsearch/java/com/android/server/cloudsearch/CloudSearchManagerServiceShellCommand.java7
-rw-r--r--services/cloudsearch/java/com/android/server/cloudsearch/CloudSearchPerUserService.java28
-rw-r--r--services/companion/TEST_MAPPING3
-rw-r--r--services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java83
-rw-r--r--services/companion/java/com/android/server/companion/CompanionApplicationController.java13
-rw-r--r--services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java5
-rw-r--r--services/companion/java/com/android/server/companion/CompanionDeviceServiceConnector.java36
-rw-r--r--services/companion/java/com/android/server/companion/presence/BluetoothCompanionDeviceConnectionListener.java2
-rw-r--r--services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java8
-rw-r--r--services/core/java/android/content/pm/PackageManagerInternal.java14
-rw-r--r--services/core/java/com/android/server/MasterClearReceiver.java4
-rw-r--r--services/core/java/com/android/server/NetworkManagementService.java12
-rw-r--r--services/core/java/com/android/server/NetworkTimeUpdateService.java37
-rw-r--r--services/core/java/com/android/server/NetworkTimeUpdateServiceShellCommand.java46
-rw-r--r--services/core/java/com/android/server/StorageManagerService.java327
-rw-r--r--services/core/java/com/android/server/TelephonyRegistry.java89
-rw-r--r--services/core/java/com/android/server/UiModeManagerService.java40
-rw-r--r--services/core/java/com/android/server/VpnManagerService.java19
-rw-r--r--services/core/java/com/android/server/am/ActiveServices.java34
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerConstants.java119
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerLocal.java5
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java403
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerShellCommand.java15
-rw-r--r--services/core/java/com/android/server/am/AppBatteryExemptionTracker.java82
-rw-r--r--services/core/java/com/android/server/am/AppBatteryTracker.java116
-rw-r--r--services/core/java/com/android/server/am/AppExitInfoTracker.java1
-rw-r--r--services/core/java/com/android/server/am/AppFGSTracker.java157
-rw-r--r--services/core/java/com/android/server/am/AppPermissionTracker.java362
-rw-r--r--services/core/java/com/android/server/am/AppProfiler.java19
-rw-r--r--services/core/java/com/android/server/am/AppRestrictionController.java26
-rw-r--r--services/core/java/com/android/server/am/BaseAppStateTracker.java24
-rw-r--r--services/core/java/com/android/server/am/BatteryExternalStatsWorker.java14
-rw-r--r--services/core/java/com/android/server/am/BatteryStatsService.java3
-rw-r--r--services/core/java/com/android/server/am/BroadcastQueue.java67
-rw-r--r--services/core/java/com/android/server/am/BroadcastRecord.java18
-rw-r--r--services/core/java/com/android/server/am/CachedAppOptimizer.java44
-rw-r--r--services/core/java/com/android/server/am/OomAdjuster.java49
-rw-r--r--services/core/java/com/android/server/am/PendingIntentRecord.java3
-rw-r--r--services/core/java/com/android/server/am/PendingStartActivityUids.java5
-rw-r--r--services/core/java/com/android/server/am/ProcessList.java46
-rw-r--r--services/core/java/com/android/server/am/ProcessRecord.java32
-rw-r--r--services/core/java/com/android/server/am/ServiceRecord.java10
-rw-r--r--services/core/java/com/android/server/am/UserController.java16
-rw-r--r--services/core/java/com/android/server/ambientcontext/AmbientContextManagerPerUserService.java7
-rw-r--r--services/core/java/com/android/server/ambientcontext/AmbientContextShellCommand.java10
-rw-r--r--services/core/java/com/android/server/ambientcontext/RemoteAmbientContextDetectionService.java6
-rw-r--r--services/core/java/com/android/server/app/GameManagerService.java3
-rw-r--r--services/core/java/com/android/server/app/GameServiceProviderInstanceFactoryImpl.java6
-rw-r--r--services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java234
-rw-r--r--services/core/java/com/android/server/app/GameSessionRecord.java18
-rw-r--r--services/core/java/com/android/server/attention/AttentionManagerService.java29
-rw-r--r--services/core/java/com/android/server/audio/AudioService.java33
-rw-r--r--services/core/java/com/android/server/audio/SpatializerHelper.java66
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/BaseClientMonitor.java18
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java14
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/BiometricSchedulerOperation.java5
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/SensorOverlays.java3
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/UserAwareBiometricScheduler.java17
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java4
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceDetectClient.java3
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java3
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java13
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java6
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java9
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java12
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java22
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java22
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java5
-rw-r--r--services/core/java/com/android/server/camera/CameraServiceProxy.java56
-rw-r--r--services/core/java/com/android/server/clipboard/EmulatorClipboardMonitor.java41
-rw-r--r--services/core/java/com/android/server/connectivity/Vpn.java42
-rw-r--r--services/core/java/com/android/server/content/ContentService.java90
-rw-r--r--services/core/java/com/android/server/display/ColorFade.java8
-rw-r--r--services/core/java/com/android/server/display/DisplayPowerController.java25
-rw-r--r--services/core/java/com/android/server/display/LocalDisplayAdapter.java8
-rw-r--r--services/core/java/com/android/server/dreams/DreamManagerService.java4
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java17
-rw-r--r--services/core/java/com/android/server/infra/AbstractMasterSystemService.java303
-rw-r--r--services/core/java/com/android/server/infra/AbstractPerUserSystemService.java123
-rw-r--r--services/core/java/com/android/server/infra/FrameworkResourcesServiceNameResolver.java139
-rw-r--r--services/core/java/com/android/server/infra/ServiceNameResolver.java71
-rw-r--r--services/core/java/com/android/server/input/GestureMonitorSpyWindow.java10
-rw-r--r--services/core/java/com/android/server/inputmethod/HandwritingEventReceiverSurface.java18
-rw-r--r--services/core/java/com/android/server/inputmethod/IInputMethodInvoker.java23
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java11
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodManagerService.java234
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodMenuController.java4
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodUtils.java40
-rw-r--r--services/core/java/com/android/server/inputmethod/OverlayableSystemBooleanResourceWrapper.java159
-rw-r--r--services/core/java/com/android/server/locales/LocaleManagerService.java34
-rw-r--r--services/core/java/com/android/server/locales/TEST_MAPPING9
-rw-r--r--services/core/java/com/android/server/location/LocationPermissions.java7
-rw-r--r--services/core/java/com/android/server/location/gnss/GnssLocationProvider.java1
-rw-r--r--services/core/java/com/android/server/locksettings/LockSettingsService.java172
-rw-r--r--services/core/java/com/android/server/logcat/LogAccessConfirmationActivity.java130
-rw-r--r--services/core/java/com/android/server/logcat/LogAccessDialogActivity.java170
-rw-r--r--services/core/java/com/android/server/logcat/LogcatManagerService.java229
-rw-r--r--services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java17
-rw-r--r--services/core/java/com/android/server/net/NetworkPolicyManagerService.java382
-rwxr-xr-xservices/core/java/com/android/server/notification/NotificationManagerService.java53
-rw-r--r--services/core/java/com/android/server/notification/PermissionHelper.java48
-rw-r--r--services/core/java/com/android/server/notification/PreferencesHelper.java10
-rw-r--r--services/core/java/com/android/server/notification/ZenModeFiltering.java69
-rw-r--r--services/core/java/com/android/server/notification/ZenModeHelper.java5
-rw-r--r--services/core/java/com/android/server/pm/ApexManager.java5
-rw-r--r--services/core/java/com/android/server/pm/ApkChecksums.java2
-rw-r--r--services/core/java/com/android/server/pm/AppDataHelper.java24
-rw-r--r--services/core/java/com/android/server/pm/AppIdSettingMap.java147
-rw-r--r--services/core/java/com/android/server/pm/AppsFilter.java9
-rw-r--r--services/core/java/com/android/server/pm/BackgroundDexOptService.java84
-rw-r--r--services/core/java/com/android/server/pm/BroadcastHelper.java12
-rw-r--r--services/core/java/com/android/server/pm/Computer.java255
-rw-r--r--services/core/java/com/android/server/pm/ComputerEngine.java43
-rw-r--r--services/core/java/com/android/server/pm/ComputerLocked.java853
-rw-r--r--services/core/java/com/android/server/pm/ComputerTracker.java1327
-rw-r--r--services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java34
-rw-r--r--services/core/java/com/android/server/pm/DeletePackageHelper.java84
-rw-r--r--services/core/java/com/android/server/pm/DexOptHelper.java39
-rw-r--r--services/core/java/com/android/server/pm/DomainVerificationConnection.java12
-rw-r--r--services/core/java/com/android/server/pm/DumpHelper.java48
-rw-r--r--services/core/java/com/android/server/pm/DynamicCodeLoggingService.java6
-rw-r--r--services/core/java/com/android/server/pm/IPackageManagerBase.java1189
-rw-r--r--services/core/java/com/android/server/pm/IncrementalProgressListener.java3
-rw-r--r--services/core/java/com/android/server/pm/InitAppsHelper.java (renamed from services/core/java/com/android/server/pm/InitAndSystemPackageHelper.java)212
-rw-r--r--services/core/java/com/android/server/pm/InstallPackageHelper.java209
-rw-r--r--services/core/java/com/android/server/pm/InstallParams.java4
-rw-r--r--services/core/java/com/android/server/pm/Installer.java85
-rw-r--r--services/core/java/com/android/server/pm/IntentResolverInterceptor.java126
-rw-r--r--services/core/java/com/android/server/pm/LauncherAppsService.java20
-rw-r--r--services/core/java/com/android/server/pm/ModuleInfoProvider.java21
-rw-r--r--services/core/java/com/android/server/pm/MovePackageHelper.java129
-rw-r--r--services/core/java/com/android/server/pm/OWNERS2
-rw-r--r--services/core/java/com/android/server/pm/OtaDexoptService.java5
-rw-r--r--services/core/java/com/android/server/pm/PackageDexOptimizer.java131
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerService.java66
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerSession.java100
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerInternalBase.java751
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerLocal.java52
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerNative.java25
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java5533
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java2
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerServiceUtils.java2
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerShellCommand.java32
-rw-r--r--services/core/java/com/android/server/pm/PackageRemovedInfo.java49
-rw-r--r--services/core/java/com/android/server/pm/PackageSender.java7
-rw-r--r--services/core/java/com/android/server/pm/PackageSessionVerifier.java36
-rw-r--r--services/core/java/com/android/server/pm/PackageSetting.java1
-rw-r--r--services/core/java/com/android/server/pm/PreferredActivityHelper.java156
-rw-r--r--services/core/java/com/android/server/pm/PreferredComponent.java11
-rw-r--r--services/core/java/com/android/server/pm/RemovePackageHelper.java16
-rw-r--r--services/core/java/com/android/server/pm/ResolveIntentHelper.java12
-rw-r--r--services/core/java/com/android/server/pm/ScanPackageUtils.java30
-rw-r--r--services/core/java/com/android/server/pm/ScanResult.java4
-rw-r--r--services/core/java/com/android/server/pm/Settings.java177
-rw-r--r--services/core/java/com/android/server/pm/SharedLibrariesImpl.java4
-rw-r--r--services/core/java/com/android/server/pm/SharedUidMigration.java99
-rw-r--r--services/core/java/com/android/server/pm/SharedUserSetting.java19
-rw-r--r--services/core/java/com/android/server/pm/ShortcutPackage.java72
-rw-r--r--services/core/java/com/android/server/pm/ShortcutService.java3
-rw-r--r--services/core/java/com/android/server/pm/StagingManager.java28
-rw-r--r--services/core/java/com/android/server/pm/StorageEventHelper.java15
-rw-r--r--services/core/java/com/android/server/pm/SuspendPackageHelper.java106
-rw-r--r--services/core/java/com/android/server/pm/TEST_MAPPING6
-rw-r--r--services/core/java/com/android/server/pm/UserDataPreparer.java7
-rw-r--r--services/core/java/com/android/server/pm/UserManagerInternal.java8
-rw-r--r--services/core/java/com/android/server/pm/UserManagerService.java190
-rw-r--r--services/core/java/com/android/server/pm/UserTypeDetails.java20
-rw-r--r--services/core/java/com/android/server/pm/UserTypeFactory.java4
-rw-r--r--services/core/java/com/android/server/pm/VerificationParams.java25
-rw-r--r--services/core/java/com/android/server/pm/WatchedIntentFilter.java2
-rw-r--r--services/core/java/com/android/server/pm/dex/ArtManagerService.java21
-rw-r--r--services/core/java/com/android/server/pm/dex/DexManager.java32
-rw-r--r--services/core/java/com/android/server/pm/dex/DynamicCodeLogger.java32
-rw-r--r--services/core/java/com/android/server/pm/dex/OWNERS1
-rw-r--r--services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java6
-rw-r--r--services/core/java/com/android/server/pm/permission/OneTimePermissionUserManager.java4
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerService.java6
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java31
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java22
-rw-r--r--services/core/java/com/android/server/pm/pkg/parsing/ParsingPackage.java5
-rw-r--r--services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageImpl.java30
-rw-r--r--services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageRead.java5
-rw-r--r--services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java55
-rw-r--r--services/core/java/com/android/server/pm/pkg/parsing/ParsingUtils.java1
-rw-r--r--services/core/java/com/android/server/pm/pkg/parsing/PkgWithoutStateAppInfo.java5
-rw-r--r--services/core/java/com/android/server/policy/KeyCombinationManager.java24
-rw-r--r--services/core/java/com/android/server/policy/PermissionPolicyInternal.java17
-rw-r--r--services/core/java/com/android/server/policy/PermissionPolicyService.java87
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java23
-rw-r--r--services/core/java/com/android/server/power/ShutdownThread.java4
-rw-r--r--services/core/java/com/android/server/slice/SliceManagerService.java2
-rw-r--r--services/core/java/com/android/server/soundtrigger_middleware/AidlUtil.java71
-rw-r--r--services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHalConcurrentCaptureHandler.java24
-rw-r--r--services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java48
-rw-r--r--services/core/java/com/android/server/stats/pull/StatsPullAtomService.java71
-rw-r--r--services/core/java/com/android/server/statusbar/StatusBarManagerService.java49
-rw-r--r--services/core/java/com/android/server/storage/DeviceStorageMonitorService.java15
-rw-r--r--services/core/java/com/android/server/trust/TEST_MAPPING15
-rw-r--r--services/core/java/com/android/server/trust/TrustAgentWrapper.java38
-rw-r--r--services/core/java/com/android/server/trust/TrustManagerService.java91
-rw-r--r--services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java125
-rw-r--r--services/core/java/com/android/server/utils/TimingsTraceAndSlog.java2
-rw-r--r--services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java40
-rw-r--r--services/core/java/com/android/server/vibrator/VibrationSettings.java12
-rw-r--r--services/core/java/com/android/server/vibrator/VibrationStepConductor.java22
-rw-r--r--services/core/java/com/android/server/vibrator/VibrationThread.java5
-rw-r--r--services/core/java/com/android/server/vibrator/VibratorManagerService.java98
-rw-r--r--services/core/java/com/android/server/wm/AccessibilityWindowsPopulator.java14
-rw-r--r--services/core/java/com/android/server/wm/ActivityClientController.java16
-rw-r--r--services/core/java/com/android/server/wm/ActivityInterceptorCallback.java6
-rw-r--r--services/core/java/com/android/server/wm/ActivityMetricsLogger.java67
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java140
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecordInputSink.java7
-rw-r--r--services/core/java/com/android/server/wm/ActivityStartInterceptor.java4
-rw-r--r--services/core/java/com/android/server/wm/ActivityStarter.java42
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java11
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerService.java34
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskSupervisor.java26
-rw-r--r--services/core/java/com/android/server/wm/AsyncRotationController.java7
-rw-r--r--services/core/java/com/android/server/wm/BLASTSync.md108
-rw-r--r--services/core/java/com/android/server/wm/BackNavigationController.java120
-rw-r--r--services/core/java/com/android/server/wm/ContentRecorder.java154
-rw-r--r--services/core/java/com/android/server/wm/DisplayArea.java2
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java277
-rw-r--r--services/core/java/com/android/server/wm/DisplayPolicy.java154
-rw-r--r--services/core/java/com/android/server/wm/DisplayWindowPolicyControllerHelper.java19
-rw-r--r--services/core/java/com/android/server/wm/DragState.java40
-rw-r--r--services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java5
-rw-r--r--services/core/java/com/android/server/wm/HighRefreshRateDenylist.java18
-rw-r--r--services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java5
-rw-r--r--services/core/java/com/android/server/wm/InputConfigAdapter.java138
-rw-r--r--services/core/java/com/android/server/wm/InputConsumerImpl.java12
-rw-r--r--services/core/java/com/android/server/wm/InputMonitor.java60
-rw-r--r--services/core/java/com/android/server/wm/InputWindowHandleWrapper.java65
-rw-r--r--services/core/java/com/android/server/wm/InsetsPolicy.java11
-rw-r--r--services/core/java/com/android/server/wm/InsetsSourceProvider.java54
-rw-r--r--services/core/java/com/android/server/wm/InsetsStateController.java18
-rw-r--r--services/core/java/com/android/server/wm/KeyguardController.java13
-rw-r--r--services/core/java/com/android/server/wm/LaunchParamsController.java12
-rw-r--r--services/core/java/com/android/server/wm/Letterbox.java7
-rw-r--r--services/core/java/com/android/server/wm/LetterboxUiController.java8
-rw-r--r--services/core/java/com/android/server/wm/MirrorActiveUids.java55
-rw-r--r--services/core/java/com/android/server/wm/PinnedTaskController.java12
-rw-r--r--services/core/java/com/android/server/wm/RecentsAnimationController.java5
-rw-r--r--services/core/java/com/android/server/wm/RefreshRatePolicy.java52
-rw-r--r--services/core/java/com/android/server/wm/RootWindowContainer.java180
-rw-r--r--services/core/java/com/android/server/wm/RunningTasks.java29
-rw-r--r--services/core/java/com/android/server/wm/Session.java8
-rw-r--r--services/core/java/com/android/server/wm/Task.java72
-rw-r--r--services/core/java/com/android/server/wm/TaskDisplayArea.java14
-rw-r--r--services/core/java/com/android/server/wm/TaskFragment.java50
-rw-r--r--services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java10
-rw-r--r--services/core/java/com/android/server/wm/TaskOrganizerController.java15
-rw-r--r--services/core/java/com/android/server/wm/TaskPositioner.java20
-rw-r--r--services/core/java/com/android/server/wm/TaskPositioningController.java15
-rw-r--r--services/core/java/com/android/server/wm/Transition.java8
-rw-r--r--services/core/java/com/android/server/wm/TransitionController.java2
-rw-r--r--services/core/java/com/android/server/wm/WindowContainer.java20
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerConstants.java6
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerInternal.java9
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java116
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerShellCommand.java7
-rw-r--r--services/core/java/com/android/server/wm/WindowOrganizerController.java66
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java139
-rw-r--r--services/core/java/com/android/server/wm/WindowStateAnimator.java46
-rw-r--r--services/core/jni/gnss/MeasurementCorrections.cpp133
-rw-r--r--services/core/jni/gnss/MeasurementCorrections.h20
-rw-r--r--services/core/jni/onload.cpp1
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java11
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java21
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DeviceManagementResourcesProvider.java53
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java404
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java2
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/Owners.java11
-rw-r--r--services/incremental/IncrementalService.cpp7
-rw-r--r--services/java/com/android/server/SystemServer.java28
-rw-r--r--services/midi/java/com/android/server/midi/MidiService.java84
-rw-r--r--services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java18
-rw-r--r--services/robotests/backup/src/com/android/server/backup/TransportManagerTest.java84
-rw-r--r--services/robotests/src/com/android/server/testing/shadows/ShadowApplicationPackageManager.java20
-rw-r--r--services/tests/PackageManagerComponentOverrideTests/src/com/android/server/pm/test/override/PackageManagerComponentLabelIconOverrideTest.kt22
-rw-r--r--services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt6
-rw-r--r--services/tests/mockingservicestests/AndroidManifest.xml1
-rw-r--r--services/tests/mockingservicestests/src/android/service/games/GameSessionTest.java15
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java4
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/am/BackgroundRestrictionTest.java508
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/app/GameServiceProviderInstanceImplTest.java304
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java62
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/pm/BackgroundDexOptServiceUnitTest.java43
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/pm/OWNERS1
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/pm/PackageFreezerTest.kt18
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/pm/PackageManagerServiceHibernationTests.kt7
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/pm/SharedLibrariesImplTest.kt28
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/pm/StagingManagerTest.java35
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/pm/SuspendPackageHelperTest.kt57
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/pm/dex/DexManagerTests.java4
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/tare/AgentTest.java9
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/tare/ScribeTest.java8
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/utils/TimingsTraceAndSlogTest.java165
-rw-r--r--services/tests/servicestests/Android.bp1
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java38
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java12
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerOperationTest.java66
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java6
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/sensors/SensorOverlaysTest.java12
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/sensors/UserAwareBiometricSchedulerTest.java82
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java5
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java5
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java42
-rw-r--r--services/tests/servicestests/src/com/android/server/display/ColorFadeTest.java75
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java22
-rw-r--r--services/tests/servicestests/src/com/android/server/job/JobStoreTest.java9
-rw-r--r--services/tests/servicestests/src/com/android/server/job/PendingJobQueueTest.java452
-rw-r--r--services/tests/servicestests/src/com/android/server/locales/SystemAppUpdateTrackerTest.java29
-rw-r--r--services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/CrossProfileAppsServiceImplTest.java92
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java12
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java147
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java55
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java59
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java9
-rw-r--r--services/tests/servicestests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImplTest.java10
-rw-r--r--services/tests/servicestests/src/com/android/server/statusbar/StatusBarManagerServiceTest.java121
-rw-r--r--services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java32
-rw-r--r--services/tests/servicestests/src/com/android/server/vibrator/VibrationSettingsTest.java14
-rw-r--r--services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java25
-rwxr-xr-xservices/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java24
-rwxr-xr-xservices/tests/uiservicestests/src/com/android/server/notification/NotificationPermissionMigrationTest.java10
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/PermissionHelperTest.java44
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java34
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/ZenModeFilteringTest.java42
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java30
-rw-r--r--services/tests/wmtests/src/com/android/server/policy/KeyCombinationTests.java69
-rw-r--r--services/tests/wmtests/src/com/android/server/policy/OWNERS1
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java15
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java42
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java10
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java47
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java3
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java62
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java145
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java43
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayWindowPolicyControllerHelperTests.java42
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/HighRefreshRateDenylistTest.java6
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java1
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java55
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/MockSurfaceControlBuilder.java6
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RefreshRatePolicyTest.java62
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java10
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java35
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/StubTransaction.java15
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java74
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRuleTest.java73
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java51
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java21
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskTests.java35
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TestIWindow.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TransitionTests.java87
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowContainerInsetsSourceProviderTest.java9
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowLayoutTests.java136
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java90
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java3
-rw-r--r--services/translation/java/com/android/server/translation/TranslationManagerServiceImpl.java48
-rw-r--r--services/usage/java/com/android/server/usage/UsageStatsService.java75
-rw-r--r--services/usb/java/com/android/server/usb/UsbDeviceManager.java2
-rw-r--r--services/usb/java/com/android/server/usb/UsbHostManager.java10
-rw-r--r--services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java82
-rw-r--r--services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java204
-rw-r--r--services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordMetricsLogger.java154
-rw-r--r--services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java24
-rw-r--r--telecomm/java/android/telecom/Call.java15
-rw-r--r--telecomm/java/android/telecom/Connection.java12
-rwxr-xr-xtelecomm/java/android/telecom/ConnectionService.java7
-rw-r--r--telephony/java/android/telephony/CarrierConfigManager.java14
-rw-r--r--telephony/java/android/telephony/SubscriptionManager.java5
-rw-r--r--telephony/java/android/telephony/TelephonyManager.java203
-rw-r--r--telephony/java/android/telephony/data/ApnSetting.java10
-rw-r--r--telephony/java/android/telephony/data/DataService.java13
-rw-r--r--telephony/java/android/telephony/data/DataServiceCallback.java12
-rw-r--r--telephony/java/android/telephony/data/EpsBearerQosSessionAttributes.java7
-rw-r--r--telephony/java/android/telephony/data/QualifiedNetworksService.java26
-rw-r--r--telephony/java/android/telephony/ims/ImsMmTelManager.java4
-rw-r--r--telephony/java/android/telephony/ims/aidl/SipDelegateAidlWrapper.java12
-rw-r--r--telephony/java/com/android/internal/telephony/ITelephony.aidl21
-rw-r--r--telephony/java/com/android/internal/telephony/TelephonyIntents.java20
-rw-r--r--tests/BandwidthTests/src/com/android/tests/bandwidthenforcement/BandwidthEnforcementTestService.java6
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/LaunchAppShowImeAndDialogThemeAppTest.kt1
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt9
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest_ShellTransit.kt49
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt2
-rw-r--r--tests/HandwritingIme/src/com/google/android/test/handwritingime/HandwritingIme.java10
-rw-r--r--tests/HandwritingIme/src/com/google/android/test/handwritingime/InkView.java4
-rw-r--r--tests/SoundTriggerTestApp/OWNERS1
-rw-r--r--tests/TrustTests/Android.bp2
-rw-r--r--tests/TrustTests/AndroidManifest.xml12
-rw-r--r--tests/TrustTests/TEST_MAPPING15
-rw-r--r--tests/TrustTests/src/android/trust/test/GrantAndRevokeTrustTest.kt19
-rw-r--r--tests/TrustTests/src/android/trust/test/LockUserTest.kt6
-rw-r--r--tests/TrustTests/src/android/trust/test/TemporaryAndRenewableTrustTest.kt159
-rw-r--r--tests/TrustTests/src/android/trust/test/UserUnlockRequestTest.kt37
-rw-r--r--tests/TrustTests/src/android/trust/test/lib/LockStateTrackingRule.kt35
-rw-r--r--tests/TrustTests/src/android/trust/test/lib/ScreenLockRule.kt61
-rw-r--r--tests/componentalias/src/android/content/componentalias/tests/BaseComponentAliasTest.java2
-rw-r--r--tests/componentalias/src/android/content/componentalias/tests/ComponentAliasEnableWithDeviceConfigTest.java2
-rw-r--r--tests/componentalias/src/android/content/componentalias/tests/ComponentAliasNotSupportedOnUserBuildTest.java2
-rw-r--r--tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java40
-rw-r--r--tools/aapt2/ResourceParser.cpp7
-rwxr-xr-xtools/aapt2/tools/finalize_res.py141
-rwxr-xr-xtools/finalize_res/finalize_res.py41
-rw-r--r--tools/processors/staledataclass/src/android/processor/staledataclass/StaleDataclassProcessor.kt18
-rw-r--r--tools/traceinjection/Android.bp49
-rw-r--r--tools/traceinjection/manifest.txt1
-rw-r--r--tools/traceinjection/src/com/android/traceinjection/Main.java121
-rw-r--r--tools/traceinjection/src/com/android/traceinjection/TraceInjectionClassVisitor.java41
-rw-r--r--tools/traceinjection/src/com/android/traceinjection/TraceInjectionConfiguration.java52
-rw-r--r--tools/traceinjection/src/com/android/traceinjection/TraceInjectionMethodAdapter.java183
-rw-r--r--tools/traceinjection/test/com/android/traceinjection/InjectionTests.java246
-rw-r--r--tools/traceinjection/test/com/android/traceinjection/Trace.java (renamed from packages/SystemUI/src/com/android/systemui/dagger/WMModule.java)14
-rw-r--r--tools/validatekeymaps/Android.bp2
-rw-r--r--wifi/java/src/android/net/wifi/nl80211/WifiNl80211Manager.java19
1799 files changed, 53797 insertions, 29296 deletions
diff --git a/Android.bp b/Android.bp
index 753cefc38ed6..149b22355c58 100644
--- a/Android.bp
+++ b/Android.bp
@@ -97,6 +97,7 @@ filegroup {
":platform-compat-native-aidl",
// AIDL sources from external directories
+ ":android.hardware.gnss-V2-java-source",
":android.hardware.graphics.common-V3-java-source",
":android.hardware.security.keymint-V2-java-source",
":android.hardware.security.secureclock-V1-java-source",
@@ -328,6 +329,7 @@ java_defaults {
"modules-utils-preconditions",
"modules-utils-synchronous-result-receiver",
"modules-utils-os",
+ "modules-utils-uieventlogger-interface",
"framework-permission-aidl-java",
"spatializer-aidl-java",
"audiopolicy-types-aidl-java",
diff --git a/ApiDocs.bp b/ApiDocs.bp
index 7f5d4a3fd504..038ee6501ded 100644
--- a/ApiDocs.bp
+++ b/ApiDocs.bp
@@ -81,7 +81,6 @@ stubs_defaults {
":framework-adservices-sources",
":framework-appsearch-sources",
- ":framework-auxiliary-sources",
":framework-connectivity-sources",
":framework-bluetooth-sources",
":framework-connectivity-tiramisu-updatable-sources",
diff --git a/ProtoLibraries.bp b/ProtoLibraries.bp
index db5ba2fd031f..0f3ea0ca298f 100644
--- a/ProtoLibraries.bp
+++ b/ProtoLibraries.bp
@@ -33,13 +33,14 @@ gensrcs {
"&& $(location soong_zip) -jar -o $(out) -C $(genDir)/$(in) -D $(genDir)/$(in)",
srcs: [
+ ":framework-connectivity-protos",
":ipconnectivity-proto-src",
":libstats_atom_enum_protos",
":libstats_atom_message_protos",
":libtombstone_proto-src",
"core/proto/**/*.proto",
"libs/incident/**/*.proto",
- ":service-permission-protos",
+ ":service-permission-streaming-proto-sources",
],
output_extension: "srcjar",
}
@@ -63,12 +64,13 @@ gensrcs {
" $(in)",
srcs: [
+ ":framework-connectivity-protos",
":ipconnectivity-proto-src",
":libstats_atom_enum_protos",
":libstats_atom_message_protos",
"core/proto/**/*.proto",
"libs/incident/**/*.proto",
- ":service-permission-protos",
+ ":service-permission-streaming-proto-sources",
],
output_extension: "proto.h",
@@ -78,6 +80,7 @@ gensrcs {
java_library_host {
name: "platformprotos",
srcs: [
+ ":framework-connectivity-protos",
":ipconnectivity-proto-src",
":libstats_atom_enum_protos",
":libstats_atom_message_protos",
@@ -87,7 +90,7 @@ java_library_host {
"cmds/statsd/src/**/*.proto",
"core/proto/**/*.proto",
"libs/incident/proto/**/*.proto",
- ":service-permission-protos",
+ ":service-permission-streaming-proto-sources",
],
proto: {
include_dirs: [
@@ -117,12 +120,13 @@ java_library {
],
sdk_version: "9",
srcs: [
+ ":framework-connectivity-protos",
":ipconnectivity-proto-src",
":libstats_atom_enum_protos",
":libstats_atom_message_protos",
"core/proto/**/*.proto",
"libs/incident/proto/android/os/**/*.proto",
- ":service-permission-protos",
+ ":service-permission-streaming-proto-sources",
],
// Protos have lots of MissingOverride and similar.
errorprone: {
@@ -139,12 +143,13 @@ java_library {
},
srcs: [
+ ":framework-connectivity-protos",
":ipconnectivity-proto-src",
":libstats_atom_enum_protos",
":libstats_atom_message_protos",
"core/proto/**/*.proto",
"libs/incident/proto/android/os/**/*.proto",
- ":service-permission-protos",
+ ":service-permission-streaming-proto-sources",
],
exclude_srcs: [
"core/proto/android/privacy.proto",
@@ -176,11 +181,12 @@ cc_defaults {
],
srcs: [
+ ":framework-connectivity-protos",
":ipconnectivity-proto-src",
":libstats_atom_enum_protos",
":libstats_atom_message_protos",
"core/proto/**/*.proto",
- ":service-permission-protos",
+ ":service-permission-streaming-proto-sources",
],
}
diff --git a/StubLibraries.bp b/StubLibraries.bp
index fef95e813ec7..32101c791242 100644
--- a/StubLibraries.bp
+++ b/StubLibraries.bp
@@ -208,6 +208,16 @@ droidstubs {
/////////////////////////////////////////////////////////////////////
java_defaults {
+ name: "android.jar_defaults",
+ sdk_version: "none",
+ system_modules: "none",
+ java_version: "1.8",
+ compile_dex: true,
+ defaults_visibility: ["//visibility:private"],
+ visibility: ["//visibility:public"],
+}
+
+java_defaults {
name: "android-non-updatable_defaults_stubs_current",
libs: ["stub-annotations"],
static_libs: ["framework-res-package-jar"], // Export package of framework-res
diff --git a/apct-tests/perftests/windowmanager/src/android/wm/RelayoutPerfTest.java b/apct-tests/perftests/windowmanager/src/android/wm/RelayoutPerfTest.java
index 4ad015dcc4e5..c92c6340a6b4 100644
--- a/apct-tests/perftests/windowmanager/src/android/wm/RelayoutPerfTest.java
+++ b/apct-tests/perftests/windowmanager/src/android/wm/RelayoutPerfTest.java
@@ -20,6 +20,7 @@ import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentat
import android.app.Activity;
import android.content.Context;
+import android.os.Bundle;
import android.os.RemoteException;
import android.perftests.utils.BenchmarkState;
import android.perftests.utils.PerfStatusReporter;
@@ -153,7 +154,8 @@ public class RelayoutPerfTest extends WindowManagerPerfTestBase
while (state.keepRunning()) {
session.relayout(mWindow, mParams, mWidth, mHeight,
mViewVisibility.getAsInt(), mFlags, mOutFrames,
- mOutMergedConfiguration, mOutSurfaceControl, mOutInsetsState, mOutControls);
+ mOutMergedConfiguration, mOutSurfaceControl, mOutInsetsState, mOutControls,
+ new Bundle());
}
}
}
diff --git a/apex/jobscheduler/framework/java/android/app/AlarmManager.java b/apex/jobscheduler/framework/java/android/app/AlarmManager.java
index 66767e21a2e7..da429af7e351 100644
--- a/apex/jobscheduler/framework/java/android/app/AlarmManager.java
+++ b/apex/jobscheduler/framework/java/android/app/AlarmManager.java
@@ -210,6 +210,8 @@ public class AlarmManager {
* on how frequently it can be scheduled. Only available (and automatically applied) to
* system alarms.
*
+ * <p>Note that alarms set with a {@link WorkSource} <b>do not</b> get this flag.
+ *
* @hide
*/
@UnsupportedAppUsage
diff --git a/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java b/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java
index e2426c2f1758..f822a188c99c 100644
--- a/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java
+++ b/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java
@@ -2,6 +2,7 @@ package com.android.server.usage;
import android.annotation.CurrentTimeMillisLong;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.ActivityManager.ProcessState;
import android.app.usage.AppStandbyInfo;
@@ -237,4 +238,11 @@ public interface AppStandbyInternal {
*/
@ProcessState
int getBroadcastResponseFgThresholdState();
+
+ /**
+ * Return the last known value corresponding to the {@code key} from
+ * {@link android.provider.DeviceConfig#NAMESPACE_APP_STANDBY} in AppStandbyController.
+ */
+ @Nullable
+ String getAppStandbyConstant(@NonNull String key);
}
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 90ec7000c6d1..528be3ca5e4b 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
@@ -4891,13 +4891,15 @@ public class AlarmManagerService extends SystemService {
filter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
filter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
filter.addDataScheme(IntentFilter.SCHEME_PACKAGE);
- getContext().registerReceiver(this, filter);
+ getContext().registerReceiverForAllUsers(this, filter,
+ /* broadcastPermission */ null, /* scheduler */ null);
// Register for events related to sdcard installation.
IntentFilter sdFilter = new IntentFilter();
sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
sdFilter.addAction(Intent.ACTION_USER_STOPPED);
sdFilter.addAction(Intent.ACTION_UID_REMOVED);
- getContext().registerReceiver(this, sdFilter);
+ getContext().registerReceiverForAllUsers(this, sdFilter,
+ /* broadcastPermission */ null, /* scheduler */ null);
}
@Override
@@ -4915,9 +4917,6 @@ public class AlarmManagerService extends SystemService {
}
}
return;
- case Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE:
- pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
- break;
case Intent.ACTION_USER_STOPPED:
final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
if (userHandle >= 0) {
@@ -4932,6 +4931,18 @@ public class AlarmManagerService extends SystemService {
mRemovalHistory.delete(uid);
mLastOpScheduleExactAlarm.delete(uid);
return;
+ case Intent.ACTION_PACKAGE_ADDED:
+ if (intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
+ 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);
+ break;
case Intent.ACTION_PACKAGE_REMOVED:
if (intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
// This package is being updated; don't kill its alarms.
@@ -4950,15 +4961,6 @@ public class AlarmManagerService extends SystemService {
}
}
break;
- case Intent.ACTION_PACKAGE_ADDED:
- if (intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
- 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;
}
if (pkgList != null && (pkgList.length > 0)) {
for (String pkg : pkgList) {
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 18f63b7ad902..23056b5670b9 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
@@ -17,6 +17,7 @@
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;
import android.annotation.IntDef;
@@ -32,9 +33,11 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.UserInfo;
+import android.os.BatteryStats;
import android.os.Handler;
import android.os.PowerManager;
import android.os.RemoteException;
+import android.os.ServiceManager;
import android.os.UserHandle;
import android.provider.DeviceConfig;
import android.util.ArraySet;
@@ -51,19 +54,24 @@ import android.util.proto.ProtoOutputStream;
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.app.IBatteryStats;
import com.android.internal.app.procstats.ProcessStats;
import com.android.internal.util.StatLogger;
import com.android.server.JobSchedulerBackgroundThread;
import com.android.server.LocalServices;
import com.android.server.job.controllers.JobStatus;
import com.android.server.job.controllers.StateController;
+import com.android.server.job.restrictions.JobRestriction;
import com.android.server.pm.UserManagerInternal;
+import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.function.Consumer;
+import java.util.function.Predicate;
/**
* This class decides, given the various configuration and the system status, which jobs can start
@@ -278,6 +286,11 @@ class JobConcurrencyManager {
String[] mRecycledShouldStopJobReason = new String[MAX_JOB_CONTEXTS_COUNT];
+ /**
+ * Set of JobServiceContexts that we use to run jobs.
+ */
+ final List<JobServiceContext> mActiveServices = new ArrayList<>();
+
private final ArraySet<JobStatus> mRunningJobs = new ArraySet<>();
private final WorkCountTracker mWorkCountTracker = new WorkCountTracker();
@@ -358,6 +371,20 @@ class JobConcurrencyManager {
onInteractiveStateChanged(mPowerManager.isInteractive());
}
+ /**
+ * Called when the boot phase reaches
+ * {@link com.android.server.SystemService#PHASE_THIRD_PARTY_APPS_CAN_START}.
+ */
+ void onThirdPartyAppsCanStart() {
+ final IBatteryStats batteryStats = IBatteryStats.Stub.asInterface(
+ ServiceManager.getService(BatteryStats.SERVICE_NAME));
+ for (int i = 0; i < MAX_JOB_CONTEXTS_COUNT; i++) {
+ mActiveServices.add(
+ new JobServiceContext(mService, this, batteryStats,
+ mService.mJobPackageTracker, mContext.getMainLooper()));
+ }
+ }
+
@GuardedBy("mLock")
void onAppRemovedLocked(String pkgName, int uid) {
final PackageStats packageStats = mActivePkgStats.get(UserHandle.getUserId(uid), pkgName);
@@ -390,6 +417,7 @@ class JobConcurrencyManager {
case PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED:
if (mPowerManager != null && mPowerManager.isDeviceIdleMode()) {
synchronized (mLock) {
+ stopUnexemptedJobsForDoze();
stopLongRunningJobsLocked("deep doze");
}
}
@@ -471,6 +499,11 @@ class JobConcurrencyManager {
}
@GuardedBy("mLock")
+ ArraySet<JobStatus> getRunningJobsLocked() {
+ return mRunningJobs;
+ }
+
+ @GuardedBy("mLock")
boolean isJobRunningLocked(JobStatus job) {
return mRunningJobs.contains(job);
}
@@ -546,7 +579,7 @@ class JobConcurrencyManager {
}
final List<JobStatus> pendingJobs = mService.mPendingJobs;
- final List<JobServiceContext> activeServices = mService.mActiveServices;
+ final List<JobServiceContext> activeServices = mActiveServices;
// To avoid GC churn, we recycle the arrays.
JobStatus[] contextIdToJobMap = mRecycledAssignContextIdToJobMap;
@@ -719,9 +752,44 @@ class JobConcurrencyManager {
}
@GuardedBy("mLock")
+ boolean stopJobOnServiceContextLocked(JobStatus job,
+ @JobParameters.StopReason int reason, int internalReasonCode, String debugReason) {
+ if (!mRunningJobs.contains(job)) {
+ return false;
+ }
+
+ for (int i = 0; i < mActiveServices.size(); i++) {
+ JobServiceContext jsc = mActiveServices.get(i);
+ final JobStatus executing = jsc.getRunningJobLocked();
+ if (executing != null && executing.matches(job.getUid(), job.getJobId())) {
+ jsc.cancelExecutingJobLocked(reason, internalReasonCode, debugReason);
+ return true;
+ }
+ }
+ Slog.wtf(TAG, "Couldn't find running job on a context");
+ mRunningJobs.remove(job);
+ return false;
+ }
+
+ @GuardedBy("mLock")
+ private void stopUnexemptedJobsForDoze() {
+ // When becoming idle, make sure no jobs are actively running,
+ // except those using the idle exemption flag.
+ for (int i = 0; i < mActiveServices.size(); i++) {
+ JobServiceContext jsc = mActiveServices.get(i);
+ final JobStatus executing = jsc.getRunningJobLocked();
+ if (executing != null && !executing.canRunInDoze()) {
+ jsc.cancelExecutingJobLocked(JobParameters.STOP_REASON_DEVICE_STATE,
+ JobParameters.INTERNAL_STOP_REASON_DEVICE_IDLE,
+ "cancelled due to doze");
+ }
+ }
+ }
+
+ @GuardedBy("mLock")
private void stopLongRunningJobsLocked(@NonNull String debugReason) {
for (int i = 0; i < MAX_JOB_CONTEXTS_COUNT; ++i) {
- final JobServiceContext jsc = mService.mActiveServices.get(i);
+ final JobServiceContext jsc = mActiveServices.get(i);
final JobStatus jobStatus = jsc.getRunningJobLocked();
if (jobStatus != null && !jsc.isWithinExecutionGuaranteeTime()) {
@@ -731,6 +799,41 @@ class JobConcurrencyManager {
}
}
+ @GuardedBy("mLock")
+ void stopNonReadyActiveJobsLocked() {
+ for (int i = 0; i < mActiveServices.size(); i++) {
+ JobServiceContext serviceContext = mActiveServices.get(i);
+ final JobStatus running = serviceContext.getRunningJobLocked();
+ if (running == null) {
+ continue;
+ }
+ if (!running.isReady()) {
+ if (running.getEffectiveStandbyBucket() == RESTRICTED_INDEX
+ && running.getStopReason() == JobParameters.STOP_REASON_APP_STANDBY) {
+ serviceContext.cancelExecutingJobLocked(
+ running.getStopReason(),
+ JobParameters.INTERNAL_STOP_REASON_RESTRICTED_BUCKET,
+ "cancelled due to restricted bucket");
+ } else {
+ serviceContext.cancelExecutingJobLocked(
+ running.getStopReason(),
+ JobParameters.INTERNAL_STOP_REASON_CONSTRAINTS_NOT_SATISFIED,
+ "cancelled due to unsatisfied constraints");
+ }
+ } else {
+ final JobRestriction restriction = mService.checkIfRestricted(running);
+ if (restriction != null) {
+ final int internalReasonCode = restriction.getInternalReason();
+ serviceContext.cancelExecutingJobLocked(restriction.getReason(),
+ internalReasonCode,
+ "restricted due to "
+ + JobParameters.getInternalReasonCodeDescription(
+ internalReasonCode));
+ }
+ }
+ }
+ }
+
private void noteConcurrency() {
mService.mJobPackageTracker.noteConcurrency(mRunningJobs.size(),
// TODO: log per type instead of only TOP
@@ -1078,6 +1181,24 @@ class JobConcurrencyManager {
}
@GuardedBy("mLock")
+ boolean executeTimeoutCommandLocked(PrintWriter pw, String pkgName, int userId,
+ boolean hasJobId, int jobId) {
+ boolean foundSome = false;
+ for (int i = 0; i < mActiveServices.size(); i++) {
+ final JobServiceContext jc = mActiveServices.get(i);
+ final JobStatus js = jc.getRunningJobLocked();
+ if (jc.timeoutIfExecutingLocked(pkgName, userId, hasJobId, jobId, "shell")) {
+ foundSome = true;
+ pw.print("Timing out: ");
+ js.printUniqueId(pw);
+ pw.print(" ");
+ pw.println(js.getServiceComponent().flattenToShortString());
+ }
+ }
+ return foundSome;
+ }
+
+ @GuardedBy("mLock")
private String printPendingQueueLocked() {
StringBuilder s = new StringBuilder("Pending queue: ");
Iterator<JobStatus> it = mService.mPendingJobs.iterator();
@@ -1200,6 +1321,43 @@ class JobConcurrencyManager {
}
}
+ @GuardedBy("mLock")
+ void dumpActiveJobsLocked(IndentingPrintWriter pw, Predicate<JobStatus> predicate,
+ long nowElapsed, long nowUptime) {
+ pw.println("Active jobs:");
+ pw.increaseIndent();
+ for (int i = 0; i < mActiveServices.size(); i++) {
+ JobServiceContext jsc = mActiveServices.get(i);
+ final JobStatus job = jsc.getRunningJobLocked();
+
+ if (job != null && !predicate.test(job)) {
+ continue;
+ }
+
+ pw.print("Slot #"); pw.print(i); pw.print(": ");
+ jsc.dumpLocked(pw, nowElapsed);
+
+ if (job != null) {
+ pw.increaseIndent();
+
+ pw.increaseIndent();
+ job.dump(pw, false, nowElapsed);
+ pw.decreaseIndent();
+
+ pw.print("Evaluated bias: ");
+ pw.println(JobInfo.getBiasString(job.lastEvaluatedBias));
+
+ pw.print("Active at ");
+ TimeUtils.formatDuration(job.madeActive - nowUptime, pw);
+ pw.print(", pending for ");
+ TimeUtils.formatDuration(job.madeActive - job.madePending, pw);
+ pw.decreaseIndent();
+ pw.println();
+ }
+ }
+ pw.decreaseIndent();
+ }
+
public void dumpProtoLocked(ProtoOutputStream proto, long tag, long now, long nowRealtime) {
final long token = proto.start(tag);
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 b9362789c6c6..3d74bc98ad32 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -57,7 +57,6 @@ import android.content.pm.ServiceInfo;
import android.net.Uri;
import android.os.BatteryManager;
import android.os.BatteryManagerInternal;
-import android.os.BatteryStats;
import android.os.BatteryStatsInternal;
import android.os.Binder;
import android.os.Handler;
@@ -67,7 +66,6 @@ import android.os.Message;
import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.os.RemoteException;
-import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.UserHandle;
import android.os.WorkSource;
@@ -90,7 +88,6 @@ import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.app.IBatteryStats;
import com.android.internal.os.SomeArgs;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.DumpUtils;
@@ -100,7 +97,6 @@ import com.android.server.AppStateTrackerImpl;
import com.android.server.DeviceIdleInternal;
import com.android.server.JobSchedulerBackgroundThread;
import com.android.server.LocalServices;
-import com.android.server.job.JobSchedulerServiceDumpProto.ActiveJob;
import com.android.server.job.JobSchedulerServiceDumpProto.PendingJob;
import com.android.server.job.controllers.BackgroundJobsController;
import com.android.server.job.controllers.BatteryController;
@@ -243,12 +239,6 @@ public class JobSchedulerService extends com.android.server.SystemService
static final int MSG_CHECK_CHANGED_JOB_LIST = 8;
static final int MSG_CHECK_MEDIA_EXEMPTION = 9;
- /**
- * Track Services that have currently active or pending jobs. The index is provided by
- * {@link JobStatus#getServiceToken()}
- */
- final List<JobServiceContext> mActiveServices = new ArrayList<>();
-
/** List of controllers that will notify this service of updates to jobs. */
final List<StateController> mControllers;
/**
@@ -307,7 +297,6 @@ public class JobSchedulerService extends com.android.server.SystemService
PackageManagerInternal mLocalPM;
ActivityManagerInternal mActivityManagerInternal;
- IBatteryStats mBatteryStats;
DeviceIdleInternal mLocalDeviceIdleController;
@VisibleForTesting
AppStateTrackerImpl mAppStateTracker;
@@ -1578,7 +1567,8 @@ public class JobSchedulerService extends com.android.server.SystemService
mJobPackageTracker.noteNonpending(cancelled);
}
// Cancel if running.
- stopJobOnServiceContextLocked(cancelled, reason, internalReasonCode, debugReason);
+ mConcurrencyManager.stopJobOnServiceContextLocked(
+ cancelled, reason, internalReasonCode, debugReason);
// If this is a replacement, bring in the new version of the job
if (incomingJob != null) {
if (DEBUG) Slog.i(TAG, "Tracking replacement job " + incomingJob.toShortString());
@@ -1627,19 +1617,7 @@ public class JobSchedulerService extends com.android.server.SystemService
if (DEBUG) {
Slog.d(TAG, "Doze state changed: " + deviceIdle);
}
- if (deviceIdle) {
- // When becoming idle, make sure no jobs are actively running,
- // except those using the idle exemption flag.
- for (int i=0; i<mActiveServices.size(); i++) {
- JobServiceContext jsc = mActiveServices.get(i);
- final JobStatus executing = jsc.getRunningJobLocked();
- if (executing != null && !executing.canRunInDoze()) {
- jsc.cancelExecutingJobLocked(JobParameters.STOP_REASON_DEVICE_STATE,
- JobParameters.INTERNAL_STOP_REASON_DEVICE_IDLE,
- "cancelled due to doze");
- }
- }
- } else {
+ if (!deviceIdle) {
// When coming out of idle, allow thing to start back up.
if (mReadyToRock) {
if (mLocalDeviceIdleController != null) {
@@ -1682,10 +1660,10 @@ public class JobSchedulerService extends com.android.server.SystemService
// active is true if pending queue contains jobs OR some job is running.
boolean active = mPendingJobs.size() > 0;
if (mPendingJobs.size() <= 0) {
- for (int i=0; i<mActiveServices.size(); i++) {
- final JobServiceContext jsc = mActiveServices.get(i);
- final JobStatus job = jsc.getRunningJobLocked();
- if (job != null && !job.canRunInDoze()) {
+ final ArraySet<JobStatus> runningJobs = mConcurrencyManager.getRunningJobsLocked();
+ for (int i = runningJobs.size() - 1; i >= 0; --i) {
+ final JobStatus job = runningJobs.valueAt(i);
+ if (!job.canRunInDoze()) {
// We will report active if we have a job running and it does not have an
// exception that allows it to run in Doze.
active = true;
@@ -1895,16 +1873,9 @@ public class JobSchedulerService extends com.android.server.SystemService
synchronized (mLock) {
// Let's go!
mReadyToRock = true;
- mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService(
- BatteryStats.SERVICE_NAME));
mLocalDeviceIdleController =
LocalServices.getService(DeviceIdleInternal.class);
- // Create the "runners".
- for (int i = 0; i < MAX_JOB_CONTEXTS_COUNT; i++) {
- mActiveServices.add(
- new JobServiceContext(this, mConcurrencyManager, mBatteryStats,
- mJobPackageTracker, getContext().getMainLooper()));
- }
+ mConcurrencyManager.onThirdPartyAppsCanStart();
// Attach jobs to their controllers.
mJobs.forEachJob((job) -> {
for (int controller = 0; controller < mControllers.size(); controller++) {
@@ -1961,19 +1932,6 @@ public class JobSchedulerService extends com.android.server.SystemService
return removed;
}
- private boolean stopJobOnServiceContextLocked(JobStatus job,
- @JobParameters.StopReason int reason, int internalReasonCode, String debugReason) {
- for (int i = 0; i < mActiveServices.size(); i++) {
- JobServiceContext jsc = mActiveServices.get(i);
- final JobStatus executing = jsc.getRunningJobLocked();
- if (executing != null && executing.matches(job.getUid(), job.getJobId())) {
- jsc.cancelExecutingJobLocked(reason, internalReasonCode, debugReason);
- return true;
- }
- }
- return false;
- }
-
/** Return {@code true} if the specified job is currently executing. */
@GuardedBy("mLock")
public boolean isCurrentlyRunningLocked(JobStatus job) {
@@ -2383,7 +2341,8 @@ public class JobSchedulerService extends com.android.server.SystemService
* - if passes all the restrictions or has {@link JobInfo#BIAS_FOREGROUND_SERVICE} bias
* or higher.
*/
- private JobRestriction checkIfRestricted(JobStatus job) {
+ @GuardedBy("mLock")
+ JobRestriction checkIfRestricted(JobStatus job) {
if (evaluateJobBiasLocked(job) >= JobInfo.BIAS_FOREGROUND_SERVICE) {
// Jobs with BIAS_FOREGROUND_SERVICE or higher should not be restricted
return null;
@@ -2397,38 +2356,9 @@ public class JobSchedulerService extends com.android.server.SystemService
return null;
}
+ @GuardedBy("mLock")
private void stopNonReadyActiveJobsLocked() {
- for (int i=0; i<mActiveServices.size(); i++) {
- JobServiceContext serviceContext = mActiveServices.get(i);
- final JobStatus running = serviceContext.getRunningJobLocked();
- if (running == null) {
- continue;
- }
- if (!running.isReady()) {
- if (running.getEffectiveStandbyBucket() == RESTRICTED_INDEX
- && running.getStopReason() == JobParameters.STOP_REASON_APP_STANDBY) {
- serviceContext.cancelExecutingJobLocked(
- running.getStopReason(),
- JobParameters.INTERNAL_STOP_REASON_RESTRICTED_BUCKET,
- "cancelled due to restricted bucket");
- } else {
- serviceContext.cancelExecutingJobLocked(
- running.getStopReason(),
- JobParameters.INTERNAL_STOP_REASON_CONSTRAINTS_NOT_SATISFIED,
- "cancelled due to unsatisfied constraints");
- }
- } else {
- final JobRestriction restriction = checkIfRestricted(running);
- if (restriction != null) {
- final int internalReasonCode = restriction.getInternalReason();
- serviceContext.cancelExecutingJobLocked(restriction.getReason(),
- internalReasonCode,
- "restricted due to "
- + JobParameters.getInternalReasonCodeDescription(
- internalReasonCode));
- }
- }
- }
+ mConcurrencyManager.stopNonReadyActiveJobsLocked();
}
/**
@@ -2598,7 +2528,7 @@ public class JobSchedulerService extends com.android.server.SystemService
debugReason = "couldn't figure out why the job should stop running";
}
}
- stopJobOnServiceContextLocked(job, job.getStopReason(),
+ mConcurrencyManager.stopJobOnServiceContextLocked(job, job.getStopReason(),
internalStopReason, debugReason);
} else if (mPendingJobs.remove(job)) {
noteJobNonPending(job);
@@ -3516,9 +3446,11 @@ public class JobSchedulerService extends com.android.server.SystemService
final ArrayList<JobInfo> runningJobs;
synchronized (mLock) {
- runningJobs = new ArrayList<>(mActiveServices.size());
- for (JobServiceContext jsc : mActiveServices) {
- final JobStatus job = jsc.getRunningJobLocked();
+ final ArraySet<JobStatus> runningJobStatuses =
+ mConcurrencyManager.getRunningJobsLocked();
+ runningJobs = new ArrayList<>(runningJobStatuses.size());
+ for (int i = runningJobStatuses.size() - 1; i >= 0; --i) {
+ final JobStatus job = runningJobStatuses.valueAt(i);
if (job != null) {
runningJobs.add(job.getJob());
}
@@ -3599,18 +3531,8 @@ public class JobSchedulerService extends com.android.server.SystemService
}
synchronized (mLock) {
- boolean foundSome = false;
- for (int i = 0; i < mActiveServices.size(); i++) {
- final JobServiceContext jc = mActiveServices.get(i);
- final JobStatus js = jc.getRunningJobLocked();
- if (jc.timeoutIfExecutingLocked(pkgName, userId, hasJobId, jobId, "shell")) {
- foundSome = true;
- pw.print("Timing out: ");
- js.printUniqueId(pw);
- pw.print(" ");
- pw.println(js.getServiceComponent().flattenToShortString());
- }
- }
+ final boolean foundSome = mConcurrencyManager.executeTimeoutCommandLocked(pw,
+ pkgName, userId, hasJobId, jobId);
if (!foundSome) {
pw.println("No matching executing jobs found.");
}
@@ -4037,38 +3959,7 @@ public class JobSchedulerService extends com.android.server.SystemService
pw.decreaseIndent();
pw.println();
- pw.println("Active jobs:");
- pw.increaseIndent();
- for (int i=0; i<mActiveServices.size(); i++) {
- JobServiceContext jsc = mActiveServices.get(i);
- final JobStatus job = jsc.getRunningJobLocked();
-
- if (job != null && !predicate.test(job)) {
- continue;
- }
-
- pw.print("Slot #"); pw.print(i); pw.print(": ");
- jsc.dumpLocked(pw, nowElapsed);
-
- if (job != null) {
- pw.increaseIndent();
-
- pw.increaseIndent();
- job.dump(pw, false, nowElapsed);
- pw.decreaseIndent();
-
- pw.print("Evaluated bias: ");
- pw.println(JobInfo.getBiasString(job.lastEvaluatedBias));
-
- pw.print("Active at ");
- TimeUtils.formatDuration(job.madeActive - nowUptime, pw);
- pw.print(", pending for ");
- TimeUtils.formatDuration(job.madeActive - job.madePending, pw);
- pw.decreaseIndent();
- pw.println();
- }
- }
- pw.decreaseIndent();
+ mConcurrencyManager.dumpActiveJobsLocked(pw, predicate, nowElapsed, nowUptime);
pw.println();
boolean recentPrinted = false;
@@ -4228,45 +4119,6 @@ public class JobSchedulerService extends com.android.server.SystemService
proto.end(pjToken);
}
- for (JobServiceContext jsc : mActiveServices) {
- final long ajToken = proto.start(JobSchedulerServiceDumpProto.ACTIVE_JOBS);
- final JobStatus job = jsc.getRunningJobLocked();
-
- if (job == null) {
- final long ijToken = proto.start(ActiveJob.INACTIVE);
-
- proto.write(ActiveJob.InactiveJob.TIME_SINCE_STOPPED_MS,
- nowElapsed - jsc.mStoppedTime);
- if (jsc.mStoppedReason != null) {
- proto.write(ActiveJob.InactiveJob.STOPPED_REASON,
- jsc.mStoppedReason);
- }
-
- proto.end(ijToken);
- } else {
- final long rjToken = proto.start(ActiveJob.RUNNING);
-
- job.writeToShortProto(proto, ActiveJob.RunningJob.INFO);
-
- proto.write(ActiveJob.RunningJob.RUNNING_DURATION_MS,
- nowElapsed - jsc.getExecutionStartTimeElapsed());
- proto.write(ActiveJob.RunningJob.TIME_UNTIL_TIMEOUT_MS,
- jsc.getTimeoutElapsed() - nowElapsed);
-
- job.dump(proto, ActiveJob.RunningJob.DUMP, false, nowElapsed);
-
- proto.write(ActiveJob.RunningJob.EVALUATED_PRIORITY,
- evaluateJobBiasLocked(job));
-
- proto.write(ActiveJob.RunningJob.TIME_SINCE_MADE_ACTIVE_MS,
- nowUptime - job.madeActive);
- proto.write(ActiveJob.RunningJob.PENDING_DURATION_MS,
- job.madeActive - job.madePending);
-
- proto.end(rjToken);
- }
- proto.end(ajToken);
- }
if (filterUid == -1) {
proto.write(JobSchedulerServiceDumpProto.IS_READY_TO_ROCK, mReadyToRock);
proto.write(JobSchedulerServiceDumpProto.REPORTED_ACTIVE, mReportedActive);
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobStore.java b/apex/jobscheduler/service/java/com/android/server/job/JobStore.java
index a8dd75248dd8..dfa1442a3192 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobStore.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobStore.java
@@ -548,7 +548,7 @@ public final class JobStore {
out.attribute(null, "sourceUserId", String.valueOf(jobStatus.getSourceUserId()));
out.attribute(null, "uid", Integer.toString(jobStatus.getUid()));
out.attribute(null, "bias", String.valueOf(jobStatus.getBias()));
- out.attribute(null, "priority", String.valueOf(jobStatus.getEffectivePriority()));
+ out.attribute(null, "priority", String.valueOf(jobStatus.getJob().getPriority()));
out.attribute(null, "flags", String.valueOf(jobStatus.getFlags()));
if (jobStatus.getInternalFlags() != 0) {
out.attribute(null, "internalFlags", String.valueOf(jobStatus.getInternalFlags()));
diff --git a/apex/jobscheduler/service/java/com/android/server/job/PendingJobQueue.java b/apex/jobscheduler/service/java/com/android/server/job/PendingJobQueue.java
new file mode 100644
index 000000000000..993e178de0ee
--- /dev/null
+++ b/apex/jobscheduler/service/java/com/android/server/job/PendingJobQueue.java
@@ -0,0 +1,407 @@
+/*
+ * 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.job;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.util.Pools;
+import android.util.SparseArray;
+
+import com.android.server.job.controllers.JobStatus;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.PriorityQueue;
+
+/**
+ * A utility class to maintain a sorted list of currently pending jobs. The sorting system is
+ * modeled after topological sort, so the returned order may not always be consistent.
+ */
+class PendingJobQueue {
+ private final Pools.Pool<AppJobQueue> mAppJobQueuePool = new Pools.SimplePool<>(8);
+
+ /** Set of currently used queues, keyed by source UID. */
+ private final SparseArray<AppJobQueue> mCurrentQueues = new SparseArray<>();
+ /**
+ * Same set of AppJobQueues as in {@link #mCurrentQueues}, but ordered by the next timestamp
+ * to make iterating through the job list faster.
+ */
+ private final PriorityQueue<AppJobQueue> mOrderedQueues = new PriorityQueue<>(
+ (ajq1, ajq2) -> {
+ final long t1 = ajq1.peekNextTimestamp();
+ final long t2 = ajq2.peekNextTimestamp();
+ if (t1 == AppJobQueue.NO_NEXT_TIMESTAMP) {
+ if (t2 == AppJobQueue.NO_NEXT_TIMESTAMP) {
+ return 0;
+ }
+ return 1;
+ } else if (t2 == AppJobQueue.NO_NEXT_TIMESTAMP) {
+ return -1;
+ }
+ return Long.compare(t1, t2);
+ });
+
+ private int mSize = 0;
+
+ private boolean mNeedToResetIterators = false;
+
+ void add(@NonNull JobStatus job) {
+ final AppJobQueue ajq = getAppJobQueue(job.getSourceUid(), true);
+ final long prevTimestamp = ajq.peekNextTimestamp();
+ ajq.add(job);
+ mSize++;
+ if (prevTimestamp != ajq.peekNextTimestamp()) {
+ mOrderedQueues.remove(ajq);
+ mOrderedQueues.offer(ajq);
+ }
+ }
+
+ void addAll(@NonNull List<JobStatus> jobs) {
+ final SparseArray<List<JobStatus>> jobsByUid = new SparseArray<>();
+ for (int i = jobs.size() - 1; i >= 0; --i) {
+ final JobStatus job = jobs.get(i);
+ List<JobStatus> appJobs = jobsByUid.get(job.getSourceUid());
+ if (appJobs == null) {
+ appJobs = new ArrayList<>();
+ jobsByUid.put(job.getSourceUid(), appJobs);
+ }
+ appJobs.add(job);
+ }
+ for (int i = jobsByUid.size() - 1; i >= 0; --i) {
+ final AppJobQueue ajq = getAppJobQueue(jobsByUid.keyAt(i), true);
+ ajq.addAll(jobsByUid.valueAt(i));
+ }
+ mSize += jobs.size();
+ mOrderedQueues.clear();
+ }
+
+ void clear() {
+ mSize = 0;
+ for (int i = mCurrentQueues.size() - 1; i >= 0; --i) {
+ final AppJobQueue ajq = mCurrentQueues.valueAt(i);
+ ajq.clear();
+ mAppJobQueuePool.release(ajq);
+ }
+ mCurrentQueues.clear();
+ mOrderedQueues.clear();
+ }
+
+ boolean contains(@NonNull JobStatus job) {
+ final AppJobQueue ajq = mCurrentQueues.get(job.getSourceUid());
+ if (ajq == null) {
+ return false;
+ }
+ return ajq.contains(job);
+ }
+
+ private AppJobQueue getAppJobQueue(int uid, boolean create) {
+ AppJobQueue ajq = mCurrentQueues.get(uid);
+ if (ajq == null && create) {
+ ajq = mAppJobQueuePool.acquire();
+ if (ajq == null) {
+ ajq = new AppJobQueue();
+ }
+ mCurrentQueues.put(uid, ajq);
+ }
+ return ajq;
+ }
+
+ @Nullable
+ JobStatus next() {
+ if (mNeedToResetIterators) {
+ mOrderedQueues.clear();
+ for (int i = mCurrentQueues.size() - 1; i >= 0; --i) {
+ final AppJobQueue ajq = mCurrentQueues.valueAt(i);
+ ajq.resetIterator(0);
+ mOrderedQueues.offer(ajq);
+ }
+ mNeedToResetIterators = false;
+ } else if (mOrderedQueues.size() == 0) {
+ for (int i = mCurrentQueues.size() - 1; i >= 0; --i) {
+ final AppJobQueue ajq = mCurrentQueues.valueAt(i);
+ mOrderedQueues.offer(ajq);
+ }
+ }
+ final AppJobQueue earliestQueue = mOrderedQueues.poll();
+ if (earliestQueue != null) {
+ JobStatus job = earliestQueue.next();
+ mOrderedQueues.offer(earliestQueue);
+ return job;
+ }
+ return null;
+ }
+
+ boolean remove(@NonNull JobStatus job) {
+ final AppJobQueue ajq = getAppJobQueue(job.getSourceUid(), false);
+ if (ajq == null) {
+ return false;
+ }
+
+ final long prevTimestamp = ajq.peekNextTimestamp();
+ if (!ajq.remove(job)) {
+ return false;
+ }
+
+ mSize--;
+ if (ajq.size() == 0) {
+ mCurrentQueues.remove(job.getSourceUid());
+ mOrderedQueues.remove(ajq);
+ ajq.clear();
+ mAppJobQueuePool.release(ajq);
+ } else if (prevTimestamp != ajq.peekNextTimestamp()) {
+ mOrderedQueues.remove(ajq);
+ mOrderedQueues.offer(ajq);
+ }
+
+ return true;
+ }
+
+ /** Resets the iterating index to the front of the queue. */
+ void resetIterator() {
+ // Lazily reset the iterating indices (avoid looping through all the current queues until
+ // absolutely necessary).
+ mNeedToResetIterators = true;
+ }
+
+ int size() {
+ return mSize;
+ }
+
+ private static final class AppJobQueue {
+ static final long NO_NEXT_TIMESTAMP = -1L;
+
+ private static class AdjustedJobStatus {
+ public long adjustedEnqueueTime;
+ public JobStatus job;
+
+ void clear() {
+ adjustedEnqueueTime = 0;
+ job = null;
+ }
+ }
+
+ private static final Comparator<AdjustedJobStatus> sJobComparator = (aj1, aj2) -> {
+ if (aj1 == aj2) {
+ return 0;
+ }
+ final JobStatus job1 = aj1.job;
+ final JobStatus job2 = aj2.job;
+ // Jobs with an override state set (via adb) should be put first as tests/developers
+ // expect the jobs to run immediately.
+ if (job1.overrideState != job2.overrideState) {
+ // Higher override state (OVERRIDE_FULL) should be before lower state
+ // (OVERRIDE_SOFT)
+ return job2.overrideState - job1.overrideState;
+ }
+
+ final boolean job1EJ = job1.isRequestedExpeditedJob();
+ final boolean job2EJ = job2.isRequestedExpeditedJob();
+ if (job1EJ != job2EJ) {
+ // Attempt to run requested expedited jobs ahead of regular jobs, regardless of
+ // expedited job quota.
+ return job1EJ ? -1 : 1;
+ }
+
+ final int job1Priority = job1.getEffectivePriority();
+ final int job2Priority = job2.getEffectivePriority();
+ if (job1Priority != job2Priority) {
+ // Use the priority set by an app for intra-app job ordering. Higher
+ // priority should be before lower priority.
+ return job2Priority - job1Priority;
+ }
+
+ if (job1.lastEvaluatedBias != job2.lastEvaluatedBias) {
+ // Higher bias should go first.
+ return job2.lastEvaluatedBias - job1.lastEvaluatedBias;
+ }
+
+ if (job1.enqueueTime < job2.enqueueTime) {
+ return -1;
+ }
+ return job1.enqueueTime > job2.enqueueTime ? 1 : 0;
+ };
+
+ private static final Pools.Pool<AdjustedJobStatus> mAdjustedJobStatusPool =
+ new Pools.SimplePool<>(16);
+
+ private final List<AdjustedJobStatus> mJobs = new ArrayList<>();
+ private int mCurIndex = 0;
+
+ void add(@NonNull JobStatus jobStatus) {
+ AdjustedJobStatus adjustedJobStatus = mAdjustedJobStatusPool.acquire();
+ if (adjustedJobStatus == null) {
+ adjustedJobStatus = new AdjustedJobStatus();
+ }
+ adjustedJobStatus.adjustedEnqueueTime = jobStatus.enqueueTime;
+ adjustedJobStatus.job = jobStatus;
+
+ int where = Collections.binarySearch(mJobs, adjustedJobStatus, sJobComparator);
+ if (where < 0) {
+ where = ~where;
+ }
+ mJobs.add(where, adjustedJobStatus);
+ if (where < mCurIndex) {
+ // Shift the current index back to make sure the new job is evaluated on the next
+ // iteration.
+ mCurIndex = where;
+ }
+
+ if (where > 0) {
+ final long prevTimestamp = mJobs.get(where - 1).adjustedEnqueueTime;
+ adjustedJobStatus.adjustedEnqueueTime =
+ Math.max(prevTimestamp, adjustedJobStatus.adjustedEnqueueTime);
+ }
+ final int numJobs = mJobs.size();
+ if (where < numJobs - 1) {
+ // Potentially need to adjust following job timestamps as well.
+ for (int i = where; i < numJobs; ++i) {
+ final AdjustedJobStatus ajs = mJobs.get(i);
+ if (adjustedJobStatus.adjustedEnqueueTime < ajs.adjustedEnqueueTime) {
+ // No further need to adjust.
+ break;
+ }
+ ajs.adjustedEnqueueTime = adjustedJobStatus.adjustedEnqueueTime;
+ }
+ }
+ }
+
+ void addAll(@NonNull List<JobStatus> jobs) {
+ int earliestIndex = Integer.MAX_VALUE;
+
+ for (int i = jobs.size() - 1; i >= 0; --i) {
+ final JobStatus job = jobs.get(i);
+
+ AdjustedJobStatus adjustedJobStatus = mAdjustedJobStatusPool.acquire();
+ if (adjustedJobStatus == null) {
+ adjustedJobStatus = new AdjustedJobStatus();
+ }
+ adjustedJobStatus.adjustedEnqueueTime = job.enqueueTime;
+ adjustedJobStatus.job = job;
+
+ int where = Collections.binarySearch(mJobs, adjustedJobStatus, sJobComparator);
+ if (where < 0) {
+ where = ~where;
+ }
+ mJobs.add(where, adjustedJobStatus);
+ if (where < mCurIndex) {
+ // Shift the current index back to make sure the new job is evaluated on the
+ // next iteration.
+ mCurIndex = where;
+ }
+ earliestIndex = Math.min(earliestIndex, where);
+ }
+
+ final int numJobs = mJobs.size();
+ for (int i = Math.max(earliestIndex, 1); i < numJobs; ++i) {
+ final AdjustedJobStatus ajs = mJobs.get(i);
+ final AdjustedJobStatus prev = mJobs.get(i - 1);
+ ajs.adjustedEnqueueTime =
+ Math.max(ajs.adjustedEnqueueTime, prev.adjustedEnqueueTime);
+ }
+ }
+
+ void clear() {
+ mJobs.clear();
+ mCurIndex = 0;
+ }
+
+ boolean contains(@NonNull JobStatus job) {
+ return indexOf(job) >= 0;
+ }
+
+ private int indexOf(@NonNull JobStatus jobStatus) {
+ AdjustedJobStatus adjustedJobStatus = mAdjustedJobStatusPool.acquire();
+ if (adjustedJobStatus == null) {
+ adjustedJobStatus = new AdjustedJobStatus();
+ }
+ adjustedJobStatus.adjustedEnqueueTime = jobStatus.enqueueTime;
+ adjustedJobStatus.job = jobStatus;
+
+ int where = Collections.binarySearch(mJobs, adjustedJobStatus, sJobComparator);
+ adjustedJobStatus.clear();
+ mAdjustedJobStatusPool.release(adjustedJobStatus);
+ return where;
+ }
+
+ @Nullable
+ JobStatus next() {
+ if (mCurIndex >= mJobs.size()) {
+ return null;
+ }
+ JobStatus next = mJobs.get(mCurIndex).job;
+ mCurIndex++;
+ return next;
+ }
+
+ long peekNextTimestamp() {
+ if (mCurIndex >= mJobs.size()) {
+ return NO_NEXT_TIMESTAMP;
+ }
+ return mJobs.get(mCurIndex).adjustedEnqueueTime;
+ }
+
+ boolean remove(@NonNull JobStatus jobStatus) {
+ final int idx = indexOf(jobStatus);
+ if (idx < 0) {
+ // Doesn't exist...
+ return false;
+ }
+ final AdjustedJobStatus adjustedJobStatus = mJobs.remove(idx);
+ adjustedJobStatus.clear();
+ mAdjustedJobStatusPool.release(adjustedJobStatus);
+ if (idx < mCurIndex) {
+ mCurIndex--;
+ }
+ return true;
+ }
+
+ /**
+ * Resets the internal index to point to the first JobStatus whose adjusted time is equal to
+ * or after the given timestamp.
+ */
+ void resetIterator(long earliestEnqueueTime) {
+ if (earliestEnqueueTime == 0 || mJobs.size() == 0) {
+ mCurIndex = 0;
+ return;
+ }
+
+ // Binary search
+ int low = 0;
+ int high = mJobs.size() - 1;
+
+ while (low < high) {
+ int mid = (low + high) >>> 1;
+ AdjustedJobStatus midVal = mJobs.get(mid);
+
+ if (midVal.adjustedEnqueueTime < earliestEnqueueTime) {
+ low = mid + 1;
+ } else if (midVal.adjustedEnqueueTime > earliestEnqueueTime) {
+ high = mid - 1;
+ } else {
+ high = mid;
+ }
+ }
+ mCurIndex = high;
+ }
+
+ int size() {
+ return mJobs.size();
+ }
+ }
+}
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
index efcf14f07ee9..30fdb1e9ad4e 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
@@ -441,11 +441,6 @@ public final class JobStatus {
/** The reason a job most recently went from ready to not ready. */
private int mReasonReadyToUnready = JobParameters.STOP_REASON_UNDEFINED;
- /** Provide a handle to the service that this job will be run on. */
- public int getServiceToken() {
- return callingUid;
- }
-
/**
* Core constructor for JobStatus instances. All other ctors funnel down to this one.
*
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/DeviceIdleModifier.java b/apex/jobscheduler/service/java/com/android/server/tare/DeviceIdleModifier.java
index 37b0aa8f4862..8a64238f1f17 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/DeviceIdleModifier.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/DeviceIdleModifier.java
@@ -103,7 +103,7 @@ class DeviceIdleModifier extends Modifier {
mIrs.onDeviceStateChanged();
}
} else if (PowerManager.ACTION_LIGHT_DEVICE_IDLE_MODE_CHANGED.equals(action)) {
- if (mDeviceIdle != mPowerManager.isLightDeviceIdleMode()) {
+ if (mDeviceLightIdle != mPowerManager.isLightDeviceIdleMode()) {
mDeviceLightIdle = mPowerManager.isLightDeviceIdleMode();
mIrs.onDeviceStateChanged();
}
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 67a3dc67e569..5ec2f5607153 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/ProcessStateModifier.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/ProcessStateModifier.java
@@ -146,8 +146,11 @@ class ProcessStateModifier extends Modifier {
return 0;
case PROC_STATE_BUCKET_FGS:
// Can't get notification priority. Just use CTP for now.
- return ctp;
+ return Math.min(ctp, price);
case PROC_STATE_BUCKET_BFGS:
+ if (price <= ctp) {
+ return price;
+ }
return (long) (ctp + .5 * (price - ctp));
case PROC_STATE_BUCKET_BG:
default:
diff --git a/apex/jobscheduler/service/java/com/android/server/usage/AppIdleHistory.java b/apex/jobscheduler/service/java/com/android/server/usage/AppIdleHistory.java
index dd102bdd726e..2e3b377d08a5 100644
--- a/apex/jobscheduler/service/java/com/android/server/usage/AppIdleHistory.java
+++ b/apex/jobscheduler/service/java/com/android/server/usage/AppIdleHistory.java
@@ -384,14 +384,16 @@ public class AppIdleHistory {
return userHistory;
}
+ // TODO (206518483): Remove unused parameter 'elapsedRealtime'.
private AppUsageHistory getPackageHistory(ArrayMap<String, AppUsageHistory> userHistory,
String packageName, long elapsedRealtime, boolean create) {
AppUsageHistory appUsageHistory = userHistory.get(packageName);
if (appUsageHistory == null && create) {
appUsageHistory = new AppUsageHistory();
- appUsageHistory.lastUsedElapsedTime = getElapsedTime(elapsedRealtime);
- appUsageHistory.lastUsedScreenTime = getScreenOnTime(elapsedRealtime);
- appUsageHistory.lastPredictedTime = getElapsedTime(0);
+ appUsageHistory.lastUsedByUserElapsedTime = Integer.MIN_VALUE;
+ appUsageHistory.lastUsedElapsedTime = Integer.MIN_VALUE;
+ appUsageHistory.lastUsedScreenTime = Integer.MIN_VALUE;
+ appUsageHistory.lastPredictedTime = Integer.MIN_VALUE;
appUsageHistory.currentBucket = STANDBY_BUCKET_NEVER;
appUsageHistory.bucketingReason = REASON_MAIN_DEFAULT;
appUsageHistory.lastInformedBucket = -1;
@@ -544,7 +546,7 @@ public class AppIdleHistory {
AppUsageHistory appUsageHistory =
getPackageHistory(userHistory, packageName, elapsedRealtime, false);
if (appUsageHistory == null || appUsageHistory.lastUsedByUserElapsedTime == Long.MIN_VALUE
- || appUsageHistory.lastUsedByUserElapsedTime == 0) {
+ || appUsageHistory.lastUsedByUserElapsedTime <= 0) {
return Long.MAX_VALUE;
}
return getElapsedTime(elapsedRealtime) - appUsageHistory.lastUsedByUserElapsedTime;
@@ -631,8 +633,12 @@ public class AppIdleHistory {
// If we don't have any state for the app, assume never used
if (appUsageHistory == null) return screenTimeThresholds.length - 1;
- long screenOnDelta = getScreenOnTime(elapsedRealtime) - appUsageHistory.lastUsedScreenTime;
- long elapsedDelta = getElapsedTime(elapsedRealtime) - appUsageHistory.lastUsedElapsedTime;
+ long screenOnDelta = appUsageHistory.lastUsedScreenTime >= 0
+ ? getScreenOnTime(elapsedRealtime) - appUsageHistory.lastUsedScreenTime
+ : Long.MAX_VALUE;
+ long elapsedDelta = appUsageHistory.lastUsedElapsedTime >= 0
+ ? getElapsedTime(elapsedRealtime) - appUsageHistory.lastUsedElapsedTime
+ : Long.MAX_VALUE;
if (DEBUG) Slog.d(TAG, packageName
+ " lastUsedScreen=" + appUsageHistory.lastUsedScreenTime
@@ -667,8 +673,8 @@ public class AppIdleHistory {
long getBucketExpiryTimeMs(String packageName, int userId, int bucket, long elapsedRealtimeMs) {
ArrayMap<String, AppUsageHistory> userHistory = getUserHistory(userId);
AppUsageHistory appUsageHistory = getPackageHistory(userHistory, packageName,
- elapsedRealtimeMs, true);
- if (appUsageHistory.bucketExpiryTimesMs == null) {
+ elapsedRealtimeMs, false /* create */);
+ if (appUsageHistory == null || appUsageHistory.bucketExpiryTimesMs == null) {
return 0;
}
return appUsageHistory.bucketExpiryTimesMs.get(bucket, 0);
@@ -951,14 +957,14 @@ public class AppIdleHistory {
+ " reason="
+ UsageStatsManager.reasonToString(appUsageHistory.bucketingReason));
idpw.print(" used=");
- TimeUtils.formatDuration(totalElapsedTime - appUsageHistory.lastUsedElapsedTime, idpw);
+ printLastActionElapsedTime(idpw, totalElapsedTime, appUsageHistory.lastUsedElapsedTime);
idpw.print(" usedByUser=");
- TimeUtils.formatDuration(totalElapsedTime - appUsageHistory.lastUsedByUserElapsedTime,
- idpw);
+ printLastActionElapsedTime(idpw, totalElapsedTime,
+ appUsageHistory.lastUsedByUserElapsedTime);
idpw.print(" usedScr=");
- TimeUtils.formatDuration(screenOnTime - appUsageHistory.lastUsedScreenTime, idpw);
+ printLastActionElapsedTime(idpw, totalElapsedTime, appUsageHistory.lastUsedScreenTime);
idpw.print(" lastPred=");
- TimeUtils.formatDuration(totalElapsedTime - appUsageHistory.lastPredictedTime, idpw);
+ printLastActionElapsedTime(idpw, totalElapsedTime, appUsageHistory.lastPredictedTime);
dumpBucketExpiryTimes(idpw, appUsageHistory, totalElapsedTime);
idpw.print(" lastJob=");
TimeUtils.formatDuration(totalElapsedTime - appUsageHistory.lastJobRunTime, idpw);
@@ -986,6 +992,15 @@ public class AppIdleHistory {
idpw.decreaseIndent();
}
+ private void printLastActionElapsedTime(IndentingPrintWriter idpw, long totalElapsedTimeMS,
+ long lastActionTimeMs) {
+ if (lastActionTimeMs < 0) {
+ idpw.print("<uninitialized>");
+ } else {
+ TimeUtils.formatDuration(totalElapsedTimeMS - lastActionTimeMs, idpw);
+ }
+ }
+
private void dumpBucketExpiryTimes(IndentingPrintWriter idpw, AppUsageHistory appUsageHistory,
long totalElapsedTimeMs) {
idpw.print(" expiryTimes=");
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 849354bd1d97..502913063a00 100644
--- a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
+++ b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
@@ -78,6 +78,7 @@ import android.content.pm.CrossProfileAppsInternal;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
+import android.content.pm.ResolveInfo;
import android.database.ContentObserver;
import android.hardware.display.DisplayManager;
import android.net.NetworkScoreManager;
@@ -99,6 +100,7 @@ import android.os.UserHandle;
import android.provider.DeviceConfig;
import android.provider.Settings.Global;
import android.telephony.TelephonyManager;
+import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.IndentingPrintWriter;
import android.util.Slog;
@@ -129,6 +131,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
+import java.util.Map;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
@@ -219,7 +222,8 @@ public class AppStandbyController
private static final int HEADLESS_APP_CHECK_FLAGS =
PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
- | PackageManager.GET_ACTIVITIES | PackageManager.MATCH_DISABLED_COMPONENTS;
+ | PackageManager.MATCH_DISABLED_COMPONENTS
+ | PackageManager.MATCH_SYSTEM_ONLY;
// To name the lock for stack traces
static class Lock {}
@@ -253,7 +257,7 @@ public class AppStandbyController
private final SparseArray<Set<String>> mActiveAdminApps = new SparseArray<>();
/**
- * Set of system apps that are headless (don't have any declared activities, enabled or
+ * Set of system apps that are headless (don't have any "front door" activities, enabled or
* disabled). Presence in this map indicates that the app is a headless system app.
*/
@GuardedBy("mHeadlessSystemApps")
@@ -373,6 +377,15 @@ public class AppStandbyController
ConstantsObserver.DEFAULT_BROADCAST_RESPONSE_FG_THRESHOLD_STATE;
/**
+ * Map of last known values of keys in {@link DeviceConfig#NAMESPACE_APP_STANDBY}.
+ *
+ * Note: We are intentionally not guarding this by any lock since this is only updated on
+ * a handler thread and when querying, if we do end up seeing slightly older values, it is fine
+ * since the values are only used in tests and doesn't need to be queried in any other cases.
+ */
+ private final Map<String, String> mAppStandbyProperties = new ArrayMap<>();
+
+ /**
* Whether we should allow apps into the
* {@link android.app.usage.UsageStatsManager#STANDBY_BUCKET_RESTRICTED} bucket or not.
* If false, any attempts to put an app into the bucket will put the app into the
@@ -885,8 +898,11 @@ public class AppStandbyController
}
}
+ final long elapsedLastUsedByUserTimeDelta = app.lastUsedByUserElapsedTime >= 0
+ ? elapsedTimeAdjusted - app.lastUsedByUserElapsedTime
+ : Long.MAX_VALUE;
if (app.lastRestrictAttemptElapsedTime > app.lastUsedByUserElapsedTime
- && elapsedTimeAdjusted - app.lastUsedByUserElapsedTime
+ && elapsedLastUsedByUserTimeDelta
>= mInjector.getAutoRestrictedBucketDelayMs()) {
newBucket = STANDBY_BUCKET_RESTRICTED;
reason = app.lastRestrictReason;
@@ -1573,8 +1589,10 @@ public class AppStandbyController
(reason & REASON_MAIN_MASK) == REASON_MAIN_FORCED_BY_SYSTEM;
if (app.currentBucket == newBucket && wasForcedBySystem && isForcedBySystem) {
- mAppIdleHistory
- .noteRestrictionAttempt(packageName, userId, elapsedRealtime, reason);
+ if (newBucket == STANDBY_BUCKET_RESTRICTED) {
+ mAppIdleHistory
+ .noteRestrictionAttempt(packageName, userId, elapsedRealtime, reason);
+ }
// Keep track of all restricting reasons
reason = REASON_MAIN_FORCED_BY_SYSTEM
| (app.bucketingReason & REASON_SUB_MASK)
@@ -1833,6 +1851,12 @@ public class AppStandbyController
}
@Override
+ @Nullable
+ public String getAppStandbyConstant(@NonNull String key) {
+ return mAppStandbyProperties.get(key);
+ }
+
+ @Override
public void flushToDisk() {
synchronized (mAppIdleLock) {
mAppIdleHistory.writeAppIdleTimes(mInjector.elapsedRealtime());
@@ -1942,7 +1966,7 @@ public class AppStandbyController
try {
PackageInfo pi = mPackageManager.getPackageInfoAsUser(
packageName, HEADLESS_APP_CHECK_FLAGS, userId);
- evaluateSystemAppException(pi);
+ maybeUpdateHeadlessSystemAppCache(pi);
} catch (PackageManager.NameNotFoundException e) {
synchronized (mHeadlessSystemApps) {
mHeadlessSystemApps.remove(packageName);
@@ -1950,19 +1974,31 @@ public class AppStandbyController
}
}
- /** Returns true if the exception status changed. */
- private boolean evaluateSystemAppException(@Nullable PackageInfo pkgInfo) {
+ /**
+ * Update the "headless system app" cache.
+ *
+ * @return true if the cache is updated.
+ */
+ private boolean maybeUpdateHeadlessSystemAppCache(@Nullable PackageInfo pkgInfo) {
if (pkgInfo == null || pkgInfo.applicationInfo == null
|| (!pkgInfo.applicationInfo.isSystemApp()
&& !pkgInfo.applicationInfo.isUpdatedSystemApp())) {
return false;
}
+ final Intent frontDoorActivityIntent = new Intent(Intent.ACTION_MAIN)
+ .addCategory(Intent.CATEGORY_LAUNCHER)
+ .setPackage(pkgInfo.packageName);
+ List<ResolveInfo> res = mPackageManager.queryIntentActivitiesAsUser(frontDoorActivityIntent,
+ HEADLESS_APP_CHECK_FLAGS, UserHandle.USER_SYSTEM);
+ return updateHeadlessSystemAppCache(pkgInfo.packageName, ArrayUtils.isEmpty(res));
+ }
+
+ private boolean updateHeadlessSystemAppCache(String packageName, boolean add) {
synchronized (mHeadlessSystemApps) {
- if (pkgInfo.activities == null || pkgInfo.activities.length == 0) {
- // Headless system app.
- return mHeadlessSystemApps.add(pkgInfo.packageName);
+ if (add) {
+ return mHeadlessSystemApps.add(packageName);
} else {
- return mHeadlessSystemApps.remove(pkgInfo.packageName);
+ return mHeadlessSystemApps.remove(packageName);
}
}
}
@@ -1999,20 +2035,45 @@ public class AppStandbyController
}
}
+ /** Returns the packages that have launcher icons. */
+ private Set<String> getSystemPackagesWithLauncherActivities() {
+ final Intent intent = new Intent(Intent.ACTION_MAIN)
+ .addCategory(Intent.CATEGORY_LAUNCHER);
+ List<ResolveInfo> activities = mPackageManager.queryIntentActivitiesAsUser(intent,
+ HEADLESS_APP_CHECK_FLAGS, UserHandle.USER_SYSTEM);
+ final ArraySet<String> ret = new ArraySet<>();
+ for (ResolveInfo ri : activities) {
+ ret.add(ri.activityInfo.packageName);
+ }
+ return ret;
+ }
+
/** Call on system boot to get the initial set of headless system apps. */
private void loadHeadlessSystemAppCache() {
- Slog.d(TAG, "Loading headless system app cache. appIdleEnabled=" + mAppIdleEnabled);
+ final long start = SystemClock.uptimeMillis();
final List<PackageInfo> packages = mPackageManager.getInstalledPackagesAsUser(
HEADLESS_APP_CHECK_FLAGS, UserHandle.USER_SYSTEM);
+
+ final Set<String> systemLauncherActivities = getSystemPackagesWithLauncherActivities();
+
final int packageCount = packages.size();
for (int i = 0; i < packageCount; i++) {
- PackageInfo pkgInfo = packages.get(i);
- if (pkgInfo != null && evaluateSystemAppException(pkgInfo)) {
+ final PackageInfo pkgInfo = packages.get(i);
+ if (pkgInfo == null) {
+ continue;
+ }
+ final String pkg = pkgInfo.packageName;
+ final boolean isHeadLess = !systemLauncherActivities.contains(pkg);
+
+ if (updateHeadlessSystemAppCache(pkg, isHeadLess)) {
mHandler.obtainMessage(MSG_CHECK_PACKAGE_IDLE_STATE,
- UserHandle.USER_SYSTEM, -1, pkgInfo.packageName)
+ UserHandle.USER_SYSTEM, -1, pkg)
.sendToTarget();
}
}
+ final long end = SystemClock.uptimeMillis();
+ Slog.d(TAG, "Loaded headless system app cache in " + (end - start) + " ms:"
+ + " appIdleEnabled=" + mAppIdleEnabled);
}
@Override
@@ -2733,6 +2794,7 @@ public class AppStandbyController
}
break;
}
+ mAppStandbyProperties.put(name, properties.getString(name, null));
}
}
}
diff --git a/boot/Android.bp b/boot/Android.bp
index 00e44f8e9143..5b265a5dc9de 100644
--- a/boot/Android.bp
+++ b/boot/Android.bp
@@ -60,10 +60,6 @@ platform_bootclasspath {
module: "art-bootclasspath-fragment",
},
{
- apex: "com.android.auxiliary",
- module: "com.android.auxiliary-bootclasspath-fragment",
- },
- {
apex: "com.android.bluetooth",
module: "com.android.bluetooth-bootclasspath-fragment",
},
diff --git a/boot/hiddenapi/hiddenapi-max-target-o.txt b/boot/hiddenapi/hiddenapi-max-target-o.txt
index d3b5be906c74..3c16915cf71f 100644
--- a/boot/hiddenapi/hiddenapi-max-target-o.txt
+++ b/boot/hiddenapi/hiddenapi-max-target-o.txt
@@ -32472,14 +32472,6 @@ Landroid/net/DhcpResults;->setLeaseDuration(I)V
Landroid/net/DhcpResults;->setServerAddress(Ljava/lang/String;)Z
Landroid/net/DhcpResults;->setVendorInfo(Ljava/lang/String;)V
Landroid/net/DhcpResults;->TAG:Ljava/lang/String;
-Landroid/net/EthernetManager;-><init>(Landroid/content/Context;Landroid/net/IEthernetManager;)V
-Landroid/net/EthernetManager;->mContext:Landroid/content/Context;
-Landroid/net/EthernetManager;->mHandler:Landroid/os/Handler;
-Landroid/net/EthernetManager;->mListeners:Ljava/util/ArrayList;
-Landroid/net/EthernetManager;->mService:Landroid/net/IEthernetManager;
-Landroid/net/EthernetManager;->mServiceListener:Landroid/net/IEthernetServiceListener$Stub;
-Landroid/net/EthernetManager;->MSG_AVAILABILITY_CHANGED:I
-Landroid/net/EthernetManager;->TAG:Ljava/lang/String;
Landroid/net/EventLogTags;-><init>()V
Landroid/net/EventLogTags;->NTP_FAILURE:I
Landroid/net/EventLogTags;->NTP_SUCCESS:I
@@ -32513,39 +32505,6 @@ Landroid/net/http/X509TrustManagerExtensions;->mCheckServerTrusted:Ljava/lang/re
Landroid/net/http/X509TrustManagerExtensions;->mDelegate:Lcom/android/org/conscrypt/TrustManagerImpl;
Landroid/net/http/X509TrustManagerExtensions;->mIsSameTrustConfiguration:Ljava/lang/reflect/Method;
Landroid/net/http/X509TrustManagerExtensions;->mTrustManager:Ljavax/net/ssl/X509TrustManager;
-Landroid/net/IEthernetManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
-Landroid/net/IEthernetManager$Stub$Proxy;->addListener(Landroid/net/IEthernetServiceListener;)V
-Landroid/net/IEthernetManager$Stub$Proxy;->getAvailableInterfaces()[Ljava/lang/String;
-Landroid/net/IEthernetManager$Stub$Proxy;->getConfiguration(Ljava/lang/String;)Landroid/net/IpConfiguration;
-Landroid/net/IEthernetManager$Stub$Proxy;->getInterfaceDescriptor()Ljava/lang/String;
-Landroid/net/IEthernetManager$Stub$Proxy;->isAvailable(Ljava/lang/String;)Z
-Landroid/net/IEthernetManager$Stub$Proxy;->mRemote:Landroid/os/IBinder;
-Landroid/net/IEthernetManager$Stub$Proxy;->removeListener(Landroid/net/IEthernetServiceListener;)V
-Landroid/net/IEthernetManager$Stub$Proxy;->setConfiguration(Ljava/lang/String;Landroid/net/IpConfiguration;)V
-Landroid/net/IEthernetManager$Stub;-><init>()V
-Landroid/net/IEthernetManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/net/IEthernetManager;
-Landroid/net/IEthernetManager$Stub;->DESCRIPTOR:Ljava/lang/String;
-Landroid/net/IEthernetManager$Stub;->TRANSACTION_addListener:I
-Landroid/net/IEthernetManager$Stub;->TRANSACTION_getAvailableInterfaces:I
-Landroid/net/IEthernetManager$Stub;->TRANSACTION_getConfiguration:I
-Landroid/net/IEthernetManager$Stub;->TRANSACTION_isAvailable:I
-Landroid/net/IEthernetManager$Stub;->TRANSACTION_removeListener:I
-Landroid/net/IEthernetManager$Stub;->TRANSACTION_setConfiguration:I
-Landroid/net/IEthernetManager;->addListener(Landroid/net/IEthernetServiceListener;)V
-Landroid/net/IEthernetManager;->getAvailableInterfaces()[Ljava/lang/String;
-Landroid/net/IEthernetManager;->getConfiguration(Ljava/lang/String;)Landroid/net/IpConfiguration;
-Landroid/net/IEthernetManager;->isAvailable(Ljava/lang/String;)Z
-Landroid/net/IEthernetManager;->removeListener(Landroid/net/IEthernetServiceListener;)V
-Landroid/net/IEthernetManager;->setConfiguration(Ljava/lang/String;Landroid/net/IpConfiguration;)V
-Landroid/net/IEthernetServiceListener$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
-Landroid/net/IEthernetServiceListener$Stub$Proxy;->getInterfaceDescriptor()Ljava/lang/String;
-Landroid/net/IEthernetServiceListener$Stub$Proxy;->mRemote:Landroid/os/IBinder;
-Landroid/net/IEthernetServiceListener$Stub$Proxy;->onAvailabilityChanged(Ljava/lang/String;Z)V
-Landroid/net/IEthernetServiceListener$Stub;-><init>()V
-Landroid/net/IEthernetServiceListener$Stub;->asInterface(Landroid/os/IBinder;)Landroid/net/IEthernetServiceListener;
-Landroid/net/IEthernetServiceListener$Stub;->DESCRIPTOR:Ljava/lang/String;
-Landroid/net/IEthernetServiceListener$Stub;->TRANSACTION_onAvailabilityChanged:I
-Landroid/net/IEthernetServiceListener;->onAvailabilityChanged(Ljava/lang/String;Z)V
Landroid/net/IIpConnectivityMetrics$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/net/IIpConnectivityMetrics$Stub$Proxy;->addNetdEventCallback(ILandroid/net/INetdEventCallback;)Z
Landroid/net/IIpConnectivityMetrics$Stub$Proxy;->getInterfaceDescriptor()Ljava/lang/String;
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index c5410a082322..b8d24e388d67 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -191,6 +191,8 @@ public class Am extends BaseCommand {
instrument.noRestart = true;
} else if (opt.equals("--always-check-signature")) {
instrument.alwaysCheckSignature = true;
+ } else if (opt.equals("--instrument-sdk-sandbox")) {
+ instrument.instrumentSdkSandbox = true;
} else {
System.err.println("Error: Unknown option: " + opt);
return;
diff --git a/cmds/am/src/com/android/commands/am/Instrument.java b/cmds/am/src/com/android/commands/am/Instrument.java
index a0562d964954..7ff4bc4bcf76 100644
--- a/cmds/am/src/com/android/commands/am/Instrument.java
+++ b/cmds/am/src/com/android/commands/am/Instrument.java
@@ -20,6 +20,7 @@ import static android.app.ActivityManager.INSTR_FLAG_ALWAYS_CHECK_SIGNATURE;
import static android.app.ActivityManager.INSTR_FLAG_DISABLE_HIDDEN_API_CHECKS;
import static android.app.ActivityManager.INSTR_FLAG_DISABLE_ISOLATED_STORAGE;
import static android.app.ActivityManager.INSTR_FLAG_DISABLE_TEST_API_CHECKS;
+import static android.app.ActivityManager.INSTR_FLAG_INSTRUMENT_SDK_SANDBOX;
import static android.app.ActivityManager.INSTR_FLAG_NO_RESTART;
import android.app.IActivityManager;
@@ -97,6 +98,7 @@ public class Instrument {
// Required
public String componentNameArg;
public boolean alwaysCheckSignature = false;
+ public boolean instrumentSdkSandbox = false;
/**
* Construct the instrument command runner.
@@ -524,6 +526,9 @@ public class Instrument {
if (alwaysCheckSignature) {
flags |= INSTR_FLAG_ALWAYS_CHECK_SIGNATURE;
}
+ if (instrumentSdkSandbox) {
+ flags |= INSTR_FLAG_INSTRUMENT_SDK_SANDBOX;
+ }
if (!mAm.startInstrumentation(cn, profileFile, flags, args, watcher, connection, userId,
abi)) {
throw new AndroidException("INSTRUMENTATION_FAILED: " + cn.flattenToString());
diff --git a/cmds/app_process/Android.bp b/cmds/app_process/Android.bp
index 6a685a79cc33..a1575173ded6 100644
--- a/cmds/app_process/Android.bp
+++ b/cmds/app_process/Android.bp
@@ -64,8 +64,6 @@ cc_binary {
"libwilhelm",
],
- header_libs: ["bionic_libc_platform_headers"],
-
compile_multilib: "both",
cflags: [
diff --git a/cmds/app_process/app_main.cpp b/cmds/app_process/app_main.cpp
index 815f9455471c..12083b6fe20b 100644
--- a/cmds/app_process/app_main.cpp
+++ b/cmds/app_process/app_main.cpp
@@ -15,7 +15,6 @@
#include <android-base/macros.h>
#include <binder/IPCThreadState.h>
-#include <bionic/pac.h>
#include <hwbinder/IPCThreadState.h>
#include <utils/Log.h>
#include <cutils/memory.h>
@@ -183,10 +182,6 @@ int main(int argc, char* const argv[])
ALOGV("app_process main with argv: %s", argv_String.string());
}
- // Because of applications that are using PAC instructions incorrectly, PAC
- // is disabled in application processes for now.
- ScopedDisablePAC x;
-
AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
// Process command line arguments
// ignore argv[0]
diff --git a/cmds/idmap2/Android.bp b/cmds/idmap2/Android.bp
index c202f6f03b5b..6ef6845c75f2 100644
--- a/cmds/idmap2/Android.bp
+++ b/cmds/idmap2/Android.bp
@@ -52,6 +52,7 @@ cc_defaults {
"-readability-braces-around-statements",
"-readability-const-return-type",
"-readability-convert-member-functions-to-static",
+ "-readability-duplicate-include",
"-readability-else-after-return",
"-readability-identifier-length",
"-readability-named-parameter",
diff --git a/core/api/current.txt b/core/api/current.txt
index f0b86df676e1..37022d0ab402 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -8,6 +8,9 @@ package android {
public static final class Manifest.permission {
ctor public Manifest.permission();
field public static final String ACCEPT_HANDOVER = "android.permission.ACCEPT_HANDOVER";
+ field public static final String ACCESS_ADSERVICES_ATTRIBUTION = "android.permission.ACCESS_ADSERVICES_ATTRIBUTION";
+ field public static final String ACCESS_ADSERVICES_CUSTOM_AUDIENCES = "android.permission.ACCESS_ADSERVICES_CUSTOM_AUDIENCES";
+ field public static final String ACCESS_ADSERVICES_TOPICS = "android.permission.ACCESS_ADSERVICES_TOPICS";
field public static final String ACCESS_BACKGROUND_LOCATION = "android.permission.ACCESS_BACKGROUND_LOCATION";
field public static final String ACCESS_BLOBS_ACROSS_USERS = "android.permission.ACCESS_BLOBS_ACROSS_USERS";
field public static final String ACCESS_CHECKIN_PROPERTIES = "android.permission.ACCESS_CHECKIN_PROPERTIES";
@@ -17,7 +20,6 @@ package android {
field public static final String ACCESS_MEDIA_LOCATION = "android.permission.ACCESS_MEDIA_LOCATION";
field public static final String ACCESS_NETWORK_STATE = "android.permission.ACCESS_NETWORK_STATE";
field public static final String ACCESS_NOTIFICATION_POLICY = "android.permission.ACCESS_NOTIFICATION_POLICY";
- field public static final String ACCESS_SUPPLEMENTAL_APIS = "android.permission.ACCESS_SUPPLEMENTAL_APIS";
field public static final String ACCESS_WIFI_STATE = "android.permission.ACCESS_WIFI_STATE";
field public static final String ACCOUNT_MANAGER = "android.permission.ACCOUNT_MANAGER";
field public static final String ACTIVITY_RECOGNITION = "android.permission.ACTIVITY_RECOGNITION";
@@ -111,8 +113,9 @@ 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 public static final String MANAGE_WIFI_AUTO_JOIN = "android.permission.MANAGE_WIFI_AUTO_JOIN";
+ 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";
field public static final String MEDIA_CONTENT_CONTROL = "android.permission.MEDIA_CONTENT_CONTROL";
field public static final String MODIFY_AUDIO_SETTINGS = "android.permission.MODIFY_AUDIO_SETTINGS";
@@ -139,7 +142,7 @@ package android {
field @Deprecated public static final String READ_INPUT_STATE = "android.permission.READ_INPUT_STATE";
field public static final String READ_LOGS = "android.permission.READ_LOGS";
field public static final String READ_MEDIA_AUDIO = "android.permission.READ_MEDIA_AUDIO";
- field public static final String READ_MEDIA_IMAGE = "android.permission.READ_MEDIA_IMAGE";
+ field public static final String READ_MEDIA_IMAGES = "android.permission.READ_MEDIA_IMAGES";
field public static final String READ_MEDIA_VIDEO = "android.permission.READ_MEDIA_VIDEO";
field public static final String READ_NEARBY_STREAMING_POLICY = "android.permission.READ_NEARBY_STREAMING_POLICY";
field public static final String READ_PHONE_NUMBERS = "android.permission.READ_PHONE_NUMBERS";
@@ -851,7 +854,6 @@ package android {
field public static final int indicatorRight = 16843022; // 0x101010e
field public static final int indicatorStart = 16843729; // 0x10103d1
field public static final int inflatedId = 16842995; // 0x10100f3
- field public static final int inheritKeyStoreKeys;
field public static final int inheritShowWhenLocked = 16844188; // 0x101059c
field public static final int initOrder = 16842778; // 0x101001a
field public static final int initialKeyguardLayout = 16843714; // 0x10103c2
@@ -979,8 +981,8 @@ package android {
field public static final int left = 16843181; // 0x10101ad
field public static final int letterSpacing = 16843958; // 0x10104b6
field public static final int level = 16844032; // 0x1010500
- field public static final int lineBreakStyle = 16844365; // 0x101064d
- field public static final int lineBreakWordStyle = 16844366; // 0x101064e
+ field public static final int lineBreakStyle;
+ field public static final int lineBreakWordStyle;
field public static final int lineHeight = 16844159; // 0x101057f
field public static final int lineSpacingExtra = 16843287; // 0x1010217
field public static final int lineSpacingMultiplier = 16843288; // 0x1010218
@@ -2094,12 +2096,8 @@ package android {
field public static final int accessibilityActionScrollUp = 16908344; // 0x1020038
field public static final int accessibilityActionSetProgress = 16908349; // 0x102003d
field public static final int accessibilityActionShowOnScreen = 16908342; // 0x1020036
- field public static final int accessibilityActionShowSuggestions;
+ field public static final int accessibilityActionShowTextSuggestions;
field public static final int accessibilityActionShowTooltip = 16908356; // 0x1020044
- field public static final int accessibilityActionSwipeDown;
- field public static final int accessibilityActionSwipeLeft;
- field public static final int accessibilityActionSwipeRight;
- field public static final int accessibilityActionSwipeUp;
field public static final int accessibilitySystemActionBack = 16908363; // 0x102004b
field public static final int accessibilitySystemActionHome = 16908364; // 0x102004c
field public static final int accessibilitySystemActionLockScreen = 16908370; // 0x1020052
@@ -3337,7 +3335,7 @@ package android.accessibilityservice {
}
public class InputMethod {
- ctor protected InputMethod(@NonNull android.accessibilityservice.AccessibilityService);
+ ctor public InputMethod(@NonNull android.accessibilityservice.AccessibilityService);
method @Nullable public final android.accessibilityservice.InputMethod.AccessibilityInputConnection getCurrentInputConnection();
method @Nullable public final android.view.inputmethod.EditorInfo getCurrentInputEditorInfo();
method public final boolean getCurrentInputStarted();
@@ -3902,6 +3900,7 @@ package android.animation {
method public Object getAnimatedValue(String);
method public long getCurrentPlayTime();
method public long getDuration();
+ method @FloatRange(from=0) public static float getDurationScale();
method public static long getFrameDelay();
method public int getRepeatCount();
method public int getRepeatMode();
@@ -3913,6 +3912,7 @@ package android.animation {
method public static android.animation.ValueAnimator ofInt(int...);
method public static android.animation.ValueAnimator ofObject(android.animation.TypeEvaluator, java.lang.Object...);
method public static android.animation.ValueAnimator ofPropertyValuesHolder(android.animation.PropertyValuesHolder...);
+ method public static boolean registerDurationScaleChangeListener(@NonNull android.animation.ValueAnimator.DurationScaleChangeListener);
method public void removeAllUpdateListeners();
method public void removeUpdateListener(android.animation.ValueAnimator.AnimatorUpdateListener);
method public void reverse();
@@ -3929,6 +3929,7 @@ package android.animation {
method public void setRepeatMode(int);
method public void setStartDelay(long);
method public void setValues(android.animation.PropertyValuesHolder...);
+ method public static boolean unregisterDurationScaleChangeListener(@NonNull android.animation.ValueAnimator.DurationScaleChangeListener);
field public static final int INFINITE = -1; // 0xffffffff
field public static final int RESTART = 1; // 0x1
field public static final int REVERSE = 2; // 0x2
@@ -3938,6 +3939,10 @@ package android.animation {
method public void onAnimationUpdate(@NonNull android.animation.ValueAnimator);
}
+ public static interface ValueAnimator.DurationScaleChangeListener {
+ method public void onChanged(@FloatRange(from=0) float);
+ }
+
}
package android.annotation {
@@ -4277,7 +4282,6 @@ package android.app {
method public void setLocusContext(@Nullable android.content.LocusId, @Nullable android.os.Bundle);
method public final void setMediaController(android.media.session.MediaController);
method public void setPictureInPictureParams(@NonNull android.app.PictureInPictureParams);
- method public void setPreferDockBigOverlays(boolean);
method @Deprecated public final void setProgress(int);
method @Deprecated public final void setProgressBarIndeterminate(boolean);
method @Deprecated public final void setProgressBarIndeterminateVisibility(boolean);
@@ -4287,6 +4291,7 @@ package android.app {
method public final void setResult(int);
method public final void setResult(int, android.content.Intent);
method @Deprecated public final void setSecondaryProgress(int);
+ method public void setShouldDockBigOverlays(boolean);
method public void setShowWhenLocked(boolean);
method public void setTaskDescription(android.app.ActivityManager.TaskDescription);
method public void setTitle(CharSequence);
@@ -4297,6 +4302,7 @@ package android.app {
method public void setVisible(boolean);
method public final void setVolumeControlStream(int);
method public void setVrModeEnabled(boolean, @NonNull android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public boolean shouldDockBigOverlays();
method public boolean shouldShowRequestPermissionRationale(@NonNull String);
method public boolean shouldUpRecreateTask(android.content.Intent);
method public boolean showAssist(android.os.Bundle);
@@ -4525,22 +4531,36 @@ package android.app {
}
public static class ActivityManager.TaskDescription implements android.os.Parcelable {
- ctor public ActivityManager.TaskDescription(String, @DrawableRes int, int);
- ctor public ActivityManager.TaskDescription(String, @DrawableRes int);
- ctor public ActivityManager.TaskDescription(String);
- ctor public ActivityManager.TaskDescription();
+ ctor @Deprecated public ActivityManager.TaskDescription(String, @DrawableRes int, int);
+ ctor @Deprecated public ActivityManager.TaskDescription(String, @DrawableRes int);
+ ctor @Deprecated public ActivityManager.TaskDescription(String);
+ ctor @Deprecated public ActivityManager.TaskDescription();
ctor @Deprecated public ActivityManager.TaskDescription(String, android.graphics.Bitmap, int);
ctor @Deprecated public ActivityManager.TaskDescription(String, android.graphics.Bitmap);
ctor public ActivityManager.TaskDescription(android.app.ActivityManager.TaskDescription);
method public int describeContents();
+ method @ColorInt public int getBackgroundColor();
method @Deprecated public android.graphics.Bitmap getIcon();
method public String getLabel();
- method public int getPrimaryColor();
+ method @ColorInt public int getNavigationBarColor();
+ method @ColorInt public int getPrimaryColor();
+ method @ColorInt public int getStatusBarColor();
method public void readFromParcel(android.os.Parcel);
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.app.ActivityManager.TaskDescription> CREATOR;
}
+ public static final class ActivityManager.TaskDescription.Builder {
+ ctor public ActivityManager.TaskDescription.Builder();
+ method @NonNull public android.app.ActivityManager.TaskDescription build();
+ method @NonNull public android.app.ActivityManager.TaskDescription.Builder setBackgroundColor(@ColorInt int);
+ method @NonNull public android.app.ActivityManager.TaskDescription.Builder setIcon(@DrawableRes int);
+ method @NonNull public android.app.ActivityManager.TaskDescription.Builder setLabel(@Nullable String);
+ method @NonNull public android.app.ActivityManager.TaskDescription.Builder setNavigationBarColor(@ColorInt int);
+ method @NonNull public android.app.ActivityManager.TaskDescription.Builder setPrimaryColor(@ColorInt int);
+ method @NonNull public android.app.ActivityManager.TaskDescription.Builder setStatusBarColor(@ColorInt int);
+ }
+
public class ActivityOptions {
method @Nullable public android.graphics.Rect getLaunchBounds();
method public int getLaunchDisplayId();
@@ -5623,6 +5643,7 @@ package android.app {
method public boolean onException(Object, Throwable);
method public void onStart();
method public void removeMonitor(android.app.Instrumentation.ActivityMonitor);
+ method public void resetInTouchMode();
method public void runOnMainSync(Runnable);
method public void sendCharacterSync(int);
method public void sendKeyDownUpSync(int);
@@ -5807,6 +5828,7 @@ package android.app {
public class LocaleManager {
method @NonNull public android.os.LocaleList getApplicationLocales();
method @NonNull @RequiresPermission(value="android.permission.READ_APP_SPECIFIC_LOCALES", conditional=true) public android.os.LocaleList getApplicationLocales(@NonNull String);
+ method @NonNull public android.os.LocaleList getSystemLocales();
method public void setApplicationLocales(@NonNull android.os.LocaleList);
}
@@ -6637,6 +6659,15 @@ package android.app {
public final class PictureInPictureParams implements android.os.Parcelable {
method public int describeContents();
+ method @NonNull public java.util.List<android.app.RemoteAction> getActions();
+ method @Nullable public android.util.Rational getAspectRatio();
+ method @Nullable public android.app.RemoteAction getCloseAction();
+ method @Nullable public android.util.Rational getExpandedAspectRatio();
+ method @Nullable public android.graphics.Rect getSourceRectHint();
+ method @Nullable public CharSequence getSubtitle();
+ method @Nullable public CharSequence getTitle();
+ method public boolean isAutoEnterEnabled();
+ method public boolean isSeamlessResizeEnabled();
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.app.PictureInPictureParams> CREATOR;
}
@@ -7390,12 +7421,6 @@ package android.app.admin {
method @NonNull public java.util.List<java.lang.String> getDelegatedScopes(@Nullable android.content.ComponentName, @NonNull String);
method public CharSequence getDeviceOwnerLockScreenInfo();
method @Nullable public String getDevicePolicyManagementRoleHolderPackage();
- method @Nullable public android.graphics.drawable.Drawable getDrawable(@NonNull String, @NonNull String, @NonNull java.util.function.Supplier<android.graphics.drawable.Drawable>);
- method @Nullable public android.graphics.drawable.Drawable getDrawable(@NonNull String, @NonNull String, @NonNull String, @NonNull java.util.function.Supplier<android.graphics.drawable.Drawable>);
- method @Nullable public android.graphics.drawable.Icon getDrawableAsIcon(@NonNull String, @NonNull String, @NonNull String, @Nullable android.graphics.drawable.Icon);
- method @Nullable public android.graphics.drawable.Icon getDrawableAsIcon(@NonNull String, @NonNull String, @Nullable android.graphics.drawable.Icon);
- method @Nullable public android.graphics.drawable.Drawable getDrawableForDensity(@NonNull String, @NonNull String, int, @NonNull java.util.function.Supplier<android.graphics.drawable.Drawable>);
- method @Nullable public android.graphics.drawable.Drawable getDrawableForDensity(@NonNull String, @NonNull String, @NonNull String, int, @NonNull java.util.function.Supplier<android.graphics.drawable.Drawable>);
method public CharSequence getEndUserSessionMessage(@NonNull android.content.ComponentName);
method @NonNull public String getEnrollmentSpecificId();
method @Nullable public android.app.admin.FactoryResetProtectionPolicy getFactoryResetProtectionPolicy(@Nullable android.content.ComponentName);
@@ -7439,9 +7464,10 @@ package android.app.admin {
method @Nullable public java.util.List<java.lang.String> getPermittedCrossProfileNotificationListeners(@NonNull android.content.ComponentName);
method @Nullable public java.util.List<java.lang.String> getPermittedInputMethods(@NonNull android.content.ComponentName);
method public int getPersonalAppsSuspendedReasons(@NonNull android.content.ComponentName);
- method @NonNull public android.app.admin.PreferentialNetworkServiceConfig getPreferentialNetworkServiceConfig();
+ method @NonNull public java.util.List<android.app.admin.PreferentialNetworkServiceConfig> getPreferentialNetworkServiceConfigs();
method public int getRequiredPasswordComplexity();
method public long getRequiredStrongAuthTimeout(@Nullable android.content.ComponentName);
+ method @NonNull public android.app.admin.DevicePolicyResourcesManager getResources();
method public boolean getScreenCaptureDisabled(@Nullable android.content.ComponentName);
method public java.util.List<android.os.UserHandle> getSecondaryUsers(@NonNull android.content.ComponentName);
method public CharSequence getShortSupportMessage(@NonNull android.content.ComponentName);
@@ -7584,7 +7610,7 @@ package android.app.admin {
method public boolean setPermittedCrossProfileNotificationListeners(@NonNull android.content.ComponentName, @Nullable java.util.List<java.lang.String>);
method public boolean setPermittedInputMethods(@NonNull android.content.ComponentName, java.util.List<java.lang.String>);
method public void setPersonalAppsSuspended(@NonNull android.content.ComponentName, boolean);
- method public void setPreferentialNetworkServiceConfig(@NonNull android.app.admin.PreferentialNetworkServiceConfig);
+ method public void setPreferentialNetworkServiceConfigs(@NonNull java.util.List<android.app.admin.PreferentialNetworkServiceConfig>);
method public void setPreferentialNetworkServiceEnabled(boolean);
method public void setProfileEnabled(@NonNull android.content.ComponentName);
method public void setProfileName(@NonNull android.content.ComponentName, String);
@@ -7689,6 +7715,7 @@ package android.app.admin {
field public static final String EXTRA_PROVISIONING_SKIP_ENCRYPTION = "android.app.extra.PROVISIONING_SKIP_ENCRYPTION";
field @Deprecated public static final String EXTRA_PROVISIONING_SKIP_USER_CONSENT = "android.app.extra.PROVISIONING_SKIP_USER_CONSENT";
field public static final String EXTRA_PROVISIONING_TIME_ZONE = "android.app.extra.PROVISIONING_TIME_ZONE";
+ field public static final String EXTRA_PROVISIONING_USE_MOBILE_DATA = "android.app.extra.PROVISIONING_USE_MOBILE_DATA";
field public static final String EXTRA_PROVISIONING_WIFI_ANONYMOUS_IDENTITY = "android.app.extra.PROVISIONING_WIFI_ANONYMOUS_IDENTITY";
field public static final String EXTRA_PROVISIONING_WIFI_CA_CERTIFICATE = "android.app.extra.PROVISIONING_WIFI_CA_CERTIFICATE";
field public static final String EXTRA_PROVISIONING_WIFI_DOMAIN = "android.app.extra.PROVISIONING_WIFI_DOMAIN";
@@ -7808,31 +7835,18 @@ package android.app.admin {
}
public final class DevicePolicyResources {
- }
-
- public static final class DevicePolicyResources.Drawables {
- field public static final String UNDEFINED = "UNDEFINED";
- field public static final String WORK_PROFILE_ICON = "WORK_PROFILE_ICON";
- field public static final String WORK_PROFILE_ICON_BADGE = "WORK_PROFILE_ICON_BADGE";
- field public static final String WORK_PROFILE_OFF_ICON = "WORK_PROFILE_OFF_ICON";
- field public static final String WORK_PROFILE_USER_ICON = "WORK_PROFILE_USER_ICON";
- }
-
- public static final class DevicePolicyResources.Drawables.Source {
- field public static final String HOME_WIDGET = "HOME_WIDGET";
- field public static final String LAUNCHER_OFF_BUTTON = "LAUNCHER_OFF_BUTTON";
- field public static final String NOTIFICATION = "NOTIFICATION";
- field public static final String PROFILE_SWITCH_ANIMATION = "PROFILE_SWITCH_ANIMATION";
- field public static final String QUICK_SETTINGS = "QUICK_SETTINGS";
- field public static final String STATUS_BAR = "STATUS_BAR";
field public static final String UNDEFINED = "UNDEFINED";
}
- public static final class DevicePolicyResources.Drawables.Style {
- field public static final String DEFAULT = "DEFAULT";
- field public static final String OUTLINE = "OUTLINE";
- field public static final String SOLID_COLORED = "SOLID_COLORED";
- field public static final String SOLID_NOT_COLORED = "SOLID_NOT_COLORED";
+ public class DevicePolicyResourcesManager {
+ method @Nullable public android.graphics.drawable.Drawable getDrawable(@NonNull String, @NonNull String, @NonNull java.util.function.Supplier<android.graphics.drawable.Drawable>);
+ method @Nullable public android.graphics.drawable.Drawable getDrawable(@NonNull String, @NonNull String, @NonNull String, @NonNull java.util.function.Supplier<android.graphics.drawable.Drawable>);
+ method @Nullable public android.graphics.drawable.Icon getDrawableAsIcon(@NonNull String, @NonNull String, @NonNull String, @Nullable android.graphics.drawable.Icon);
+ method @Nullable public android.graphics.drawable.Icon getDrawableAsIcon(@NonNull String, @NonNull String, @Nullable android.graphics.drawable.Icon);
+ method @Nullable public android.graphics.drawable.Drawable getDrawableForDensity(@NonNull String, @NonNull String, int, @NonNull java.util.function.Supplier<android.graphics.drawable.Drawable>);
+ method @Nullable public android.graphics.drawable.Drawable getDrawableForDensity(@NonNull String, @NonNull String, @NonNull String, int, @NonNull java.util.function.Supplier<android.graphics.drawable.Drawable>);
+ method @Nullable public String getString(@NonNull String, @NonNull java.util.function.Supplier<java.lang.String>);
+ method @Nullable public String getString(@NonNull String, @NonNull java.util.function.Supplier<java.lang.String>, @NonNull java.lang.Object...);
}
public final class DnsEvent extends android.app.admin.NetworkEvent implements android.os.Parcelable {
@@ -9719,8 +9733,8 @@ package android.content {
method @Nullable public abstract android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, @Nullable String, @Nullable android.os.Handler, int);
method @Deprecated @RequiresPermission(android.Manifest.permission.BROADCAST_STICKY) public abstract void removeStickyBroadcast(@RequiresPermission android.content.Intent);
method @Deprecated @RequiresPermission(allOf={"android.permission.INTERACT_ACROSS_USERS", android.Manifest.permission.BROADCAST_STICKY}) public abstract void removeStickyBroadcastAsUser(@RequiresPermission android.content.Intent, android.os.UserHandle);
- method public void revokeOwnPermissionOnKill(@NonNull String);
- method public void revokeOwnPermissionsOnKill(@NonNull java.util.Collection<java.lang.String>);
+ method public void revokeSelfPermissionOnKill(@NonNull String);
+ method public void revokeSelfPermissionsOnKill(@NonNull java.util.Collection<java.lang.String>);
method public abstract void revokeUriPermission(android.net.Uri, int);
method public abstract void revokeUriPermission(String, android.net.Uri, int);
method public abstract void sendBroadcast(@RequiresPermission android.content.Intent);
@@ -10108,12 +10122,16 @@ package android.content {
method @Nullable public long[] getLongArrayExtra(String);
method public long getLongExtra(String, long);
method @Nullable public String getPackage();
- method @Nullable public android.os.Parcelable[] getParcelableArrayExtra(String);
- method @Nullable public <T extends android.os.Parcelable> java.util.ArrayList<T> getParcelableArrayListExtra(String);
- method @Nullable public <T extends android.os.Parcelable> T getParcelableExtra(String);
+ method @Deprecated @Nullable public android.os.Parcelable[] getParcelableArrayExtra(String);
+ method @Nullable public <T> T[] getParcelableArrayExtra(@Nullable String, @NonNull Class<T>);
+ method @Deprecated @Nullable public <T extends android.os.Parcelable> java.util.ArrayList<T> getParcelableArrayListExtra(String);
+ method @Nullable public <T> java.util.ArrayList<T> getParcelableArrayListExtra(@Nullable String, @NonNull Class<? extends T>);
+ method @Deprecated @Nullable public <T extends android.os.Parcelable> T getParcelableExtra(String);
+ method @Nullable public <T> T getParcelableExtra(@Nullable String, @NonNull Class<T>);
method @Nullable public String getScheme();
method @Nullable public android.content.Intent getSelector();
- method @Nullable public java.io.Serializable getSerializableExtra(String);
+ method @Deprecated @Nullable public java.io.Serializable getSerializableExtra(String);
+ method @Nullable public <T extends java.io.Serializable> T getSerializableExtra(@Nullable String, @NonNull Class<T>);
method @Nullable public short[] getShortArrayExtra(String);
method public short getShortExtra(String, short);
method @Nullable public android.graphics.Rect getSourceBounds();
@@ -10422,13 +10440,11 @@ package android.content {
field public static final String EXTRA_LOCAL_ONLY = "android.intent.extra.LOCAL_ONLY";
field public static final String EXTRA_LOCUS_ID = "android.intent.extra.LOCUS_ID";
field public static final String EXTRA_MIME_TYPES = "android.intent.extra.MIME_TYPES";
- field public static final String EXTRA_NEW_UID = "android.intent.extra.NEW_UID";
field public static final String EXTRA_NOT_UNKNOWN_SOURCE = "android.intent.extra.NOT_UNKNOWN_SOURCE";
field public static final String EXTRA_ORIGINATING_URI = "android.intent.extra.ORIGINATING_URI";
field public static final String EXTRA_PACKAGE_NAME = "android.intent.extra.PACKAGE_NAME";
field public static final String EXTRA_PERMISSION_GROUP_NAME = "android.intent.extra.PERMISSION_GROUP_NAME";
field public static final String EXTRA_PHONE_NUMBER = "android.intent.extra.PHONE_NUMBER";
- field public static final String EXTRA_PREVIOUS_UID = "android.intent.extra.PREVIOUS_UID";
field public static final String EXTRA_PROCESS_TEXT = "android.intent.extra.PROCESS_TEXT";
field public static final String EXTRA_PROCESS_TEXT_READONLY = "android.intent.extra.PROCESS_TEXT_READONLY";
field public static final String EXTRA_QUICK_VIEW_FEATURES = "android.intent.extra.QUICK_VIEW_FEATURES";
@@ -10460,7 +10476,6 @@ package android.content {
field public static final String EXTRA_TIMEZONE = "time-zone";
field public static final String EXTRA_TITLE = "android.intent.extra.TITLE";
field public static final String EXTRA_UID = "android.intent.extra.UID";
- field public static final String EXTRA_UID_CHANGING = "android.intent.extra.UID_CHANGING";
field public static final String EXTRA_USER = "android.intent.extra.USER";
field public static final String EXTRA_USER_INITIATED = "android.intent.extra.USER_INITIATED";
field public static final int FILL_IN_ACTION = 1; // 0x1
@@ -11223,6 +11238,33 @@ package android.content.pm {
field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.Attribution> CREATOR;
}
+ public final class Capability implements android.os.Parcelable {
+ method public int describeContents();
+ method @NonNull public String getName();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.Capability> CREATOR;
+ }
+
+ public static final class Capability.Builder {
+ ctor public Capability.Builder(@NonNull String);
+ method @NonNull public android.content.pm.Capability build();
+ }
+
+ public final class CapabilityParams implements android.os.Parcelable {
+ method public int describeContents();
+ method @NonNull public java.util.List<java.lang.String> getAliases();
+ method @NonNull public String getName();
+ method @NonNull public String getValue();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.CapabilityParams> CREATOR;
+ }
+
+ public static final class CapabilityParams.Builder {
+ ctor public CapabilityParams.Builder(@NonNull String, @NonNull String);
+ method @NonNull public android.content.pm.CapabilityParams.Builder addAlias(@NonNull String);
+ method @NonNull public android.content.pm.CapabilityParams build();
+ }
+
public final class ChangedPackages implements android.os.Parcelable {
ctor public ChangedPackages(int, @NonNull java.util.List<java.lang.String>);
method public int describeContents();
@@ -11293,6 +11335,7 @@ package android.content.pm {
method @RequiresPermission(anyOf={android.Manifest.permission.INTERACT_ACROSS_PROFILES, "android.permission.INTERACT_ACROSS_USERS"}) public void startActivity(@NonNull android.content.Intent, @NonNull android.os.UserHandle, @Nullable android.app.Activity);
method @RequiresPermission(anyOf={android.Manifest.permission.INTERACT_ACROSS_PROFILES, "android.permission.INTERACT_ACROSS_USERS"}) public void startActivity(@NonNull android.content.Intent, @NonNull android.os.UserHandle, @Nullable android.app.Activity, @Nullable android.os.Bundle);
method public void startMainActivity(@NonNull android.content.ComponentName, @NonNull android.os.UserHandle);
+ method public void startMainActivity(@NonNull android.content.ComponentName, @NonNull android.os.UserHandle, @Nullable android.app.Activity, @Nullable android.os.Bundle);
field public static final String ACTION_CAN_INTERACT_ACROSS_PROFILES_CHANGED = "android.content.pm.action.CAN_INTERACT_ACROSS_PROFILES_CHANGED";
}
@@ -12283,7 +12326,8 @@ package android.content.pm {
method @NonNull public static android.content.pm.ShortcutInfo createFromGenericDocument(@NonNull android.content.Context, @NonNull android.app.appsearch.GenericDocument);
method public int describeContents();
method @Nullable public android.content.ComponentName getActivity();
- method @NonNull public java.util.List<java.lang.String> getCapabilityParameterValues(@NonNull String, @NonNull String);
+ method @NonNull public java.util.List<android.content.pm.Capability> getCapabilities();
+ method @NonNull public java.util.List<android.content.pm.CapabilityParams> getCapabilityParams(@NonNull android.content.pm.Capability);
method @Nullable public java.util.Set<java.lang.String> getCategories();
method @Nullable public CharSequence getDisabledMessage();
method public int getDisabledReason();
@@ -12298,7 +12342,6 @@ package android.content.pm {
method public int getRank();
method @Nullable public CharSequence getShortLabel();
method public android.os.UserHandle getUserHandle();
- method public boolean hasCapability(@NonNull String);
method public boolean hasKeyFieldsOnly();
method public boolean isCached();
method public boolean isDeclaredInManifest();
@@ -12323,7 +12366,7 @@ package android.content.pm {
public static class ShortcutInfo.Builder {
ctor public ShortcutInfo.Builder(android.content.Context, String);
- method @NonNull public android.content.pm.ShortcutInfo.Builder addCapabilityBinding(@NonNull String, @Nullable String, @Nullable java.util.List<java.lang.String>);
+ method @NonNull public android.content.pm.ShortcutInfo.Builder addCapabilityBinding(@NonNull android.content.pm.Capability, @Nullable android.content.pm.CapabilityParams);
method @NonNull public android.content.pm.ShortcutInfo build();
method @NonNull public android.content.pm.ShortcutInfo.Builder setActivity(@NonNull android.content.ComponentName);
method @NonNull public android.content.pm.ShortcutInfo.Builder setCategories(java.util.Set<java.lang.String>);
@@ -16400,12 +16443,8 @@ package android.graphics.pdf {
package android.graphics.text {
public final class LineBreakConfig {
- ctor public LineBreakConfig();
method public int getLineBreakStyle();
method public int getLineBreakWordStyle();
- method public void set(@NonNull android.graphics.text.LineBreakConfig);
- method public void setLineBreakStyle(int);
- method public void setLineBreakWordStyle(int);
field public static final int LINE_BREAK_STYLE_LOOSE = 1; // 0x1
field public static final int LINE_BREAK_STYLE_NONE = 0; // 0x0
field public static final int LINE_BREAK_STYLE_NORMAL = 2; // 0x2
@@ -16414,6 +16453,13 @@ package android.graphics.text {
field public static final int LINE_BREAK_WORD_STYLE_PHRASE = 1; // 0x1
}
+ public static final class LineBreakConfig.Builder {
+ ctor public LineBreakConfig.Builder();
+ method @NonNull public android.graphics.text.LineBreakConfig build();
+ method @NonNull public android.graphics.text.LineBreakConfig.Builder setLineBreakStyle(int);
+ method @NonNull public android.graphics.text.LineBreakConfig.Builder setLineBreakWordStyle(int);
+ }
+
public class LineBreaker {
method @NonNull public android.graphics.text.LineBreaker.Result computeLineBreaks(@NonNull android.graphics.text.MeasuredText, @NonNull android.graphics.text.LineBreaker.ParagraphConstraints, @IntRange(from=0) int);
field public static final int BREAK_STRATEGY_BALANCED = 2; // 0x2
@@ -17401,7 +17447,7 @@ package android.hardware.camera2 {
field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Long> REQUEST_RECOMMENDED_TEN_BIT_DYNAMIC_RANGE_PROFILE;
field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Float> SCALER_AVAILABLE_MAX_DIGITAL_ZOOM;
field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> SCALER_AVAILABLE_ROTATE_AND_CROP_MODES;
- field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> SCALER_AVAILABLE_STREAM_USE_CASES;
+ field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<long[]> SCALER_AVAILABLE_STREAM_USE_CASES;
field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> SCALER_CROPPING_TYPE;
field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<android.util.Size> SCALER_DEFAULT_SECURE_IMAGE_SIZE;
field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<android.hardware.camera2.params.MandatoryStreamCombination[]> SCALER_MANDATORY_CONCURRENT_STREAM_COMBINATIONS;
@@ -18186,7 +18232,7 @@ package android.hardware.camera2.params {
method public int get10BitFormat();
method @NonNull public java.util.List<android.util.Size> getAvailableSizes();
method public int getFormat();
- method public int getStreamUseCase();
+ method public long getStreamUseCase();
method public boolean is10BitCapable();
method public boolean isInput();
method public boolean isMaximumSize();
@@ -18244,7 +18290,7 @@ package android.hardware.camera2.params {
method public long getDynamicRangeProfile();
method public int getMaxSharedSurfaceCount();
method public int getMirrorMode();
- method public int getStreamUseCase();
+ method public long getStreamUseCase();
method @Nullable public android.view.Surface getSurface();
method public int getSurfaceGroupId();
method @NonNull public java.util.List<android.view.Surface> getSurfaces();
@@ -18254,7 +18300,7 @@ package android.hardware.camera2.params {
method public void setDynamicRangeProfile(long);
method public void setMirrorMode(int);
method public void setPhysicalCameraId(@Nullable String);
- method public void setStreamUseCase(int);
+ method public void setStreamUseCase(long);
method public void setTimestampBase(int);
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.hardware.camera2.params.OutputConfiguration> CREATOR;
@@ -18820,6 +18866,7 @@ package android.inputmethodservice {
method public void onStartInput(android.view.inputmethod.EditorInfo, boolean);
method public void onStartInputView(android.view.inputmethod.EditorInfo, boolean);
method public boolean onStartStylusHandwriting();
+ method public void onStylusHandwritingMotionEvent(@NonNull android.view.MotionEvent);
method public void onUnbindInput();
method @Deprecated public void onUpdateCursor(android.graphics.Rect);
method public void onUpdateCursorAnchorInfo(android.view.inputmethod.CursorAnchorInfo);
@@ -19465,26 +19512,26 @@ package android.location {
method @NonNull public static String convert(@FloatRange double, int);
method @FloatRange public static double convert(@NonNull String);
method public int describeContents();
- method public static void distanceBetween(@FloatRange double, @FloatRange double, @FloatRange double, @FloatRange double, float[]);
- method @FloatRange public float distanceTo(@NonNull android.location.Location);
- method public void dump(@NonNull android.util.Printer, @Nullable String);
- method @FloatRange public float getAccuracy();
+ method public static void distanceBetween(@FloatRange(from=-90.0, to=90.0) double, @FloatRange(from=-180.0, to=180.0) double, @FloatRange(from=-90.0, to=90.0) double, @FloatRange(from=-180.0, to=180.0) double, float[]);
+ method @FloatRange(from=0.0) public float distanceTo(@NonNull android.location.Location);
+ method @Deprecated public void dump(@NonNull android.util.Printer, @Nullable String);
+ method @FloatRange(from=0.0) public float getAccuracy();
method @FloatRange public double getAltitude();
- method @FloatRange(from=0.0f, to=360.0f, toInclusive=false) public float getBearing();
- method @FloatRange public float getBearingAccuracyDegrees();
- method @IntRange public long getElapsedRealtimeAgeMillis();
- method @IntRange public long getElapsedRealtimeAgeMillis(@IntRange long);
- method @IntRange public long getElapsedRealtimeMillis();
- method @IntRange public long getElapsedRealtimeNanos();
- method @FloatRange public double getElapsedRealtimeUncertaintyNanos();
+ method @FloatRange(from=0.0, to=360.0, toInclusive=false) public float getBearing();
+ method @FloatRange(from=0.0) public float getBearingAccuracyDegrees();
+ method @IntRange(from=0) public long getElapsedRealtimeAgeMillis();
+ method public long getElapsedRealtimeAgeMillis(@IntRange(from=0) long);
+ method @IntRange(from=0) public long getElapsedRealtimeMillis();
+ method @IntRange(from=0) public long getElapsedRealtimeNanos();
+ method @FloatRange(from=0.0) public double getElapsedRealtimeUncertaintyNanos();
method @Nullable public android.os.Bundle getExtras();
- method @FloatRange public double getLatitude();
- method @FloatRange public double getLongitude();
+ method @FloatRange(from=-90.0, to=90.0) public double getLatitude();
+ method @FloatRange(from=-180.0, to=180.0) public double getLongitude();
method @Nullable public String getProvider();
- method @FloatRange public float getSpeed();
- method @FloatRange public float getSpeedAccuracyMetersPerSecond();
- method @IntRange public long getTime();
- method @FloatRange public float getVerticalAccuracyMeters();
+ method @FloatRange(from=0.0) public float getSpeed();
+ method @FloatRange(from=0.0) public float getSpeedAccuracyMetersPerSecond();
+ method @IntRange(from=0) public long getTime();
+ method @FloatRange(from=0.0) public float getVerticalAccuracyMeters();
method public boolean hasAccuracy();
method public boolean hasAltitude();
method public boolean hasBearing();
@@ -19506,21 +19553,21 @@ package android.location {
method public void removeVerticalAccuracy();
method public void reset();
method public void set(@NonNull android.location.Location);
- method public void setAccuracy(@FloatRange float);
+ method public void setAccuracy(@FloatRange(from=0.0) float);
method public void setAltitude(@FloatRange double);
method public void setBearing(@FloatRange(fromInclusive=false, toInclusive=false) float);
- method public void setBearingAccuracyDegrees(@FloatRange float);
- method public void setElapsedRealtimeNanos(@IntRange long);
- method public void setElapsedRealtimeUncertaintyNanos(@FloatRange double);
+ method public void setBearingAccuracyDegrees(@FloatRange(from=0.0) float);
+ method public void setElapsedRealtimeNanos(@IntRange(from=0) long);
+ method public void setElapsedRealtimeUncertaintyNanos(@FloatRange(from=0.0) double);
method public void setExtras(@Nullable android.os.Bundle);
- method public void setLatitude(@FloatRange double);
- method public void setLongitude(@FloatRange double);
+ method public void setLatitude(@FloatRange(from=-90.0, to=90.0) double);
+ method public void setLongitude(@FloatRange(from=-180.0, to=180.0) double);
method public void setMock(boolean);
method public void setProvider(@Nullable String);
- method public void setSpeed(@FloatRange float);
- method public void setSpeedAccuracyMetersPerSecond(@FloatRange float);
- method public void setTime(@IntRange long);
- method public void setVerticalAccuracyMeters(@FloatRange float);
+ method public void setSpeed(@FloatRange(from=0.0) float);
+ method public void setSpeedAccuracyMetersPerSecond(@FloatRange(from=0.0) float);
+ method public void setTime(@IntRange(from=0) long);
+ method public void setVerticalAccuracyMeters(@FloatRange(from=0.0) float);
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.location.Location> CREATOR;
field public static final int FORMAT_DEGREES = 0; // 0x0
@@ -22164,7 +22211,7 @@ package android.media {
field public static final String KEY_AAC_DRC_OUTPUT_LOUDNESS = "aac-drc-output-loudness";
field public static final String KEY_AAC_DRC_TARGET_REFERENCE_LEVEL = "aac-target-ref-level";
field public static final String KEY_AAC_ENCODED_TARGET_LEVEL = "aac-encoded-target-level";
- field public static final String KEY_AAC_MAX_OUTPUT_CHANNEL_COUNT = "aac-max-output-channel_count";
+ field @Deprecated public static final String KEY_AAC_MAX_OUTPUT_CHANNEL_COUNT = "aac-max-output-channel_count";
field public static final String KEY_AAC_PROFILE = "aac-profile";
field public static final String KEY_AAC_SBR_MODE = "aac-sbr-mode";
field public static final String KEY_ALLOW_FRAME_DROP = "allow-frame-drop";
@@ -22183,6 +22230,10 @@ package android.media {
field public static final String KEY_COLOR_TRANSFER_REQUEST = "color-transfer-request";
field public static final String KEY_COMPLEXITY = "complexity";
field public static final String KEY_CREATE_INPUT_SURFACE_SUSPENDED = "create-input-buffers-suspended";
+ field public static final String KEY_CROP_BOTTOM = "crop-bottom";
+ field public static final String KEY_CROP_LEFT = "crop-left";
+ field public static final String KEY_CROP_RIGHT = "crop-right";
+ field public static final String KEY_CROP_TOP = "crop-top";
field public static final String KEY_DURATION = "durationUs";
field public static final String KEY_ENCODER_DELAY = "encoder-delay";
field public static final String KEY_ENCODER_PADDING = "encoder-padding";
@@ -22872,7 +22923,6 @@ package android.media {
method public int describeContents();
method @Nullable public String getClientPackageName();
method public int getConnectionState();
- method @NonNull public java.util.Set<java.lang.String> getDeduplicationIds();
method @Nullable public CharSequence getDescription();
method @Nullable public android.os.Bundle getExtras();
method @NonNull public java.util.List<java.lang.String> getFeatures();
@@ -22906,7 +22956,6 @@ package android.media {
method @NonNull public android.media.MediaRoute2Info.Builder clearFeatures();
method @NonNull public android.media.MediaRoute2Info.Builder setClientPackageName(@Nullable String);
method @NonNull public android.media.MediaRoute2Info.Builder setConnectionState(int);
- method @NonNull public android.media.MediaRoute2Info.Builder setDeduplicationIds(@NonNull java.util.Set<java.lang.String>);
method @NonNull public android.media.MediaRoute2Info.Builder setDescription(@Nullable CharSequence);
method @NonNull public android.media.MediaRoute2Info.Builder setExtras(@Nullable android.os.Bundle);
method @NonNull public android.media.MediaRoute2Info.Builder setIconUri(@Nullable android.net.Uri);
@@ -23433,11 +23482,8 @@ package android.media {
public final class RouteDiscoveryPreference implements android.os.Parcelable {
method public int describeContents();
- method @NonNull public java.util.List<java.lang.String> getAllowedPackages();
- method @NonNull public java.util.List<java.lang.String> getDeduplicationPackageOrder();
method @NonNull public java.util.List<java.lang.String> getPreferredFeatures();
method public boolean shouldPerformActiveScan();
- method public boolean shouldRemoveDuplicates();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.media.RouteDiscoveryPreference> CREATOR;
}
@@ -23446,8 +23492,6 @@ package android.media {
ctor public RouteDiscoveryPreference.Builder(@NonNull java.util.List<java.lang.String>, boolean);
ctor public RouteDiscoveryPreference.Builder(@NonNull android.media.RouteDiscoveryPreference);
method @NonNull public android.media.RouteDiscoveryPreference build();
- method @NonNull public android.media.RouteDiscoveryPreference.Builder setAllowedPackages(@NonNull java.util.List<java.lang.String>);
- method @NonNull public android.media.RouteDiscoveryPreference.Builder setDeduplicationPackageOrder(@NonNull java.util.List<java.lang.String>);
method @NonNull public android.media.RouteDiscoveryPreference.Builder setPreferredFeatures(@NonNull java.util.List<java.lang.String>);
method @NonNull public android.media.RouteDiscoveryPreference.Builder setShouldPerformActiveScan(boolean);
}
@@ -23526,17 +23570,24 @@ package android.media {
}
public class Spatializer {
+ method public void addOnHeadTrackerAvailableListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.Spatializer.OnHeadTrackerAvailableListener);
method public void addOnSpatializerStateChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.Spatializer.OnSpatializerStateChangedListener);
method public boolean canBeSpatialized(@NonNull android.media.AudioAttributes, @NonNull android.media.AudioFormat);
method public int getImmersiveAudioLevel();
method public boolean isAvailable();
method public boolean isEnabled();
+ method public boolean isHeadTrackerAvailable();
+ method public void removeOnHeadTrackerAvailableListener(@NonNull android.media.Spatializer.OnHeadTrackerAvailableListener);
method public void removeOnSpatializerStateChangedListener(@NonNull android.media.Spatializer.OnSpatializerStateChangedListener);
field public static final int SPATIALIZER_IMMERSIVE_LEVEL_MULTICHANNEL = 1; // 0x1
field public static final int SPATIALIZER_IMMERSIVE_LEVEL_NONE = 0; // 0x0
field public static final int SPATIALIZER_IMMERSIVE_LEVEL_OTHER = -1; // 0xffffffff
}
+ public static interface Spatializer.OnHeadTrackerAvailableListener {
+ method public void onHeadTrackerAvailableChanged(@NonNull android.media.Spatializer, boolean);
+ }
+
public static interface Spatializer.OnSpatializerStateChangedListener {
method public void onSpatializerAvailableChanged(@NonNull android.media.Spatializer, boolean);
method public void onSpatializerEnabledChanged(@NonNull android.media.Spatializer, boolean);
@@ -25169,17 +25220,23 @@ package android.media.tv {
}
public final class CommandRequest extends android.media.tv.BroadcastInfoRequest implements android.os.Parcelable {
- ctor public CommandRequest(int, int, @NonNull String, @NonNull String, @NonNull String);
+ ctor public CommandRequest(int, int, @NonNull String, @NonNull String, @NonNull String, @NonNull String);
+ method @NonNull public String getArgumentType();
method @NonNull public String getArguments();
method @NonNull public String getName();
- method @NonNull public String getNameSpace();
+ method @NonNull public String getNamespace();
+ field public static final String ARGUMENT_TYPE_JSON = "json";
+ field public static final String ARGUMENT_TYPE_XML = "xml";
field @NonNull public static final android.os.Parcelable.Creator<android.media.tv.CommandRequest> CREATOR;
}
public final class CommandResponse extends android.media.tv.BroadcastInfoResponse implements android.os.Parcelable {
- ctor public CommandResponse(int, int, int, @Nullable String);
+ ctor public CommandResponse(int, int, int, @Nullable String, @NonNull String);
method @Nullable public String getResponse();
+ method @NonNull public String getResponseType();
field @NonNull public static final android.os.Parcelable.Creator<android.media.tv.CommandResponse> CREATOR;
+ field public static final String RESPONSE_TYPE_JSON = "json";
+ field public static final String RESPONSE_TYPE_XML = "xml";
}
public final class DsmccRequest extends android.media.tv.BroadcastInfoRequest implements android.os.Parcelable {
@@ -25244,7 +25301,7 @@ package android.media.tv {
ctor public StreamEventResponse(int, int, int, int, long, @Nullable byte[]);
method @Nullable public byte[] getData();
method public int getEventId();
- method public long getNpt();
+ method public long getNptMillis();
field @NonNull public static final android.os.Parcelable.Creator<android.media.tv.StreamEventResponse> CREATOR;
}
@@ -25274,7 +25331,7 @@ package android.media.tv {
public final class TimelineResponse extends android.media.tv.BroadcastInfoResponse implements android.os.Parcelable {
ctor public TimelineResponse(int, int, int, @Nullable String, int, int, long, long);
- method @Nullable public String getSelector();
+ method @Nullable public android.net.Uri getSelector();
method public long getTicks();
method public int getUnitsPerSecond();
method public int getUnitsPerTick();
@@ -26037,7 +26094,7 @@ package android.media.tv {
method public void onContentAllowed(String);
method public void onContentBlocked(String, android.media.tv.TvContentRating);
method public void onDisconnected(String);
- method public void onSignalStrength(@NonNull String, int);
+ method public void onSignalStrengthUpdated(@NonNull String, int);
method public void onTimeShiftStatusChanged(String, int);
method public void onTrackSelected(String, int, String);
method public void onTracksChanged(String, java.util.List<android.media.tv.TvTrackInfo>);
@@ -26052,44 +26109,18 @@ package android.media.tv {
package android.media.tv.interactive {
public final class AppLinkInfo implements android.os.Parcelable {
+ ctor public AppLinkInfo(@NonNull String, @NonNull String, @NonNull String);
method public int describeContents();
- method @NonNull public String getClassName();
- method @NonNull public String getPackageName();
- method @Nullable public String getUriHost();
- method @Nullable public String getUriPrefix();
- method @Nullable public String getUriScheme();
+ method @NonNull public android.content.ComponentName getComponentName();
+ method @NonNull public android.net.Uri getUri();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.media.tv.interactive.AppLinkInfo> CREATOR;
}
- public static final class AppLinkInfo.Builder {
- ctor public AppLinkInfo.Builder(@NonNull String, @NonNull String);
- method @NonNull public android.media.tv.interactive.AppLinkInfo build();
- method @NonNull public android.media.tv.interactive.AppLinkInfo.Builder setClassName(@NonNull String);
- method @NonNull public android.media.tv.interactive.AppLinkInfo.Builder setPackageName(@NonNull String);
- method @NonNull public android.media.tv.interactive.AppLinkInfo.Builder setUriHost(@Nullable String);
- method @NonNull public android.media.tv.interactive.AppLinkInfo.Builder setUriPrefix(@Nullable String);
- method @NonNull public android.media.tv.interactive.AppLinkInfo.Builder setUriScheme(@Nullable String);
- }
-
- public final class TvInteractiveAppInfo implements android.os.Parcelable {
- ctor public TvInteractiveAppInfo(@NonNull android.content.Context, @NonNull android.content.ComponentName);
- method public int describeContents();
- method @NonNull public String getId();
- method @Nullable public android.content.pm.ServiceInfo getServiceInfo();
- method @NonNull public int getSupportedTypes();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.media.tv.interactive.TvInteractiveAppInfo> CREATOR;
- field public static final int INTERACTIVE_APP_TYPE_ATSC = 2; // 0x2
- field public static final int INTERACTIVE_APP_TYPE_GINGA = 4; // 0x4
- field public static final int INTERACTIVE_APP_TYPE_HBBTV = 1; // 0x1
- }
-
public final class TvInteractiveAppManager {
- method @NonNull public java.util.List<android.media.tv.interactive.TvInteractiveAppInfo> getTvInteractiveAppServiceList();
- method public void prepare(@NonNull String, int);
+ method @NonNull public java.util.List<android.media.tv.interactive.TvInteractiveAppServiceInfo> getTvInteractiveAppServiceList();
method public void registerAppLinkInfo(@NonNull String, @NonNull android.media.tv.interactive.AppLinkInfo);
- method public void registerCallback(@NonNull android.media.tv.interactive.TvInteractiveAppManager.TvInteractiveAppCallback, @NonNull java.util.concurrent.Executor);
+ method public void registerCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.tv.interactive.TvInteractiveAppManager.TvInteractiveAppCallback);
method public void sendAppLinkCommand(@NonNull String, @NonNull android.os.Bundle);
method public void unregisterAppLinkInfo(@NonNull String, @NonNull android.media.tv.interactive.AppLinkInfo);
method public void unregisterCallback(@NonNull android.media.tv.interactive.TvInteractiveAppManager.TvInteractiveAppCallback);
@@ -26110,6 +26141,7 @@ package android.media.tv.interactive {
field public static final String INTENT_KEY_BI_INTERACTIVE_APP_TYPE = "bi_interactive_app_type";
field public static final String INTENT_KEY_BI_INTERACTIVE_APP_URI = "bi_interactive_app_uri";
field public static final String INTENT_KEY_CHANNEL_URI = "channel_uri";
+ field public static final String INTENT_KEY_COMMAND_TYPE = "command_type";
field public static final String INTENT_KEY_INTERACTIVE_APP_SERVICE_ID = "interactive_app_id";
field public static final String INTENT_KEY_TV_INPUT_ID = "tv_input_id";
field public static final int INTERACTIVE_APP_STATE_ERROR = 3; // 0x3
@@ -26138,7 +26170,6 @@ package android.media.tv.interactive {
method public void onAppLinkCommand(@NonNull android.os.Bundle);
method @Nullable public final android.os.IBinder onBind(@NonNull android.content.Intent);
method @Nullable public abstract android.media.tv.interactive.TvInteractiveAppService.Session onCreateSession(@NonNull String, int);
- method public abstract void onPrepare(int);
method public void onRegisterAppLinkInfo(@NonNull android.media.tv.interactive.AppLinkInfo);
method public void onUnregisterAppLinkInfo(@NonNull android.media.tv.interactive.AppLinkInfo);
field public static final String COMMAND_PARAMETER_KEY_CHANGE_CHANNEL_QUIETLY = "command_change_channel_quietly";
@@ -26159,31 +26190,33 @@ package android.media.tv.interactive {
public abstract static class TvInteractiveAppService.Session implements android.view.KeyEvent.Callback {
ctor public TvInteractiveAppService.Session(@NonNull android.content.Context);
- method public void layoutSurface(int, int, int, int);
- method public final void notifyBiInteractiveAppCreated(@NonNull android.net.Uri, @Nullable String);
- method public void notifySessionStateChanged(int, int);
- method public final void notifyTeletextAppStateChanged(int);
+ method public boolean isMediaViewEnabled();
+ method @CallSuper public void layoutSurface(int, int, int, int);
+ method @CallSuper public final void notifyBiInteractiveAppCreated(@NonNull android.net.Uri, @Nullable String);
+ method @CallSuper public void notifySessionStateChanged(int, int);
+ method @CallSuper public final void notifyTeletextAppStateChanged(int);
method public void onAdResponse(@NonNull android.media.tv.AdResponse);
method public void onBroadcastInfoResponse(@NonNull android.media.tv.BroadcastInfoResponse);
method public void onContentAllowed();
method public void onContentBlocked(@NonNull android.media.tv.TvContentRating);
- method public void onCreateBiInteractiveApp(@NonNull android.net.Uri, @Nullable android.os.Bundle);
+ method public void onCreateBiInteractiveAppRequest(@NonNull android.net.Uri, @Nullable android.os.Bundle);
method @Nullable public android.view.View onCreateMediaView();
method public void onCurrentChannelLcn(int);
method public void onCurrentChannelUri(@Nullable android.net.Uri);
method public void onCurrentTvInputId(@Nullable String);
- method public void onDestroyBiInteractiveApp(@NonNull String);
+ method public void onDestroyBiInteractiveAppRequest(@NonNull String);
method public boolean onGenericMotionEvent(@NonNull android.view.MotionEvent);
method public boolean onKeyDown(int, @NonNull android.view.KeyEvent);
method public boolean onKeyLongPress(int, @NonNull android.view.KeyEvent);
method public boolean onKeyMultiple(int, int, @NonNull android.view.KeyEvent);
method public boolean onKeyUp(int, @NonNull android.view.KeyEvent);
- method public void onMediaViewSizeChanged(int, int);
+ method public void onMediaViewSizeChanged(@Px int, @Px int);
method public abstract void onRelease();
method public void onResetInteractiveApp();
method public abstract boolean onSetSurface(@Nullable android.view.Surface);
method public void onSetTeletextAppEnabled(boolean);
method public void onSignalStrength(int);
+ method public void onSigningResult(@NonNull String, @NonNull byte[]);
method public void onStartInteractiveApp();
method public void onStopInteractiveApp();
method public void onStreamVolume(float);
@@ -26196,17 +26229,31 @@ package android.media.tv.interactive {
method public void onTuned(@NonNull android.net.Uri);
method public void onVideoAvailable();
method public void onVideoUnavailable(int);
- method public void removeBroadcastInfo(int);
- method public void requestAd(@NonNull android.media.tv.AdRequest);
- method public void requestBroadcastInfo(@NonNull android.media.tv.BroadcastInfoRequest);
- method public void requestCurrentChannelLcn();
- method public void requestCurrentChannelUri();
- method public void requestCurrentTvInputId();
- method public void requestStreamVolume();
- method public void requestTrackInfoList();
- method public void sendPlaybackCommandRequest(@NonNull String, @Nullable android.os.Bundle);
- method public void setMediaViewEnabled(boolean);
- method public void setVideoBounds(@NonNull android.graphics.Rect);
+ method @CallSuper public void removeBroadcastInfo(int);
+ method @CallSuper public void requestAd(@NonNull android.media.tv.AdRequest);
+ method @CallSuper public void requestBroadcastInfo(@NonNull android.media.tv.BroadcastInfoRequest);
+ method @CallSuper public void requestCurrentChannelLcn();
+ method @CallSuper public void requestCurrentChannelUri();
+ method @CallSuper public void requestCurrentTvInputId();
+ method @CallSuper public void requestSigning(@NonNull String, @NonNull String, @NonNull String, @NonNull byte[]);
+ method @CallSuper public void requestStreamVolume();
+ method @CallSuper public void requestTrackInfoList();
+ method @CallSuper public void sendPlaybackCommandRequest(@NonNull String, @Nullable android.os.Bundle);
+ method @CallSuper public void setMediaViewEnabled(boolean);
+ method @CallSuper public void setVideoBounds(@NonNull android.graphics.Rect);
+ }
+
+ public final class TvInteractiveAppServiceInfo implements android.os.Parcelable {
+ ctor public TvInteractiveAppServiceInfo(@NonNull android.content.Context, @NonNull android.content.ComponentName);
+ method public int describeContents();
+ method @NonNull public String getId();
+ method @Nullable public android.content.pm.ServiceInfo getServiceInfo();
+ method @NonNull public int getSupportedTypes();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.media.tv.interactive.TvInteractiveAppServiceInfo> CREATOR;
+ field public static final int INTERACTIVE_APP_TYPE_ATSC = 2; // 0x2
+ field public static final int INTERACTIVE_APP_TYPE_GINGA = 4; // 0x4
+ field public static final int INTERACTIVE_APP_TYPE_HBBTV = 1; // 0x1
}
public class TvInteractiveAppView extends android.view.ViewGroup {
@@ -26218,6 +26265,7 @@ package android.media.tv.interactive {
method public void createBiInteractiveApp(@NonNull android.net.Uri, @Nullable android.os.Bundle);
method public void destroyBiInteractiveApp(@NonNull String);
method public boolean dispatchUnhandledInputEvent(@NonNull android.view.InputEvent);
+ method @Nullable public android.media.tv.interactive.TvInteractiveAppView.OnUnhandledInputEventListener getOnUnhandledInputEventListener();
method public void onAttachedToWindow();
method public void onDetachedFromWindow();
method public void onLayout(boolean, int, int, int, int);
@@ -26230,6 +26278,7 @@ package android.media.tv.interactive {
method public void sendCurrentChannelLcn(int);
method public void sendCurrentChannelUri(@Nullable android.net.Uri);
method public void sendCurrentTvInputId(@Nullable String);
+ method public void sendSigningResult(@NonNull String, @NonNull byte[]);
method public void sendStreamVolume(float);
method public void sendTrackInfoList(@Nullable java.util.List<android.media.tv.TvTrackInfo>);
method public void setCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.tv.interactive.TvInteractiveAppView.TvInteractiveAppCallback);
@@ -26238,6 +26287,11 @@ package android.media.tv.interactive {
method public int setTvView(@Nullable android.media.tv.TvView);
method public void startInteractiveApp();
method public void stopInteractiveApp();
+ field public static final String BI_INTERACTIVE_APP_KEY_ALIAS = "alias";
+ field public static final String BI_INTERACTIVE_APP_KEY_CERTIFICATE = "certificate";
+ field public static final String BI_INTERACTIVE_APP_KEY_HTTP_ADDITIONAL_HEADERS = "http_additional_headers";
+ field public static final String BI_INTERACTIVE_APP_KEY_HTTP_USER_AGENT = "http_user_agent";
+ field public static final String BI_INTERACTIVE_APP_KEY_PRIVATE_KEY = "private_key";
}
public static interface TvInteractiveAppView.OnUnhandledInputEventListener {
@@ -26251,6 +26305,7 @@ package android.media.tv.interactive {
method public void onRequestCurrentChannelLcn(@NonNull String);
method public void onRequestCurrentChannelUri(@NonNull String);
method public void onRequestCurrentTvInputId(@NonNull String);
+ method public void onRequestSigning(@NonNull String, @NonNull String, @NonNull String, @NonNull String, @NonNull byte[]);
method public void onRequestStreamVolume(@NonNull String);
method public void onRequestTrackInfoList(@NonNull String);
method public void onSetVideoBounds(@NonNull String, @NonNull android.graphics.Rect);
@@ -26509,16 +26564,9 @@ package android.net {
method public int getUid();
}
- public final class EthernetNetworkSpecifier extends android.net.NetworkSpecifier implements android.os.Parcelable {
- ctor public EthernetNetworkSpecifier(@NonNull String);
- method public int describeContents();
- method @Nullable public String getInterfaceName();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.EthernetNetworkSpecifier> CREATOR;
- }
-
public final class Ikev2VpnProfile extends android.net.PlatformVpnProfile {
method @NonNull public java.util.List<java.lang.String> getAllowedAlgorithms();
+ method @Nullable public android.net.ipsec.ike.IkeTunnelConnectionParams getIkeTunnelConnectionParams();
method public int getMaxMtu();
method @Nullable public String getPassword();
method @Nullable public byte[] getPresharedKey();
@@ -26813,11 +26861,13 @@ package android.net {
public class VpnManager {
method public void deleteProvisionedVpnProfile();
+ method @Nullable public android.net.VpnProfileState getProvisionedVpnProfileState();
method @Nullable public android.content.Intent provisionVpnProfile(@NonNull android.net.PlatformVpnProfile);
method @Deprecated public void startProvisionedVpnProfile();
method @NonNull public String startProvisionedVpnProfileSession();
method public void stopProvisionedVpnProfile();
field public static final String ACTION_VPN_MANAGER_EVENT = "android.net.action.VPN_MANAGER_EVENT";
+ field public static final String CATEGORY_EVENT_ALWAYS_ON_STATE_CHANGED = "android.net.category.EVENT_ALWAYS_ON_STATE_CHANGED";
field public static final String CATEGORY_EVENT_DEACTIVATED_BY_USER = "android.net.category.EVENT_DEACTIVATED_BY_USER";
field public static final String CATEGORY_EVENT_IKE_ERROR = "android.net.category.EVENT_IKE_ERROR";
field public static final String CATEGORY_EVENT_NETWORK_ERROR = "android.net.category.EVENT_NETWORK_ERROR";
@@ -26834,6 +26884,22 @@ package android.net {
field public static final String EXTRA_UNDERLYING_LINK_PROPERTIES = "android.net.extra.UNDERLYING_LINK_PROPERTIES";
field public static final String EXTRA_UNDERLYING_NETWORK = "android.net.extra.UNDERLYING_NETWORK";
field public static final String EXTRA_UNDERLYING_NETWORK_CAPABILITIES = "android.net.extra.UNDERLYING_NETWORK_CAPABILITIES";
+ field public static final String EXTRA_VPN_PROFILE_STATE = "android.net.extra.VPN_PROFILE_STATE";
+ }
+
+ public final class VpnProfileState implements android.os.Parcelable {
+ ctor public VpnProfileState(int, @Nullable String, boolean, boolean);
+ method public int describeContents();
+ method @Nullable public String getSessionId();
+ method public int getState();
+ method public boolean isAlwaysOn();
+ method public boolean isLockdownEnabled();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.VpnProfileState> CREATOR;
+ field public static final int STATE_CONNECTED = 2; // 0x2
+ field public static final int STATE_CONNECTING = 1; // 0x1
+ field public static final int STATE_DISCONNECTED = 0; // 0x0
+ field public static final int STATE_FAILED = 3; // 0x3
}
public class VpnService extends android.app.Service {
@@ -38135,6 +38201,7 @@ package android.service.autofill {
method public int getNoSaveUiReason();
method @NonNull public java.util.Set<java.lang.String> getSelectedDatasetIds();
method public int getType();
+ method public int getUiType();
field public static final int NO_SAVE_UI_REASON_DATASET_MATCH = 6; // 0x6
field public static final int NO_SAVE_UI_REASON_FIELD_VALIDATION_FAILED = 5; // 0x5
field public static final int NO_SAVE_UI_REASON_HAS_EMPTY_REQUIRED = 3; // 0x3
@@ -38148,6 +38215,10 @@ package android.service.autofill {
field public static final int TYPE_DATASET_AUTHENTICATION_SELECTED = 1; // 0x1
field public static final int TYPE_DATASET_SELECTED = 0; // 0x0
field public static final int TYPE_SAVE_SHOWN = 3; // 0x3
+ field public static final int UI_TYPE_DIALOG = 3; // 0x3
+ field public static final int UI_TYPE_INLINE = 2; // 0x2
+ field public static final int UI_TYPE_MENU = 1; // 0x1
+ field public static final int UI_TYPE_UNKNOWN = 0; // 0x0
}
public final class FillRequest implements android.os.Parcelable {
@@ -38162,6 +38233,7 @@ package android.service.autofill {
field @NonNull public static final android.os.Parcelable.Creator<android.service.autofill.FillRequest> CREATOR;
field public static final int FLAG_COMPATIBILITY_MODE_REQUEST = 2; // 0x2
field public static final int FLAG_MANUAL_REQUEST = 1; // 0x1
+ field public static final int FLAG_SUPPORTS_FILL_DIALOG = 64; // 0x40
}
public final class FillResponse implements android.os.Parcelable {
@@ -43784,6 +43856,7 @@ package android.telephony.data {
method public int getNetworkTypeBitmask();
method public String getOperatorNumeric();
method public String getPassword();
+ method public int getProfileId();
method public int getProtocol();
method @Deprecated public java.net.InetAddress getProxyAddress();
method public String getProxyAddressAsString();
@@ -43791,6 +43864,7 @@ package android.telephony.data {
method public int getRoamingProtocol();
method public String getUser();
method public boolean isEnabled();
+ method public boolean isPersistent();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field public static final int AUTH_TYPE_CHAP = 2; // 0x2
field public static final int AUTH_TYPE_NONE = 0; // 0x0
@@ -45064,7 +45138,7 @@ package android.text {
public static final class PrecomputedText.Params {
method public int getBreakStrategy();
method public int getHyphenationFrequency();
- method @Nullable public android.graphics.text.LineBreakConfig getLineBreakConfig();
+ method @NonNull public android.graphics.text.LineBreakConfig getLineBreakConfig();
method @NonNull public android.text.TextDirectionHeuristic getTextDirection();
method @NonNull public android.text.TextPaint getTextPaint();
}
@@ -49278,6 +49352,7 @@ package android.view {
method @NonNull public android.view.SurfaceControl.Transaction setAlpha(@NonNull android.view.SurfaceControl, @FloatRange(from=0.0, to=1.0) float);
method @NonNull public android.view.SurfaceControl.Transaction setBuffer(@NonNull android.view.SurfaceControl, @Nullable android.hardware.HardwareBuffer);
method @NonNull public android.view.SurfaceControl.Transaction setBuffer(@NonNull android.view.SurfaceControl, @Nullable android.hardware.HardwareBuffer, @Nullable android.hardware.SyncFence);
+ method @NonNull public android.view.SurfaceControl.Transaction setBuffer(@NonNull android.view.SurfaceControl, @Nullable android.hardware.HardwareBuffer, @Nullable android.hardware.SyncFence, @Nullable java.util.function.Consumer<android.hardware.SyncFence>);
method @NonNull public android.view.SurfaceControl.Transaction setBufferSize(@NonNull android.view.SurfaceControl, @IntRange(from=0) int, @IntRange(from=0) int);
method @NonNull public android.view.SurfaceControl.Transaction setBufferTransform(@NonNull android.view.SurfaceControl, int);
method @NonNull public android.view.SurfaceControl.Transaction setCrop(@NonNull android.view.SurfaceControl, @Nullable android.graphics.Rect);
@@ -51931,12 +52006,8 @@ package android.view.accessibility {
field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_SET_SELECTION;
field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_SET_TEXT;
field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_SHOW_ON_SCREEN;
- field @NonNull public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_SHOW_SUGGESTIONS;
+ field @NonNull public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_SHOW_TEXT_SUGGESTIONS;
field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_SHOW_TOOLTIP;
- field @NonNull public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_SWIPE_DOWN;
- field @NonNull public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_SWIPE_LEFT;
- field @NonNull public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_SWIPE_RIGHT;
- field @NonNull public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_SWIPE_UP;
field @NonNull public static final android.os.Parcelable.Creator<android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction> CREATOR;
}
@@ -54058,9 +54129,13 @@ package android.view.translation {
public interface UiTranslationStateCallback {
method public void onFinished();
+ method public default void onFinished(@NonNull String);
method public void onPaused();
+ method public default void onPaused(@NonNull String);
method public default void onResumed(@NonNull android.icu.util.ULocale, @NonNull android.icu.util.ULocale);
+ method public default void onResumed(@NonNull android.icu.util.ULocale, @NonNull android.icu.util.ULocale, @NonNull String);
method public default void onStarted(@NonNull android.icu.util.ULocale, @NonNull android.icu.util.ULocale);
+ method public default void onStarted(@NonNull android.icu.util.ULocale, @NonNull android.icu.util.ULocale, @NonNull String);
}
@UiThread public interface ViewTranslationCallback {
@@ -57358,7 +57433,8 @@ package android.widget {
method public final android.text.Layout getLayout();
method public float getLetterSpacing();
method public int getLineBounds(int, android.graphics.Rect);
- method @NonNull public android.graphics.text.LineBreakConfig getLineBreakConfig();
+ method public int getLineBreakStyle();
+ method public int getLineBreakWordStyle();
method public int getLineCount();
method public int getLineHeight();
method public float getLineSpacingExtra();
@@ -57486,7 +57562,8 @@ package android.widget {
method public void setKeyListener(android.text.method.KeyListener);
method public void setLastBaselineToBottomHeight(@IntRange(from=0) @Px int);
method public void setLetterSpacing(float);
- method public void setLineBreakConfig(@NonNull android.graphics.text.LineBreakConfig);
+ method public void setLineBreakStyle(int);
+ method public void setLineBreakWordStyle(int);
method public void setLineHeight(@IntRange(from=0) @Px int);
method public void setLineSpacing(float, float);
method public void setLines(int);
@@ -57896,7 +57973,7 @@ package android.window {
}
public interface OnBackInvokedDispatcher {
- method public void registerOnBackInvokedCallback(@NonNull android.window.OnBackInvokedCallback, @IntRange(from=0) int);
+ method public void registerOnBackInvokedCallback(@IntRange(from=0) int, @NonNull android.window.OnBackInvokedCallback);
method public void unregisterOnBackInvokedCallback(@NonNull android.window.OnBackInvokedCallback);
field public static final int PRIORITY_DEFAULT = 0; // 0x0
field public static final int PRIORITY_OVERLAY = 1000000; // 0xf4240
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index 5bc5bbc08074..44a79c61e216 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -4,6 +4,7 @@ package android {
public static final class Manifest.permission {
field public static final String CONTROL_AUTOMOTIVE_GNSS = "android.permission.CONTROL_AUTOMOTIVE_GNSS";
field public static final String GET_INTENT_SENDER_INTENT = "android.permission.GET_INTENT_SENDER_INTENT";
+ field public static final String MAKE_UID_VISIBLE = "android.permission.MAKE_UID_VISIBLE";
}
}
@@ -20,10 +21,6 @@ package android.app {
method @RequiresPermission(android.Manifest.permission.CHANGE_CONFIGURATION) public boolean updateMccMncConfiguration(@NonNull String, @NonNull String);
}
- public class ActivityOptions {
- method @NonNull public static android.app.ActivityOptions fromBundle(@NonNull android.os.Bundle);
- }
-
public class AppOpsManager {
field public static final String OPSTR_NO_ISOLATED_STORAGE = "android:no_isolated_storage";
}
@@ -54,22 +51,6 @@ package android.app {
method public void onCanceled(@NonNull android.app.PendingIntent);
}
- public class PropertyInvalidatedCache<Query, Result> {
- ctor public PropertyInvalidatedCache(int, @NonNull String, @NonNull String, @NonNull String, @NonNull android.app.PropertyInvalidatedCache.QueryHandler<Query,Result>);
- method public final void disableForCurrentProcess();
- method public final void invalidateCache();
- method public static void invalidateCache(@NonNull String, @NonNull String);
- method @Nullable public final Result query(@NonNull Query);
- field public static final String MODULE_BLUETOOTH = "bluetooth";
- field public static final String MODULE_TELEPHONY = "telephony";
- }
-
- public abstract static class PropertyInvalidatedCache.QueryHandler<Q, R> {
- ctor public PropertyInvalidatedCache.QueryHandler();
- method @Nullable public abstract R apply(@NonNull Q);
- method public boolean shouldBypassCache(@NonNull Q);
- }
-
public class StatusBarManager {
method @RequiresPermission(android.Manifest.permission.STATUS_BAR) public void setExpansionDisabledForSimNetworkLock(boolean);
}
@@ -122,6 +103,8 @@ package android.content.pm {
public abstract class PackageManager {
method @NonNull public String getPermissionControllerPackageName();
method @NonNull public String getSdkSandboxPackageName();
+ method @RequiresPermission(android.Manifest.permission.MAKE_UID_VISIBLE) public void makeUidVisible(int, int);
+ field public static final String EXTRA_VERIFICATION_ROOT_HASH = "android.content.pm.extra.VERIFICATION_ROOT_HASH";
field public static final int MATCH_STATIC_SHARED_AND_SDK_LIBRARIES = 67108864; // 0x4000000
}
@@ -251,22 +234,6 @@ package android.media.session {
package android.net {
- public class EthernetManager {
- method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void addInterfaceStateListener(@NonNull java.util.concurrent.Executor, @NonNull android.net.EthernetManager.InterfaceStateListener);
- method public void removeInterfaceStateListener(@NonNull android.net.EthernetManager.InterfaceStateListener);
- method public void setIncludeTestInterfaces(boolean);
- field public static final int ROLE_CLIENT = 1; // 0x1
- field public static final int ROLE_NONE = 0; // 0x0
- field public static final int ROLE_SERVER = 2; // 0x2
- field public static final int STATE_ABSENT = 0; // 0x0
- field public static final int STATE_LINK_DOWN = 1; // 0x1
- field public static final int STATE_LINK_UP = 2; // 0x2
- }
-
- public static interface EthernetManager.InterfaceStateListener {
- method public void onInterfaceStateChanged(@NonNull String, int, int, @Nullable android.net.IpConfiguration);
- }
-
public class LocalSocket implements java.io.Closeable {
ctor public LocalSocket(@NonNull java.io.FileDescriptor);
}
@@ -277,7 +244,8 @@ package android.net {
method @Nullable @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) public android.telephony.SubscriptionPlan getSubscriptionPlan(@NonNull android.net.NetworkTemplate);
method @RequiresPermission(android.Manifest.permission.OBSERVE_NETWORK_POLICY) public boolean isUidNetworkingBlocked(int, boolean);
method @RequiresPermission(android.Manifest.permission.OBSERVE_NETWORK_POLICY) public boolean isUidRestrictedOnMeteredNetworks(int);
- method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) public void notifyStatsProviderWarningOrLimitReached();
+ method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) public void notifyStatsProviderLimitReached();
+ method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) public void notifyStatsProviderWarningReached();
method @RequiresPermission(android.Manifest.permission.OBSERVE_NETWORK_POLICY) public void registerNetworkPolicyCallback(@Nullable java.util.concurrent.Executor, @NonNull android.net.NetworkPolicyManager.NetworkPolicyCallback);
method @RequiresPermission(android.Manifest.permission.OBSERVE_NETWORK_POLICY) public void unregisterNetworkPolicyCallback(@NonNull android.net.NetworkPolicyManager.NetworkPolicyCallback);
}
@@ -358,13 +326,29 @@ package android.os {
field public static final int DEVICE_INITIAL_SDK_INT;
}
+ public class IpcDataCache<Query, Result> {
+ ctor public IpcDataCache(int, @NonNull String, @NonNull String, @NonNull String, @NonNull android.os.IpcDataCache.QueryHandler<Query,Result>);
+ method public void disableForCurrentProcess();
+ method public static void disableForCurrentProcess(@NonNull String);
+ method public void invalidateCache();
+ method public static void invalidateCache(@NonNull String, @NonNull String);
+ method @Nullable public Result query(@NonNull Query);
+ field public static final String MODULE_BLUETOOTH = "bluetooth";
+ }
+
+ public abstract static class IpcDataCache.QueryHandler<Q, R> {
+ ctor public IpcDataCache.QueryHandler();
+ method @Nullable public abstract R apply(@NonNull Q);
+ method public boolean shouldBypassCache(@NonNull Q);
+ }
+
public interface Parcelable {
method public default int getStability();
}
public class Process {
+ method public static final int getAppUidForSdkSandboxUid(int);
method public static final boolean isSdkSandboxUid(int);
- method public static final int sdkSandboxToAppUid(int);
method public static final int toSdkSandboxUid(int);
field public static final int NFC_UID = 1027; // 0x403
field public static final int VPN_UID = 1016; // 0x3f8
@@ -458,6 +442,14 @@ package android.provider {
}
+package android.telecom {
+
+ public abstract class ConnectionService extends android.app.Service {
+ method @Nullable @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public android.telecom.Connection onCreateUnknownConnection(@NonNull android.telecom.PhoneAccountHandle, @NonNull android.telecom.ConnectionRequest);
+ }
+
+}
+
package android.telephony {
public abstract class CellSignalStrength {
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 15666017f431..61309e3e9222 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -5,6 +5,7 @@ package android {
field public static final String ACCESS_AMBIENT_CONTEXT_EVENT = "android.permission.ACCESS_AMBIENT_CONTEXT_EVENT";
field public static final String ACCESS_AMBIENT_LIGHT_STATS = "android.permission.ACCESS_AMBIENT_LIGHT_STATS";
field public static final String ACCESS_BROADCAST_RADIO = "android.permission.ACCESS_BROADCAST_RADIO";
+ field public static final String ACCESS_BROADCAST_RESPONSE_STATS = "android.permission.ACCESS_BROADCAST_RESPONSE_STATS";
field public static final String ACCESS_CACHE_FILESYSTEM = "android.permission.ACCESS_CACHE_FILESYSTEM";
field public static final String ACCESS_CONTEXT_HUB = "android.permission.ACCESS_CONTEXT_HUB";
field public static final String ACCESS_DRM_CERTIFICATES = "android.permission.ACCESS_DRM_CERTIFICATES";
@@ -34,6 +35,7 @@ package android {
field public static final String ALLOCATE_AGGRESSIVE = "android.permission.ALLOCATE_AGGRESSIVE";
field public static final String ALLOW_ANY_CODEC_FOR_PLAYBACK = "android.permission.ALLOW_ANY_CODEC_FOR_PLAYBACK";
field public static final String ALLOW_PLACE_IN_MULTI_PANE_SETTINGS = "android.permission.ALLOW_PLACE_IN_MULTI_PANE_SETTINGS";
+ field public static final String ALLOW_SLIPPERY_TOUCHES = "android.permission.ALLOW_SLIPPERY_TOUCHES";
field public static final String AMBIENT_WALLPAPER = "android.permission.AMBIENT_WALLPAPER";
field public static final String APPROVE_INCIDENT_REPORTS = "android.permission.APPROVE_INCIDENT_REPORTS";
field public static final String ASSOCIATE_COMPANION_DEVICES = "android.permission.ASSOCIATE_COMPANION_DEVICES";
@@ -234,6 +236,7 @@ package android {
field public static final String POWER_SAVER = "android.permission.POWER_SAVER";
field public static final String PROVIDE_RESOLVER_RANKER_SERVICE = "android.permission.PROVIDE_RESOLVER_RANKER_SERVICE";
field public static final String PROVIDE_TRUST_AGENT = "android.permission.PROVIDE_TRUST_AGENT";
+ field public static final String PROVISION_DEMO_DEVICE = "android.permission.PROVISION_DEMO_DEVICE";
field public static final String QUERY_ADMIN_POLICY = "android.permission.QUERY_ADMIN_POLICY";
field public static final String QUERY_TIME_ZONE_RULES = "android.permission.QUERY_TIME_ZONE_RULES";
field public static final String QUERY_USERS = "android.permission.QUERY_USERS";
@@ -242,6 +245,7 @@ package android {
field public static final String READ_APP_SPECIFIC_LOCALES = "android.permission.READ_APP_SPECIFIC_LOCALES";
field public static final String READ_CARRIER_APP_INFO = "android.permission.READ_CARRIER_APP_INFO";
field public static final String READ_CELL_BROADCASTS = "android.permission.READ_CELL_BROADCASTS";
+ field public static final String READ_CLIPBOARD_IN_BACKGROUND = "android.permission.READ_CLIPBOARD_IN_BACKGROUND";
field public static final String READ_CONTENT_RATING_SYSTEMS = "android.permission.READ_CONTENT_RATING_SYSTEMS";
field public static final String READ_DEVICE_CONFIG = "android.permission.READ_DEVICE_CONFIG";
field public static final String READ_DREAM_STATE = "android.permission.READ_DREAM_STATE";
@@ -399,6 +403,7 @@ package android {
public static final class R.drawable {
field public static final int ic_info = 17301684; // 0x10800b4
+ field public static final int ic_safety_protection;
}
public static final class R.raw {
@@ -444,6 +449,7 @@ package android {
field public static final int config_systemVisualIntelligence = 17039415; // 0x1040037
field public static final int config_systemWellbeing = 17039408; // 0x1040030
field public static final int config_systemWifiCoexManager = 17039407; // 0x104002f
+ field public static final int safety_protection_display_text;
}
public static final class R.style {
@@ -468,7 +474,6 @@ package android.app {
method public boolean convertToTranslucent(android.app.Activity.TranslucentConversionListener, android.app.ActivityOptions);
method @Deprecated public boolean isBackgroundVisibleBehind();
method @Deprecated public void onBackgroundVisibleBehindChanged(boolean);
- method @RequiresPermission(anyOf={android.Manifest.permission.INTERACT_ACROSS_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS_FULL}) public void startActivityAsUser(@NonNull android.content.Intent, @Nullable android.os.Bundle, @NonNull android.os.UserHandle);
method @RequiresPermission(anyOf={android.Manifest.permission.INTERACT_ACROSS_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS_FULL}) public void startActivityForResultAsUser(@NonNull android.content.Intent, int, @NonNull android.os.UserHandle);
method @RequiresPermission(anyOf={android.Manifest.permission.INTERACT_ACROSS_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS_FULL}) public void startActivityForResultAsUser(@NonNull android.content.Intent, int, @Nullable android.os.Bundle, @NonNull android.os.UserHandle);
method @RequiresPermission(anyOf={android.Manifest.permission.INTERACT_ACROSS_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS_FULL}) public void startActivityForResultAsUser(@NonNull android.content.Intent, @NonNull String, int, @Nullable android.os.Bundle, @NonNull android.os.UserHandle);
@@ -1078,6 +1083,7 @@ package android.app.admin {
method @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public int checkProvisioningPrecondition(@NonNull String, @NonNull String);
method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public android.os.UserHandle createAndProvisionManagedProfile(@NonNull android.app.admin.ManagedProfileProvisioningParams) throws android.app.admin.ProvisioningException;
method @Nullable public android.content.Intent createProvisioningIntentFromNfcIntent(@NonNull android.content.Intent);
+ method @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public void finalizeWorkProfileProvisioning(@NonNull android.os.UserHandle, @Nullable android.accounts.Account);
method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public boolean getBluetoothContactSharingDisabled(@NonNull android.os.UserHandle);
method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public String getDeviceOwner();
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS}) public android.content.ComponentName getDeviceOwnerComponentOnAnyUser();
@@ -1086,10 +1092,9 @@ package android.app.admin {
method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public android.os.UserHandle getDeviceOwnerUser();
method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.QUERY_ADMIN_POLICY}) public java.util.List<java.lang.String> getPermittedAccessibilityServices(int);
method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.QUERY_ADMIN_POLICY}) public java.util.List<java.lang.String> getPermittedInputMethodsForCurrentUser();
+ method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public java.util.List<android.os.UserHandle> getPolicyManagedProfiles(@NonNull android.os.UserHandle);
method @Nullable public android.content.ComponentName getProfileOwner() throws java.lang.IllegalArgumentException;
method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS}) public String getProfileOwnerNameAsUser(int) throws java.lang.IllegalArgumentException;
- method @Nullable public String getString(@NonNull String, @NonNull java.util.function.Supplier<java.lang.String>);
- method @Nullable public String getString(@NonNull String, @NonNull java.util.function.Supplier<java.lang.String>, @NonNull java.lang.Object...);
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS}) public int getUserProvisioningState();
method public boolean isDeviceManaged();
method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isDeviceProvisioned();
@@ -1101,18 +1106,15 @@ package android.app.admin {
method @RequiresPermission("android.permission.NOTIFY_PENDING_SYSTEM_UPDATE") public void notifyPendingSystemUpdate(long);
method @RequiresPermission("android.permission.NOTIFY_PENDING_SYSTEM_UPDATE") public void notifyPendingSystemUpdate(long, boolean);
method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public boolean packageHasActiveAdmins(String);
- method @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public void provisionFullyManagedDevice(@NonNull android.app.admin.FullyManagedDeviceProvisioningParams) throws android.app.admin.ProvisioningException;
- method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES) public void resetDrawables(@NonNull String[]);
- method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES) public void resetStrings(@NonNull String[]);
+ method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS, android.Manifest.permission.PROVISION_DEMO_DEVICE}) public void provisionFullyManagedDevice(@NonNull android.app.admin.FullyManagedDeviceProvisioningParams) throws android.app.admin.ProvisioningException;
method @RequiresPermission(android.Manifest.permission.SEND_LOST_MODE_LOCATION_UPDATES) public void sendLostModeLocationUpdate(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
method @Deprecated @RequiresPermission(android.Manifest.permission.MANAGE_DEVICE_ADMINS) public boolean setActiveProfileOwner(@NonNull android.content.ComponentName, String) throws java.lang.IllegalArgumentException;
method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public void setDeviceProvisioningConfigApplied();
method @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public void setDpcDownloaded(boolean);
- method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES) public void setDrawables(@NonNull java.util.Set<android.app.admin.DevicePolicyDrawableResource>);
method @Deprecated @RequiresPermission(value=android.Manifest.permission.GRANT_PROFILE_OWNER_DEVICE_IDS_ACCESS, conditional=true) public void setProfileOwnerCanAccessDeviceIds(@NonNull android.content.ComponentName);
method public void setSecondaryLockscreenEnabled(@NonNull android.content.ComponentName, boolean);
- method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES) public void setStrings(@NonNull java.util.Set<android.app.admin.DevicePolicyStringResource>);
method @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public void setUserProvisioningState(int, @NonNull android.os.UserHandle);
+ method @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public boolean shouldAllowBypassingDevicePolicyManagementRoleQualification();
field public static final String ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_ALLOWED = "android.account.DEVICE_OR_PROFILE_OWNER_ALLOWED";
field public static final String ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_DISALLOWED = "android.account.DEVICE_OR_PROFILE_OWNER_DISALLOWED";
field public static final String ACTION_BIND_SECONDARY_LOCKSCREEN_SERVICE = "android.app.action.BIND_SECONDARY_LOCKSCREEN_SERVICE";
@@ -1127,7 +1129,7 @@ package android.app.admin {
field @RequiresPermission(android.Manifest.permission.LAUNCH_DEVICE_MANAGER_SETUP) public static final String ACTION_ROLE_HOLDER_PROVISION_MANAGED_PROFILE = "android.app.action.ROLE_HOLDER_PROVISION_MANAGED_PROFILE";
field public static final String ACTION_SET_PROFILE_OWNER = "android.app.action.SET_PROFILE_OWNER";
field @Deprecated public static final String ACTION_STATE_USER_SETUP_COMPLETE = "android.app.action.STATE_USER_SETUP_COMPLETE";
- field @RequiresPermission(android.Manifest.permission.LAUNCH_DEVICE_MANAGER_SETUP) public static final String ACTION_UPDATE_DEVICE_MANAGEMENT_ROLE_HOLDER = "android.app.action.UPDATE_DEVICE_MANAGEMENT_ROLE_HOLDER";
+ field @RequiresPermission(android.Manifest.permission.LAUNCH_DEVICE_MANAGER_SETUP) public static final String ACTION_UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER = "android.app.action.UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER";
field public static final String EXTRA_FORCE_UPDATE_ROLE_HOLDER = "android.app.extra.FORCE_UPDATE_ROLE_HOLDER";
field public static final String EXTRA_LOST_MODE_LOCATION = "android.app.extra.LOST_MODE_LOCATION";
field public static final String EXTRA_PROFILE_OWNER_NAME = "android.app.extra.PROFILE_OWNER_NAME";
@@ -1147,6 +1149,7 @@ package android.app.admin {
field public static final String EXTRA_RESTRICTION = "android.app.extra.RESTRICTION";
field public static final String EXTRA_ROLE_HOLDER_PROVISIONING_INITIATOR_PACKAGE = "android.app.extra.ROLE_HOLDER_PROVISIONING_INITIATOR_PACKAGE";
field public static final String EXTRA_ROLE_HOLDER_STATE = "android.app.extra.ROLE_HOLDER_STATE";
+ field public static final String EXTRA_ROLE_HOLDER_UPDATE_RESULT_CODE = "android.app.extra.ROLE_HOLDER_UPDATE_RESULT_CODE";
field public static final int FLAG_SUPPORTED_MODES_DEVICE_OWNER = 4; // 0x4
field public static final int FLAG_SUPPORTED_MODES_ORGANIZATION_OWNED = 1; // 0x1
field public static final int FLAG_SUPPORTED_MODES_PERSONALLY_OWNED = 2; // 0x2
@@ -1160,8 +1163,9 @@ package android.app.admin {
field public static final String REQUIRED_APP_MANAGED_PROFILE = "android.app.REQUIRED_APP_MANAGED_PROFILE";
field public static final String REQUIRED_APP_MANAGED_USER = "android.app.REQUIRED_APP_MANAGED_USER";
field public static final int RESULT_DEVICE_OWNER_SET = 123; // 0x7b
- field public static final int RESULT_UPDATE_DEVICE_MANAGEMENT_ROLE_HOLDER_RECOVERABLE_ERROR = 1; // 0x1
- field public static final int RESULT_UPDATE_DEVICE_MANAGEMENT_ROLE_HOLDER_UNRECOVERABLE_ERROR = 2; // 0x2
+ field public static final int RESULT_UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER_PROVISIONING_DISABLED = 3; // 0x3
+ field public static final int RESULT_UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER_RECOVERABLE_ERROR = 1; // 0x1
+ field public static final int RESULT_UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER_UNRECOVERABLE_ERROR = 2; // 0x2
field public static final int RESULT_UPDATE_ROLE_HOLDER = 2; // 0x2
field public static final int RESULT_WORK_PROFILE_CREATED = 122; // 0x7a
field public static final int STATE_USER_PROFILE_COMPLETE = 4; // 0x4
@@ -1188,43 +1192,6 @@ package android.app.admin {
}
public static final class DevicePolicyResources.Strings {
- field public static final String UNDEFINED = "UNDEFINED";
- }
-
- public static final class DevicePolicyResources.Strings.Dialer {
- field public static final String NOTIFICATION_INCOMING_WORK_CALL_TITLE = "Dialer.NOTIFICATION_INCOMING_WORK_CALL_TITLE";
- field public static final String NOTIFICATION_MISSED_WORK_CALL_TITLE = "Dialer.NOTIFICATION_MISSED_WORK_CALL_TITLE";
- field public static final String NOTIFICATION_ONGOING_WORK_CALL_TITLE = "Dialer.NOTIFICATION_ONGOING_WORK_CALL_TITLE";
- field public static final String NOTIFICATION_WIFI_WORK_CALL_LABEL = "Dialer.NOTIFICATION_WIFI_WORK_CALL_LABEL";
- }
-
- public static final class DevicePolicyResources.Strings.DocumentsUi {
- field public static final String CANT_SAVE_TO_PERSONAL_MESSAGE = "DocumentsUi.CANT_SAVE_TO_PERSONAL_MESSAGE";
- field public static final String CANT_SAVE_TO_PERSONAL_TITLE = "DocumentsUi.CANT_SAVE_TO_PERSONAL_TITLE";
- field public static final String CANT_SAVE_TO_WORK_MESSAGE = "DocumentsUi.CANT_SAVE_TO_WORK_MESSAGE";
- field public static final String CANT_SAVE_TO_WORK_TITLE = "DocumentsUi.CANT_SAVE_TO_WORK_TITLE";
- field public static final String CANT_SELECT_PERSONAL_FILES_MESSAGE = "DocumentsUi.CANT_SELECT_PERSONAL_FILES_MESSAGE";
- field public static final String CANT_SELECT_PERSONAL_FILES_TITLE = "DocumentsUi.CANT_SELECT_PERSONAL_FILES_TITLE";
- field public static final String CANT_SELECT_WORK_FILES_MESSAGE = "DocumentsUi.CANT_SELECT_WORK_FILES_MESSAGE";
- field public static final String CANT_SELECT_WORK_FILES_TITLE = "DocumentsUi.CANT_SELECT_WORK_FILES_TITLE";
- field public static final String CROSS_PROFILE_NOT_ALLOWED_MESSAGE = "DocumentsUi.CROSS_PROFILE_NOT_ALLOWED_MESSAGE";
- field public static final String CROSS_PROFILE_NOT_ALLOWED_TITLE = "DocumentsUi.CROSS_PROFILE_NOT_ALLOWED_TITLE";
- field public static final String PERSONAL_TAB = "DocumentsUi.PERSONAL_TAB";
- field public static final String PREVIEW_WORK_FILE_ACCESSIBILITY = "DocumentsUi.PREVIEW_WORK_FILE_ACCESSIBILITY";
- field public static final String WORK_ACCESSIBILITY = "DocumentsUi.WORK_ACCESSIBILITY";
- field public static final String WORK_PROFILE_OFF_ENABLE_BUTTON = "DocumentsUi.WORK_PROFILE_OFF_ENABLE_BUTTON";
- field public static final String WORK_PROFILE_OFF_ERROR_TITLE = "DocumentsUi.WORK_PROFILE_OFF_ERROR_TITLE";
- field public static final String WORK_TAB = "DocumentsUi.WORK_TAB";
- }
-
- public static final class DevicePolicyResources.Strings.MediaProvider {
- field public static final String BLOCKED_BY_ADMIN_TITLE = "MediaProvider.BLOCKED_BY_ADMIN_TITLE";
- field public static final String BLOCKED_FROM_PERSONAL_MESSAGE = "MediaProvider.BLOCKED_FROM_PERSONAL_MESSAGE";
- field public static final String BLOCKED_FROM_WORK_MESSAGE = "MediaProvider.BLOCKED_FROM_WORK_MESSAGE";
- field public static final String SWITCH_TO_PERSONAL_MESSAGE = "MediaProvider.SWITCH_TO_PERSONAL_MESSAGE";
- field public static final String SWITCH_TO_WORK_MESSAGE = "MediaProvider.SWITCH_TO_WORK_MESSAGE";
- field public static final String WORK_PROFILE_PAUSED_MESSAGE = "MediaProvider.WORK_PROFILE_PAUSED_MESSAGE";
- field public static final String WORK_PROFILE_PAUSED_TITLE = "MediaProvider.WORK_PROFILE_PAUSED_TITLE";
}
public static final class DevicePolicyResources.Strings.PermissionController {
@@ -1236,6 +1203,13 @@ package android.app.admin {
field public static final String WORK_PROFILE_DEFAULT_APPS_TITLE = "PermissionController.WORK_PROFILE_DEFAULT_APPS_TITLE";
}
+ public class DevicePolicyResourcesManager {
+ method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES) public void resetDrawables(@NonNull java.util.Set<java.lang.String>);
+ method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES) public void resetStrings(@NonNull java.util.Set<java.lang.String>);
+ method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES) public void setDrawables(@NonNull java.util.Set<android.app.admin.DevicePolicyDrawableResource>);
+ method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES) public void setStrings(@NonNull java.util.Set<android.app.admin.DevicePolicyStringResource>);
+ }
+
public final class DevicePolicyStringResource implements android.os.Parcelable {
ctor public DevicePolicyStringResource(@NonNull android.content.Context, @NonNull String, @StringRes int);
method public int describeContents();
@@ -1254,6 +1228,7 @@ package android.app.admin {
method @Nullable public java.util.Locale getLocale();
method @NonNull public String getOwnerName();
method @Nullable public String getTimeZone();
+ method public boolean isDemoDevice();
method public boolean isLeaveAllSystemAppsEnabled();
method public void writeToParcel(@NonNull android.os.Parcel, @Nullable int);
field @NonNull public static final android.os.Parcelable.Creator<android.app.admin.FullyManagedDeviceProvisioningParams> CREATOR;
@@ -1264,6 +1239,7 @@ package android.app.admin {
method @NonNull public android.app.admin.FullyManagedDeviceProvisioningParams build();
method @NonNull public android.app.admin.FullyManagedDeviceProvisioningParams.Builder setAdminExtras(@NonNull android.os.PersistableBundle);
method @NonNull public android.app.admin.FullyManagedDeviceProvisioningParams.Builder setCanDeviceOwnerGrantSensorsPermissions(boolean);
+ method @NonNull public android.app.admin.FullyManagedDeviceProvisioningParams.Builder setDemoDevice(boolean);
method @NonNull public android.app.admin.FullyManagedDeviceProvisioningParams.Builder setLeaveAllSystemAppsEnabled(boolean);
method @NonNull public android.app.admin.FullyManagedDeviceProvisioningParams.Builder setLocalTime(long);
method @NonNull public android.app.admin.FullyManagedDeviceProvisioningParams.Builder setLocale(@Nullable java.util.Locale);
@@ -1647,13 +1623,13 @@ package android.app.cloudsearch {
public final class SearchRequest implements android.os.Parcelable {
method public int describeContents();
+ method @NonNull public String getCallerPackageName();
method public float getMaxLatencyMillis();
method @NonNull public String getQuery();
method @NonNull public String getRequestId();
method public int getResultNumber();
method public int getResultOffset();
method @NonNull public android.os.Bundle getSearchConstraints();
- method @NonNull public String getSource();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field public static final String CONSTRAINT_IS_PRESUBMIT_SUGGESTION = "android.app.cloudsearch.IS_PRESUBMIT_SUGGESTION";
field public static final String CONSTRAINT_SEARCH_PROVIDER_FILTER = "android.app.cloudsearch.SEARCH_PROVIDER_FILTER";
@@ -1698,8 +1674,10 @@ package android.app.cloudsearch {
method @NonNull public String getTitle();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.app.cloudsearch.SearchResult> CREATOR;
+ field public static final String EXTRAINFO_ACTION_APP_CARD = "android.app.cloudsearch.ACTION_APP_CARD";
field public static final String EXTRAINFO_ACTION_BUTTON_IMAGE_PREREGISTERING = "android.app.cloudsearch.ACTION_BUTTON_IMAGE";
field public static final String EXTRAINFO_ACTION_BUTTON_TEXT_PREREGISTERING = "android.app.cloudsearch.ACTION_BUTTON_TEXT";
+ field public static final String EXTRAINFO_ACTION_INSTALL_BUTTON = "android.app.cloudsearch.ACTION_INSTALL_BUTTON";
field public static final String EXTRAINFO_APP_BADGES = "android.app.cloudsearch.APP_BADGES";
field public static final String EXTRAINFO_APP_CONTAINS_ADS_DISCLAIMER = "android.app.cloudsearch.APP_CONTAINS_ADS_DISCLAIMER";
field public static final String EXTRAINFO_APP_CONTAINS_IAP_DISCLAIMER = "android.app.cloudsearch.APP_CONTAINS_IAP_DISCLAIMER";
@@ -1707,6 +1685,8 @@ package android.app.cloudsearch {
field public static final String EXTRAINFO_APP_DOMAIN_URL = "android.app.cloudsearch.APP_DOMAIN_URL";
field public static final String EXTRAINFO_APP_IARC = "android.app.cloudsearch.APP_IARC";
field public static final String EXTRAINFO_APP_ICON = "android.app.cloudsearch.APP_ICON";
+ field public static final String EXTRAINFO_APP_INSTALL_COUNT = "android.app.cloudsearch.APP_INSTALL_COUNT";
+ field public static final String EXTRAINFO_APP_PACKAGE_NAME = "android.app.cloudsearch.APP_PACKAGE_NAME";
field public static final String EXTRAINFO_APP_REVIEW_COUNT = "android.app.cloudsearch.APP_REVIEW_COUNT";
field public static final String EXTRAINFO_APP_SIZE_BYTES = "android.app.cloudsearch.APP_SIZE_BYTES";
field public static final String EXTRAINFO_APP_STAR_RATING = "android.app.cloudsearch.APP_STAR_RATING";
@@ -1918,6 +1898,7 @@ package android.app.prediction {
field public static final int ACTION_DISMISS = 2; // 0x2
field public static final int ACTION_LAUNCH = 1; // 0x1
field public static final int ACTION_PIN = 3; // 0x3
+ field public static final int ACTION_UNDISMISS = 5; // 0x5
field public static final int ACTION_UNPIN = 4; // 0x4
field @NonNull public static final android.os.Parcelable.Creator<android.app.prediction.AppTargetEvent> CREATOR;
}
@@ -2613,13 +2594,13 @@ package android.app.usage {
}
public final class UsageStatsManager {
- method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public void clearBroadcastResponseStats(@Nullable String, @IntRange(from=0) long);
+ method @RequiresPermission(android.Manifest.permission.ACCESS_BROADCAST_RESPONSE_STATS) public void clearBroadcastResponseStats(@Nullable String, @IntRange(from=0) long);
method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public int getAppStandbyBucket(String);
method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public java.util.Map<java.lang.String,java.lang.Integer> getAppStandbyBuckets();
method @RequiresPermission(allOf={android.Manifest.permission.INTERACT_ACROSS_USERS, android.Manifest.permission.PACKAGE_USAGE_STATS}) public long getLastTimeAnyComponentUsed(@NonNull String);
method public int getUsageSource();
method @RequiresPermission(android.Manifest.permission.BIND_CARRIER_SERVICES) public void onCarrierPrivilegedAppsChanged();
- method @NonNull @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public java.util.List<android.app.usage.BroadcastResponseStats> queryBroadcastResponseStats(@Nullable String, @IntRange(from=0) long);
+ method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_BROADCAST_RESPONSE_STATS) public java.util.List<android.app.usage.BroadcastResponseStats> queryBroadcastResponseStats(@Nullable String, @IntRange(from=0) long);
method @RequiresPermission(allOf={android.Manifest.permission.SUSPEND_APPS, android.Manifest.permission.OBSERVE_APP_USAGE}) public void registerAppUsageLimitObserver(int, @NonNull String[], @NonNull java.time.Duration, @NonNull java.time.Duration, @Nullable android.app.PendingIntent);
method @RequiresPermission(android.Manifest.permission.OBSERVE_APP_USAGE) public void registerAppUsageObserver(int, @NonNull String[], long, @NonNull java.util.concurrent.TimeUnit, @NonNull android.app.PendingIntent);
method @RequiresPermission(android.Manifest.permission.OBSERVE_APP_USAGE) public void registerUsageSessionObserver(int, @NonNull String[], @NonNull java.time.Duration, @NonNull java.time.Duration, @NonNull android.app.PendingIntent, @Nullable android.app.PendingIntent);
@@ -2945,6 +2926,7 @@ package android.content {
method public void sendBroadcastMultiplePermissions(@NonNull android.content.Intent, @NonNull String[], @Nullable android.app.BroadcastOptions);
method public abstract void sendOrderedBroadcast(@NonNull android.content.Intent, @Nullable String, @Nullable android.os.Bundle, @Nullable android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle);
method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public void startActivityAsUser(@NonNull @RequiresPermission android.content.Intent, @NonNull android.os.UserHandle);
+ method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public void startActivityAsUser(@NonNull @RequiresPermission android.content.Intent, @Nullable android.os.Bundle, @NonNull android.os.UserHandle);
field public static final String AMBIENT_CONTEXT_SERVICE = "ambient_context";
field public static final String APP_HIBERNATION_SERVICE = "app_hibernation";
field public static final String APP_INTEGRITY_SERVICE = "app_integrity";
@@ -3184,6 +3166,7 @@ package android.content.pm {
}
public class CrossProfileApps {
+ method @RequiresPermission(anyOf={android.Manifest.permission.INTERACT_ACROSS_PROFILES, android.Manifest.permission.START_CROSS_PROFILE_ACTIVITIES}) public void startActivity(@NonNull android.content.ComponentName, @NonNull android.os.UserHandle, @Nullable android.app.Activity, @Nullable android.os.Bundle);
method @RequiresPermission(anyOf={android.Manifest.permission.INTERACT_ACROSS_PROFILES, android.Manifest.permission.START_CROSS_PROFILE_ACTIVITIES}) public void startActivity(@NonNull android.content.ComponentName, @NonNull android.os.UserHandle);
}
@@ -3403,6 +3386,8 @@ package android.content.pm {
field public static final String EXTRA_REQUEST_PERMISSIONS_RESULTS = "android.content.pm.extra.REQUEST_PERMISSIONS_RESULTS";
field public static final String FEATURE_BROADCAST_RADIO = "android.hardware.broadcastradio";
field public static final String FEATURE_CONTEXT_HUB = "android.hardware.context_hub";
+ field public static final String FEATURE_EROFS = "android.software.erofs";
+ field public static final String FEATURE_EROFS_LEGACY = "android.software.erofs_legacy";
field public static final String FEATURE_GAME_SERVICE = "android.software.game_service";
field public static final String FEATURE_INCREMENTAL_DELIVERY = "android.software.incremental_delivery";
field public static final String FEATURE_REBOOT_ESCROW = "android.hardware.reboot_escrow";
@@ -5480,6 +5465,32 @@ package android.location {
method @NonNull public android.location.GnssCapabilities.Builder setHasSatellitePvt(boolean);
}
+ public final class GnssExcessPathInfo implements android.os.Parcelable {
+ method public int describeContents();
+ method @FloatRange(from=0.0f) public float getAttenuationDb();
+ method @FloatRange(from=0.0f) public float getExcessPathLengthMeters();
+ method @FloatRange(from=0.0f) public float getExcessPathLengthUncertaintyMeters();
+ method @NonNull public android.location.GnssReflectingPlane getReflectingPlane();
+ method public boolean hasAttenuation();
+ method public boolean hasExcessPathLength();
+ method public boolean hasExcessPathLengthUncertainty();
+ method public boolean hasReflectingPlane();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssExcessPathInfo> CREATOR;
+ }
+
+ public static final class GnssExcessPathInfo.Builder {
+ ctor public GnssExcessPathInfo.Builder();
+ method @NonNull public android.location.GnssExcessPathInfo build();
+ method @NonNull public android.location.GnssExcessPathInfo.Builder clearAttenuationDb();
+ method @NonNull public android.location.GnssExcessPathInfo.Builder clearExcessPathLengthMeters();
+ method @NonNull public android.location.GnssExcessPathInfo.Builder clearExcessPathLengthUncertaintyMeters();
+ method @NonNull public android.location.GnssExcessPathInfo.Builder setAttenuationDb(@FloatRange(from=0.0f) float);
+ method @NonNull public android.location.GnssExcessPathInfo.Builder setExcessPathLengthMeters(@FloatRange(from=0.0f) float);
+ method @NonNull public android.location.GnssExcessPathInfo.Builder setExcessPathLengthUncertaintyMeters(@FloatRange(from=0.0f) float);
+ method @NonNull public android.location.GnssExcessPathInfo.Builder setReflectingPlane(@Nullable android.location.GnssReflectingPlane);
+ }
+
public final class GnssMeasurement implements android.os.Parcelable {
method @Nullable public java.util.Collection<android.location.CorrelationVector> getCorrelationVectors();
method @Nullable public android.location.SatellitePvt getSatellitePvt();
@@ -5561,15 +5572,18 @@ package android.location {
public final class GnssSingleSatCorrection implements android.os.Parcelable {
method public int describeContents();
method @FloatRange(from=0.0f, fromInclusive=false) public float getCarrierFrequencyHz();
+ method @FloatRange(from=0.0f) public float getCombinedAttenuationDb();
method public int getConstellationType();
method @FloatRange(from=0.0f) public float getExcessPathLengthMeters();
method @FloatRange(from=0.0f) public float getExcessPathLengthUncertaintyMeters();
+ method @NonNull public java.util.List<android.location.GnssExcessPathInfo> getGnssExcessPathInfoList();
method @FloatRange(from=0.0f, to=1.0f) public float getProbabilityLineOfSight();
- method @Nullable public android.location.GnssReflectingPlane getReflectingPlane();
+ method @Deprecated @Nullable public android.location.GnssReflectingPlane getReflectingPlane();
method @IntRange(from=0) public int getSatelliteId();
+ method public boolean hasCombinedAttenuation();
method public boolean hasExcessPathLength();
method public boolean hasExcessPathLengthUncertainty();
- method public boolean hasReflectingPlane();
+ method @Deprecated public boolean hasReflectingPlane();
method public boolean hasValidSatelliteLineOfSight();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.location.GnssSingleSatCorrection> CREATOR;
@@ -5578,15 +5592,18 @@ package android.location {
public static final class GnssSingleSatCorrection.Builder {
ctor public GnssSingleSatCorrection.Builder();
method @NonNull public android.location.GnssSingleSatCorrection build();
+ method @NonNull public android.location.GnssSingleSatCorrection.Builder clearCombinedAttenuationDb();
method @NonNull public android.location.GnssSingleSatCorrection.Builder clearExcessPathLengthMeters();
method @NonNull public android.location.GnssSingleSatCorrection.Builder clearExcessPathLengthUncertaintyMeters();
method @NonNull public android.location.GnssSingleSatCorrection.Builder clearProbabilityLineOfSight();
method @NonNull public android.location.GnssSingleSatCorrection.Builder setCarrierFrequencyHz(@FloatRange(from=0.0f, fromInclusive=false) float);
+ method @NonNull public android.location.GnssSingleSatCorrection.Builder setCombinedAttenuationDb(@FloatRange(from=0.0f) float);
method @NonNull public android.location.GnssSingleSatCorrection.Builder setConstellationType(int);
method @NonNull public android.location.GnssSingleSatCorrection.Builder setExcessPathLengthMeters(@FloatRange(from=0.0f) float);
method @NonNull public android.location.GnssSingleSatCorrection.Builder setExcessPathLengthUncertaintyMeters(@FloatRange(from=0.0f) float);
+ method @NonNull public android.location.GnssSingleSatCorrection.Builder setGnssExcessPathInfoList(@NonNull java.util.List<android.location.GnssExcessPathInfo>);
method @NonNull public android.location.GnssSingleSatCorrection.Builder setProbabilityLineOfSight(@FloatRange(from=0.0f, to=1.0f) float);
- method @NonNull public android.location.GnssSingleSatCorrection.Builder setReflectingPlane(@Nullable android.location.GnssReflectingPlane);
+ method @Deprecated @NonNull public android.location.GnssSingleSatCorrection.Builder setReflectingPlane(@Nullable android.location.GnssReflectingPlane);
method @NonNull public android.location.GnssSingleSatCorrection.Builder setSatelliteId(@IntRange(from=0) int);
}
@@ -5828,9 +5845,9 @@ package android.location {
ctor public LastLocationRequest.Builder();
ctor public LastLocationRequest.Builder(@NonNull android.location.LastLocationRequest);
method @NonNull public android.location.LastLocationRequest build();
- method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.WRITE_SECURE_SETTINGS, android.Manifest.permission.LOCATION_BYPASS}) public android.location.LastLocationRequest.Builder setAdasGnssBypass(boolean);
+ method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_BYPASS) public android.location.LastLocationRequest.Builder setAdasGnssBypass(boolean);
method @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_APP_OPS_STATS) public android.location.LastLocationRequest.Builder setHiddenFromAppOps(boolean);
- method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.WRITE_SECURE_SETTINGS, android.Manifest.permission.LOCATION_BYPASS}) public android.location.LastLocationRequest.Builder setLocationSettingsIgnored(boolean);
+ method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_BYPASS) public android.location.LastLocationRequest.Builder setLocationSettingsIgnored(boolean);
}
public class Location implements android.os.Parcelable {
@@ -5859,7 +5876,7 @@ package android.location {
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull android.location.LocationListener, @Nullable android.os.Looper);
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull java.util.concurrent.Executor, @NonNull android.location.LocationListener);
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull android.app.PendingIntent);
- method @RequiresPermission(anyOf={android.Manifest.permission.WRITE_SECURE_SETTINGS, android.Manifest.permission.LOCATION_BYPASS}) public void setAdasGnssLocationEnabled(boolean);
+ method @RequiresPermission(android.Manifest.permission.LOCATION_BYPASS) public void setAdasGnssLocationEnabled(boolean);
method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void setExtraLocationControllerPackage(@Nullable String);
method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void setExtraLocationControllerPackageEnabled(boolean);
method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void setLocationEnabledForUser(boolean, @NonNull android.os.UserHandle);
@@ -5892,7 +5909,7 @@ package android.location {
method @Deprecated @NonNull public android.location.LocationRequest setFastestInterval(long);
method @Deprecated public void setHideFromAppOps(boolean);
method @Deprecated @NonNull public android.location.LocationRequest setInterval(long);
- method @Deprecated @NonNull @RequiresPermission(anyOf={android.Manifest.permission.WRITE_SECURE_SETTINGS, android.Manifest.permission.LOCATION_BYPASS}) public android.location.LocationRequest setLocationSettingsIgnored(boolean);
+ method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_BYPASS) public android.location.LocationRequest setLocationSettingsIgnored(boolean);
method @Deprecated @NonNull public android.location.LocationRequest setLowPowerMode(boolean);
method @Deprecated @NonNull public android.location.LocationRequest setNumUpdates(int);
method @Deprecated @NonNull public android.location.LocationRequest setProvider(@NonNull String);
@@ -5908,9 +5925,9 @@ package android.location {
}
public static final class LocationRequest.Builder {
- method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.WRITE_SECURE_SETTINGS, android.Manifest.permission.LOCATION_BYPASS}) public android.location.LocationRequest.Builder setAdasGnssBypass(boolean);
+ method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_BYPASS) public android.location.LocationRequest.Builder setAdasGnssBypass(boolean);
method @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_APP_OPS_STATS) public android.location.LocationRequest.Builder setHiddenFromAppOps(boolean);
- method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.WRITE_SECURE_SETTINGS, android.Manifest.permission.LOCATION_BYPASS}) public android.location.LocationRequest.Builder setLocationSettingsIgnored(boolean);
+ method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_BYPASS) public android.location.LocationRequest.Builder setLocationSettingsIgnored(boolean);
method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public android.location.LocationRequest.Builder setLowPower(boolean);
method @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public android.location.LocationRequest.Builder setWorkSource(@Nullable android.os.WorkSource);
}
@@ -6943,7 +6960,7 @@ package android.media.tv.tuner {
}
public class Lnb implements java.lang.AutoCloseable {
- method public void addCallback(@NonNull android.media.tv.tuner.LnbCallback, @NonNull java.util.concurrent.Executor);
+ method public void addCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.tv.tuner.LnbCallback);
method public void close();
method public boolean removeCallback(@NonNull android.media.tv.tuner.LnbCallback);
method public int sendDiseqcMessage(@NonNull byte[]);
@@ -8518,45 +8535,6 @@ package android.metrics {
package android.net {
- public class EthernetManager {
- method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}) public void connectNetwork(@NonNull String, @Nullable java.util.concurrent.Executor, @Nullable java.util.function.BiConsumer<android.net.Network,android.net.EthernetNetworkManagementException>);
- method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}) public void disconnectNetwork(@NonNull String, @Nullable java.util.concurrent.Executor, @Nullable java.util.function.BiConsumer<android.net.Network,android.net.EthernetNetworkManagementException>);
- method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public android.net.EthernetManager.TetheredInterfaceRequest requestTetheredInterface(@NonNull java.util.concurrent.Executor, @NonNull android.net.EthernetManager.TetheredInterfaceCallback);
- method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}) public void updateConfiguration(@NonNull String, @NonNull android.net.EthernetNetworkUpdateRequest, @Nullable java.util.concurrent.Executor, @Nullable java.util.function.BiConsumer<android.net.Network,android.net.EthernetNetworkManagementException>);
- }
-
- public static interface EthernetManager.TetheredInterfaceCallback {
- method public void onAvailable(@NonNull String);
- method public void onUnavailable();
- }
-
- public static class EthernetManager.TetheredInterfaceRequest {
- method public void release();
- }
-
- public final class EthernetNetworkManagementException extends java.lang.RuntimeException implements android.os.Parcelable {
- ctor public EthernetNetworkManagementException(@NonNull String);
- method public int describeContents();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.EthernetNetworkManagementException> CREATOR;
- }
-
- public final class EthernetNetworkUpdateRequest implements android.os.Parcelable {
- method public int describeContents();
- method @NonNull public android.net.IpConfiguration getIpConfiguration();
- method @NonNull public android.net.NetworkCapabilities getNetworkCapabilities();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.EthernetNetworkUpdateRequest> CREATOR;
- }
-
- public static final class EthernetNetworkUpdateRequest.Builder {
- ctor public EthernetNetworkUpdateRequest.Builder();
- ctor public EthernetNetworkUpdateRequest.Builder(@NonNull android.net.EthernetNetworkUpdateRequest);
- method @NonNull public android.net.EthernetNetworkUpdateRequest build();
- method @NonNull public android.net.EthernetNetworkUpdateRequest.Builder setIpConfiguration(@NonNull android.net.IpConfiguration);
- method @NonNull public android.net.EthernetNetworkUpdateRequest.Builder setNetworkCapabilities(@NonNull android.net.NetworkCapabilities);
- }
-
public final class MatchAllNetworkSpecifier extends android.net.NetworkSpecifier implements android.os.Parcelable {
ctor public MatchAllNetworkSpecifier();
method public int describeContents();
@@ -9027,6 +9005,7 @@ package android.net.wifi.nl80211 {
method public void enableVerboseLogging(boolean);
method @NonNull public int[] getChannelsMhzForBand(int);
method @Nullable public android.net.wifi.nl80211.DeviceWiphyCapabilities getDeviceWiphyCapabilities(@NonNull String);
+ method public int getMaxSsidsPerScan(@NonNull String);
method @NonNull public java.util.List<android.net.wifi.nl80211.NativeScanResult> getScanResults(@NonNull String, int);
method @Nullable public android.net.wifi.nl80211.WifiNl80211Manager.TxPacketCounters getTxPacketCounters(@NonNull String);
method public void notifyCountryCodeChanged(@Nullable String);
@@ -9816,11 +9795,12 @@ package android.os {
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional=true) public boolean hasUserRestrictionForUser(@NonNull String, @NonNull android.os.UserHandle);
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS, android.Manifest.permission.QUERY_USERS}) public boolean isAdminUser();
method public boolean isCloneProfile();
- method public boolean isCredentialSharedWithParent();
+ method public boolean isCredentialSharableWithParent();
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS, android.Manifest.permission.QUERY_USERS}) public boolean isGuestUser();
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.QUERY_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional=true) public boolean isManagedProfile(int);
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional=true) public boolean isMediaSharedWithParent();
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS, android.Manifest.permission.QUERY_USERS}) public boolean isPrimaryUser();
+ method public static boolean isRemoveResultSuccessful(int);
method public boolean isRestrictedProfile();
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}, conditional=true) public boolean isRestrictedProfile(@NonNull android.os.UserHandle);
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.QUERY_USERS}) public boolean isSameProfileGroup(@NonNull android.os.UserHandle, @NonNull android.os.UserHandle);
@@ -9838,7 +9818,10 @@ package android.os {
field public static final String DISALLOW_RUN_IN_BACKGROUND = "no_run_in_background";
field public static final int REMOVE_RESULT_ALREADY_BEING_REMOVED = 2; // 0x2
field public static final int REMOVE_RESULT_DEFERRED = 1; // 0x1
- field public static final int REMOVE_RESULT_ERROR = 3; // 0x3
+ field public static final int REMOVE_RESULT_ERROR_SYSTEM_USER = -4; // 0xfffffffc
+ field public static final int REMOVE_RESULT_ERROR_UNKNOWN = -1; // 0xffffffff
+ field public static final int REMOVE_RESULT_ERROR_USER_NOT_FOUND = -3; // 0xfffffffd
+ field public static final int REMOVE_RESULT_ERROR_USER_RESTRICTION = -2; // 0xfffffffe
field public static final int REMOVE_RESULT_REMOVED = 0; // 0x0
field public static final int RESTRICTION_NOT_SET = 0; // 0x0
field public static final int RESTRICTION_SOURCE_DEVICE_OWNER = 2; // 0x2
@@ -10073,9 +10056,9 @@ package android.permission {
method @BinderThread public void onOneTimePermissionSessionTimeout(@NonNull String);
method @Deprecated @BinderThread public void onRestoreDelayedRuntimePermissionsBackup(@NonNull String, @NonNull android.os.UserHandle, @NonNull java.util.function.Consumer<java.lang.Boolean>);
method @Deprecated @BinderThread public void onRestoreRuntimePermissionsBackup(@NonNull android.os.UserHandle, @NonNull java.io.InputStream, @NonNull Runnable);
- method @BinderThread public void onRevokeOwnPermissionsOnKill(@NonNull String, @NonNull java.util.List<java.lang.String>, @NonNull Runnable);
method @BinderThread public abstract void onRevokeRuntimePermission(@NonNull String, @NonNull String, @NonNull Runnable);
method @BinderThread public abstract void onRevokeRuntimePermissions(@NonNull java.util.Map<java.lang.String,java.util.List<java.lang.String>>, boolean, int, @NonNull String, @NonNull java.util.function.Consumer<java.util.Map<java.lang.String,java.util.List<java.lang.String>>>);
+ method @BinderThread public void onRevokeSelfPermissionsOnKill(@NonNull String, @NonNull java.util.List<java.lang.String>, @NonNull Runnable);
method @Deprecated @BinderThread public abstract void onSetRuntimePermissionGrantStateByDeviceAdmin(@NonNull String, @NonNull String, @NonNull String, int, @NonNull java.util.function.Consumer<java.lang.Boolean>);
method @BinderThread public void onSetRuntimePermissionGrantStateByDeviceAdmin(@NonNull String, @NonNull android.permission.AdminPermissionControlParams, @NonNull java.util.function.Consumer<java.lang.Boolean>);
method @BinderThread public void onStageAndApplyRuntimePermissionsBackup(@NonNull android.os.UserHandle, @NonNull java.io.InputStream, @NonNull Runnable);
@@ -10101,10 +10084,10 @@ package android.permission {
public final class PermissionManager {
method public int checkDeviceIdentifierAccess(@Nullable String, @Nullable String, @Nullable String, int, int);
- method public int checkPermissionForDataDelivery(@NonNull String, @NonNull android.content.AttributionSource, @Nullable String);
- method public int checkPermissionForDataDeliveryFromDataSource(@NonNull String, @NonNull android.content.AttributionSource, @Nullable String);
+ method @RequiresPermission(value=android.Manifest.permission.UPDATE_APP_OPS_STATS, conditional=true) public int checkPermissionForDataDelivery(@NonNull String, @NonNull android.content.AttributionSource, @Nullable String);
+ method @RequiresPermission(value=android.Manifest.permission.UPDATE_APP_OPS_STATS, conditional=true) public int checkPermissionForDataDeliveryFromDataSource(@NonNull String, @NonNull android.content.AttributionSource, @Nullable String);
method public int checkPermissionForPreflight(@NonNull String, @NonNull android.content.AttributionSource);
- method public int checkPermissionForStartDataDelivery(@NonNull String, @NonNull android.content.AttributionSource, @Nullable String);
+ method @RequiresPermission(value=android.Manifest.permission.UPDATE_APP_OPS_STATS, conditional=true) public int checkPermissionForStartDataDelivery(@NonNull String, @NonNull android.content.AttributionSource, @Nullable String);
method public void finishDataDelivery(@NonNull String, @NonNull android.content.AttributionSource);
method @NonNull @RequiresPermission(android.Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY) public java.util.Set<java.lang.String> getAutoRevokeExemptionGrantedPackages();
method @NonNull @RequiresPermission(android.Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY) public java.util.Set<java.lang.String> getAutoRevokeExemptionRequestedPackages();
@@ -10328,6 +10311,7 @@ package android.provider {
field public static final String NAMESPACE_MEDIA_NATIVE = "media_native";
field public static final String NAMESPACE_NETD_NATIVE = "netd_native";
field public static final String NAMESPACE_NNAPI_NATIVE = "nnapi_native";
+ field public static final String NAMESPACE_ON_DEVICE_PERSONALIZATION = "on_device_personalization";
field public static final String NAMESPACE_OTA = "ota";
field public static final String NAMESPACE_PACKAGE_MANAGER_SERVICE = "package_manager_service";
field public static final String NAMESPACE_PERMISSIONS = "permissions";
@@ -10577,7 +10561,6 @@ package android.provider {
field public static final String AUTO_REVOKE_DISABLED = "auto_revoke_disabled";
field public static final String COMPLETED_CATEGORY_PREFIX = "suggested.completed_category.";
field public static final String DOZE_ALWAYS_ON = "doze_always_on";
- field public static final String FAST_PAIR_SCAN_ENABLED = "fast_pair_scan_enabled";
field public static final String HUSH_GESTURE_USED = "hush_gesture_used";
field public static final String INSTANT_APPS_ENABLED = "instant_apps_enabled";
field public static final String LAST_SETUP_SHOWN = "last_setup_shown";
@@ -10889,10 +10872,11 @@ package android.service.ambientcontext {
}
public static final class AmbientContextDetectionResult.Builder {
- ctor public AmbientContextDetectionResult.Builder();
+ ctor public AmbientContextDetectionResult.Builder(@NonNull String);
method @NonNull public android.service.ambientcontext.AmbientContextDetectionResult.Builder addEvent(@NonNull android.app.ambientcontext.AmbientContextEvent);
+ method @NonNull public android.service.ambientcontext.AmbientContextDetectionResult.Builder addEvents(@NonNull java.util.List<android.app.ambientcontext.AmbientContextEvent>);
method @NonNull public android.service.ambientcontext.AmbientContextDetectionResult build();
- method @NonNull public android.service.ambientcontext.AmbientContextDetectionResult.Builder setPackageName(@NonNull String);
+ method @NonNull public android.service.ambientcontext.AmbientContextDetectionResult.Builder clearEvents();
}
public abstract class AmbientContextDetectionService extends android.app.Service {
@@ -10913,9 +10897,8 @@ package android.service.ambientcontext {
}
public static final class AmbientContextDetectionServiceStatus.Builder {
- ctor public AmbientContextDetectionServiceStatus.Builder();
+ ctor public AmbientContextDetectionServiceStatus.Builder(@NonNull String);
method @NonNull public android.service.ambientcontext.AmbientContextDetectionServiceStatus build();
- method @NonNull public android.service.ambientcontext.AmbientContextDetectionServiceStatus.Builder setPackageName(@NonNull String);
method @NonNull public android.service.ambientcontext.AmbientContextDetectionServiceStatus.Builder setStatusCode(int);
}
@@ -11397,12 +11380,12 @@ package android.service.games {
method @RequiresPermission(android.Manifest.permission.MANAGE_GAME_ACTIVITY) public final boolean restartGame();
method public void setTaskOverlayView(@NonNull android.view.View, @NonNull android.view.ViewGroup.LayoutParams);
method @RequiresPermission(android.Manifest.permission.MANAGE_GAME_ACTIVITY) public final void startActivityFromGameSessionForResult(@NonNull android.content.Intent, @Nullable android.os.Bundle, @NonNull java.util.concurrent.Executor, @NonNull android.service.games.GameSessionActivityCallback);
- method public void takeScreenshot(@NonNull java.util.concurrent.Executor, @NonNull android.service.games.GameSession.ScreenshotCallback);
+ method @RequiresPermission(android.Manifest.permission.MANAGE_GAME_ACTIVITY) public void takeScreenshot(@NonNull java.util.concurrent.Executor, @NonNull android.service.games.GameSession.ScreenshotCallback);
}
public static interface GameSession.ScreenshotCallback {
method public void onFailure(int);
- method public void onSuccess(@NonNull android.graphics.Bitmap);
+ method public void onSuccess();
field public static final int ERROR_TAKE_SCREENSHOT_INTERNAL_ERROR = 0; // 0x0
}
@@ -11821,11 +11804,23 @@ package android.service.translation {
package android.service.trust {
+ public final class GrantTrustResult implements android.os.Parcelable {
+ method public int describeContents();
+ method public int getStatus();
+ method @NonNull public static String statusToString(int);
+ method @NonNull public static android.service.trust.GrantTrustResult withStatus(int);
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.service.trust.GrantTrustResult> CREATOR;
+ field public static final int STATUS_UNKNOWN = 0; // 0x0
+ field public static final int STATUS_UNLOCKED_BY_GRANT = 1; // 0x1
+ }
+
public class TrustAgentService extends android.app.Service {
ctor public TrustAgentService();
method public final void addEscrowToken(byte[], android.os.UserHandle);
method @Deprecated public final void grantTrust(CharSequence, long, boolean);
- method public final void grantTrust(CharSequence, long, int);
+ method @Deprecated public final void grantTrust(CharSequence, long, int);
+ method public final void grantTrust(@NonNull CharSequence, long, int, @Nullable java.util.function.Consumer<android.service.trust.GrantTrustResult>);
method public final void isEscrowTokenActive(long, android.os.UserHandle);
method public final void lockUser();
method public final android.os.IBinder onBind(android.content.Intent);
@@ -11838,7 +11833,8 @@ package android.service.trust {
method public void onEscrowTokenStateReceived(long, int);
method public void onTrustTimeout();
method public void onUnlockAttempt(boolean);
- method public void onUserRequestedUnlock();
+ method public void onUserMayRequestUnlock();
+ method public void onUserRequestedUnlock(boolean);
method public final void removeEscrowToken(long, android.os.UserHandle);
method public final void revokeTrust();
method public final void setManagingTrust(boolean);
@@ -12214,7 +12210,6 @@ package android.telecom {
public abstract class ConnectionService extends android.app.Service {
method public final void addExistingConnection(@NonNull android.telecom.PhoneAccountHandle, @NonNull android.telecom.Connection, @NonNull android.telecom.Conference);
- method @Nullable @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public android.telecom.Connection onCreateUnknownConnection(@NonNull android.telecom.PhoneAccountHandle, @NonNull android.telecom.ConnectionRequest);
}
public abstract class InCallService extends android.app.Service {
@@ -13372,7 +13367,7 @@ package android.telephony {
}
public class TelephonyManager {
- method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void addCarrierPrivilegesListener(int, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.TelephonyManager.CarrierPrivilegesListener);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void addCarrierPrivilegesListener(int, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.TelephonyManager.CarrierPrivilegesListener);
method @RequiresPermission(anyOf={android.Manifest.permission.MODIFY_PHONE_STATE, android.Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION}) @WorkerThread public void bootstrapAuthenticationRequest(int, @NonNull android.net.Uri, @NonNull android.telephony.gba.UaSecurityProtocolIdentifier, boolean, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.TelephonyManager.BootstrapAuthenticationCallback);
method @Deprecated @RequiresPermission(android.Manifest.permission.CALL_PHONE) public void call(String, String);
method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public android.telephony.PinResult changeIccLockPin(@NonNull String, @NonNull String);
@@ -13472,7 +13467,8 @@ package android.telephony {
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void notifyOtaEmergencyNumberDbInstalled();
method @RequiresPermission(android.Manifest.permission.REBOOT) public int prepareForUnattendedReboot();
method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean rebootRadio();
- method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void removeCarrierPrivilegesListener(@NonNull android.telephony.TelephonyManager.CarrierPrivilegesListener);
+ method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void registerCarrierPrivilegesCallback(int, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.TelephonyManager.CarrierPrivilegesCallback);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void removeCarrierPrivilegesListener(@NonNull android.telephony.TelephonyManager.CarrierPrivilegesListener);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void reportDefaultNetworkStatus(boolean);
method @RequiresPermission(allOf={android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.MODIFY_PHONE_STATE}) public void requestCellInfoUpdate(@NonNull android.os.WorkSource, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.TelephonyManager.CellInfoCallback);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void requestModemActivityInfo(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<android.telephony.ModemActivityInfo,android.telephony.TelephonyManager.ModemActivityInfoException>);
@@ -13522,6 +13518,7 @@ package android.telephony {
method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int[] supplyPukReportResult(String, String);
method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean switchSlots(int[]);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void toggleRadioOnOff();
+ method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void unregisterCarrierPrivilegesCallback(@NonNull android.telephony.TelephonyManager.CarrierPrivilegesCallback);
method @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public void updateOtaEmergencyNumberDbFilePath(@NonNull android.os.ParcelFileDescriptor);
method public void updateServiceLocation();
field @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final String ACTION_ANOMALY_REPORTED = "android.telephony.action.ANOMALY_REPORTED";
@@ -13627,8 +13624,13 @@ package android.telephony {
field public static final int RESULT_SUCCESS = 0; // 0x0
}
- public static interface TelephonyManager.CarrierPrivilegesListener {
- method public void onCarrierPrivilegesChanged(@NonNull java.util.List<java.lang.String>, @NonNull int[]);
+ public static interface TelephonyManager.CarrierPrivilegesCallback {
+ method public void onCarrierPrivilegesChanged(@NonNull java.util.Set<java.lang.String>, @NonNull java.util.Set<java.lang.Integer>);
+ method public default void onCarrierServiceChanged(@Nullable String, int);
+ }
+
+ @Deprecated public static interface TelephonyManager.CarrierPrivilegesListener {
+ method @Deprecated public void onCarrierPrivilegesChanged(@NonNull java.util.List<java.lang.String>, @NonNull int[]);
}
public static class TelephonyManager.ModemActivityInfoException extends java.lang.Exception {
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 1b627b2adfc9..a67d002cdddf 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -19,6 +19,7 @@ package android {
field public static final String FORCE_STOP_PACKAGES = "android.permission.FORCE_STOP_PACKAGES";
field public static final String INSTALL_TEST_ONLY_PACKAGE = "android.permission.INSTALL_TEST_ONLY_PACKAGE";
field public static final String KEEP_UNINSTALLED_PACKAGES = "android.permission.KEEP_UNINSTALLED_PACKAGES";
+ field public static final String MAKE_UID_VISIBLE = "android.permission.MAKE_UID_VISIBLE";
field @Deprecated public static final String MANAGE_ACTIVITY_STACKS = "android.permission.MANAGE_ACTIVITY_STACKS";
field public static final String MANAGE_ACTIVITY_TASKS = "android.permission.MANAGE_ACTIVITY_TASKS";
field public static final String MANAGE_CRATES = "android.permission.MANAGE_CRATES";
@@ -95,8 +96,7 @@ package android.accessibilityservice {
package android.animation {
public class ValueAnimator extends android.animation.Animator {
- method public static float getDurationScale();
- method public static void setDurationScale(float);
+ method @MainThread public static void setDurationScale(@FloatRange(from=0) float);
}
}
@@ -154,7 +154,6 @@ package android.app {
}
public class ActivityOptions {
- method @NonNull public static android.app.ActivityOptions fromBundle(@NonNull android.os.Bundle);
method public boolean isEligibleForLegacyPermissionPrompt();
method @NonNull public static android.app.ActivityOptions makeCustomAnimation(@NonNull android.content.Context, int, int, int, @Nullable android.os.Handler, @Nullable android.app.ActivityOptions.OnAnimationStartedListener, @Nullable android.app.ActivityOptions.OnAnimationFinishedListener);
method @NonNull @RequiresPermission(android.Manifest.permission.START_TASKS_FROM_RECENTS) public static android.app.ActivityOptions makeCustomTaskAnimation(@NonNull android.content.Context, int, int, @Nullable android.os.Handler, @Nullable android.app.ActivityOptions.OnAnimationStartedListener, @Nullable android.app.ActivityOptions.OnAnimationFinishedListener);
@@ -301,7 +300,6 @@ package android.app {
}
public class LocaleManager {
- method @Nullable public android.os.LocaleList getSystemLocales();
method public void setSystemLocales(@NonNull android.os.LocaleList);
}
@@ -357,14 +355,8 @@ package android.app {
}
public final class PictureInPictureParams implements android.os.Parcelable {
- method public java.util.List<android.app.RemoteAction> getActions();
- method public float getAspectRatio();
- method @Nullable public android.app.RemoteAction getCloseAction();
- method public float getExpandedAspectRatio();
- method public android.graphics.Rect getSourceRectHint();
- method @Nullable public CharSequence getSubtitle();
- method @Nullable public CharSequence getTitle();
- method public boolean isSeamlessResizeEnabled();
+ method public float getAspectRatioFloat();
+ method public float getExpandedAspectRatioFloat();
}
public final class PictureInPictureUiState implements android.os.Parcelable {
@@ -374,16 +366,17 @@ package android.app {
public class PropertyInvalidatedCache<Query, Result> {
ctor public PropertyInvalidatedCache(int, @NonNull String, @NonNull String, @NonNull String, @NonNull android.app.PropertyInvalidatedCache.QueryHandler<Query,Result>);
method @NonNull public static String createPropertyName(@NonNull String, @NonNull String);
- method public final void disableForCurrentProcess();
+ method public void disableForCurrentProcess();
+ method public static void disableForCurrentProcess(@NonNull String);
method public static void disableForTestMode();
method public final void disableInstance();
method public final void disableSystemWide();
method public final void forgetDisableLocal();
method public boolean getDisabledState();
- method public final void invalidateCache();
+ method public void invalidateCache();
method public static void invalidateCache(@NonNull String, @NonNull String);
method public final boolean isDisabled();
- method @Nullable public final Result query(@NonNull Query);
+ method @Nullable public Result query(@NonNull Query);
method public static void setTestMode(boolean);
method public void testPropertyName();
field public static final String MODULE_BLUETOOTH = "bluetooth";
@@ -422,9 +415,9 @@ package android.app {
method @NonNull public android.content.res.Configuration getConfiguration();
method public int getParentTaskId();
method @Nullable public android.app.PictureInPictureParams getPictureInPictureParams();
- method public boolean getPreferDockBigOverlays();
method @NonNull public android.window.WindowContainerToken getToken();
method public boolean hasParentTask();
+ method public boolean shouldDockBigOverlays();
}
public class TimePickerDialog extends android.app.AlertDialog implements android.content.DialogInterface.OnClickListener android.widget.TimePicker.OnTimeChangedListener {
@@ -508,6 +501,7 @@ package android.app.admin {
method public void forceUpdateUserSetupComplete(int);
method @NonNull public java.util.Set<java.lang.String> getDefaultCrossProfilePackages();
method public int getDeviceOwnerType(@NonNull android.content.ComponentName);
+ method @Nullable public String getDevicePolicyManagementRoleHolderUpdaterPackage();
method @NonNull public java.util.Set<java.lang.String> getDisallowedSystemApps(@NonNull android.content.ComponentName, int, @NonNull String);
method public long getLastBugReportRequestTime();
method public long getLastNetworkLogRetrievalTime();
@@ -518,7 +512,6 @@ package android.app.admin {
method public boolean isFactoryResetProtectionPolicySupported();
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}) public boolean isNewUserDisclaimerAcknowledged();
method public boolean isRemovingAdmin(@NonNull android.content.ComponentName, int);
- method @RequiresPermission(anyOf={android.Manifest.permission.MARK_DEVICE_ORGANIZATION_OWNED, android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS}, conditional=true) public void markProfileOwnerOnOrganizationOwnedDevice(@NonNull android.content.ComponentName);
method @NonNull public static String operationSafetyReasonToString(int);
method @NonNull public static String operationToString(int);
method @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public void resetDefaultCrossProfileIntentFilters(int);
@@ -527,6 +520,7 @@ package android.app.admin {
method @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public boolean setDeviceOwnerOnly(@NonNull android.content.ComponentName, @Nullable String, int);
method public void setDeviceOwnerType(@NonNull android.content.ComponentName, int);
method @RequiresPermission(android.Manifest.permission.MANAGE_DEVICE_ADMINS) public void setNextOperationSafety(int, int);
+ method @RequiresPermission(anyOf={android.Manifest.permission.MARK_DEVICE_ORGANIZATION_OWNED, android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS}, conditional=true) public void setProfileOwnerOnOrganizationOwnedDevice(@NonNull android.content.ComponentName, boolean);
field public static final String ACTION_DATA_SHARING_RESTRICTION_APPLIED = "android.app.action.DATA_SHARING_RESTRICTION_APPLIED";
field public static final String ACTION_DEVICE_POLICY_CONSTANTS_CHANGED = "android.app.action.DEVICE_POLICY_CONSTANTS_CHANGED";
field public static final int DEVICE_OWNER_TYPE_DEFAULT = 0; // 0x0
@@ -622,7 +616,7 @@ package android.app.blob {
package android.app.cloudsearch {
public static final class SearchRequest.Builder {
- method @NonNull public android.app.cloudsearch.SearchRequest.Builder setSource(@NonNull String);
+ method @NonNull public android.app.cloudsearch.SearchRequest.Builder setCallerPackageName(@NonNull String);
}
}
@@ -836,6 +830,7 @@ package android.content.pm {
method @Nullable public String getSystemTextClassifierPackageName();
method @Nullable public String getWellbeingPackageName();
method public void holdLock(android.os.IBinder, int);
+ method @RequiresPermission(android.Manifest.permission.MAKE_UID_VISIBLE) public void makeUidVisible(int, int);
method @RequiresPermission(android.Manifest.permission.KEEP_UNINSTALLED_PACKAGES) public void setKeepUninstalledPackages(@NonNull java.util.List<java.lang.String>);
field public static final String FEATURE_ADOPTABLE_STORAGE = "android.software.adoptable_storage";
field public static final String FEATURE_COMMUNAL_MODE = "android.software.communal_mode";
@@ -1466,6 +1461,7 @@ package android.media {
method @NonNull @RequiresPermission(android.Manifest.permission.CALL_AUDIO_INTERCEPTION) public android.media.AudioTrack getCallUplinkInjectionAudioTrack(@NonNull android.media.AudioFormat);
method @Nullable public static android.media.AudioDeviceInfo getDeviceInfoFromType(int);
method @IntRange(from=0) @RequiresPermission("android.permission.QUERY_AUDIO_STATE") public long getFadeOutDurationOnFocusLossMillis(@NonNull android.media.AudioAttributes);
+ method @Nullable public static String getHalVersion();
method public static final int[] getPublicStreamTypes();
method @NonNull public java.util.List<java.lang.Integer> getReportedSurroundFormats();
method public int getStreamMinVolumeInt(int);
@@ -1726,6 +1722,19 @@ package android.os {
method @NonNull public static byte[] digest(@NonNull java.io.InputStream, @NonNull String) throws java.io.IOException, java.security.NoSuchAlgorithmException;
}
+ public class IpcDataCache<Query, Result> extends android.app.PropertyInvalidatedCache<Query,Result> {
+ ctor public IpcDataCache(int, @NonNull String, @NonNull String, @NonNull String, @NonNull android.os.IpcDataCache.QueryHandler<Query,Result>);
+ method public static void disableForCurrentProcess(@NonNull String);
+ method public static void invalidateCache(@NonNull String, @NonNull String);
+ field public static final String MODULE_BLUETOOTH = "bluetooth";
+ field public static final String MODULE_SYSTEM = "system_server";
+ field public static final String MODULE_TEST = "test";
+ }
+
+ public abstract static class IpcDataCache.QueryHandler<Q, R> extends android.app.PropertyInvalidatedCache.QueryHandler<Q,R> {
+ ctor public IpcDataCache.QueryHandler();
+ }
+
public final class MessageQueue {
method public int postSyncBarrier();
method public void removeSyncBarrier(int);
@@ -1777,9 +1786,9 @@ package android.os {
}
public class Process {
+ method public static final int getAppUidForSdkSandboxUid(int);
method public static final int getThreadScheduler(int) throws java.lang.IllegalArgumentException;
method public static final boolean isSdkSandboxUid(int);
- method public static final int sdkSandboxToAppUid(int);
method public static final int toSdkSandboxUid(int);
field public static final int FIRST_APP_ZYGOTE_ISOLATED_UID = 90000; // 0x15f90
field public static final int FIRST_ISOLATED_UID = 99000; // 0x182b8
@@ -1787,6 +1796,7 @@ package android.os {
field public static final int LAST_ISOLATED_UID = 99999; // 0x1869f
field public static final int NFC_UID = 1027; // 0x403
field public static final int NUM_UIDS_PER_APP_ZYGOTE = 100; // 0x64
+ field public static final int SDK_SANDBOX_VIRTUAL_UID = 1090; // 0x442
}
public final class StrictMode {
@@ -2163,6 +2173,7 @@ package android.provider {
field @Deprecated public static final String NOTIFICATION_BUBBLES = "notification_bubbles";
field public static final String OVERLAY_DISPLAY_DEVICES = "overlay_display_devices";
field public static final String SHOW_FIRST_CRASH_DIALOG = "show_first_crash_dialog";
+ field public static final String STYLUS_HANDWRITING_ENABLED = "stylus_handwriting_enabled";
field public static final String USER_DISABLED_HDR_FORMATS = "user_disabled_hdr_formats";
field public static final String USER_PREFERRED_REFRESH_RATE = "user_preferred_refresh_rate";
field public static final String USER_PREFERRED_RESOLUTION_HEIGHT = "user_preferred_resolution_height";
@@ -2418,7 +2429,7 @@ package android.service.quicksettings {
package android.service.voice {
public class AlwaysOnHotwordDetector implements android.service.voice.HotwordDetector {
- method @RequiresPermission(allOf={android.Manifest.permission.RECORD_AUDIO, android.Manifest.permission.CAPTURE_AUDIO_HOTWORD}) public void triggerHardwareRecognitionEventForTest(int, int, boolean, int, int, int, boolean, @NonNull android.media.AudioFormat, @Nullable byte[]);
+ method @RequiresPermission(allOf={android.Manifest.permission.RECORD_AUDIO, android.Manifest.permission.CAPTURE_AUDIO_HOTWORD}) public void triggerHardwareRecognitionEventForTest(int, int, boolean, int, int, int, boolean, @NonNull android.media.AudioFormat, @Nullable byte[], @NonNull java.util.List<android.hardware.soundtrigger.SoundTrigger.KeyphraseRecognitionExtra>);
}
public static final class AlwaysOnHotwordDetector.EventPayload.Builder {
@@ -2876,6 +2887,7 @@ package android.view {
method public static int getHoverTooltipHideTimeout();
method public static int getHoverTooltipShowTimeout();
method public static int getLongPressTooltipHideTimeout();
+ method public int getPreferKeepClearForFocusDelay();
}
public class ViewDebug {
diff --git a/core/java/Android.bp b/core/java/Android.bp
index a5526bc66431..f081a439c49c 100644
--- a/core/java/Android.bp
+++ b/core/java/Android.bp
@@ -145,16 +145,16 @@ genrule {
out: ["com/android/internal/util/FrameworkStatsLog.java"],
}
+// Library that provides functionality to log UiEvents in framework space.
+// If this functionality is needed outside the framework, the interfaces library
+// can be re-used and a local implementation is needed.
java_library {
name: "uieventloggerlib",
srcs: [
- "com/android/internal/logging/UiEvent.java",
- "com/android/internal/logging/UiEventLogger.java",
"com/android/internal/logging/UiEventLoggerImpl.java",
- "com/android/internal/logging/InstanceId.java",
- "com/android/internal/logging/InstanceIdSequence.java",
":statslog-framework-java-gen",
],
+ static_libs: ["modules-utils-uieventlogger-interface"],
}
filegroup {
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index c82f5f6d54fc..3cb04e710d3b 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -825,17 +825,7 @@ public abstract class AccessibilityService extends Service {
for (int i = 0; i < mMagnificationControllers.size(); i++) {
mMagnificationControllers.valueAt(i).onServiceConnectedLocked();
}
- AccessibilityServiceInfo info = getServiceInfo();
- if (info != null) {
- boolean requestIme = (info.flags
- & AccessibilityServiceInfo.FLAG_INPUT_METHOD_EDITOR) != 0;
- if (requestIme && !mInputMethodInitialized) {
- mInputMethod = onCreateInputMethod();
- mInputMethodInitialized = true;
- }
- } else {
- Log.e(LOG_TAG, "AccessibilityServiceInfo is null in dispatchServiceConnected");
- }
+ updateInputMethod(getServiceInfo());
}
if (mSoftKeyboardController != null) {
mSoftKeyboardController.onServiceConnected();
@@ -846,6 +836,20 @@ public abstract class AccessibilityService extends Service {
onServiceConnected();
}
+ private void updateInputMethod(AccessibilityServiceInfo info) {
+ if (info != null) {
+ boolean requestIme = (info.flags
+ & AccessibilityServiceInfo.FLAG_INPUT_METHOD_EDITOR) != 0;
+ if (requestIme && !mInputMethodInitialized) {
+ mInputMethod = onCreateInputMethod();
+ mInputMethodInitialized = true;
+ } else if (!requestIme & mInputMethodInitialized) {
+ mInputMethod = null;
+ mInputMethodInitialized = false;
+ }
+ }
+ }
+
/**
* This method is a part of the {@link AccessibilityService} lifecycle and is
* called after the system has successfully bound to the service. If is
@@ -2521,6 +2525,7 @@ public abstract class AccessibilityService extends Service {
*/
public final void setServiceInfo(AccessibilityServiceInfo info) {
mInfo = info;
+ updateInputMethod(info);
sendServiceInfo();
}
diff --git a/core/java/android/accessibilityservice/AccessibilityShortcutInfo.java b/core/java/android/accessibilityservice/AccessibilityShortcutInfo.java
index 4e6cfb358901..f53cfe457b64 100644
--- a/core/java/android/accessibilityservice/AccessibilityShortcutInfo.java
+++ b/core/java/android/accessibilityservice/AccessibilityShortcutInfo.java
@@ -169,10 +169,6 @@ public final class AccessibilityShortcutInfo {
mIntroResId = asAttributes.getResourceId(
com.android.internal.R.styleable.AccessibilityShortcutTarget_intro, 0);
asAttributes.recycle();
-
- if ((mDescriptionResId == 0 && mHtmlDescriptionRes == 0) || mSummaryResId == 0) {
- throw new XmlPullParserException("No description or summary in meta-data");
- }
} catch (PackageManager.NameNotFoundException e) {
throw new XmlPullParserException("Unable to create context for: "
+ mActivityInfo.packageName);
diff --git a/core/java/android/accessibilityservice/InputMethod.java b/core/java/android/accessibilityservice/InputMethod.java
index 001d804b22d6..c0e5e84d369a 100644
--- a/core/java/android/accessibilityservice/InputMethod.java
+++ b/core/java/android/accessibilityservice/InputMethod.java
@@ -67,7 +67,11 @@ public class InputMethod {
private InputConnection mStartedInputConnection;
private EditorInfo mInputEditorInfo;
- protected InputMethod(@NonNull AccessibilityService service) {
+ /**
+ * Creates a new InputMethod instance for the given <code>service</code>, so that the
+ * accessibility service can control editing.
+ */
+ public InputMethod(@NonNull AccessibilityService service) {
mService = service;
}
diff --git a/core/java/android/accounts/CantAddAccountActivity.java b/core/java/android/accounts/CantAddAccountActivity.java
index 107efc3cce95..3fac1a0bdea0 100644
--- a/core/java/android/accounts/CantAddAccountActivity.java
+++ b/core/java/android/accounts/CantAddAccountActivity.java
@@ -39,7 +39,7 @@ public class CantAddAccountActivity extends Activity {
setContentView(R.layout.app_not_authorized);
TextView view = findViewById(R.id.description);
- String text = getSystemService(DevicePolicyManager.class).getString(
+ String text = getSystemService(DevicePolicyManager.class).getResources().getString(
CANT_ADD_ACCOUNT_MESSAGE,
() -> getString(R.string.error_message_change_not_allowed));
view.setText(text);
diff --git a/core/java/android/accounts/ChooseTypeAndAccountActivity.java b/core/java/android/accounts/ChooseTypeAndAccountActivity.java
index 0d82ac942148..f623295dee3e 100644
--- a/core/java/android/accounts/ChooseTypeAndAccountActivity.java
+++ b/core/java/android/accounts/ChooseTypeAndAccountActivity.java
@@ -205,7 +205,7 @@ public class ChooseTypeAndAccountActivity extends Activity
setContentView(R.layout.app_not_authorized);
TextView view = findViewById(R.id.description);
- String text = getSystemService(DevicePolicyManager.class).getString(
+ String text = getSystemService(DevicePolicyManager.class).getResources().getString(
CANT_ADD_ACCOUNT_MESSAGE,
() -> getString(R.string.error_message_change_not_allowed));
view.setText(text);
diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java
index 06b424bcb417..6ab7ae6d0cee 100644
--- a/core/java/android/animation/ValueAnimator.java
+++ b/core/java/android/animation/ValueAnimator.java
@@ -17,7 +17,9 @@
package android.animation;
import android.annotation.CallSuper;
+import android.annotation.FloatRange;
import android.annotation.IntDef;
+import android.annotation.MainThread;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.TestApi;
@@ -35,8 +37,10 @@ import android.view.animation.LinearInterpolator;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.List;
/**
* This class provides a simple timing engine for running animations
@@ -91,6 +95,9 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
private static float sDurationScale = 1.0f;
+ private static final ArrayList<WeakReference<DurationScaleChangeListener>>
+ sDurationScaleChangeListeners = new ArrayList<>();
+
/**
* Internal variables
* NOTE: This object implements the clone() method, making a deep copy of any referenced
@@ -308,20 +315,92 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio
*/
@UnsupportedAppUsage
@TestApi
- public static void setDurationScale(float durationScale) {
+ @MainThread
+ public static void setDurationScale(@FloatRange(from = 0) float durationScale) {
sDurationScale = durationScale;
+ List<WeakReference<DurationScaleChangeListener>> listenerCopy;
+
+ synchronized (sDurationScaleChangeListeners) {
+ listenerCopy = new ArrayList<>(sDurationScaleChangeListeners);
+ }
+
+ for (WeakReference<DurationScaleChangeListener> listenerRef : listenerCopy) {
+ final DurationScaleChangeListener listener = listenerRef.get();
+ if (listener != null) {
+ listener.onChanged(durationScale);
+ }
+ }
}
/**
- * @hide
+ * Returns the system-wide scaling factor for Animator-based animations.
+ *
+ * This affects both the start delay and duration of all such animations. Setting to 0 will
+ * cause animations to end immediately. The default value is 1.0f.
+ *
+ * @return the duration scale.
*/
- @UnsupportedAppUsage
- @TestApi
+ @FloatRange(from = 0)
public static float getDurationScale() {
return sDurationScale;
}
/**
+ * Registers a {@link DurationScaleChangeListener}
+ *
+ * This listens for changes to the system-wide scaling factor for Animator-based animations.
+ * Listeners will be called on the main thread.
+ *
+ * @param listener the listener to register.
+ * @return true if the listener was registered.
+ */
+ public static boolean registerDurationScaleChangeListener(
+ @NonNull DurationScaleChangeListener listener) {
+ int posToReplace = -1;
+ synchronized (sDurationScaleChangeListeners) {
+ for (int i = 0; i < sDurationScaleChangeListeners.size(); i++) {
+ final WeakReference<DurationScaleChangeListener> ref =
+ sDurationScaleChangeListeners.get(i);
+ if (ref.get() == null) {
+ if (posToReplace == -1) {
+ posToReplace = i;
+ }
+ } else if (ref.get() == listener) {
+ return false;
+ }
+ }
+ if (posToReplace != -1) {
+ sDurationScaleChangeListeners.set(posToReplace, new WeakReference<>(listener));
+ return true;
+ } else {
+ return sDurationScaleChangeListeners.add(new WeakReference<>(listener));
+ }
+ }
+ }
+
+ /**
+ * Unregisters a DurationScaleChangeListener.
+ *
+ * @see #registerDurationScaleChangeListener(DurationScaleChangeListener)
+ * @param listener the listener to unregister.
+ * @return true if the listener was unregistered.
+ */
+ public static boolean unregisterDurationScaleChangeListener(
+ @NonNull DurationScaleChangeListener listener) {
+ synchronized (sDurationScaleChangeListeners) {
+ WeakReference<DurationScaleChangeListener> listenerRefToRemove = null;
+ for (WeakReference<DurationScaleChangeListener> listenerRef :
+ sDurationScaleChangeListeners) {
+ if (listenerRef.get() == listener) {
+ listenerRefToRemove = listenerRef;
+ break;
+ }
+ }
+ return sDurationScaleChangeListeners.remove(listenerRefToRemove);
+ }
+ }
+
+ /**
* Returns whether animators are currently enabled, system-wide. By default, all
* animators are enabled. This can change if either the user sets a Developer Option
* to set the animator duration scale to 0 or by Battery Savery mode being enabled
@@ -1709,4 +1788,18 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio
public void setAnimationHandler(@Nullable AnimationHandler animationHandler) {
mAnimationHandler = animationHandler;
}
+
+ /**
+ * Listener interface for the system-wide scaling factor for Animator-based animations.
+ *
+ * @see #registerDurationScaleChangeListener(DurationScaleChangeListener)
+ * @see #unregisterDurationScaleChangeListener(DurationScaleChangeListener)
+ */
+ public interface DurationScaleChangeListener {
+ /**
+ * Called when the duration scale changes.
+ * @param scale the duration scale
+ */
+ void onChanged(@FloatRange(from = 0) float scale);
+ }
}
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 8f348a4e81d6..a28b3e9fc545 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -872,7 +872,7 @@ public class Activity extends ContextThemeWrapper
@UnsupportedAppUsage
/*package*/ int mConfigChangeFlags;
@UnsupportedAppUsage
- /*package*/ Configuration mCurrentConfig;
+ /*package*/ Configuration mCurrentConfig = Configuration.EMPTY;
private SearchManager mSearchManager;
private MenuInflater mMenuInflater;
@@ -984,6 +984,8 @@ public class Activity extends ContextThemeWrapper
private boolean mIsInMultiWindowMode;
private boolean mIsInPictureInPictureMode;
+ private boolean mShouldDockBigOverlays;
+
private UiTranslationController mUiTranslationController;
private SplashScreen mSplashScreen;
@@ -2977,13 +2979,28 @@ public class Activity extends ContextThemeWrapper
* <p> If specified, the system will try to respect the preference, but it may be
* overridden by a user preference.
*
- * @param preferDockBigOverlays indicates that the activity prefers big overlays to be
- * docked next to it instead of overlaying its content
+ * @param shouldDockBigOverlays indicates that big overlays should be docked next to the
+ * activity instead of overlay its content
*
* @see PictureInPictureParams.Builder#setExpandedAspectRatio
+ * @see #shouldDockBigOverlays
+ */
+ public void setShouldDockBigOverlays(boolean shouldDockBigOverlays) {
+ ActivityClient.getInstance().setShouldDockBigOverlays(mToken, shouldDockBigOverlays);
+ mShouldDockBigOverlays = shouldDockBigOverlays;
+ }
+
+ /**
+ * Returns whether big overlays should be docked next to the activity as set by
+ * {@link #setShouldDockBigOverlays}.
+ *
+ * @return {@code true} if big overlays should be docked next to the activity instead
+ * of overlay its content
+ *
+ * @see #setShouldDockBigOverlays
*/
- public void setPreferDockBigOverlays(boolean preferDockBigOverlays) {
- ActivityClient.getInstance().setPreferDockBigOverlays(mToken, preferDockBigOverlays);
+ public boolean shouldDockBigOverlays() {
+ return mShouldDockBigOverlays;
}
void dispatchMovedToDisplay(int displayId, Configuration config) {
@@ -5663,7 +5680,6 @@ public class Activity extends ContextThemeWrapper
* @throws ActivityNotFoundException &nbsp;
* @hide
*/
- @SystemApi
@RequiresPermission(anyOf = {INTERACT_ACROSS_USERS, INTERACT_ACROSS_USERS_FULL})
public void startActivityAsUser(@NonNull Intent intent,
@Nullable Bundle options, @NonNull UserHandle user) {
@@ -8249,6 +8265,7 @@ public class Activity extends ContextThemeWrapper
.getWindowingMode();
mIsInMultiWindowMode = inMultiWindowMode(windowingMode);
mIsInPictureInPictureMode = windowingMode == WINDOWING_MODE_PINNED;
+ mShouldDockBigOverlays = getResources().getBoolean(R.bool.config_dockBigOverlayWindows);
restoreHasCurrentPermissionRequest(icicle);
if (persistentState != null) {
onCreate(icicle, persistentState);
diff --git a/core/java/android/app/ActivityClient.java b/core/java/android/app/ActivityClient.java
index cf8480c6b9c8..7b7b1efdb86b 100644
--- a/core/java/android/app/ActivityClient.java
+++ b/core/java/android/app/ActivityClient.java
@@ -324,9 +324,9 @@ public class ActivityClient {
}
}
- void setPreferDockBigOverlays(IBinder token, boolean preferDockBigOverlays) {
+ void setShouldDockBigOverlays(IBinder token, boolean shouldDockBigOverlays) {
try {
- getActivityClientController().setPreferDockBigOverlays(token, preferDockBigOverlays);
+ getActivityClientController().setShouldDockBigOverlays(token, shouldDockBigOverlays);
} catch (RemoteException e) {
e.rethrowFromSystemServer();
}
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 9f1510526bae..e8c903fc2f13 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -22,6 +22,7 @@ import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
import android.Manifest;
+import android.annotation.ColorInt;
import android.annotation.DrawableRes;
import android.annotation.IntDef;
import android.annotation.IntRange;
@@ -185,6 +186,11 @@ public class ActivityManager {
* @hide
*/
public static final int INSTR_FLAG_ALWAYS_CHECK_SIGNATURE = 1 << 4;
+ /**
+ * Instrument Sdk Sandbox process that corresponds to the target package.
+ * @hide
+ */
+ public static final int INSTR_FLAG_INSTRUMENT_SDK_SANDBOX = 1 << 5;
static final class UidObserver extends IUidObserver.Stub {
final OnUidImportanceListener mListener;
@@ -1264,6 +1270,104 @@ public class ActivityManager {
private int mMinWidth;
private int mMinHeight;
+ /**
+ * Provides a convenient way to set the fields of a {@link TaskDescription} when creating a
+ * new instance.
+ */
+ public static final class Builder {
+ /**
+ * Default values for the TaskDescription
+ */
+ @Nullable
+ private String mLabel = null;
+ @DrawableRes
+ private int mIconRes = Resources.ID_NULL;
+ private int mPrimaryColor = 0;
+ private int mBackgroundColor = 0;
+ private int mStatusBarColor = 0;
+ private int mNavigationBarColor = 0;
+
+ /**
+ * Set the label to use in the TaskDescription.
+ * @param label A label and description of the current state of this activity.
+ * @return The same instance of the builder.
+ */
+ @NonNull
+ public Builder setLabel(@Nullable String label) {
+ this.mLabel = label;
+ return this;
+ }
+
+ /**
+ * Set the drawable resource of the icon to use in the TaskDescription.
+ * @param iconRes A drawable resource of an icon that represents the current state of
+ * this activity.
+ * @return The same instance of the builder.
+ */
+ @NonNull
+ public Builder setIcon(@DrawableRes int iconRes) {
+ this.mIconRes = iconRes;
+ return this;
+ }
+
+ /**
+ * Set the primary color to use in the TaskDescription.
+ * @param color A color to override the theme's primary color. The color must be opaque.
+ * @return The same instance of the builder.
+ */
+ @NonNull
+ public Builder setPrimaryColor(@ColorInt int color) {
+ this.mPrimaryColor = color;
+ return this;
+ }
+
+ /**
+ * Set the background color to use in the TaskDescription.
+ * @param color A color to override the theme's background color. The color must be
+ * opaque.
+ * @return The same instance of the builder.
+ */
+ @NonNull
+ public Builder setBackgroundColor(@ColorInt int color) {
+ this.mBackgroundColor = color;
+ return this;
+ }
+
+ /**
+ * Set the status bar color to use in the TaskDescription.
+ * @param color A color to override the theme's status bar color.
+ * @return The same instance of the builder.
+ */
+ @NonNull
+ public Builder setStatusBarColor(@ColorInt int color) {
+ this.mStatusBarColor = color;
+ return this;
+ }
+
+ /**
+ * Set the navigation bar color to use in the TaskDescription.
+ * @param color A color to override the theme's navigation bar color.
+ * @return The same instance of the builder.
+ */
+ @NonNull
+ public Builder setNavigationBarColor(@ColorInt int color) {
+ this.mNavigationBarColor = color;
+ return this;
+ }
+
+ /**
+ * Build the TaskDescription.
+ * @return the TaskDescription object.
+ */
+ @NonNull
+ public TaskDescription build() {
+ final Icon icon = mIconRes == Resources.ID_NULL ? null :
+ Icon.createWithResource(ActivityThread.currentPackageName(), mIconRes);
+ return new TaskDescription(mLabel, icon, mPrimaryColor, mBackgroundColor,
+ mStatusBarColor, mNavigationBarColor, false, false, RESIZE_MODE_RESIZEABLE,
+ -1, -1, 0);
+ }
+ }
/**
* Creates the TaskDescription to the specified values.
@@ -1273,7 +1377,10 @@ public class ActivityManager {
* activity.
* @param colorPrimary A color to override the theme's primary color. This color must be
* opaque.
+ *
+ * @deprecated Use {@link Builder} instead.
*/
+ @Deprecated
public TaskDescription(String label, @DrawableRes int iconRes, int colorPrimary) {
this(label, Icon.createWithResource(ActivityThread.currentPackageName(), iconRes),
colorPrimary, 0, 0, 0, false, false, RESIZE_MODE_RESIZEABLE, -1, -1, 0);
@@ -1288,7 +1395,10 @@ public class ActivityManager {
* @param label A label and description of the current state of this activity.
* @param iconRes A drawable resource of an icon that represents the current state of this
* activity.
+ *
+ * @deprecated Use {@link Builder} instead.
*/
+ @Deprecated
public TaskDescription(String label, @DrawableRes int iconRes) {
this(label, Icon.createWithResource(ActivityThread.currentPackageName(), iconRes),
0, 0, 0, 0, false, false, RESIZE_MODE_RESIZEABLE, -1, -1, 0);
@@ -1298,14 +1408,20 @@ public class ActivityManager {
* Creates the TaskDescription to the specified values.
*
* @param label A label and description of the current state of this activity.
+ *
+ * @deprecated Use {@link Builder} instead.
*/
+ @Deprecated
public TaskDescription(String label) {
this(label, null, 0, 0, 0, 0, false, false, RESIZE_MODE_RESIZEABLE, -1, -1, 0);
}
/**
* Creates an empty TaskDescription.
+ *
+ * @deprecated Use {@link Builder} instead.
*/
+ @Deprecated
public TaskDescription() {
this(null, null, 0, 0, 0, 0, false, false, RESIZE_MODE_RESIZEABLE, -1, -1, 0);
}
@@ -1317,7 +1433,8 @@ public class ActivityManager {
* @param icon An icon that represents the current state of this task.
* @param colorPrimary A color to override the theme's primary color. This color must be
* opaque.
- * @deprecated use TaskDescription constructor with icon resource instead
+ *
+ * @deprecated Use {@link Builder} instead.
*/
@Deprecated
public TaskDescription(String label, Bitmap icon, int colorPrimary) {
@@ -1333,7 +1450,8 @@ public class ActivityManager {
*
* @param label A label and description of the current state of this activity.
* @param icon An icon that represents the current state of this activity.
- * @deprecated use TaskDescription constructor with icon resource instead
+ *
+ * @deprecated Use {@link Builder} instead.
*/
@Deprecated
public TaskDescription(String label, Bitmap icon) {
@@ -1635,15 +1753,15 @@ public class ActivityManager {
/**
* @return The color override on the theme's primary color.
*/
+ @ColorInt
public int getPrimaryColor() {
return mColorPrimary;
}
/**
- * @return The background color.
- * @hide
+ * @return The color override on the theme's background color.
*/
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
+ @ColorInt
public int getBackgroundColor() {
return mColorBackground;
}
@@ -1657,15 +1775,17 @@ public class ActivityManager {
}
/**
- * @hide
+ * @return The color override on the theme's status bar color.
*/
+ @ColorInt
public int getStatusBarColor() {
return mStatusBarColor;
}
/**
- * @hide
+ * @return The color override on the theme's navigation bar color.
*/
+ @ColorInt
public int getNavigationBarColor() {
return mNavigationBarColor;
}
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index 87ac6cb1fe4c..0178fa143445 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -1421,17 +1421,9 @@ public class ActivityOptions extends ComponentOptions {
return mRemoteTransition;
}
- /**
- * Creates an ActivityOptions from the Bundle generated from {@link ActivityOptions#toBundle()}.
- * Returns an instance of ActivityOptions populated with options with known keys from the
- * provided Bundle, stripping out unknown entries.
- * @hide
- */
- @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
- @TestApi
- @NonNull
- public static ActivityOptions fromBundle(@NonNull Bundle bOptions) {
- return new ActivityOptions(bOptions);
+ /** @hide */
+ public static ActivityOptions fromBundle(Bundle bOptions) {
+ return bOptions != null ? new ActivityOptions(bOptions) : null;
}
/** @hide */
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 64f0301fab22..3b843a9c622a 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -868,6 +868,7 @@ public final class ActivityThread extends ClientTransactionHandler
String processName;
@UnsupportedAppUsage
ApplicationInfo appInfo;
+ String sdkSandboxClientAppPackage;
@UnsupportedAppUsage
List<ProviderInfo> providers;
ComponentName instrumentationName;
@@ -1113,9 +1114,9 @@ public final class ActivityThread extends ClientTransactionHandler
@Override
public final void bindApplication(String processName, ApplicationInfo appInfo,
- ProviderInfoList providerList, ComponentName instrumentationName,
- ProfilerInfo profilerInfo, Bundle instrumentationArgs,
- IInstrumentationWatcher instrumentationWatcher,
+ String sdkSandboxClientAppPackage, ProviderInfoList providerList,
+ ComponentName instrumentationName, ProfilerInfo profilerInfo,
+ Bundle instrumentationArgs, IInstrumentationWatcher instrumentationWatcher,
IUiAutomationConnection instrumentationUiConnection, int debugMode,
boolean enableBinderTracking, boolean trackAllocation,
boolean isRestrictedBackupMode, boolean persistent, Configuration config,
@@ -1155,6 +1156,7 @@ public final class ActivityThread extends ClientTransactionHandler
AppBindData data = new AppBindData();
data.processName = processName;
data.appInfo = appInfo;
+ data.sdkSandboxClientAppPackage = sdkSandboxClientAppPackage;
data.providers = providerList.getList();
data.instrumentationName = instrumentationName;
data.instrumentationArgs = instrumentationArgs;
@@ -3587,7 +3589,7 @@ public final class ActivityThread extends ClientTransactionHandler
}
try {
- Application app = r.packageInfo.makeApplication(false, mInstrumentation);
+ Application app = r.packageInfo.makeApplicationInner(false, mInstrumentation);
if (localLOGV) Slog.v(TAG, "Performing launch of " + r);
if (localLOGV) Slog.v(
@@ -4286,7 +4288,7 @@ public final class ActivityThread extends ClientTransactionHandler
BroadcastReceiver receiver;
ContextImpl context;
try {
- app = packageInfo.makeApplication(false, mInstrumentation);
+ app = packageInfo.makeApplicationInner(false, mInstrumentation);
context = (ContextImpl) app.getBaseContext();
if (data.info.splitName != null) {
context = (ContextImpl) context.createContextForSplit(data.info.splitName);
@@ -4475,7 +4477,7 @@ public final class ActivityThread extends ClientTransactionHandler
try {
if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name);
- Application app = packageInfo.makeApplication(false, mInstrumentation);
+ Application app = packageInfo.makeApplicationInner(false, mInstrumentation);
final java.lang.ClassLoader cl;
if (data.info.splitName != null) {
@@ -5883,19 +5885,17 @@ public final class ActivityThread extends ClientTransactionHandler
final boolean movedToDifferentDisplay = isDifferentDisplay(activity.getDisplayId(),
displayId);
final Configuration currentConfig = activity.mCurrentConfig;
- final int diff = (currentConfig == null) ? 0xffffffff
- : currentConfig.diffPublicOnly(newConfig);
+ final int diff = currentConfig.diffPublicOnly(newConfig);
final boolean hasPublicConfigChange = diff != 0;
+ final ActivityClientRecord r = getActivityClient(activityToken);
// TODO(b/173090263): Use diff instead after the improvement of AssetManager and
// ResourcesImpl constructions.
final boolean shouldUpdateResources = hasPublicConfigChange
|| shouldUpdateResources(activityToken, currentConfig, newConfig, amOverrideConfig,
movedToDifferentDisplay, hasPublicConfigChange);
- final boolean shouldReportChange = hasPublicConfigChange
- // If this activity doesn't handle any of the config changes, then don't bother
- // calling onConfigurationChanged. Otherwise, report to the activity for the
- // changes.
- && (~activity.mActivityInfo.getRealConfigChanged() & diff) == 0;
+ final boolean shouldReportChange = shouldReportChange(diff, currentConfig, newConfig,
+ r != null ? r.mSizeConfigurations : null,
+ activity.mActivityInfo.getRealConfigChanged());
// Nothing significant, don't proceed with updating and reporting.
if (!shouldUpdateResources) {
return null;
@@ -5942,6 +5942,40 @@ public final class ActivityThread extends ClientTransactionHandler
return configToReport;
}
+ /**
+ * Returns {@code true} if {@link Activity#onConfigurationChanged(Configuration)} should be
+ * dispatched.
+ *
+ * @param publicDiff Usually computed by {@link Configuration#diffPublicOnly(Configuration)}.
+ * This parameter is to prevent we compute it again.
+ * @param currentConfig The current configuration cached in {@link Activity#mCurrentConfig}.
+ * It is {@code null} before the first config update from the server side.
+ * @param newConfig The updated {@link Configuration}
+ * @param sizeBuckets The Activity's {@link SizeConfigurationBuckets} if not {@code null}
+ * @param handledConfigChanges Bit mask of configuration changes that the activity can handle
+ * @return {@code true} if the config change should be reported to the Activity
+ */
+ @VisibleForTesting
+ public static boolean shouldReportChange(int publicDiff, @Nullable Configuration currentConfig,
+ @NonNull Configuration newConfig, @Nullable SizeConfigurationBuckets sizeBuckets,
+ int handledConfigChanges) {
+ // Don't report the change if there's no public diff between current and new config.
+ if (publicDiff == 0) {
+ return false;
+ }
+ final int diffWithBucket = SizeConfigurationBuckets.filterDiff(publicDiff, currentConfig,
+ newConfig, sizeBuckets);
+ // Compare to the diff which filter the change without crossing size buckets with
+ // {@code handledConfigChanges}. The small changes should not block Activity to receive
+ // its handled config updates. Also, if Activity handles all small changes, we should
+ // dispatch the updated config to it.
+ final int diff = diffWithBucket != 0 ? diffWithBucket : publicDiff;
+ // If this activity doesn't handle any of the config changes, then don't bother
+ // calling onConfigurationChanged. Otherwise, report to the activity for the
+ // changes.
+ return (~handledConfigChanges & diff) == 0;
+ }
+
public final void applyConfigurationToResources(Configuration config) {
synchronized (mResourcesManager) {
mResourcesManager.applyConfigurationToResources(config, null);
@@ -6536,6 +6570,9 @@ public final class ActivityThread extends ClientTransactionHandler
}
data.info = getPackageInfoNoCheck(data.appInfo, data.compatInfo);
+ if (data.sdkSandboxClientAppPackage != null) {
+ data.info.setSdkSandboxStorage(data.sdkSandboxClientAppPackage);
+ }
if (agent != null) {
handleAttachAgent(agent, data.info);
@@ -6695,7 +6732,7 @@ public final class ActivityThread extends ClientTransactionHandler
try {
// If the app is being launched for full backup or restore, bring it up in
// a restricted environment with the base application class.
- app = data.info.makeApplication(data.restrictedBackupMode, null);
+ app = data.info.makeApplicationInner(data.restrictedBackupMode, null);
// Propagate autofill compat state
app.setAutofillOptions(data.autofillOptions);
@@ -7565,7 +7602,7 @@ public final class ActivityThread extends ClientTransactionHandler
mInstrumentation.basicInit(this);
ContextImpl context = ContextImpl.createAppContext(
this, getSystemContext().mPackageInfo);
- mInitialApplication = context.mPackageInfo.makeApplication(true, null);
+ mInitialApplication = context.mPackageInfo.makeApplicationInner(true, null);
mInitialApplication.onCreate();
} catch (Exception e) {
throw new RuntimeException(
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 7c7c7ef382c1..4829dc085bd9 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -2367,7 +2367,7 @@ public class AppOpsManager {
null, // no permission for OP_WRITE_MEDIA_AUDIO
Manifest.permission.READ_MEDIA_VIDEO,
null, // no permission for OP_WRITE_MEDIA_VIDEO
- Manifest.permission.READ_MEDIA_IMAGE,
+ Manifest.permission.READ_MEDIA_IMAGES,
null, // no permission for OP_WRITE_MEDIA_IMAGES
null, // no permission for OP_LEGACY_STORAGE
null, // no permission for OP_ACCESS_ACCESSIBILITY
diff --git a/core/java/android/app/ApplicationExitInfo.java b/core/java/android/app/ApplicationExitInfo.java
index 60e22f4ecd12..9bdddd037e21 100644
--- a/core/java/android/app/ApplicationExitInfo.java
+++ b/core/java/android/app/ApplicationExitInfo.java
@@ -360,6 +360,53 @@ public final class ApplicationExitInfo implements Parcelable {
*/
public static final int SUBREASON_FREEZER_BINDER_TRANSACTION = 20;
+ /**
+ * The process was killed because of force-stop, it could be due to that
+ * the user clicked the "Force stop" button of the application in the Settings;
+ * this would be set only when the reason is {@link #REASON_USER_REQUESTED}.
+ *
+ * For internal use only.
+ * @hide
+ */
+ public static final int SUBREASON_FORCE_STOP = 21;
+
+ /**
+ * The process was killed because the user removed the application away from Recents;
+ * this would be set only when the reason is {@link #REASON_USER_REQUESTED}.
+ *
+ * For internal use only.
+ * @hide
+ */
+ public static final int SUBREASON_REMOVE_TASK = 22;
+
+ /**
+ * The process was killed because the user stopped the application from the task manager;
+ * this would be set only when the reason is {@link #REASON_USER_REQUESTED}.
+ *
+ * For internal use only.
+ * @hide
+ */
+ public static final int SUBREASON_STOP_APP = 23;
+
+ /**
+ * The process was killed because the user stopped the application from developer options,
+ * or via the adb shell commmand interface; this would be set only when the reason is
+ * {@link #REASON_USER_REQUESTED}.
+ *
+ * For internal use only.
+ * @hide
+ */
+ public static final int SUBREASON_KILL_BACKGROUND = 24;
+
+ /**
+ * The process was killed because of package update; this would be set only when the reason is
+ * {@link #REASON_USER_REQUESTED}.
+ *
+ * For internal use only.
+ * @hide
+ */
+ public static final int SUBREASON_PACKAGE_UPDATE = 25;
+
// If there is any OEM code which involves additional app kill reasons, it should
// be categorized in {@link #REASON_OTHER}, with subreason code starting from 1000.
@@ -520,6 +567,11 @@ public final class ApplicationExitInfo implements Parcelable {
SUBREASON_ISOLATED_NOT_NEEDED,
SUBREASON_FREEZER_BINDER_IOCTL,
SUBREASON_FREEZER_BINDER_TRANSACTION,
+ SUBREASON_FORCE_STOP,
+ SUBREASON_REMOVE_TASK,
+ SUBREASON_STOP_APP,
+ SUBREASON_KILL_BACKGROUND,
+ SUBREASON_PACKAGE_UPDATE,
})
@Retention(RetentionPolicy.SOURCE)
public @interface SubReason {}
@@ -1193,6 +1245,16 @@ public final class ApplicationExitInfo implements Parcelable {
return "FREEZER BINDER IOCTL";
case SUBREASON_FREEZER_BINDER_TRANSACTION:
return "FREEZER BINDER TRANSACTION";
+ case SUBREASON_FORCE_STOP:
+ return "FORCE STOP";
+ case SUBREASON_REMOVE_TASK:
+ return "REMOVE TASK";
+ case SUBREASON_STOP_APP:
+ return "STOP APP";
+ case SUBREASON_KILL_BACKGROUND:
+ return "KILL BACKGROUND";
+ case SUBREASON_PACKAGE_UPDATE:
+ return "PACKAGE UPDATE";
default:
return "UNKNOWN";
}
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index dca5c542af17..d641a3b469a6 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -18,9 +18,9 @@ package android.app;
import static android.app.admin.DevicePolicyResources.Drawables.Style.SOLID_COLORED;
import static android.app.admin.DevicePolicyResources.Drawables.Style.SOLID_NOT_COLORED;
-import static android.app.admin.DevicePolicyResources.Drawables.UNDEFINED;
import static android.app.admin.DevicePolicyResources.Drawables.WORK_PROFILE_ICON;
import static android.app.admin.DevicePolicyResources.Drawables.WORK_PROFILE_ICON_BADGE;
+import static android.app.admin.DevicePolicyResources.UNDEFINED;
import static android.content.pm.Checksum.TYPE_PARTIAL_MERKLE_ROOT_1M_SHA256;
import static android.content.pm.Checksum.TYPE_PARTIAL_MERKLE_ROOT_1M_SHA512;
import static android.content.pm.Checksum.TYPE_WHOLE_MD5;
@@ -1886,7 +1886,7 @@ public class ApplicationPackageManager extends PackageManager {
return icon;
}
- final Drawable badgeForeground = getDevicePolicyManager().getDrawable(
+ final Drawable badgeForeground = getDevicePolicyManager().getResources().getDrawable(
getUpdatableUserIconBadgeId(user),
SOLID_COLORED,
() -> getDefaultUserIconBadge(user));
@@ -1938,11 +1938,12 @@ public class ApplicationPackageManager extends PackageManager {
return null;
}
- final Drawable badgeForeground = getDevicePolicyManager().getDrawableForDensity(
- getUpdatableUserBadgeId(user),
- SOLID_COLORED,
- density,
- () -> getDefaultUserBadgeForDensity(user, density));
+ final Drawable badgeForeground = getDevicePolicyManager().getResources()
+ .getDrawableForDensity(
+ getUpdatableUserBadgeId(user),
+ SOLID_COLORED,
+ density,
+ () -> getDefaultUserBadgeForDensity(user, density));
badgeForeground.setTint(getUserBadgeColor(user, false));
Drawable badge = new LayerDrawable(new Drawable[] {badgeColor, badgeForeground });
@@ -1968,7 +1969,7 @@ public class ApplicationPackageManager extends PackageManager {
return null;
}
- final Drawable badge = getDevicePolicyManager().getDrawableForDensity(
+ final Drawable badge = getDevicePolicyManager().getResources().getDrawableForDensity(
getUpdatableUserBadgeId(user),
SOLID_NOT_COLORED,
density,
@@ -3832,4 +3833,13 @@ public class ApplicationPackageManager extends PackageManager {
throw re.rethrowAsRuntimeException();
}
}
+
+ @Override
+ public void makeUidVisible(int recipientUid, int visibleUid) {
+ try {
+ mPM.makeUidVisible(recipientUid, visibleUid);
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
}
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index a3dd705a7e29..ac46066997ff 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -77,6 +77,7 @@ import android.os.Trace;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.storage.StorageManager;
+import android.permission.PermissionControllerManager;
import android.permission.PermissionManager;
import android.system.ErrnoException;
import android.system.Os;
@@ -216,6 +217,12 @@ class ContextImpl extends Context {
@UnsupportedAppUsage
private @Nullable ClassLoader mClassLoader;
+ /**
+ * The {@link com.android.server.wm.WindowToken} representing this instance if it is
+ * {@link #CONTEXT_TYPE_WINDOW_CONTEXT} or {@link #CONTEXT_TYPE_SYSTEM_OR_SYSTEM_UI}.
+ * If the type is {@link #CONTEXT_TYPE_ACTIVITY}, then represents the
+ * {@link android.window.WindowContainerToken} of the activity.
+ */
private final @Nullable IBinder mToken;
private final @NonNull UserHandle mUser;
@@ -1998,7 +2005,7 @@ class ContextImpl extends Context {
private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags,
String instanceName, Handler handler, Executor executor, UserHandle user) {
// Keep this in sync with DevicePolicyManager.bindDeviceAdminServiceAsUser and
- // ActivityManagerLocal.bindSupplementalProcessService
+ // ActivityManagerLocal.bindSdkSandboxService
IServiceConnection sd;
if (conn == null) {
throw new IllegalArgumentException("connection is null");
@@ -2180,8 +2187,9 @@ class ContextImpl extends Context {
}
@Override
- public void revokeOwnPermissionsOnKill(@NonNull Collection<String> permissions) {
- getSystemService(PermissionManager.class).revokeOwnPermissionsOnKill(permissions);
+ public void revokeSelfPermissionsOnKill(@NonNull Collection<String> permissions) {
+ getSystemService(PermissionControllerManager.class).revokeSelfPermissionsOnKill(
+ getPackageName(), new ArrayList<String>(permissions));
}
@Override
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index 82ff42b41799..a763b1464b6d 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -465,7 +465,8 @@ public class Dialog implements DialogInterface, Window.Callback,
onBackPressed();
}
};
- getOnBackInvokedDispatcher().registerSystemOnBackInvokedCallback(mDefaultBackCallback);
+ getOnBackInvokedDispatcher().registerOnBackInvokedCallback(
+ OnBackInvokedDispatcher.PRIORITY_DEFAULT, mDefaultBackCallback);
mDefaultBackCallback = null;
}
}
diff --git a/core/java/android/app/GameManager.java b/core/java/android/app/GameManager.java
index 6f49c9e647a4..a138fa1f6fd5 100644
--- a/core/java/android/app/GameManager.java
+++ b/core/java/android/app/GameManager.java
@@ -191,7 +191,7 @@ public final class GameManager {
*/
@TestApi
@RequiresPermission(Manifest.permission.MANAGE_GAME_MODE)
- public @GameMode boolean isAngleEnabled(@NonNull String packageName) {
+ public boolean isAngleEnabled(@NonNull String packageName) {
try {
return mService.isAngleEnabled(packageName, mContext.getUserId());
} catch (RemoteException e) {
diff --git a/core/java/android/app/IActivityClientController.aidl b/core/java/android/app/IActivityClientController.aidl
index caf1c41b7622..130716122ed2 100644
--- a/core/java/android/app/IActivityClientController.aidl
+++ b/core/java/android/app/IActivityClientController.aidl
@@ -88,7 +88,7 @@ interface IActivityClientController {
boolean enterPictureInPictureMode(in IBinder token, in PictureInPictureParams params);
void setPictureInPictureParams(in IBinder token, in PictureInPictureParams params);
- oneway void setPreferDockBigOverlays(in IBinder token, in boolean preferDockBigOverlays);
+ oneway void setShouldDockBigOverlays(in IBinder token, in boolean shouldDockBigOverlays);
void toggleFreeformWindowingMode(in IBinder token);
oneway void startLockTaskModeByToken(in IBinder token);
diff --git a/core/java/android/app/IApplicationThread.aidl b/core/java/android/app/IApplicationThread.aidl
index 77657d58cc4c..f4fbcceeab8f 100644
--- a/core/java/android/app/IApplicationThread.aidl
+++ b/core/java/android/app/IApplicationThread.aidl
@@ -72,6 +72,7 @@ oneway interface IApplicationThread {
@UnsupportedAppUsage
void scheduleStopService(IBinder token);
void bindApplication(in String packageName, in ApplicationInfo info,
+ in String sdkSandboxClientAppPackage,
in ProviderInfoList providerList, in ComponentName testName,
in ProfilerInfo profilerInfo, in Bundle testArguments,
IInstrumentationWatcher testWatcher, IUiAutomationConnection uiAutomationConnection,
diff --git a/core/java/android/app/ILocaleManager.aidl b/core/java/android/app/ILocaleManager.aidl
index 348cb2d30739..3002c8bb9c3e 100644
--- a/core/java/android/app/ILocaleManager.aidl
+++ b/core/java/android/app/ILocaleManager.aidl
@@ -40,4 +40,9 @@ import android.os.LocaleList;
*/
LocaleList getApplicationLocales(String packageName, int userId);
+ /**
+ * Returns the current system locales.
+ */
+ LocaleList getSystemLocales();
+
} \ No newline at end of file
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index a82ecce2dc04..4fbe232556ed 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -116,7 +116,7 @@ interface INotificationManager
ParceledListSlice getNotificationChannelGroups(String pkg);
boolean onlyHasDefaultChannel(String pkg, int uid);
boolean areChannelsBypassingDnd();
- ParceledListSlice getNotificationChannelsBypassingDnd(String pkg, int userId);
+ ParceledListSlice getNotificationChannelsBypassingDnd(String pkg, int uid);
boolean isPackagePaused(String pkg);
void deleteNotificationHistoryItem(String pkg, int uid, long postedTime);
boolean isPermissionFixed(String pkg, int userId);
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index e0c69df0aa18..ac979c495cf3 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -393,6 +393,15 @@ public class Instrumentation {
}
/**
+ * Resets the {@link #setInTouchMode touch mode} to the device default.
+ */
+ public void resetInTouchMode() {
+ final boolean defaultInTouchMode = getContext().getResources().getBoolean(
+ com.android.internal.R.bool.config_defaultInTouchMode);
+ setInTouchMode(defaultInTouchMode);
+ }
+
+ /**
* Schedule a callback for when the application's main thread goes idle
* (has no more events to process).
*
diff --git a/core/java/android/app/KeyguardManager.java b/core/java/android/app/KeyguardManager.java
index cedf483eb076..e9c29b8aa0a5 100644
--- a/core/java/android/app/KeyguardManager.java
+++ b/core/java/android/app/KeyguardManager.java
@@ -1103,9 +1103,12 @@ public class KeyguardManager {
}
/**
- * Registers a listener to execute when the keyguard visibility changes.
+ * Registers a listener to execute when the keyguard locked state changes.
*
- * @param listener The listener to add to receive keyguard visibility changes.
+ * @param listener The listener to add to receive keyguard locked state changes.
+ *
+ * @see #isKeyguardLocked()
+ * @see #removeKeyguardLockedStateListener(KeyguardLockedStateListener)
*/
@RequiresPermission(Manifest.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE)
public void addKeyguardLockedStateListener(@NonNull @CallbackExecutor Executor executor,
@@ -1124,7 +1127,12 @@ public class KeyguardManager {
}
/**
- * Unregisters a listener that executes when the keyguard visibility changes.
+ * Unregisters a listener that executes when the keyguard locked state changes.
+ *
+ * @param listener The listener to remove.
+ *
+ * @see #isKeyguardLocked()
+ * @see #addKeyguardLockedStateListener(Executor, KeyguardLockedStateListener)
*/
@RequiresPermission(Manifest.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE)
public void removeKeyguardLockedStateListener(@NonNull KeyguardLockedStateListener listener) {
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index cf259e577a5a..deefea83c13d 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -37,6 +37,7 @@ import android.content.res.CompatibilityInfo;
import android.content.res.Resources;
import android.os.Build;
import android.os.Bundle;
+import android.os.Environment;
import android.os.FileUtils;
import android.os.GraphicsEnvironment;
import android.os.Handler;
@@ -411,6 +412,26 @@ public final class LoadedApk {
}
}
+ /** @hide */
+ void setSdkSandboxStorage(String sdkSandboxClientAppPackage) {
+ int userId = UserHandle.myUserId();
+ mDeviceProtectedDataDirFile = Environment
+ .getDataMiscDeSharedSdkSandboxDirectory(userId, sdkSandboxClientAppPackage)
+ .getAbsoluteFile();
+ mCredentialProtectedDataDirFile = Environment
+ .getDataMiscCeSharedSdkSandboxDirectory(userId, sdkSandboxClientAppPackage)
+ .getAbsoluteFile();
+
+ if ((mApplicationInfo.privateFlags
+ & ApplicationInfo.PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE) != 0
+ && PackageManager.APPLY_DEFAULT_TO_DEVICE_PROTECTED_STORAGE) {
+ mDataDirFile = mDeviceProtectedDataDirFile;
+ } else {
+ mDataDirFile = mCredentialProtectedDataDirFile;
+ }
+ mDataDir = mDataDirFile.getAbsolutePath();
+ }
+
public static void makePaths(ActivityThread activityThread,
ApplicationInfo aInfo,
List<String> outZipPaths) {
@@ -1352,9 +1373,28 @@ public final class LoadedApk {
return mResources;
}
+ /**
+ * This is for 3p apps accessing this hidden API directly... in which case, we don't return
+ * the cached Application instance.
+ */
@UnsupportedAppUsage
public Application makeApplication(boolean forceDefaultAppClass,
Instrumentation instrumentation) {
+ return makeApplicationInner(forceDefaultAppClass, instrumentation,
+ /* allowDuplicateInstances= */ true);
+ }
+
+ /**
+ * This is for all the (internal) callers, for which we do return the cached instance.
+ */
+ public Application makeApplicationInner(boolean forceDefaultAppClass,
+ Instrumentation instrumentation) {
+ return makeApplicationInner(forceDefaultAppClass, instrumentation,
+ /* allowDuplicateInstances= */ false);
+ }
+
+ private Application makeApplicationInner(boolean forceDefaultAppClass,
+ Instrumentation instrumentation, boolean allowDuplicateInstances) {
if (mApplication != null) {
return mApplication;
}
@@ -1366,11 +1406,15 @@ public final class LoadedApk {
// Looks like this is always happening for the system server, because
// the LoadedApk created in systemMain() -> attach() isn't cached properly?
if (!"android".equals(mPackageName)) {
- Slog.wtf(TAG, "App instance already created for package=" + mPackageName
+ Slog.wtfStack(TAG, "App instance already created for package=" + mPackageName
+ " instance=" + cached);
}
- mApplication = cached;
- return cached;
+ if (!allowDuplicateInstances) {
+ mApplication = cached;
+ return cached;
+ }
+ // Some apps intentionally call makeApplication() to create a new Application
+ // instance... Sigh...
}
}
@@ -1421,8 +1465,10 @@ public final class LoadedApk {
}
mActivityThread.mAllApplications.add(app);
mApplication = app;
- synchronized (sApplications) {
- sApplications.put(mPackageName, app);
+ if (!allowDuplicateInstances) {
+ synchronized (sApplications) {
+ sApplications.put(mPackageName, app);
+ }
}
if (instrumentation != null) {
diff --git a/core/java/android/app/LocaleManager.java b/core/java/android/app/LocaleManager.java
index 522dc845f57c..efe9e35d4c64 100644
--- a/core/java/android/app/LocaleManager.java
+++ b/core/java/android/app/LocaleManager.java
@@ -18,7 +18,6 @@ package android.app;
import android.Manifest;
import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.SystemService;
@@ -127,31 +126,36 @@ public class LocaleManager {
}
/**
- * Sets the current system locales to the provided value.
+ * Returns the current system locales, ignoring app-specific overrides.
*
- * @hide
+ * <p><b>Note:</b> Apps should generally access the user's locale preferences as indicated in
+ * their in-process {@link LocaleList}s. However, in case an app-specific locale is set, this
+ * method helps cater to rare use-cases which might require specifically knowing the system
+ * locale.
+ *
+ * <p><b>Note:</b> This API is not user-aware. It returns the system locales for the foreground
+ * user.
*/
- @TestApi
- public void setSystemLocales(@NonNull LocaleList locales) {
+ @NonNull
+ public LocaleList getSystemLocales() {
try {
- Configuration conf = ActivityManager.getService().getConfiguration();
- conf.setLocales(locales);
- ActivityManager.getService().updatePersistentConfiguration(conf);
+ return mService.getSystemLocales();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
- * Returns the current system locales for the device.
+ * Sets the current system locales to the provided value.
*
* @hide
*/
@TestApi
- @Nullable
- public LocaleList getSystemLocales() {
+ public void setSystemLocales(@NonNull LocaleList locales) {
try {
- return ActivityManager.getService().getConfiguration().getLocales();
+ Configuration conf = ActivityManager.getService().getConfiguration();
+ conf.setLocales(locales);
+ ActivityManager.getService().updatePersistentConfiguration(conf);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 7e0cea8921a4..6e1d1cd2e4c9 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -19,8 +19,8 @@ package android.app;
import static android.annotation.Dimension.DP;
import static android.app.admin.DevicePolicyResources.Drawables.Source.NOTIFICATION;
import static android.app.admin.DevicePolicyResources.Drawables.Style.SOLID_COLORED;
-import static android.app.admin.DevicePolicyResources.Drawables.UNDEFINED;
import static android.app.admin.DevicePolicyResources.Drawables.WORK_PROFILE_ICON;
+import static android.app.admin.DevicePolicyResources.UNDEFINED;
import static android.graphics.drawable.Icon.TYPE_URI;
import static android.graphics.drawable.Icon.TYPE_URI_ADAPTIVE_BITMAP;
@@ -5079,7 +5079,7 @@ public class Notification implements Parcelable
// Note: This assumes that the current user can read the profile badge of the
// originating user.
DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class);
- return dpm.getDrawable(
+ return dpm.getResources().getDrawable(
getUpdatableProfileBadgeId(), SOLID_COLORED, NOTIFICATION,
this::getDefaultProfileBadgeDrawable);
}
diff --git a/core/java/android/app/PictureInPictureParams.java b/core/java/android/app/PictureInPictureParams.java
index 2d2788ca91a3..3f1844e2ba8a 100644
--- a/core/java/android/app/PictureInPictureParams.java
+++ b/core/java/android/app/PictureInPictureParams.java
@@ -280,7 +280,7 @@ public final class PictureInPictureParams implements Parcelable {
private Rational mAspectRatio;
/**
- * The expected aspect ratio of the vertically expanded picture-in-picture window.
+ * The expected aspect ratio of the expanded picture-in-picture window.
*/
@Nullable
private Rational mExpandedAspectRatio;
@@ -441,15 +441,21 @@ public final class PictureInPictureParams implements Parcelable {
* @hide
*/
@TestApi
- public float getAspectRatio() {
+ public float getAspectRatioFloat() {
if (mAspectRatio != null) {
return mAspectRatio.floatValue();
}
return 0f;
}
- /** @hide */
- public Rational getAspectRatioRational() {
+ /**
+ * Returns the expected aspect ratio of the picture-in-picture window.
+ *
+ * @return aspect ratio as the desired width / height or {@code null} if not set.
+ * @see PictureInPictureParams.Builder#setAspectRatio(Rational)
+ */
+ @Nullable
+ public Rational getAspectRatio() {
return mAspectRatio;
}
@@ -466,7 +472,7 @@ public final class PictureInPictureParams implements Parcelable {
* @hide
*/
@TestApi
- public float getExpandedAspectRatio() {
+ public float getExpandedAspectRatioFloat() {
if (mExpandedAspectRatio != null) {
return mExpandedAspectRatio.floatValue();
}
@@ -474,6 +480,17 @@ public final class PictureInPictureParams implements Parcelable {
}
/**
+ * Returns the desired aspect ratio of the expanded picture-in-picture window.
+ *
+ * @return aspect ratio as the desired width / height or {@code null} if not set.
+ * @see PictureInPictureParams.Builder#setExpandedAspectRatio(Rational)
+ */
+ @Nullable
+ public Rational getExpandedAspectRatio() {
+ return mExpandedAspectRatio;
+ }
+
+ /**
* @return whether the expanded aspect ratio is set
* @hide
*/
@@ -482,11 +499,17 @@ public final class PictureInPictureParams implements Parcelable {
}
/**
- * @return the set of user actions.
- * @hide
+ * Returns the list of user actions that are associated with the activity when in
+ * picture-in-picture mode.
+ *
+ * @return the user actions in a new list.
+ * @see PictureInPictureParams.Builder#setActions(List)
*/
- @TestApi
+ @NonNull
public List<RemoteAction> getActions() {
+ if (mUserActions == null) {
+ return new ArrayList<>();
+ }
return mUserActions;
}
@@ -499,10 +522,11 @@ public final class PictureInPictureParams implements Parcelable {
}
/**
- * @return the close action.
- * @hide
+ * Returns the action that is to replace the system close action.
+ *
+ * @return the close action or {@code null} if not set.
+ * @see PictureInPictureParams.Builder#setCloseAction(RemoteAction)
*/
- @TestApi
@Nullable
public RemoteAction getCloseAction() {
return mCloseAction;
@@ -528,10 +552,12 @@ public final class PictureInPictureParams implements Parcelable {
}
/**
- * @return the source rect hint
- * @hide
+ * Returns the source rect hint.
+ *
+ * @return the source rect hint also known as launch bounds or {@code null} if not set.
+ * @see PictureInPictureParams.Builder#setSourceRectHint(Rect)
*/
- @TestApi
+ @Nullable
public Rect getSourceRectHint() {
return mSourceRectHint;
}
@@ -545,18 +571,23 @@ public final class PictureInPictureParams implements Parcelable {
}
/**
- * @return whether auto pip is enabled.
- * @hide
+ * Returns whether auto enter picture-in-picture is enabled.
+ *
+ * @return {@code true} if the system will automatically put the activity in
+ * picture-in-picture mode.
+ * @see PictureInPictureParams.Builder#setAutoEnterEnabled(boolean)
*/
public boolean isAutoEnterEnabled() {
return mAutoEnterEnabled == null ? false : mAutoEnterEnabled;
}
/**
- * @return whether seamless resize is enabled.
- * @hide
+ * Returns whether seamless resize is enabled.
+ *
+ * @return true if the system can seamlessly resize the window while activity is in
+ * picture-in-picture mode.
+ * @see PictureInPictureParams.Builder#setSeamlessResizeEnabled(boolean)
*/
- @TestApi
public boolean isSeamlessResizeEnabled() {
return mSeamlessResizeEnabled == null ? true : mSeamlessResizeEnabled;
}
@@ -570,10 +601,11 @@ public final class PictureInPictureParams implements Parcelable {
}
/**
- * @return title of the pip.
- * @hide
+ * Returns the title of the picture-in-picture window that may be displayed to the user.
+ *
+ * @return title of the picture-in-picture window.
+ * @see PictureInPictureParams.Builder#setTitle(CharSequence)
*/
- @TestApi
@Nullable
public CharSequence getTitle() {
return mTitle;
@@ -588,10 +620,11 @@ public final class PictureInPictureParams implements Parcelable {
}
/**
- * @return subtitle of the pip.
- * @hide
+ * Returns the subtitle of the picture-in-picture window that may be displayed to the user.
+ *
+ * @return subtitle of the picture-in-picture window.
+ * @see PictureInPictureParams.Builder#setSubtitle(CharSequence)
*/
- @TestApi
@Nullable
public CharSequence getSubtitle() {
return mSubtitle;
@@ -716,7 +749,7 @@ public final class PictureInPictureParams implements Parcelable {
@Override
public String toString() {
return "PictureInPictureParams("
- + " aspectRatio=" + getAspectRatioRational()
+ + " aspectRatio=" + getAspectRatio()
+ " expandedAspectRatio=" + mExpandedAspectRatio
+ " sourceRectHint=" + getSourceRectHint()
+ " hasSetActions=" + hasSetActions()
diff --git a/core/java/android/app/PropertyInvalidatedCache.java b/core/java/android/app/PropertyInvalidatedCache.java
index 2f202d95e0e3..df7bf7b94700 100644
--- a/core/java/android/app/PropertyInvalidatedCache.java
+++ b/core/java/android/app/PropertyInvalidatedCache.java
@@ -18,7 +18,6 @@ package android.app;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.os.Handler;
import android.os.Looper;
@@ -137,6 +136,26 @@ import java.util.concurrent.atomic.AtomicLong;
* With this cache, clients perform a binder call to birthdayd if asking for a user's birthday
* for the first time; on subsequent queries, we return the already-known Birthday object.
*
+ * The second parameter to the IpcDataCache constructor is a string that identifies the "module"
+ * that owns the cache. There are some well-known modules (such as {@code MODULE_SYSTEM} but any
+ * string is permitted. The third parameters is the name of the API being cached; this, too, can
+ * any value. The fourth is the name of the cache. The cache is usually named after th API.
+ * Some things you must know about the three strings:
+ * <list>
+ * <ul> The system property that controls the cache is named {@code cache_key.<module>.<api>}.
+ * Usually, the SELinux rules permit a process to write a system property (and therefore
+ * invalidate a cache) based on the wildcard {@code cache_key.<module>.*}. This means that
+ * although the cache can be constructed with any module string, whatever string is chosen must be
+ * consistent with the SELinux configuration.
+ * <ul> The API name can be any string of alphanumeric characters. All caches with the same API
+ * are invalidated at the same time. If a server supports several caches and all are invalidated
+ * in common, then it is most efficient to assign the same API string to every cache.
+ * <ul> The cache name can be any string. In debug output, the name is used to distiguish between
+ * caches with the same API name. The cache name is also used when disabling caches in the
+ * current process. So, invalidation is based on the module+api but disabling (which is generally
+ * a once-per-process operation) is based on the cache name.
+ * </list>
+ *
* User birthdays do occasionally change, so we have to modify the server to invalidate this
* cache when necessary. That invalidation code looks like this:
*
@@ -192,25 +211,23 @@ import java.util.concurrent.atomic.AtomicLong;
* <pre>
* public class ActivityThread {
* ...
- * private static final int BDAY_CACHE_MAX = 8; // Maximum birthdays to cache
- * private static final String BDAY_CACHE_KEY = "cache_key.birthdayd";
- * private final PropertyInvalidatedCache&lt;Integer, Birthday%&gt; mBirthdayCache = new
- * PropertyInvalidatedCache&lt;Integer, Birthday%&gt;(BDAY_CACHE_MAX, BDAY_CACHE_KEY) {
- * {@literal @}Override
- * protected Birthday recompute(Integer userId) {
- * return GetService("birthdayd").getUserBirthday(userId);
- * }
- * {@literal @}Override
- * protected boolean bypass(Integer userId) {
- * return userId == NEXT_BIRTHDAY;
- * }
- * };
+ * private final IpcDataCache.QueryHandler&lt;Integer, Birthday&gt; mBirthdayQuery =
+ * new IpcDataCache.QueryHandler&lt;Integer, Birthday&gt;() {
+ * {@literal @}Override
+ * public Birthday apply(Integer) {
+ * return GetService("birthdayd").getUserBirthday(userId);
+ * }
+ * {@literal @}Override
+ * public boolean shouldBypassQuery(Integer userId) {
+ * return userId == NEXT_BIRTHDAY;
+ * }
+ * };
* ...
* }
* </pre>
*
- * If the {@code bypass()} method returns true then the cache is not used for that
- * particular query. The {@code bypass()} method is not abstract and the default
+ * If the {@code shouldBypassQuery()} method returns true then the cache is not used for that
+ * particular query. The {@code shouldBypassQuery()} method is not abstract and the default
* implementation returns false.
*
* For security, there is a allowlist of processes that are allowed to invalidate a cache.
@@ -231,14 +248,12 @@ import java.util.concurrent.atomic.AtomicLong;
* @param <Result> The class holding cache entries; use a boxed primitive if possible
* @hide
*/
-@SystemApi(client=SystemApi.Client.MODULE_LIBRARIES)
@TestApi
public class PropertyInvalidatedCache<Query, Result> {
/**
* This is a configuration class that customizes a cache instance.
* @hide
*/
- @SystemApi(client=SystemApi.Client.MODULE_LIBRARIES)
@TestApi
public static abstract class QueryHandler<Q,R> {
/**
@@ -285,7 +300,6 @@ public class PropertyInvalidatedCache<Query, Result> {
* The module used for bluetooth caches.
* @hide
*/
- @SystemApi(client=SystemApi.Client.MODULE_LIBRARIES)
@TestApi
public static final String MODULE_BLUETOOTH = "bluetooth";
@@ -533,7 +547,6 @@ public class PropertyInvalidatedCache<Query, Result> {
* @param computer The code to compute values that are not in the cache.
* @hide
*/
- @SystemApi(client=SystemApi.Client.MODULE_LIBRARIES)
@TestApi
public PropertyInvalidatedCache(int maxEntries, @NonNull String module, @NonNull String api,
@NonNull String cacheName, @NonNull QueryHandler<Query, Result> computer) {
@@ -792,7 +805,7 @@ public class PropertyInvalidatedCache<Query, Result> {
* TODO(216112648) Remove this in favor of disableForCurrentProcess().
* @hide
*/
- public final void disableLocal() {
+ public void disableLocal() {
disableForCurrentProcess();
}
@@ -802,12 +815,17 @@ public class PropertyInvalidatedCache<Query, Result> {
* property.
* @hide
*/
- @SystemApi(client=SystemApi.Client.MODULE_LIBRARIES)
@TestApi
- public final void disableForCurrentProcess() {
+ public void disableForCurrentProcess() {
disableLocal(mCacheName);
}
+ /** @hide */
+ @TestApi
+ public static void disableForCurrentProcess(@NonNull String cacheName) {
+ disableLocal(cacheName);
+ }
+
/**
* Return whether a cache instance is disabled.
* @hide
@@ -821,9 +839,8 @@ public class PropertyInvalidatedCache<Query, Result> {
* Get a value from the cache or recompute it.
* @hide
*/
- @SystemApi(client=SystemApi.Client.MODULE_LIBRARIES)
@TestApi
- public final @Nullable Result query(@NonNull Query query) {
+ public @Nullable Result query(@NonNull Query query) {
// Let access to mDisabled race: it's atomic anyway.
long currentNonce = (!isDisabled()) ? getCurrentNonce() : NONCE_DISABLED;
if (bypass(query)) {
@@ -964,9 +981,8 @@ public class PropertyInvalidatedCache<Query, Result> {
* PropertyInvalidatedCache is keyed on a particular property value.
* @hide
*/
- @SystemApi(client=SystemApi.Client.MODULE_LIBRARIES)
@TestApi
- public final void invalidateCache() {
+ public void invalidateCache() {
invalidateCache(mPropertyName);
}
@@ -974,7 +990,6 @@ public class PropertyInvalidatedCache<Query, Result> {
* Invalidate caches in all processes that are keyed for the module and api.
* @hide
*/
- @SystemApi(client=SystemApi.Client.MODULE_LIBRARIES)
@TestApi
public static void invalidateCache(@NonNull String module, @NonNull String api) {
invalidateCache(createPropertyName(module, api));
diff --git a/core/java/android/app/StatusBarManager.java b/core/java/android/app/StatusBarManager.java
index c6e36a36701b..ae0fc09e35a6 100644
--- a/core/java/android/app/StatusBarManager.java
+++ b/core/java/android/app/StatusBarManager.java
@@ -24,6 +24,9 @@ import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.annotation.TestApi;
+import android.app.compat.CompatChanges;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledSince;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
import android.content.Context;
@@ -39,6 +42,7 @@ import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.UserHandle;
import android.util.Pair;
import android.util.Slog;
import android.view.View;
@@ -520,6 +524,27 @@ public class StatusBarManager {
private final Map<NearbyMediaDevicesProvider, NearbyMediaDevicesProviderWrapper>
nearbyMediaDevicesProviderMap = new HashMap<>();
+ /**
+ * Media controls based on {@link android.app.Notification.MediaStyle} notifications will have
+ * actions based on the media session's {@link android.media.session.PlaybackState}, rather than
+ * the notification's actions.
+ *
+ * These actions will be:
+ * - Play/Pause (depending on whether the current state is a playing state)
+ * - Previous (if declared), or a custom action if the slot is not reserved with
+ * {@code SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_PREV}
+ * - Next (if declared), or a custom action if the slot is not reserved with
+ * {@code SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_NEXT}
+ * - Custom action
+ * - Custom action
+ *
+ * @see androidx.media.utils.MediaConstants#SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_PREV
+ * @see androidx.media.utils.MediaConstants#SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_NEXT
+ */
+ @ChangeId
+ @EnabledSince(targetSdkVersion = Build.VERSION_CODES.TIRAMISU)
+ private static final long MEDIA_CONTROL_SESSION_ACTIONS = 203800354L;
+
@UnsupportedAppUsage
private Context mContext;
private IStatusBarService mService;
@@ -844,6 +869,24 @@ public class StatusBarManager {
}
/**
+ * Sets an active {@link android.service.quicksettings.TileService} to listening state
+ *
+ * The {@code componentName}'s package must match the calling package.
+ *
+ * @param componentName the tile to set into listening state
+ * @see android.service.quicksettings.TileService#requestListeningState
+ * @hide
+ */
+ public void requestTileServiceListeningState(@NonNull ComponentName componentName) {
+ Objects.requireNonNull(componentName);
+ try {
+ getService().requestTileServiceListeningState(componentName, mContext.getUserId());
+ } catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Request to the user to add a {@link android.service.quicksettings.TileService}
* to the set of current QS tiles.
* <p>
@@ -1109,6 +1152,21 @@ public class StatusBarManager {
}
}
+ /**
+ * Checks whether the given package should use session-based actions for its media controls.
+ *
+ * @param packageName App posting media controls
+ * @param user Current user handle
+ * @return true if the app supports session actions
+ *
+ * @hide
+ */
+ @RequiresPermission(allOf = {android.Manifest.permission.READ_COMPAT_CHANGE_CONFIG,
+ android.Manifest.permission.LOG_COMPAT_CHANGE})
+ public static boolean useMediaSessionActionsForApp(String packageName, UserHandle user) {
+ return CompatChanges.isChangeEnabled(MEDIA_CONTROL_SESSION_ACTIONS, packageName, user);
+ }
+
/** @hide */
public static String windowStateToString(int state) {
if (state == WINDOW_STATE_HIDING) return "WINDOW_STATE_HIDING";
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 58db93c123bb..6615374f71ec 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -138,8 +138,6 @@ import android.media.tv.tunerresourcemanager.TunerResourceManager;
import android.nearby.NearbyFrameworkInitializer;
import android.net.ConnectivityFrameworkInitializer;
import android.net.ConnectivityFrameworkInitializerTiramisu;
-import android.net.EthernetManager;
-import android.net.IEthernetManager;
import android.net.INetworkPolicyManager;
import android.net.IPacProxyManager;
import android.net.IVpnManager;
@@ -156,6 +154,7 @@ import android.net.vcn.VcnManager;
import android.net.wifi.WifiFrameworkInitializer;
import android.net.wifi.nl80211.WifiNl80211Manager;
import android.nfc.NfcManager;
+import android.ondevicepersonalization.OnDevicePersonalizationFrameworkInitializer;
import android.os.BatteryManager;
import android.os.BatteryStats;
import android.os.BatteryStatsManager;
@@ -789,15 +788,6 @@ public final class SystemServiceRegistry {
return new LowpanManager(ctx.getOuterContext(), service);
}});
- registerService(Context.ETHERNET_SERVICE, EthernetManager.class,
- new CachedServiceFetcher<EthernetManager>() {
- @Override
- public EthernetManager createService(ContextImpl ctx) throws ServiceNotFoundException {
- IBinder b = ServiceManager.getServiceOrThrow(Context.ETHERNET_SERVICE);
- IEthernetManager service = IEthernetManager.Stub.asInterface(b);
- return new EthernetManager(ctx.getOuterContext(), service);
- }});
-
registerService(Context.WIFI_NL80211_SERVICE, WifiNl80211Manager.class,
new CachedServiceFetcher<WifiNl80211Manager>() {
@Override
@@ -1571,6 +1561,7 @@ public final class SystemServiceRegistry {
SafetyCenterFrameworkInitializer.registerServiceWrappers();
ConnectivityFrameworkInitializerTiramisu.registerServiceWrappers();
NearbyFrameworkInitializer.registerServiceWrappers();
+ OnDevicePersonalizationFrameworkInitializer.registerServiceWrappers();
} finally {
// If any of the above code throws, we're in a pretty bad shape and the process
// will likely crash, but we'll reset it just in case there's an exception handler...
diff --git a/core/java/android/app/TEST_MAPPING b/core/java/android/app/TEST_MAPPING
index 32207af22dc1..649f90442536 100644
--- a/core/java/android/app/TEST_MAPPING
+++ b/core/java/android/app/TEST_MAPPING
@@ -146,15 +146,6 @@
}
],
"file_patterns": ["(/|^)ContextImpl.java"]
- },
- {
- "file_patterns": ["(/|^)LocaleManager.java"],
- "name": "CtsLocaleManagerTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
}
],
"presubmit-large": [
@@ -182,6 +173,16 @@
{
"file_patterns": ["(/|^)ActivityThreadTest.java"],
"name": "FrameworksCoreTests"
+ },
+ // TODO(b/225192026): Move back to presubmit after b/225192026 is fixed
+ {
+ "file_patterns": ["(/|^)LocaleManager.java"],
+ "name": "CtsLocaleManagerTestCases",
+ "options": [
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ }
+ ]
}
]
}
diff --git a/core/java/android/app/TaskInfo.java b/core/java/android/app/TaskInfo.java
index 5c7c73c2d683..1a38fcfba5a0 100644
--- a/core/java/android/app/TaskInfo.java
+++ b/core/java/android/app/TaskInfo.java
@@ -188,7 +188,7 @@ public class TaskInfo {
/**
* @hide
*/
- public boolean preferDockBigOverlays;
+ public boolean shouldDockBigOverlays;
/**
* The task id of the host Task of the launch-into-pip Activity, i.e., it points to the Task
@@ -392,8 +392,8 @@ public class TaskInfo {
/** @hide */
@TestApi
- public boolean getPreferDockBigOverlays() {
- return preferDockBigOverlays;
+ public boolean shouldDockBigOverlays() {
+ return shouldDockBigOverlays;
}
/** @hide */
@@ -465,7 +465,7 @@ public class TaskInfo {
&& displayAreaFeatureId == that.displayAreaFeatureId
&& Objects.equals(positionInParent, that.positionInParent)
&& Objects.equals(pictureInPictureParams, that.pictureInPictureParams)
- && Objects.equals(preferDockBigOverlays, that.preferDockBigOverlays)
+ && Objects.equals(shouldDockBigOverlays, that.shouldDockBigOverlays)
&& Objects.equals(displayCutoutInsets, that.displayCutoutInsets)
&& getWindowingMode() == that.getWindowingMode()
&& Objects.equals(taskDescription, that.taskDescription)
@@ -522,7 +522,7 @@ public class TaskInfo {
token = WindowContainerToken.CREATOR.createFromParcel(source);
topActivityType = source.readInt();
pictureInPictureParams = source.readTypedObject(PictureInPictureParams.CREATOR);
- preferDockBigOverlays = source.readBoolean();
+ shouldDockBigOverlays = source.readBoolean();
launchIntoPipHostTaskId = source.readInt();
displayCutoutInsets = source.readTypedObject(Rect.CREATOR);
topActivityInfo = source.readTypedObject(ActivityInfo.CREATOR);
@@ -569,7 +569,7 @@ public class TaskInfo {
token.writeToParcel(dest, flags);
dest.writeInt(topActivityType);
dest.writeTypedObject(pictureInPictureParams, flags);
- dest.writeBoolean(preferDockBigOverlays);
+ dest.writeBoolean(shouldDockBigOverlays);
dest.writeInt(launchIntoPipHostTaskId);
dest.writeTypedObject(displayCutoutInsets, flags);
dest.writeTypedObject(topActivityInfo, flags);
@@ -610,7 +610,7 @@ public class TaskInfo {
+ " token=" + token
+ " topActivityType=" + topActivityType
+ " pictureInPictureParams=" + pictureInPictureParams
- + " preferDockBigOverlays=" + preferDockBigOverlays
+ + " shouldDockBigOverlays=" + shouldDockBigOverlays
+ " launchIntoPipHostTaskId=" + launchIntoPipHostTaskId
+ " displayCutoutSafeInsets=" + displayCutoutInsets
+ " topActivityInfo=" + topActivityInfo
diff --git a/core/java/android/app/admin/DevicePolicyDrawableResource.java b/core/java/android/app/admin/DevicePolicyDrawableResource.java
index 7fd8e896bac2..dab98884ff82 100644
--- a/core/java/android/app/admin/DevicePolicyDrawableResource.java
+++ b/core/java/android/app/admin/DevicePolicyDrawableResource.java
@@ -20,7 +20,6 @@ import android.annotation.DrawableRes;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
-import android.app.admin.DevicePolicyResources.Drawables;
import android.content.Context;
import android.os.Parcel;
import android.os.Parcelable;
@@ -29,21 +28,21 @@ import java.util.Objects;
/**
* Used to pass in the required information for updating an enterprise drawable resource using
- * {@link DevicePolicyManager#setDrawables}.
+ * {@link DevicePolicyResourcesManager#setDrawables}.
*
* @hide
*/
@SystemApi
public final class DevicePolicyDrawableResource implements Parcelable {
- @NonNull private final @DevicePolicyResources.UpdatableDrawableId String mDrawableId;
- @NonNull private final @DevicePolicyResources.UpdatableDrawableStyle String mDrawableStyle;
- @NonNull private final @DevicePolicyResources.UpdatableDrawableSource String mDrawableSource;
+ @NonNull private final String mDrawableId;
+ @NonNull private final String mDrawableStyle;
+ @NonNull private final String mDrawableSource;
private final @DrawableRes int mResourceIdInCallingPackage;
@NonNull private ParcelableResource mResource;
/**
* Creates an object containing the required information for updating an enterprise drawable
- * resource using {@link DevicePolicyManager#setDrawables}.
+ * resource using {@link DevicePolicyResourcesManager#setDrawables}.
*
* <p>It will be used to update the drawable defined by {@code drawableId} with style
* {@code drawableStyle} located in source {@code drawableSource} to the drawable with ID
@@ -60,9 +59,9 @@ public final class DevicePolicyDrawableResource implements Parcelable {
*/
public DevicePolicyDrawableResource(
@NonNull Context context,
- @NonNull @DevicePolicyResources.UpdatableDrawableId String drawableId,
- @NonNull @DevicePolicyResources.UpdatableDrawableStyle String drawableStyle,
- @NonNull @DevicePolicyResources.UpdatableDrawableSource String drawableSource,
+ @NonNull String drawableId,
+ @NonNull String drawableStyle,
+ @NonNull String drawableSource,
@DrawableRes int resourceIdInCallingPackage) {
this(drawableId, drawableStyle, drawableSource, resourceIdInCallingPackage,
new ParcelableResource(context, resourceIdInCallingPackage,
@@ -70,9 +69,9 @@ public final class DevicePolicyDrawableResource implements Parcelable {
}
private DevicePolicyDrawableResource(
- @NonNull @DevicePolicyResources.UpdatableDrawableId String drawableId,
- @NonNull @DevicePolicyResources.UpdatableDrawableStyle String drawableStyle,
- @NonNull @DevicePolicyResources.UpdatableDrawableSource String drawableSource,
+ @NonNull String drawableId,
+ @NonNull String drawableStyle,
+ @NonNull String drawableSource,
@DrawableRes int resourceIdInCallingPackage,
@NonNull ParcelableResource resource) {
@@ -90,7 +89,7 @@ public final class DevicePolicyDrawableResource implements Parcelable {
/**
* Creates an object containing the required information for updating an enterprise drawable
- * resource using {@link DevicePolicyManager#setDrawables}.
+ * resource using {@link DevicePolicyResourcesManager#setDrawables}.
* <p>It will be used to update the drawable defined by {@code drawableId} with style
* {@code drawableStyle} to the drawable with ID {@code resourceIdInCallingPackage} in the
* calling package</p>
@@ -105,10 +104,10 @@ public final class DevicePolicyDrawableResource implements Parcelable {
*/
public DevicePolicyDrawableResource(
@NonNull Context context,
- @NonNull @DevicePolicyResources.UpdatableDrawableId String drawableId,
- @NonNull @DevicePolicyResources.UpdatableDrawableStyle String drawableStyle,
+ @NonNull String drawableId,
+ @NonNull String drawableStyle,
@DrawableRes int resourceIdInCallingPackage) {
- this(context, drawableId, drawableStyle, Drawables.Source.UNDEFINED,
+ this(context, drawableId, drawableStyle, DevicePolicyResources.UNDEFINED,
resourceIdInCallingPackage);
}
@@ -116,7 +115,6 @@ public final class DevicePolicyDrawableResource implements Parcelable {
* Returns the ID of the drawable to update.
*/
@NonNull
- @DevicePolicyResources.UpdatableDrawableId
public String getDrawableId() {
return mDrawableId;
}
@@ -125,7 +123,6 @@ public final class DevicePolicyDrawableResource implements Parcelable {
* Returns the style of the drawable to update
*/
@NonNull
- @DevicePolicyResources.UpdatableDrawableStyle
public String getDrawableStyle() {
return mDrawableStyle;
}
@@ -134,7 +131,6 @@ public final class DevicePolicyDrawableResource implements Parcelable {
* Returns the source of the drawable to update.
*/
@NonNull
- @DevicePolicyResources.UpdatableDrawableSource
public String getDrawableSource() {
return mDrawableSource;
}
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index b436f6e7374f..487674066815 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -16,9 +16,12 @@
package android.app.admin;
+import static android.net.NetworkCapabilities.NET_ENTERPRISE_ID_1;
+
import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
import android.Manifest.permission;
+import android.accounts.Account;
import android.annotation.CallbackExecutor;
import android.annotation.ColorInt;
import android.annotation.IntDef;
@@ -39,7 +42,6 @@ import android.annotation.WorkerThread;
import android.app.Activity;
import android.app.IServiceConnection;
import android.app.KeyguardManager;
-import android.app.admin.DevicePolicyResources.Drawables;
import android.app.admin.SecurityLog.SecurityEvent;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
@@ -53,10 +55,8 @@ import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ParceledListSlice;
import android.content.pm.UserInfo;
-import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
-import android.graphics.drawable.Icon;
import android.net.PrivateDnsConnectivityChecker;
import android.net.ProxyInfo;
import android.net.Uri;
@@ -95,7 +95,6 @@ import android.telephony.data.ApnSetting;
import android.text.TextUtils;
import android.util.ArraySet;
import android.util.DebugUtils;
-import android.util.DisplayMetrics;
import android.util.Log;
import android.util.Pair;
@@ -136,7 +135,6 @@ import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.function.Consumer;
-import java.util.function.Supplier;
// TODO(b/172376923) - add CarDevicePolicyManager examples below (or remove reference to it).
/**
@@ -171,6 +169,7 @@ public class DevicePolicyManager {
private final Context mContext;
private final IDevicePolicyManager mService;
private final boolean mParentInstance;
+ private final DevicePolicyResourcesManager mResourcesManager;
/** @hide */
public DevicePolicyManager(Context context, IDevicePolicyManager service) {
@@ -184,6 +183,7 @@ public class DevicePolicyManager {
mContext = context;
mService = service;
mParentInstance = parentInstance;
+ mResourcesManager = new DevicePolicyResourcesManager(context, service);
}
/** @hide test will override it. */
@@ -717,10 +717,11 @@ public class DevicePolicyManager {
/**
* A {@code boolean} extra which determines whether to force a role holder update, regardless
- * of any internal conditions {@link #ACTION_UPDATE_DEVICE_MANAGEMENT_ROLE_HOLDER} might have.
+ * of any internal conditions {@link #ACTION_UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER} might
+ * have.
*
* <p>This extra can be provided to intents with action {@link
- * #ACTION_UPDATE_DEVICE_MANAGEMENT_ROLE_HOLDER}.
+ * #ACTION_UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER}.
*
* @hide
*/
@@ -1413,6 +1414,9 @@ public class DevicePolicyManager {
* admin app when performing the admin-integrated provisioning flow as a result of the
* {@link #ACTION_GET_PROVISIONING_MODE} activity.
*
+ * <p>This extra may also be provided to the admin app via an intent extra for {@link
+ * #ACTION_GET_PROVISIONING_MODE}.
+ *
* @see #ACTION_GET_PROVISIONING_MODE
*/
public static final String EXTRA_PROVISIONING_SENSORS_PERMISSION_GRANT_OPT_OUT =
@@ -1617,14 +1621,26 @@ public class DevicePolicyManager {
"android.app.extra.PROVISIONING_SKIP_EDUCATION_SCREENS";
/**
- * A boolean extra indicating if mobile data should be used during NFC device owner provisioning
- * for downloading the mobile device management application. If {@link
- * #EXTRA_PROVISIONING_WIFI_SSID} is also specified, wifi network will be used instead.
+ * A boolean extra indicating if mobile data should be used during the provisioning flow
+ * for downloading the admin app. If {@link #EXTRA_PROVISIONING_WIFI_SSID} is also specified,
+ * wifi network will be used instead.
*
- * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner
- * provisioning via an NFC bump.
+ * <p>Default value is {@code false}.
*
- * @hide
+ * <p>If this extra is set to {@code true} and {@link #EXTRA_PROVISIONING_WIFI_SSID} is not
+ * specified, this extra has different behaviour depending on the way provisioning is triggered:
+ * <ul>
+ * <li>
+ * For provisioning started via a QR code or an NFC tag, mobile data is always used for
+ * downloading the admin app.
+ * </li>
+ * <li>
+ * For all other provisioning methods, a mobile data connection check is made at the start
+ * of provisioning. If mobile data is connected at that point, the admin app download will
+ * happen using mobile data. If mobile data is not connected at that point, the end-user
+ * will be asked to pick a wifi network and the admin app download will proceed over wifi.
+ * </li>
+ * </ul>
*/
public static final String EXTRA_PROVISIONING_USE_MOBILE_DATA =
"android.app.extra.PROVISIONING_USE_MOBILE_DATA";
@@ -3062,6 +3078,8 @@ public class DevicePolicyManager {
* <li>{@link #EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE}</li>
* <li>{@link #EXTRA_PROVISIONING_IMEI}</li>
* <li>{@link #EXTRA_PROVISIONING_SERIAL_NUMBER}</li>
+ * <li>{@link #EXTRA_PROVISIONING_ALLOWED_PROVISIONING_MODES}</li>
+ * <li>{@link #EXTRA_PROVISIONING_SENSORS_PERMISSION_GRANT_OPT_OUT}</li>
* </ul>
*
* <p>The target activity should return one of the following values in
@@ -3085,8 +3103,22 @@ public class DevicePolicyManager {
* activity, along with the values of the {@link #EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE} extra
* that are already supplied to this activity.
*
- * @see #EXTRA_PROVISIONING_KEEP_ACCOUNT_ON_MIGRATION
- * @see #EXTRA_PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED
+ * <p>Other extras the target activity may include in the intent result:
+ * <ul>
+ * <li>{@link #EXTRA_PROVISIONING_DISCLAIMERS}</li>
+ * <li>{@link #EXTRA_PROVISIONING_SKIP_ENCRYPTION}</li>
+ * <li>{@link #EXTRA_PROVISIONING_KEEP_SCREEN_ON}</li>
+ * <li>{@link #EXTRA_PROVISIONING_KEEP_ACCOUNT_ON_MIGRATION} for work profile
+ * provisioning</li>
+ * <li>{@link #EXTRA_PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED} for work profile
+ * provisioning</li>
+ * <li>{@link #EXTRA_PROVISIONING_SENSORS_PERMISSION_GRANT_OPT_OUT} for fully-managed
+ * device provisioning</li>
+ * <li>{@link #EXTRA_PROVISIONING_LOCALE} for fully-managed device provisioning</li>
+ * <li>{@link #EXTRA_PROVISIONING_LOCAL_TIME} for fully-managed device provisioning</li>
+ * <li>{@link #EXTRA_PROVISIONING_TIME_ZONE} for fully-managed device provisioning</li>
+ * </ul>
+ *
* @see #ACTION_ADMIN_POLICY_COMPLIANCE
*/
public static final String ACTION_GET_PROVISIONING_MODE =
@@ -3260,39 +3292,84 @@ public class DevicePolicyManager {
*
* <p>The activity must handle the device policy management role holder update and set the
* intent result to either {@link Activity#RESULT_OK} if the update was successful, {@link
- * #RESULT_UPDATE_DEVICE_MANAGEMENT_ROLE_HOLDER_RECOVERABLE_ERROR} if it encounters a problem
- * that may be solved by relaunching it again, or {@link
- * #RESULT_UPDATE_DEVICE_MANAGEMENT_ROLE_HOLDER_UNRECOVERABLE_ERROR} if it encounters a problem
- * that will not be solved by relaunching it again.
+ * #RESULT_UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER_RECOVERABLE_ERROR} if it encounters a
+ * problem that may be solved by relaunching it again, {@link
+ * #RESULT_UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER_PROVISIONING_DISABLED} if role holder
+ * provisioning is disabled, or {@link
+ * #RESULT_UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER_UNRECOVERABLE_ERROR} if it encounters
+ * any other problem that will not be solved by relaunching it again.
*
* <p>If this activity has additional internal conditions which are not met, it should return
- * {@link #RESULT_UPDATE_DEVICE_MANAGEMENT_ROLE_HOLDER_UNRECOVERABLE_ERROR}.
+ * {@link #RESULT_UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER_UNRECOVERABLE_ERROR}.
*
* @hide
*/
@RequiresPermission(android.Manifest.permission.LAUNCH_DEVICE_MANAGER_SETUP)
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
@SystemApi
- public static final String ACTION_UPDATE_DEVICE_MANAGEMENT_ROLE_HOLDER =
- "android.app.action.UPDATE_DEVICE_MANAGEMENT_ROLE_HOLDER";
+ public static final String ACTION_UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER =
+ "android.app.action.UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER";
/**
- * Result code that can be returned by the {@link #ACTION_UPDATE_DEVICE_MANAGEMENT_ROLE_HOLDER}
- * handler if it encounters a problem that may be solved by relaunching it again.
+ * Result code that can be returned by the {@link
+ * #ACTION_UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER} handler if it encounters a problem
+ * that may be solved by relaunching it again.
*
* @hide
*/
@SystemApi
- public static final int RESULT_UPDATE_DEVICE_MANAGEMENT_ROLE_HOLDER_RECOVERABLE_ERROR = 1;
+ public static final int RESULT_UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER_RECOVERABLE_ERROR =
+ 1;
/**
- * Result code that can be returned by the {@link #ACTION_UPDATE_DEVICE_MANAGEMENT_ROLE_HOLDER}
- * handler if it encounters a problem that will not be solved by relaunching it again.
+ * Result code that can be returned by the {@link
+ * #ACTION_UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER} handler if it encounters a problem that
+ * will not be solved by relaunching it again.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int RESULT_UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER_UNRECOVERABLE_ERROR =
+ 2;
+
+ /**
+ * Result code that can be returned by the {@link
+ * #ACTION_UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER} handler if role holder provisioning
+ * is disabled.
*
* @hide
*/
@SystemApi
- public static final int RESULT_UPDATE_DEVICE_MANAGEMENT_ROLE_HOLDER_UNRECOVERABLE_ERROR = 2;
+ public static final int
+ RESULT_UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER_PROVISIONING_DISABLED = 3;
+
+ /**
+ * An {@code int} extra which contains the result code of the last attempt to update
+ * the device policy management role holder.
+ *
+ * <p>This extra is provided to the device policy management role holder via either {@link
+ * #ACTION_ROLE_HOLDER_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE} or {@link
+ * #ACTION_ROLE_HOLDER_PROVISION_MANAGED_PROFILE} when started after the role holder
+ * had previously returned {@link #RESULT_UPDATE_ROLE_HOLDER}.
+ *
+ * <p>If the role holder update had failed, the role holder can use the value of this extra to
+ * make a decision whether to fail the provisioning flow or to carry on with the older version
+ * of the role holder.
+ *
+ * <p>Possible values can be:
+ * <ul>
+ * <li>{@link Activity#RESULT_OK} if the update was successful
+ * <li>{@link #RESULT_UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER_RECOVERABLE_ERROR} if it
+ * encounters a problem that may be solved by relaunching it again.
+ * <li>{@link #RESULT_UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER_UNRECOVERABLE_ERROR} if
+ * it encounters a problem that will not be solved by relaunching it again.
+ * </ul>
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final String EXTRA_ROLE_HOLDER_UPDATE_RESULT_CODE =
+ "android.app.extra.ROLE_HOLDER_UPDATE_RESULT_CODE";
/**
* An {@link Intent} extra which resolves to a custom user consent screen.
@@ -3314,6 +3391,16 @@ public class DevicePolicyManager {
* <li>General disclaimer relevant to the provisioning mode</li>
* </ul>
*
+ * <p>When this {@link Intent} is started, the following intent extras will be supplied:
+ * <ul>
+ * <li>{@link #EXTRA_PROVISIONING_DISCLAIMERS}</li>
+ * <li>{@link #EXTRA_PROVISIONING_MODE}</li>
+ * <li>{@link #EXTRA_PROVISIONING_LOCALE}</li>
+ * <li>{@link #EXTRA_PROVISIONING_LOCAL_TIME}</li>
+ * <li>{@link #EXTRA_PROVISIONING_TIME_ZONE}</li>
+ * <li>{@link #EXTRA_PROVISIONING_SKIP_EDUCATION_SCREENS}</li>
+ * </ul>
+ *
* <p>If the custom consent screens are granted by the user {@link Activity#RESULT_OK} is
* returned, otherwise {@link Activity#RESULT_CANCELED} is returned. The device policy
* management role holder should ensure that the provisioning flow terminates immediately if
@@ -3648,7 +3735,8 @@ public class DevicePolicyManager {
/**
* Broadcast action: notify system apps (e.g. settings, SysUI, etc) that the device management
* resources with IDs {@link #EXTRA_RESOURCE_IDS} has been updated, the updated resources can be
- * retrieved using {@link #getDrawable} and {@code #getString}.
+ * retrieved using {@link DevicePolicyResourcesManager#getDrawable} and
+ * {@link DevicePolicyResourcesManager#getString}.
*
* <p>This broadcast is sent to registered receivers only.
*
@@ -11012,7 +11100,7 @@ public class DevicePolicyManager {
}
/**
- * Sets whether preferential network service is enabled on the work profile.
+ * Sets whether preferential network service is enabled.
* For example, an organization can have a deal/agreement with a carrier that all of
* the work data from its employees’ devices will be sent via a network service dedicated
* for enterprise use.
@@ -11020,75 +11108,72 @@ public class DevicePolicyManager {
* An example of a supported preferential network service is the Enterprise
* slice on 5G networks.
*
- * By default, preferential network service is disabled on the work profile on supported
- * carriers and devices. Admins can explicitly enable it with this API.
- * On fully-managed devices this method is unsupported because all traffic is considered
- * work traffic.
+ * By default, preferential network service is disabled on the work profile and
+ * fully managed devices, on supported carriers and devices.
+ * Admins can explicitly enable it with this API.
*
* <p> This method enables preferential network service with a default configuration.
- * To fine-tune the configuration, use {@link #setPreferentialNetworkServiceConfig) instead.
+ * To fine-tune the configuration, use {@link #setPreferentialNetworkServiceConfigs) instead.
+ * <p> Before Android version {@link android.os.Build.VERSION_CODES#TIRAMISU}:
+ * this method can be called by the profile owner of a managed profile.
+ * <p> Starting from Android version {@link android.os.Build.VERSION_CODES#TIRAMISU}:
+ * This method can be called by the profile owner of a managed profile
+ * or device owner.
*
- * <p>This method can only be called by the profile owner of a managed profile.
* @param enabled whether preferential network service should be enabled.
- * @throws SecurityException if the caller is not the profile owner.
+ * @throws SecurityException if the caller is not the profile owner or device owner.
**/
public void setPreferentialNetworkServiceEnabled(boolean enabled) {
throwIfParentInstance("setPreferentialNetworkServiceEnabled");
- if (mService == null) {
- return;
- }
-
- try {
- mService.setPreferentialNetworkServiceEnabled(enabled);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
+ PreferentialNetworkServiceConfig.Builder configBuilder =
+ new PreferentialNetworkServiceConfig.Builder();
+ configBuilder.setEnabled(enabled);
+ if (enabled) {
+ configBuilder.setNetworkId(NET_ENTERPRISE_ID_1);
}
+ setPreferentialNetworkServiceConfigs(List.of(configBuilder.build()));
}
/**
* Indicates whether preferential network service is enabled.
*
- * <p>This method can be called by the profile owner of a managed profile.
+ * <p> Before Android version {@link android.os.Build.VERSION_CODES#TIRAMISU}:
+ * This method can be called by the profile owner of a managed profile.
+ * <p> Starting from Android version {@link android.os.Build.VERSION_CODES#TIRAMISU}:
+ * This method can be called by the profile owner of a managed profile
+ * or device owner.
*
* @return whether preferential network service is enabled.
- * @throws SecurityException if the caller is not the profile owner.
+ * @throws SecurityException if the caller is not the profile owner or device owner.
*/
public boolean isPreferentialNetworkServiceEnabled() {
throwIfParentInstance("isPreferentialNetworkServiceEnabled");
- if (mService == null) {
- return false;
- }
- try {
- return mService.isPreferentialNetworkServiceEnabled(myUserId());
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ return getPreferentialNetworkServiceConfigs().stream().anyMatch(c -> c.isEnabled());
}
/**
- * Sets preferential network configuration on the work profile.
+ * Sets preferential network configurations.
* {@see PreferentialNetworkServiceConfig}
*
* An example of a supported preferential network service is the Enterprise
* slice on 5G networks.
*
- * By default, preferential network service is disabled on the work profile on supported
- * carriers and devices. Admins can explicitly enable it with this API.
- * On fully-managed devices this method is unsupported because all traffic is considered
- * work traffic.
+ * By default, preferential network service is disabled on the work profile and fully managed
+ * devices, on supported carriers and devices. Admins can explicitly enable it with this API.
+ * If admin wants to have multiple enterprise slices,
+ * it can be configured by passing list of {@link PreferentialNetworkServiceConfig} objects.
*
- * <p>This method can only be called by the profile owner of a managed profile.
- * @param preferentialNetworkServiceConfig preferential network configuration.
- * @throws SecurityException if the caller is not the profile owner.
+ * @param preferentialNetworkServiceConfigs list of preferential network configurations.
+ * @throws SecurityException if the caller is not the profile owner or device owner.
**/
- public void setPreferentialNetworkServiceConfig(
- @NonNull PreferentialNetworkServiceConfig preferentialNetworkServiceConfig) {
- throwIfParentInstance("setPreferentialNetworkServiceConfig");
+ public void setPreferentialNetworkServiceConfigs(
+ @NonNull List<PreferentialNetworkServiceConfig> preferentialNetworkServiceConfigs) {
+ throwIfParentInstance("setPreferentialNetworkServiceConfigs");
if (mService == null) {
return;
}
try {
- mService.setPreferentialNetworkServiceConfig(preferentialNetworkServiceConfig);
+ mService.setPreferentialNetworkServiceConfigs(preferentialNetworkServiceConfigs);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -11098,18 +11183,16 @@ public class DevicePolicyManager {
* Get preferential network configuration
* {@see PreferentialNetworkServiceConfig}
*
- * <p>This method can be called by the profile owner of a managed profile.
- *
* @return preferential network configuration.
- * @throws SecurityException if the caller is not the profile owner.
+ * @throws SecurityException if the caller is not the profile owner or device owner.
*/
- public @NonNull PreferentialNetworkServiceConfig getPreferentialNetworkServiceConfig() {
- throwIfParentInstance("getPreferentialNetworkServiceConfig");
+ public @NonNull List<PreferentialNetworkServiceConfig> getPreferentialNetworkServiceConfigs() {
+ throwIfParentInstance("getPreferentialNetworkServiceConfigs");
if (mService == null) {
- return PreferentialNetworkServiceConfig.DEFAULT;
+ return List.of(PreferentialNetworkServiceConfig.DEFAULT);
}
try {
- return mService.getPreferentialNetworkServiceConfig();
+ return mService.getPreferentialNetworkServiceConfigs();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -13593,13 +13676,18 @@ public class DevicePolicyManager {
}
/**
- * Called by device owner to add an override APN.
+ * Called by device owner or profile owner to add an override APN.
*
* <p>This method may returns {@code -1} if {@code apnSetting} conflicts with an existing
* override APN. Update the existing conflicted APN with
* {@link #updateOverrideApn(ComponentName, int, ApnSetting)} instead of adding a new entry.
* <p>Two override APNs are considered to conflict when all the following APIs return
* the same values on both override APNs:
+ * <p> Before Android version {@link android.os.Build.VERSION_CODES#TIRAMISU}:
+ * Only device owners can add APNs.
+ * <p> Starting from Android version {@link android.os.Build.VERSION_CODES#TIRAMISU}:
+ * Device and profile owners can add enterprise APNs
+ * ({@link ApnSetting#TYPE_ENTERPRISE}), while only device owners can add other type of APNs.
* <ul>
* <li>{@link ApnSetting#getOperatorNumeric()}</li>
* <li>{@link ApnSetting#getApnName()}</li>
@@ -13618,7 +13706,8 @@ public class DevicePolicyManager {
* @param apnSetting the override APN to insert
* @return The {@code id} of inserted override APN. Or {@code -1} when failed to insert into
* the database.
- * @throws SecurityException if {@code admin} is not a device owner.
+ * @throws SecurityException If request is for enterprise APN {@code admin} is either device
+ * owner or profile owner and in all other types of APN if {@code admin} is not a device owner.
*
* @see #setOverrideApnsEnabled(ComponentName, boolean)
*/
@@ -13635,20 +13724,26 @@ public class DevicePolicyManager {
}
/**
- * Called by device owner to update an override APN.
+ * Called by device owner or profile owner to update an override APN.
*
* <p>This method may returns {@code false} if there is no override APN with the given
* {@code apnId}.
* <p>This method may also returns {@code false} if {@code apnSetting} conflicts with an
* existing override APN. Update the existing conflicted APN instead.
* <p>See {@link #addOverrideApn} for the definition of conflict.
+ * <p> Before Android version {@link android.os.Build.VERSION_CODES#TIRAMISU}:
+ * Only device owners can update APNs.
+ * <p> Starting from Android version {@link android.os.Build.VERSION_CODES#TIRAMISU}:
+ * Device and profile owners can update enterprise APNs
+ * ({@link ApnSetting#TYPE_ENTERPRISE}), while only device owners can update other type of APNs.
*
* @param admin which {@link DeviceAdminReceiver} this request is associated with
* @param apnId the {@code id} of the override APN to update
* @param apnSetting the override APN to update
* @return {@code true} if the required override APN is successfully updated,
* {@code false} otherwise.
- * @throws SecurityException if {@code admin} is not a device owner.
+ * @throws SecurityException If request is for enterprise APN {@code admin} is either device
+ * owner or profile owner and in all other types of APN if {@code admin} is not a device owner.
*
* @see #setOverrideApnsEnabled(ComponentName, boolean)
*/
@@ -13666,16 +13761,22 @@ public class DevicePolicyManager {
}
/**
- * Called by device owner to remove an override APN.
+ * Called by device owner or profile owner to remove an override APN.
*
* <p>This method may returns {@code false} if there is no override APN with the given
* {@code apnId}.
+ * <p> Before Android version {@link android.os.Build.VERSION_CODES#TIRAMISU}:
+ * Only device owners can remove APNs.
+ * <p> Starting from Android version {@link android.os.Build.VERSION_CODES#TIRAMISU}:
+ * Device and profile owners can remove enterprise APNs
+ * ({@link ApnSetting#TYPE_ENTERPRISE}), while only device owners can remove other type of APNs.
*
* @param admin which {@link DeviceAdminReceiver} this request is associated with
* @param apnId the {@code id} of the override APN to remove
* @return {@code true} if the required override APN is successfully removed, {@code false}
* otherwise.
- * @throws SecurityException if {@code admin} is not a device owner.
+ * @throws SecurityException If request is for enterprise APN {@code admin} is either device
+ * owner or profile owner and in all other types of APN if {@code admin} is not a device owner.
*
* @see #setOverrideApnsEnabled(ComponentName, boolean)
*/
@@ -13970,12 +14071,12 @@ public class DevicePolicyManager {
/**
* Deprecated. Use {@code markProfileOwnerOnOrganizationOwnedDevice} instead.
* When called by an app targeting SDK level {@link android.os.Build.VERSION_CODES#Q} or
- * below, will behave the same as {@link #markProfileOwnerOnOrganizationOwnedDevice}.
+ * below, will behave the same as {@link #setProfileOwnerOnOrganizationOwnedDevice}.
*
* When called by an app targeting SDK level {@link android.os.Build.VERSION_CODES#R}
* or above, will throw an UnsupportedOperationException when called.
*
- * @deprecated Use {@link #markProfileOwnerOnOrganizationOwnedDevice} instead.
+ * @deprecated Use {@link #setProfileOwnerOnOrganizationOwnedDevice} instead.
*
* @hide
*/
@@ -13990,14 +14091,14 @@ public class DevicePolicyManager {
"This method is deprecated. use markProfileOwnerOnOrganizationOwnedDevice"
+ " instead.");
} else {
- markProfileOwnerOnOrganizationOwnedDevice(who);
+ setProfileOwnerOnOrganizationOwnedDevice(who, true);
}
}
/**
- * Marks the profile owner of the given user as managing an organization-owned device.
- * That will give it access to device identifiers (such as serial number, IMEI and MEID)
- * as well as other privileges.
+ * Sets whether the profile owner of the given user as managing an organization-owned device.
+ * Managing an organization-owned device will give it access to device identifiers (such as
+ * serial number, IMEI and MEID) as well as other privileges.
*
* @hide
*/
@@ -14005,13 +14106,15 @@ public class DevicePolicyManager {
@RequiresPermission(anyOf = {
android.Manifest.permission.MARK_DEVICE_ORGANIZATION_OWNED,
android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS
- }, conditional = true)
- public void markProfileOwnerOnOrganizationOwnedDevice(@NonNull ComponentName who) {
+ }, conditional = true)
+ public void setProfileOwnerOnOrganizationOwnedDevice(@NonNull ComponentName who,
+ boolean isProfileOwnerOnOrganizationOwnedDevice) {
if (mService == null) {
return;
}
try {
- mService.markProfileOwnerOnOrganizationOwnedDevice(who, myUserId());
+ mService.setProfileOwnerOnOrganizationOwnedDevice(who, myUserId(),
+ isProfileOwnerOnOrganizationOwnedDevice);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
@@ -14761,6 +14864,28 @@ public class DevicePolicyManager {
}
/**
+ * Called when a managed profile has been provisioned.
+ *
+ * @throws SecurityException if the caller does not hold
+ * {@link android.Manifest.permission#MANAGE_PROFILE_AND_DEVICE_OWNERS}.
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS)
+ public void finalizeWorkProfileProvisioning(
+ @NonNull UserHandle managedProfileUser, @Nullable Account migratedAccount) {
+ Objects.requireNonNull(managedProfileUser, "managedProfileUser can't be null");
+ if (mService == null) {
+ throw new IllegalStateException("Could not find DevicePolicyManagerService");
+ }
+ try {
+ mService.finalizeWorkProfileProvisioning(managedProfileUser, migratedAccount);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* The localized error message to show to the end-user. If {@code null}, a generic error
* message will be shown.
*/
@@ -14776,17 +14901,20 @@ public class DevicePolicyManager {
* <p>The method {@link #checkProvisioningPrecondition} must be returning {@link #STATUS_OK}
* before calling this method.
*
+ * <p>Holders of {@link android.Manifest.permission#PROVISION_DEMO_DEVICE} can call this API
+ * only if {@link FullyManagedDeviceProvisioningParams#isDemoDevice()} is {@code true}.</p>
+ *
* @param provisioningParams Params required to provision a fully managed device,
* see {@link FullyManagedDeviceProvisioningParams}.
*
- * @throws SecurityException if the caller does not hold
- * {@link android.Manifest.permission#MANAGE_PROFILE_AND_DEVICE_OWNERS}.
* @throws ProvisioningException if an error occurred during provisioning.
*
* @hide
*/
@SystemApi
- @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS)
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS,
+ android.Manifest.permission.PROVISION_DEMO_DEVICE})
public void provisionFullyManagedDevice(
@NonNull FullyManagedDeviceProvisioningParams provisioningParams)
throws ProvisioningException {
@@ -15165,376 +15293,53 @@ public class DevicePolicyManager {
}
/**
- * For each {@link DevicePolicyDrawableResource} item in {@code drawables}, if
- * {@link DevicePolicyDrawableResource#getDrawableSource()} is not set or is set to
- * {@link DevicePolicyResources.Drawables.Source#UNDEFINED}, it updates the drawable resource for
- * the combination of {@link DevicePolicyDrawableResource#getDrawableId()} and
- * {@link DevicePolicyDrawableResource#getDrawableStyle()}, (see
- * {@link DevicePolicyResources.Drawables} and {@link DevicePolicyResources.Drawables.Style}) to
- * the drawable with ID {@link DevicePolicyDrawableResource#getResourceIdInCallingPackage()},
- * meaning any system UI surface calling {@link #getDrawable}
- * with {@code drawableId} and {@code drawableStyle} will get the new resource after this API
- * is called.
- *
- * <p>Otherwise, if {@link DevicePolicyDrawableResource#getDrawableSource()} is set (see
- * {@link DevicePolicyResources.Drawables.Source}, it overrides any drawables that was set for
- * the same {@code drawableId} and {@code drawableStyle} for the provided source.
- *
- * <p>Sends a broadcast with action {@link #ACTION_DEVICE_POLICY_RESOURCE_UPDATED} to
- * registered receivers when a resource has been updated successfully.
- *
- * <p>Important notes to consider when using this API:
- * <ul>
- * <li>{@link #getDrawable} references the resource
- * {@link DevicePolicyDrawableResource#getResourceIdInCallingPackage()} in the
- * calling package each time it gets called. You have to ensure that the resource is always
- * available in the calling package as long as it is used as an updated resource.
- * <li>You still have to re-call {@code setDrawables} even if you only make changes to the
- * content of the resource with ID
- * {@link DevicePolicyDrawableResource#getResourceIdInCallingPackage()} as the content might be
- * cached and would need updating.
- * </ul>
- *
- * @param drawables The list of {@link DevicePolicyDrawableResource} to update.
- *
- * @hide
- */
- @SystemApi
- @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES)
- public void setDrawables(@NonNull Set<DevicePolicyDrawableResource> drawables) {
- if (mService != null) {
- try {
- mService.setDrawables(new ArrayList<>(drawables));
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
- }
-
- /**
- * Removes all updated drawables for the list of {@code drawableIds} (see
- * {@link DevicePolicyResources.Drawables} that was previously set by calling
- * {@link #setDrawables}, meaning any subsequent calls to {@link #getDrawable} for the provided
- * IDs with any {@link DevicePolicyResources.Drawables.Style} and any
- * {@link DevicePolicyResources.Drawables.Source} will return the default drawable from
- * {@code defaultDrawableLoader}.
- *
- * <p>Sends a broadcast with action {@link #ACTION_DEVICE_POLICY_RESOURCE_UPDATED} to
- * registered receivers when a resource has been reset successfully.
- *
- * @param drawableIds The list of IDs to remove.
- *
- * @hide
- */
- @SystemApi
- @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES)
- public void resetDrawables(@NonNull String[] drawableIds) {
- if (mService != null) {
- try {
- mService.resetDrawables(drawableIds);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
- }
-
- /**
- * Returns the appropriate updated drawable for the {@code drawableId}
- * (see {@link DevicePolicyResources.Drawables}), with style {@code drawableStyle}
- * (see {@link DevicePolicyResources.Drawables.Style}) if one was set using
- * {@code setDrawables}, otherwise returns the drawable from {@code defaultDrawableLoader}.
- *
- * <p>Also returns the drawable from {@code defaultDrawableLoader} if
- * {@link DevicePolicyResources.Drawables#UNDEFINED} was passed.
- *
- * <p>Calls to this API will not return {@code null} unless no updated drawable was found
- * and the call to {@code defaultDrawableLoader} returned {@code null}.
- *
- * <p>This API uses the screen density returned from {@link Resources#getConfiguration()}, to
- * set a different value use
- * {@link #getDrawableForDensity(String, String, int, Supplier)}.
- *
- * <p>Callers should register for {@link #ACTION_DEVICE_POLICY_RESOURCE_UPDATED} to get
- * notified when a resource has been updated.
- *
- * <p>Note that each call to this API loads the resource from the package that called
- * {@code setDrawables} to set the updated resource.
- *
- * @param drawableId The drawable ID to get the updated resource for.
- * @param drawableStyle The drawable style to use.
- * @param defaultDrawableLoader To get the default drawable if no updated drawable was set for
- * the provided params.
- */
- @Nullable
- public Drawable getDrawable(
- @NonNull @DevicePolicyResources.UpdatableDrawableId String drawableId,
- @NonNull @DevicePolicyResources.UpdatableDrawableStyle String drawableStyle,
- @NonNull Supplier<Drawable> defaultDrawableLoader) {
- return getDrawable(
- drawableId, drawableStyle, Drawables.Source.UNDEFINED, defaultDrawableLoader);
- }
-
- /**
- * Similar to {@link #getDrawable(String, String, Supplier)}, but also accepts
- * a {@code drawableSource} (see {@link DevicePolicyResources.Drawables.Source}) which
- * could result in returning a different drawable than
- * {@link #getDrawable(String, String, Supplier)}
- * if an override was set for that specific source.
- *
- * <p>Calls to this API will not return {@code null} unless no updated drawable was found
- * and the call to {@code defaultDrawableLoader} returned {@code null}.
- *
- * <p>Callers should register for {@link #ACTION_DEVICE_POLICY_RESOURCE_UPDATED} to get
- * notified when a resource has been updated.
- *
- * @param drawableId The drawable ID to get the updated resource for.
- * @param drawableStyle The drawable style to use.
- * @param drawableSource The source for the caller.
- * @param defaultDrawableLoader To get the default drawable if no updated drawable was set for
- * the provided params.
- */
- @Nullable
- public Drawable getDrawable(
- @NonNull @DevicePolicyResources.UpdatableDrawableId String drawableId,
- @NonNull @DevicePolicyResources.UpdatableDrawableStyle String drawableStyle,
- @NonNull @DevicePolicyResources.UpdatableDrawableSource String drawableSource,
- @NonNull Supplier<Drawable> defaultDrawableLoader) {
-
- Objects.requireNonNull(drawableId, "drawableId can't be null");
- Objects.requireNonNull(drawableStyle, "drawableStyle can't be null");
- Objects.requireNonNull(drawableSource, "drawableSource can't be null");
- Objects.requireNonNull(defaultDrawableLoader, "defaultDrawableLoader can't be null");
-
- if (Drawables.UNDEFINED.equals(drawableId)) {
- return ParcelableResource.loadDefaultDrawable(defaultDrawableLoader);
- }
- if (mService != null) {
- try {
- ParcelableResource resource = mService.getDrawable(
- drawableId, drawableStyle, drawableSource);
- if (resource == null) {
- return ParcelableResource.loadDefaultDrawable(
- defaultDrawableLoader);
- }
- return resource.getDrawable(
- mContext,
- /* density= */ 0,
- defaultDrawableLoader);
-
- } catch (RemoteException e) {
- Log.e(
- TAG,
- "Error getting the updated drawable from DevicePolicyManagerService.",
- e);
- return ParcelableResource.loadDefaultDrawable(defaultDrawableLoader);
- }
- }
- return ParcelableResource.loadDefaultDrawable(defaultDrawableLoader);
- }
-
- /**
- * Similar to {@link #getDrawable(String, String, Supplier)}, but also accepts
- * {@code density}. See {@link Resources#getDrawableForDensity(int, int, Resources.Theme)}.
- *
- * <p>Calls to this API will not return {@code null} unless no updated drawable was found
- * and the call to {@code defaultDrawableLoader} returned {@code null}.
- *
- * <p>Callers should register for {@link #ACTION_DEVICE_POLICY_RESOURCE_UPDATED} to get
- * notified when a resource has been updated.
- *
- * @param drawableId The drawable ID to get the updated resource for.
- * @param drawableStyle The drawable style to use.
- * @param density The desired screen density indicated by the resource as
- * found in {@link DisplayMetrics}. A value of 0 means to use the
- * density returned from {@link Resources#getConfiguration()}.
- * @param defaultDrawableLoader To get the default drawable if no updated drawable was set for
- * the provided params.
- */
- @Nullable
- public Drawable getDrawableForDensity(
- @NonNull @DevicePolicyResources.UpdatableDrawableId String drawableId,
- @NonNull @DevicePolicyResources.UpdatableDrawableStyle String drawableStyle,
- int density,
- @NonNull Supplier<Drawable> defaultDrawableLoader) {
- return getDrawableForDensity(
- drawableId,
- drawableStyle,
- Drawables.Source.UNDEFINED,
- density,
- defaultDrawableLoader);
- }
-
- /**
- * Similar to {@link #getDrawable(String, String, String, Supplier)}, but also accepts
- * {@code density}. See {@link Resources#getDrawableForDensity(int, int, Resources.Theme)}.
- *
- * <p>Calls to this API will not return {@code null} unless no updated drawable was found
- * and the call to {@code defaultDrawableLoader} returned {@code null}.
- *
- * <p>Callers should register for {@link #ACTION_DEVICE_POLICY_RESOURCE_UPDATED} to get
- * notified when a resource has been updated.
- *
- * @param drawableId The drawable ID to get the updated resource for.
- * @param drawableStyle The drawable style to use.
- * @param drawableSource The source for the caller.
- * @param density The desired screen density indicated by the resource as
- * found in {@link DisplayMetrics}. A value of 0 means to use the
- * density returned from {@link Resources#getConfiguration()}.
- * @param defaultDrawableLoader To get the default drawable if no updated drawable was set for
- * the provided params.
- */
- @Nullable
- public Drawable getDrawableForDensity(
- @NonNull @DevicePolicyResources.UpdatableDrawableId String drawableId,
- @NonNull @DevicePolicyResources.UpdatableDrawableStyle String drawableStyle,
- @NonNull @DevicePolicyResources.UpdatableDrawableSource String drawableSource,
- int density,
- @NonNull Supplier<Drawable> defaultDrawableLoader) {
-
- Objects.requireNonNull(drawableId, "drawableId can't be null");
- Objects.requireNonNull(drawableStyle, "drawableStyle can't be null");
- Objects.requireNonNull(drawableSource, "drawableSource can't be null");
- Objects.requireNonNull(defaultDrawableLoader, "defaultDrawableLoader can't be null");
-
- if (Drawables.UNDEFINED.equals(drawableId)) {
- return ParcelableResource.loadDefaultDrawable(defaultDrawableLoader);
- }
- if (mService != null) {
- try {
- ParcelableResource resource = mService.getDrawable(
- drawableId, drawableStyle, drawableSource);
- if (resource == null) {
- return ParcelableResource.loadDefaultDrawable(
- defaultDrawableLoader);
- }
- return resource.getDrawable(mContext, density, defaultDrawableLoader);
- } catch (RemoteException e) {
- Log.e(
- TAG,
- "Error getting the updated drawable from DevicePolicyManagerService.",
- e);
- return ParcelableResource.loadDefaultDrawable(defaultDrawableLoader);
- }
- }
- return ParcelableResource.loadDefaultDrawable(defaultDrawableLoader);
- }
-
- /**
- * Similar to {@link #getDrawable(String, String, String, Supplier)} but returns an
- * {@link Icon} instead of a {@link Drawable}.
- *
- * @param drawableId The drawable ID to get the updated resource for.
- * @param drawableStyle The drawable style to use.
- * @param drawableSource The source for the caller.
- * @param defaultIcon Returned if no updated drawable was set for the provided params.
+ * Returns a {@link DevicePolicyResourcesManager} containing the required APIs to set, reset,
+ * and get device policy related resources.
*/
- @Nullable
- public Icon getDrawableAsIcon(
- @NonNull @DevicePolicyResources.UpdatableDrawableId String drawableId,
- @NonNull @DevicePolicyResources.UpdatableDrawableStyle String drawableStyle,
- @NonNull @DevicePolicyResources.UpdatableDrawableSource String drawableSource,
- @Nullable Icon defaultIcon) {
- Objects.requireNonNull(drawableId, "drawableId can't be null");
- Objects.requireNonNull(drawableStyle, "drawableStyle can't be null");
- Objects.requireNonNull(drawableSource, "drawableSource can't be null");
- Objects.requireNonNull(defaultIcon, "defaultIcon can't be null");
-
- if (Drawables.UNDEFINED.equals(drawableId)) {
- return defaultIcon;
- }
- if (mService != null) {
- try {
- ParcelableResource resource = mService.getDrawable(
- drawableId, drawableStyle, drawableSource);
- if (resource == null) {
- return defaultIcon;
- }
- return Icon.createWithResource(resource.getPackageName(), resource.getResourceId());
- } catch (RemoteException e) {
- Log.e(
- TAG,
- "Error getting the updated drawable from DevicePolicyManagerService.",
- e);
- return defaultIcon;
- }
- }
- return defaultIcon;
- }
-
- /**
- * Similar to {@link #getDrawable(String, String, Supplier)} but returns an {@link Icon}
- * instead of a {@link Drawable}.
- *
- * @param drawableId The drawable ID to get the updated resource for.
- * @param drawableStyle The drawable style to use.
- * @param defaultIcon Returned if no updated drawable was set for the provided params.
- */
- @Nullable
- public Icon getDrawableAsIcon(
- @NonNull @DevicePolicyResources.UpdatableDrawableId String drawableId,
- @NonNull @DevicePolicyResources.UpdatableDrawableStyle String drawableStyle,
- @Nullable Icon defaultIcon) {
- return getDrawableAsIcon(
- drawableId, drawableStyle, Drawables.Source.UNDEFINED, defaultIcon);
+ @NonNull
+ public DevicePolicyResourcesManager getResources() {
+ return mResourcesManager;
}
-
/**
- * For each {@link DevicePolicyStringResource} item in {@code strings}, it updates the string
- * resource for {@link DevicePolicyStringResource#getStringId()} to the string with ID
- * {@code callingPackageResourceId} (see {@link DevicePolicyResources.Strings}), meaning any
- * system UI surface calling {@link #getString} with {@code stringId} will get
- * the new resource after this API is called.
- *
- * <p>Sends a broadcast with action {@link #ACTION_DEVICE_POLICY_RESOURCE_UPDATED} to
- * registered receivers when a resource has been updated successfully.
- *
- * <p>Important notes to consider when using this API:
- * <ul>
- * <li> {@link #getString} references the resource
- * {@code callingPackageResourceId} in the calling package each time it gets called. You have to
- * ensure that the resource is always available in the calling package as long as it is used as
- * an updated resource.
- * <li> You still have to re-call {@code setStrings} even if you only make changes to the
- * content of the resource with ID {@code callingPackageResourceId} as the content might be
- * cached and would need updating.
- * </ul>
+ * Returns a boolean for whether the DPC
+ * (Device Policy Controller, the agent responsible for enforcing policy)
+ * has been downloaded during provisioning.
*
- * @param strings The list of {@link DevicePolicyStringResource} to update.
+ * <p>If true is returned, then any attempts to begin setup again should result in factory reset
*
* @hide
*/
@SystemApi
- @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES)
- public void setStrings(@NonNull Set<DevicePolicyStringResource> strings) {
+ @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS)
+ public boolean isDpcDownloaded() {
+ throwIfParentInstance("isDpcDownloaded");
if (mService != null) {
try {
- mService.setStrings(new ArrayList<>(strings));
+ return mService.isDpcDownloaded();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
+ return false;
}
/**
- * Removes the updated strings for the list of {@code stringIds} (see
- * {@link DevicePolicyResources.Strings}) that was previously set by calling {@link #setStrings},
- * meaning any subsequent calls to {@link #getString} for the provided IDs will
- * return the default string from {@code defaultStringLoader}.
- *
- * <p>Sends a broadcast with action {@link #ACTION_DEVICE_POLICY_RESOURCE_UPDATED} to
- * registered receivers when a resource has been reset successfully.
+ * Indicates that the DPC (Device Policy Controller, the agent responsible for enforcing policy)
+ * has or has not been downloaded during provisioning.
*
- * @param stringIds The list of IDs to remove the updated resources for.
+ * @param downloaded {@code true} if the dpc has been downloaded during provisioning.
+ * {@code false} otherwise.
*
* @hide
*/
@SystemApi
- @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES)
- public void resetStrings(@NonNull String[] stringIds) {
+ @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS)
+ public void setDpcDownloaded(boolean downloaded) {
+ throwIfParentInstance("setDpcDownloaded");
if (mService != null) {
try {
- mService.resetStrings(stringIds);
+ mService.setDpcDownloaded(downloaded);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -15542,162 +15347,58 @@ public class DevicePolicyManager {
}
/**
- * Returns the appropriate updated string for the {@code stringId} (see
- * {@link DevicePolicyResources.Strings}) if one was set using
- * {@link #setStrings}, otherwise returns the string from {@code defaultStringLoader}.
- *
- * <p>Also returns the string from {@code defaultStringLoader} if
- * {@link DevicePolicyResources.Strings#UNDEFINED} was passed.
- *
- * <p>Calls to this API will not return {@code null} unless no updated drawable was found
- * and the call to {@code defaultStringLoader} returned {@code null}.
- *
- * <p>Callers should register for {@link #ACTION_DEVICE_POLICY_RESOURCE_UPDATED} to get
- * notified when a resource has been updated.
- *
- * <p>Note that each call to this API loads the resource from the package that called
- * {@link #setStrings} to set the updated resource.
- *
- * @param stringId The IDs to get the updated resource for.
- * @param defaultStringLoader To get the default string if no updated string was set for
- * {@code stringId}.
+ * Returns the package name of the device policy management role holder.
*
- * @hide
+ * <p>If the device policy management role holder is not configured for this device, returns
+ * {@code null}.
*/
- @SystemApi
@Nullable
- public String getString(
- @NonNull @DevicePolicyResources.UpdatableStringId String stringId,
- @NonNull Supplier<String> defaultStringLoader) {
-
- Objects.requireNonNull(stringId, "stringId can't be null");
- Objects.requireNonNull(defaultStringLoader, "defaultStringLoader can't be null");
-
- if (stringId.equals(DevicePolicyResources.Strings.UNDEFINED)) {
- return ParcelableResource.loadDefaultString(defaultStringLoader);
- }
- if (mService != null) {
- try {
- ParcelableResource resource = mService.getString(stringId);
- if (resource == null) {
- return ParcelableResource.loadDefaultString(defaultStringLoader);
- }
- return resource.getString(mContext, defaultStringLoader);
- } catch (RemoteException e) {
- Log.e(
- TAG,
- "Error getting the updated string from DevicePolicyManagerService.",
- e);
- return ParcelableResource.loadDefaultString(defaultStringLoader);
- }
- }
- return ParcelableResource.loadDefaultString(defaultStringLoader);
+ public String getDevicePolicyManagementRoleHolderPackage() {
+ String devicePolicyManagementConfig = mContext.getString(
+ com.android.internal.R.string.config_devicePolicyManagement);
+ return extractPackageNameFromDeviceManagerConfig(devicePolicyManagementConfig);
}
/**
- * Similar to {@link #getString(String, Supplier)} but accepts {@code formatArgs} and returns a
- * localized formatted string, substituting the format arguments as defined in
- * {@link java.util.Formatter} and {@link java.lang.String#format}, (see
- * {@link Resources#getString(int, Object...)}).
- *
- * <p>Calls to this API will not return {@code null} unless no updated drawable was found
- * and the call to {@code defaultStringLoader} returned {@code null}.
+ * Returns the package name of the device policy management role holder updater.
*
- * @param stringId The IDs to get the updated resource for.
- * @param defaultStringLoader To get the default string if no updated string was set for
- * {@code stringId}.
- * @param formatArgs The format arguments that will be used for substitution.
+ * <p>If the device policy management role holder updater is not configured for this device,
+ * returns {@code null}.
*
* @hide
*/
- @SystemApi
@Nullable
- @SuppressLint("SamShouldBeLast")
- public String getString(
- @NonNull @DevicePolicyResources.UpdatableStringId String stringId,
- @NonNull Supplier<String> defaultStringLoader,
- @NonNull Object... formatArgs) {
-
- Objects.requireNonNull(stringId, "stringId can't be null");
- Objects.requireNonNull(defaultStringLoader, "defaultStringLoader can't be null");
-
- if (stringId.equals(DevicePolicyResources.Strings.UNDEFINED)) {
- return ParcelableResource.loadDefaultString(defaultStringLoader);
- }
- if (mService != null) {
- try {
- ParcelableResource resource = mService.getString(stringId);
- if (resource == null) {
- return ParcelableResource.loadDefaultString(defaultStringLoader);
- }
- return resource.getString(mContext, defaultStringLoader, formatArgs);
- } catch (RemoteException e) {
- Log.e(
- TAG,
- "Error getting the updated string from DevicePolicyManagerService.",
- e);
- return ParcelableResource.loadDefaultString(defaultStringLoader);
- }
- }
- return ParcelableResource.loadDefaultString(defaultStringLoader);
- }
-
- /**
- * Returns a boolean for whether the DPC
- * (Device Policy Controller, the agent responsible for enforcing policy)
- * has been downloaded during provisioning.
- *
- * <p>If true is returned, then any attempts to begin setup again should result in factory reset
- *
- * @hide
- */
- @SystemApi
- @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS)
- public boolean isDpcDownloaded() {
- throwIfParentInstance("isDpcDownloaded");
- if (mService != null) {
- try {
- return mService.isDpcDownloaded();
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ @TestApi
+ public String getDevicePolicyManagementRoleHolderUpdaterPackage() {
+ String devicePolicyManagementUpdaterConfig = mContext.getString(
+ com.android.internal.R.string.config_devicePolicyManagementUpdater);
+ if (TextUtils.isEmpty(devicePolicyManagementUpdaterConfig)) {
+ return null;
}
- return false;
+ return devicePolicyManagementUpdaterConfig;
}
/**
- * Indicates that the DPC (Device Policy Controller, the agent responsible for enforcing policy)
- * has or has not been downloaded during provisioning.
+ * Returns a {@link List} of managed profiles managed by some profile owner within the profile
+ * group of the given user, or an empty {@link List} if there is not one.
*
- * @param downloaded {@code true} if the dpc has been downloaded during provisioning.
- * {@code false} otherwise.
+ * @param user the user whose profile group to look within to return managed profiles
*
* @hide
*/
@SystemApi
- @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS)
- public void setDpcDownloaded(boolean downloaded) {
- throwIfParentInstance("setDpcDownloaded");
+ @RequiresPermission(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS)
+ @NonNull
+ public List<UserHandle> getPolicyManagedProfiles(@NonNull UserHandle user) {
+ Objects.requireNonNull(user);
if (mService != null) {
try {
- mService.setDpcDownloaded(downloaded);
+ return mService.getPolicyManagedProfiles(user);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
- }
-
- /**
- * Returns the package name of the device policy management role holder.
- *
- * <p>If the device policy management role holder is not configured for this device, returns
- * {@code null}.
- */
- @Nullable
- public String getDevicePolicyManagementRoleHolderPackage() {
- String deviceManagerConfig = mContext.getString(
- com.android.internal.R.string.config_devicePolicyManagement);
- return extractPackageNameFromDeviceManagerConfig(deviceManagerConfig);
+ return Collections.emptyList();
}
/**
@@ -15723,4 +15424,23 @@ public class DevicePolicyManager {
}
return deviceManagerConfig;
}
+
+ /**
+ * @return {@code true} if bypassing the device policy management role qualification is allowed
+ * with the current state of the device.
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS)
+ public boolean shouldAllowBypassingDevicePolicyManagementRoleQualification() {
+ if (mService != null) {
+ try {
+ return mService.shouldAllowBypassingDevicePolicyManagementRoleQualification();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ return false;
+ }
}
diff --git a/core/java/android/app/admin/DevicePolicyResources.java b/core/java/android/app/admin/DevicePolicyResources.java
index 042e407becb4..2b3780e5a32b 100644
--- a/core/java/android/app/admin/DevicePolicyResources.java
+++ b/core/java/android/app/admin/DevicePolicyResources.java
@@ -16,531 +16,39 @@
package android.app.admin;
-import static android.app.admin.DevicePolicyResources.Strings.Core.CANT_ADD_ACCOUNT_MESSAGE;
-import static android.app.admin.DevicePolicyResources.Strings.Core.FORWARD_INTENT_TO_PERSONAL;
-import static android.app.admin.DevicePolicyResources.Strings.Core.FORWARD_INTENT_TO_WORK;
-import static android.app.admin.DevicePolicyResources.Strings.Core.LOCATION_CHANGED_MESSAGE;
-import static android.app.admin.DevicePolicyResources.Strings.Core.LOCATION_CHANGED_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Core.NETWORK_LOGGING_MESSAGE;
-import static android.app.admin.DevicePolicyResources.Strings.Core.NETWORK_LOGGING_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Core.NOTIFICATION_CHANNEL_DEVICE_ADMIN;
-import static android.app.admin.DevicePolicyResources.Strings.Core.NOTIFICATION_WORK_PROFILE_CONTENT_DESCRIPTION;
-import static android.app.admin.DevicePolicyResources.Strings.Core.PACKAGE_DELETED_BY_DO;
-import static android.app.admin.DevicePolicyResources.Strings.Core.PACKAGE_INSTALLED_BY_DO;
-import static android.app.admin.DevicePolicyResources.Strings.Core.PACKAGE_UPDATED_BY_DO;
-import static android.app.admin.DevicePolicyResources.Strings.Core.PERSONAL_APP_SUSPENSION_MESSAGE;
-import static android.app.admin.DevicePolicyResources.Strings.Core.PERSONAL_APP_SUSPENSION_SOON_MESSAGE;
-import static android.app.admin.DevicePolicyResources.Strings.Core.PERSONAL_APP_SUSPENSION_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Core.PERSONAL_APP_SUSPENSION_TURN_ON_PROFILE;
-import static android.app.admin.DevicePolicyResources.Strings.Core.PRINTING_DISABLED_NAMED_ADMIN;
-import static android.app.admin.DevicePolicyResources.Strings.Core.PROFILE_ENCRYPTED_DETAIL;
-import static android.app.admin.DevicePolicyResources.Strings.Core.PROFILE_ENCRYPTED_MESSAGE;
-import static android.app.admin.DevicePolicyResources.Strings.Core.PROFILE_ENCRYPTED_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_CANT_ACCESS_PERSONAL;
-import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_CANT_ACCESS_WORK;
-import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_CANT_SHARE_WITH_PERSONAL;
-import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_CANT_SHARE_WITH_WORK;
-import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_CROSS_PROFILE_BLOCKED_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_NO_PERSONAL_APPS;
-import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_NO_WORK_APPS;
-import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_PERSONAL_TAB;
-import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_PERSONAL_TAB_ACCESSIBILITY;
-import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_WORK_PAUSED_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_WORK_PROFILE_NOT_SUPPORTED;
-import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_WORK_TAB;
-import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_WORK_TAB_ACCESSIBILITY;
-import static android.app.admin.DevicePolicyResources.Strings.Core.SWITCH_TO_PERSONAL_LABEL;
-import static android.app.admin.DevicePolicyResources.Strings.Core.SWITCH_TO_WORK_LABEL;
-import static android.app.admin.DevicePolicyResources.Strings.Core.UNLAUNCHABLE_APP_WORK_PAUSED_MESSAGE;
-import static android.app.admin.DevicePolicyResources.Strings.Core.UNLAUNCHABLE_APP_WORK_PAUSED_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Core.WORK_PROFILE_BADGED_LABEL;
-import static android.app.admin.DevicePolicyResources.Strings.Core.WORK_PROFILE_DELETED_FAILED_PASSWORD_ATTEMPTS_MESSAGE;
-import static android.app.admin.DevicePolicyResources.Strings.Core.WORK_PROFILE_DELETED_GENERIC_MESSAGE;
-import static android.app.admin.DevicePolicyResources.Strings.Core.WORK_PROFILE_DELETED_ORG_OWNED_MESSAGE;
-import static android.app.admin.DevicePolicyResources.Strings.Core.WORK_PROFILE_DELETED_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Dialer.NOTIFICATION_INCOMING_WORK_CALL_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Dialer.NOTIFICATION_MISSED_WORK_CALL_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Dialer.NOTIFICATION_ONGOING_WORK_CALL_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Dialer.NOTIFICATION_WIFI_WORK_CALL_LABEL;
-import static android.app.admin.DevicePolicyResources.Strings.DocumentsUi.CANT_SAVE_TO_PERSONAL_MESSAGE;
-import static android.app.admin.DevicePolicyResources.Strings.DocumentsUi.CANT_SAVE_TO_PERSONAL_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.DocumentsUi.CANT_SAVE_TO_WORK_MESSAGE;
-import static android.app.admin.DevicePolicyResources.Strings.DocumentsUi.CANT_SAVE_TO_WORK_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.DocumentsUi.CANT_SELECT_PERSONAL_FILES_MESSAGE;
-import static android.app.admin.DevicePolicyResources.Strings.DocumentsUi.CANT_SELECT_PERSONAL_FILES_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.DocumentsUi.CANT_SELECT_WORK_FILES_MESSAGE;
-import static android.app.admin.DevicePolicyResources.Strings.DocumentsUi.CANT_SELECT_WORK_FILES_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.DocumentsUi.CROSS_PROFILE_NOT_ALLOWED_MESSAGE;
-import static android.app.admin.DevicePolicyResources.Strings.DocumentsUi.CROSS_PROFILE_NOT_ALLOWED_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.DocumentsUi.PERSONAL_TAB;
-import static android.app.admin.DevicePolicyResources.Strings.DocumentsUi.PREVIEW_WORK_FILE_ACCESSIBILITY;
-import static android.app.admin.DevicePolicyResources.Strings.DocumentsUi.WORK_ACCESSIBILITY;
-import static android.app.admin.DevicePolicyResources.Strings.DocumentsUi.WORK_PROFILE_OFF_ENABLE_BUTTON;
-import static android.app.admin.DevicePolicyResources.Strings.DocumentsUi.WORK_PROFILE_OFF_ERROR_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.DocumentsUi.WORK_TAB;
-import static android.app.admin.DevicePolicyResources.Strings.Launcher.ALL_APPS_PERSONAL_TAB;
-import static android.app.admin.DevicePolicyResources.Strings.Launcher.ALL_APPS_PERSONAL_TAB_ACCESSIBILITY;
-import static android.app.admin.DevicePolicyResources.Strings.Launcher.ALL_APPS_WORK_TAB;
-import static android.app.admin.DevicePolicyResources.Strings.Launcher.ALL_APPS_WORK_TAB_ACCESSIBILITY;
-import static android.app.admin.DevicePolicyResources.Strings.Launcher.DISABLED_BY_ADMIN_MESSAGE;
-import static android.app.admin.DevicePolicyResources.Strings.Launcher.WIDGETS_PERSONAL_TAB;
-import static android.app.admin.DevicePolicyResources.Strings.Launcher.WIDGETS_WORK_TAB;
-import static android.app.admin.DevicePolicyResources.Strings.Launcher.WORK_FOLDER_NAME;
-import static android.app.admin.DevicePolicyResources.Strings.Launcher.WORK_PROFILE_EDU;
-import static android.app.admin.DevicePolicyResources.Strings.Launcher.WORK_PROFILE_EDU_ACCEPT;
-import static android.app.admin.DevicePolicyResources.Strings.Launcher.WORK_PROFILE_ENABLE_BUTTON;
-import static android.app.admin.DevicePolicyResources.Strings.Launcher.WORK_PROFILE_PAUSED_DESCRIPTION;
-import static android.app.admin.DevicePolicyResources.Strings.Launcher.WORK_PROFILE_PAUSE_BUTTON;
-import static android.app.admin.DevicePolicyResources.Strings.MediaProvider.BLOCKED_BY_ADMIN_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.MediaProvider.BLOCKED_FROM_PERSONAL_MESSAGE;
-import static android.app.admin.DevicePolicyResources.Strings.MediaProvider.BLOCKED_FROM_WORK_MESSAGE;
-import static android.app.admin.DevicePolicyResources.Strings.MediaProvider.SWITCH_TO_PERSONAL_MESSAGE;
-import static android.app.admin.DevicePolicyResources.Strings.MediaProvider.SWITCH_TO_WORK_MESSAGE;
-import static android.app.admin.DevicePolicyResources.Strings.MediaProvider.WORK_PROFILE_PAUSED_MESSAGE;
-import static android.app.admin.DevicePolicyResources.Strings.PermissionController.BACKGROUND_ACCESS_DISABLED_BY_ADMIN_MESSAGE;
-import static android.app.admin.DevicePolicyResources.Strings.PermissionController.BACKGROUND_ACCESS_ENABLED_BY_ADMIN_MESSAGE;
-import static android.app.admin.DevicePolicyResources.Strings.PermissionController.FOREGROUND_ACCESS_ENABLED_BY_ADMIN_MESSAGE;
-import static android.app.admin.DevicePolicyResources.Strings.PermissionController.HOME_MISSING_WORK_PROFILE_SUPPORT_MESSAGE;
-import static android.app.admin.DevicePolicyResources.Strings.PermissionController.LOCATION_AUTO_GRANTED_MESSAGE;
-import static android.app.admin.DevicePolicyResources.Strings.PermissionController.WORK_PROFILE_DEFAULT_APPS_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.ACCESSIBILITY_CATEGORY_PERSONAL;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.ACCESSIBILITY_CATEGORY_WORK;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.ACCESSIBILITY_PERSONAL_ACCOUNT_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.ACCESSIBILITY_WORK_ACCOUNT_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.ACCOUNTS_SEARCH_KEYWORDS;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.ACTIVATE_DEVICE_ADMIN_APP;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.ACTIVATE_DEVICE_ADMIN_APP_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.ACTIVATE_THIS_DEVICE_ADMIN_APP;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.ACTIVE_DEVICE_ADMIN_WARNING;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.ADMIN_ACTIONS_APPS_COUNT;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.ADMIN_ACTIONS_APPS_COUNT_MINIMUM;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.ADMIN_ACTION_ACCESS_CAMERA;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.ADMIN_ACTION_ACCESS_LOCATION;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.ADMIN_ACTION_ACCESS_MICROPHONE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.ADMIN_ACTION_APPS_COUNT_ESTIMATED;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.ADMIN_ACTION_APPS_INSTALLED;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.ADMIN_ACTION_NONE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.ADMIN_ACTION_SET_CURRENT_INPUT_METHOD;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.ADMIN_ACTION_SET_DEFAULT_APPS;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.ADMIN_ACTION_SET_HTTP_PROXY;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.ADMIN_ACTION_SET_INPUT_METHOD_NAME;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.ADMIN_CAN_LOCK_DEVICE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.ADMIN_CAN_SEE_APPS_WARNING;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.ADMIN_CAN_SEE_BUG_REPORT_WARNING;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.ADMIN_CAN_SEE_NETWORK_LOGS_WARNING;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.ADMIN_CAN_SEE_SECURITY_LOGS_WARNING;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.ADMIN_CAN_SEE_USAGE_WARNING;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.ADMIN_CAN_SEE_WORK_DATA_WARNING;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.ADMIN_CAN_WIPE_DEVICE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.ADMIN_CONFIGURED_FAILED_PASSWORD_WIPE_DEVICE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.ADMIN_CONFIGURED_FAILED_PASSWORD_WIPE_WORK_PROFILE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.ALWAYS_ON_VPN_DEVICE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.ALWAYS_ON_VPN_PERSONAL_PROFILE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.ALWAYS_ON_VPN_WORK_PROFILE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.APP_CAN_ACCESS_PERSONAL_DATA;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.APP_CAN_ACCESS_PERSONAL_PERMISSIONS;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.CA_CERTS_DEVICE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.CA_CERTS_PERSONAL_PROFILE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.CA_CERTS_WORK_PROFILE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.CHANGES_MADE_BY_YOUR_ORGANIZATION_ADMIN_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.CONFIRM_WORK_PROFILE_PASSWORD_HEADER;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.CONFIRM_WORK_PROFILE_PATTERN_HEADER;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.CONFIRM_WORK_PROFILE_PIN_HEADER;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.CONNECTED_APPS_SEARCH_KEYWORDS;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.CONNECTED_APPS_SHARE_PERMISSIONS_AND_DATA;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.CONNECTED_WORK_AND_PERSONAL_APPS_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.CONNECT_APPS_DIALOG_SUMMARY;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.CONNECT_APPS_DIALOG_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.CONTACT_YOUR_IT_ADMIN;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.CONTROLLED_BY_ADMIN_SUMMARY;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.CROSS_PROFILE_CALENDAR_SUMMARY;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.CROSS_PROFILE_CALENDAR_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.DEVICE_ADMIN_POLICIES_WARNING;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.DEVICE_ADMIN_SETTINGS_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.DEVICE_MANAGED_WITHOUT_NAME;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.DEVICE_MANAGED_WITH_NAME;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.DEVICE_OWNER_INSTALLED_CERTIFICATE_AUTHORITY_WARNING;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.DISABLED_BY_IT_ADMIN_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.ENABLE_WORK_PROFILE_SYNC_WITH_PERSONAL_SOUNDS_DIALOG_MESSAGE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.ENABLE_WORK_PROFILE_SYNC_WITH_PERSONAL_SOUNDS_DIALOG_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.ENTERPRISE_PRIVACY_HEADER;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.ERROR_MOVE_DEVICE_ADMIN;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.FACE_SETTINGS_FOR_WORK_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.FACE_UNLOCK_DISABLED;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.FINGERPRINT_FOR_WORK;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.FINGERPRINT_UNLOCK_DISABLED;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.FINGERPRINT_UNLOCK_DISABLED_EXPLANATION;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.FORGOT_PASSWORD_TEXT;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.FORGOT_PASSWORD_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.HOW_TO_DISCONNECT_APPS;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.INFORMATION_YOUR_ORGANIZATION_CAN_SEE_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.INSTALL_IN_PERSONAL_PROFILE_TO_CONNECT_PROMPT;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.INSTALL_IN_WORK_PROFILE_TO_CONNECT_PROMPT;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.IT_ADMIN_POLICY_DISABLING_INFO_URL;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.MANAGED_BY;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.MANAGED_DEVICE_INFO;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.MANAGED_DEVICE_INFO_SUMMARY;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.MANAGED_DEVICE_INFO_SUMMARY_WITH_NAME;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.MANAGED_PROFILE_SETTINGS_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.MANAGE_DEVICE_ADMIN_APPS;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.NEW_DEVICE_ADMIN_WARNING;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.NEW_DEVICE_ADMIN_WARNING_SIMPLIFIED;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.NO_DEVICE_ADMINS;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.NUMBER_OF_DEVICE_ADMINS;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.NUMBER_OF_DEVICE_ADMINS_NONE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.ONLY_CONNECT_TRUSTED_APPS;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.OTHER_OPTIONS_DISABLED_BY_ADMIN;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.PASSWORD_RECENTLY_USED;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.PERSONAL_CATEGORY_HEADER;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.PERSONAL_PROFILE_APP_SUBTEXT;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.PIN_RECENTLY_USED;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.REENTER_WORK_PROFILE_PASSWORD_HEADER;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.REENTER_WORK_PROFILE_PIN_HEADER;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.REMOVE_ACCOUNT_FAILED_ADMIN_RESTRICTION;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.REMOVE_AND_UNINSTALL_DEVICE_ADMIN;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.REMOVE_DEVICE_ADMIN;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.REMOVE_WORK_PROFILE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.SELECT_DEVICE_ADMIN_APPS;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.SET_PROFILE_OWNER_DIALOG_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.SET_PROFILE_OWNER_POSTSETUP_WARNING;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.SET_PROFILE_OWNER_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.SET_WORK_PROFILE_PASSWORD_HEADER;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.SET_WORK_PROFILE_PATTERN_HEADER;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.SET_WORK_PROFILE_PIN_HEADER;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.SHARE_REMOTE_BUGREPORT_DIALOG_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.SHARE_REMOTE_BUGREPORT_FINISHED_REQUEST_CONSENT;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.SHARE_REMOTE_BUGREPORT_NOT_FINISHED_REQUEST_CONSENT;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.SHARING_REMOTE_BUGREPORT_MESSAGE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.UNINSTALL_DEVICE_ADMIN;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.USER_ADMIN_POLICIES_WARNING;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_APPS_CANNOT_ACCESS_NOTIFICATION_SETTINGS;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_CATEGORY_HEADER;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_ADMIN_POLICIES_WARNING;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_ALARM_RINGTONE_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_APP_SUBTEXT;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_CONFIRM_PATTERN;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_CONFIRM_PIN;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_CONFIRM_REMOVE_MESSAGE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_CONFIRM_REMOVE_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_CONTACT_SEARCH_SUMMARY;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_CONTACT_SEARCH_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_DISABLE_USAGE_ACCESS_WARNING;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_FINGERPRINT_LAST_DELETE_MESSAGE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_INSTALLED_CERTIFICATE_AUTHORITY_WARNING;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_IT_ADMIN_CANT_RESET_SCREEN_LOCK;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_KEYBOARDS_AND_TOOLS;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_LAST_PASSWORD_ATTEMPT_BEFORE_WIPE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_LAST_PATTERN_ATTEMPT_BEFORE_WIPE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_LAST_PIN_ATTEMPT_BEFORE_WIPE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_LOCATION_SWITCH_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_LOCKED_NOTIFICATION_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_LOCK_ATTEMPTS_FAILED;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_LOCK_SCREEN_REDACT_NOTIFICATION_SUMMARY;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_LOCK_SCREEN_REDACT_NOTIFICATION_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_MANAGED_BY;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_NOTIFICATIONS_SECTION_HEADER;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_NOTIFICATION_LISTENER_BLOCKED;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_NOTIFICATION_RINGTONE_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_NOT_AVAILABLE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_OFF_CONDITION_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_PASSWORD_REQUIRED;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_PRIVACY_POLICY_INFO;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_PRIVACY_POLICY_INFO_SUMMARY;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_RINGTONE_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_SCREEN_LOCK_SETUP_MESSAGE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_SECURITY_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_SETTING;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_SETTING_OFF_SUMMARY;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_SETTING_ON_SUMMARY;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_SET_UNLOCK_LAUNCH_PICKER_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_SOUND_SETTINGS_SECTION_HEADER;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_SYNC_WITH_PERSONAL_SOUNDS_ACTIVE_SUMMARY;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_UNIFICATION_SEARCH_KEYWORDS;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_UNIFY_LOCKS_DETAIL;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_UNIFY_LOCKS_NONCOMPLIANT;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_UNIFY_LOCKS_SUMMARY;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_UNIFY_LOCKS_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_USER_LABEL;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_USE_PERSONAL_SOUNDS_SUMMARY;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_USE_PERSONAL_SOUNDS_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.YOUR_ACCESS_TO_THIS_DEVICE_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.SystemUi.BIOMETRIC_DIALOG_WORK_LOCK_FAILED_ATTEMPTS;
-import static android.app.admin.DevicePolicyResources.Strings.SystemUi.BIOMETRIC_DIALOG_WORK_PASSWORD_LAST_ATTEMPT;
-import static android.app.admin.DevicePolicyResources.Strings.SystemUi.BIOMETRIC_DIALOG_WORK_PATTERN_LAST_ATTEMPT;
-import static android.app.admin.DevicePolicyResources.Strings.SystemUi.BIOMETRIC_DIALOG_WORK_PIN_LAST_ATTEMPT;
-import static android.app.admin.DevicePolicyResources.Strings.SystemUi.KEYGUARD_MANAGEMENT_DISCLOSURE;
-import static android.app.admin.DevicePolicyResources.Strings.SystemUi.KEYGUARD_NAMED_MANAGEMENT_DISCLOSURE;
-import static android.app.admin.DevicePolicyResources.Strings.SystemUi.ONGOING_PRIVACY_DIALOG_WORK;
-import static android.app.admin.DevicePolicyResources.Strings.SystemUi.QS_DIALOG_MANAGEMENT;
-import static android.app.admin.DevicePolicyResources.Strings.SystemUi.QS_DIALOG_MANAGEMENT_CA_CERT;
-import static android.app.admin.DevicePolicyResources.Strings.SystemUi.QS_DIALOG_MANAGEMENT_NAMED_VPN;
-import static android.app.admin.DevicePolicyResources.Strings.SystemUi.QS_DIALOG_MANAGEMENT_NETWORK;
-import static android.app.admin.DevicePolicyResources.Strings.SystemUi.QS_DIALOG_MANAGEMENT_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.SystemUi.QS_DIALOG_MANAGEMENT_TWO_NAMED_VPN;
-import static android.app.admin.DevicePolicyResources.Strings.SystemUi.QS_DIALOG_NAMED_MANAGEMENT;
-import static android.app.admin.DevicePolicyResources.Strings.SystemUi.QS_DIALOG_PERSONAL_PROFILE_NAMED_VPN;
-import static android.app.admin.DevicePolicyResources.Strings.SystemUi.QS_DIALOG_VIEW_POLICIES;
-import static android.app.admin.DevicePolicyResources.Strings.SystemUi.QS_DIALOG_WORK_PROFILE_CA_CERT;
-import static android.app.admin.DevicePolicyResources.Strings.SystemUi.QS_DIALOG_WORK_PROFILE_NAMED_VPN;
-import static android.app.admin.DevicePolicyResources.Strings.SystemUi.QS_DIALOG_WORK_PROFILE_NETWORK;
-import static android.app.admin.DevicePolicyResources.Strings.SystemUi.QS_MSG_MANAGEMENT;
-import static android.app.admin.DevicePolicyResources.Strings.SystemUi.QS_MSG_MANAGEMENT_MONITORING;
-import static android.app.admin.DevicePolicyResources.Strings.SystemUi.QS_MSG_MANAGEMENT_MULTIPLE_VPNS;
-import static android.app.admin.DevicePolicyResources.Strings.SystemUi.QS_MSG_MANAGEMENT_NAMED_VPN;
-import static android.app.admin.DevicePolicyResources.Strings.SystemUi.QS_MSG_NAMED_MANAGEMENT;
-import static android.app.admin.DevicePolicyResources.Strings.SystemUi.QS_MSG_NAMED_MANAGEMENT_MONITORING;
-import static android.app.admin.DevicePolicyResources.Strings.SystemUi.QS_MSG_NAMED_MANAGEMENT_MULTIPLE_VPNS;
-import static android.app.admin.DevicePolicyResources.Strings.SystemUi.QS_MSG_NAMED_MANAGEMENT_NAMED_VPN;
-import static android.app.admin.DevicePolicyResources.Strings.SystemUi.QS_MSG_NAMED_WORK_PROFILE_MONITORING;
-import static android.app.admin.DevicePolicyResources.Strings.SystemUi.QS_MSG_PERSONAL_PROFILE_NAMED_VPN;
-import static android.app.admin.DevicePolicyResources.Strings.SystemUi.QS_MSG_WORK_PROFILE_MONITORING;
-import static android.app.admin.DevicePolicyResources.Strings.SystemUi.QS_MSG_WORK_PROFILE_NAMED_VPN;
-import static android.app.admin.DevicePolicyResources.Strings.SystemUi.QS_MSG_WORK_PROFILE_NETWORK;
-import static android.app.admin.DevicePolicyResources.Strings.SystemUi.STATUS_BAR_WORK_ICON_ACCESSIBILITY;
-import static android.app.admin.DevicePolicyResources.Strings.SystemUi.WORK_LOCK_ACCESSIBILITY;
-
-import android.annotation.StringDef;
-import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.os.UserHandle;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.HashSet;
-import java.util.Set;
-
/**
* Class containing the required identifiers to update device management resources.
*
- * <p>See {@link DevicePolicyManager#getDrawable} and
- * {@code DevicePolicyManager#getString}.
+ * <p>See {@link DevicePolicyResourcesManager#getDrawable} and
+ * {@link DevicePolicyResourcesManager#getString}.
*/
public final class DevicePolicyResources {
private DevicePolicyResources() {}
/**
- * Resource identifiers used to update device management-related system drawable resources.
- *
- * @hide
- */
- @Retention(RetentionPolicy.SOURCE)
- @StringDef(value = {
- Drawables.UNDEFINED,
- Drawables.WORK_PROFILE_ICON_BADGE,
- Drawables.WORK_PROFILE_ICON,
- Drawables.WORK_PROFILE_OFF_ICON,
- Drawables.WORK_PROFILE_USER_ICON
- })
- public @interface UpdatableDrawableId {
- }
-
- /**
- * Identifiers to specify the desired style for the updatable device management system
- * resource.
- *
- * @hide
- */
- @Retention(RetentionPolicy.SOURCE)
- @StringDef(value = {
- Drawables.Style.SOLID_COLORED,
- Drawables.Style.SOLID_NOT_COLORED,
- Drawables.Style.OUTLINE,
- Drawables.Style.DEFAULT
- })
- public @interface UpdatableDrawableStyle {
- }
-
- /**
- * Identifiers to specify the location if the updatable device management system resource.
- *
- * @hide
+ * An identifier used for:
+ * <ul>
+ * <li>un-updatable resource IDs</li>
+ * <li>undefined sources</li>
+ * </ul>
*/
- @Retention(RetentionPolicy.SOURCE)
- @StringDef(value = {
- Drawables.Source.UNDEFINED,
- Drawables.Source.NOTIFICATION,
- Drawables.Source.PROFILE_SWITCH_ANIMATION,
- Drawables.Source.HOME_WIDGET,
- Drawables.Source.LAUNCHER_OFF_BUTTON,
- Drawables.Source.QUICK_SETTINGS,
- Drawables.Source.STATUS_BAR
- })
- public @interface UpdatableDrawableSource {
- }
+ public static final String UNDEFINED = "UNDEFINED";
/**
- * Resource identifiers used to update device management-related string resources.
+ * Class containing the identifiers used to update device management-related system drawable.
*
* @hide
*/
- @Retention(RetentionPolicy.SOURCE)
- @StringDef({
- // Launcher Strings
- WORK_PROFILE_EDU, WORK_PROFILE_EDU_ACCEPT, Strings.Launcher.WORK_PROFILE_PAUSED_TITLE,
- WORK_PROFILE_PAUSED_DESCRIPTION, WORK_PROFILE_PAUSE_BUTTON, WORK_PROFILE_ENABLE_BUTTON,
- ALL_APPS_WORK_TAB, ALL_APPS_PERSONAL_TAB, ALL_APPS_WORK_TAB_ACCESSIBILITY,
- ALL_APPS_PERSONAL_TAB_ACCESSIBILITY, WORK_FOLDER_NAME, WIDGETS_WORK_TAB,
- WIDGETS_PERSONAL_TAB, DISABLED_BY_ADMIN_MESSAGE,
-
- // SysUI Strings
- QS_MSG_MANAGEMENT, QS_MSG_NAMED_MANAGEMENT, QS_MSG_MANAGEMENT_MONITORING,
- QS_MSG_NAMED_MANAGEMENT_MONITORING, QS_MSG_MANAGEMENT_NAMED_VPN,
- QS_MSG_NAMED_MANAGEMENT_NAMED_VPN, QS_MSG_MANAGEMENT_MULTIPLE_VPNS,
- QS_MSG_NAMED_MANAGEMENT_MULTIPLE_VPNS, QS_MSG_WORK_PROFILE_MONITORING,
- QS_MSG_NAMED_WORK_PROFILE_MONITORING, QS_MSG_WORK_PROFILE_NETWORK,
- QS_MSG_WORK_PROFILE_NAMED_VPN, QS_MSG_PERSONAL_PROFILE_NAMED_VPN,
- QS_DIALOG_MANAGEMENT_TITLE, QS_DIALOG_VIEW_POLICIES, QS_DIALOG_MANAGEMENT,
- QS_DIALOG_NAMED_MANAGEMENT, QS_DIALOG_MANAGEMENT_CA_CERT,
- QS_DIALOG_WORK_PROFILE_CA_CERT, QS_DIALOG_MANAGEMENT_NETWORK,
- QS_DIALOG_WORK_PROFILE_NETWORK, QS_DIALOG_MANAGEMENT_NAMED_VPN,
- QS_DIALOG_MANAGEMENT_TWO_NAMED_VPN, QS_DIALOG_WORK_PROFILE_NAMED_VPN,
- QS_DIALOG_PERSONAL_PROFILE_NAMED_VPN, BIOMETRIC_DIALOG_WORK_PIN_LAST_ATTEMPT,
- BIOMETRIC_DIALOG_WORK_PATTERN_LAST_ATTEMPT, BIOMETRIC_DIALOG_WORK_PASSWORD_LAST_ATTEMPT,
- BIOMETRIC_DIALOG_WORK_LOCK_FAILED_ATTEMPTS, STATUS_BAR_WORK_ICON_ACCESSIBILITY,
- ONGOING_PRIVACY_DIALOG_WORK, KEYGUARD_MANAGEMENT_DISCLOSURE,
- KEYGUARD_NAMED_MANAGEMENT_DISCLOSURE, WORK_LOCK_ACCESSIBILITY,
-
- // Core Strings
- WORK_PROFILE_DELETED_TITLE, WORK_PROFILE_DELETED_FAILED_PASSWORD_ATTEMPTS_MESSAGE,
- WORK_PROFILE_DELETED_GENERIC_MESSAGE, WORK_PROFILE_DELETED_ORG_OWNED_MESSAGE,
- PERSONAL_APP_SUSPENSION_TITLE, PERSONAL_APP_SUSPENSION_MESSAGE,
- PERSONAL_APP_SUSPENSION_SOON_MESSAGE, PERSONAL_APP_SUSPENSION_TURN_ON_PROFILE,
- PRINTING_DISABLED_NAMED_ADMIN, LOCATION_CHANGED_TITLE, LOCATION_CHANGED_MESSAGE,
- NETWORK_LOGGING_TITLE, NETWORK_LOGGING_MESSAGE,
- NOTIFICATION_WORK_PROFILE_CONTENT_DESCRIPTION, NOTIFICATION_CHANNEL_DEVICE_ADMIN,
- SWITCH_TO_WORK_LABEL, SWITCH_TO_PERSONAL_LABEL, FORWARD_INTENT_TO_WORK,
- FORWARD_INTENT_TO_PERSONAL, RESOLVER_WORK_PROFILE_NOT_SUPPORTED, RESOLVER_PERSONAL_TAB,
- RESOLVER_WORK_TAB, RESOLVER_PERSONAL_TAB_ACCESSIBILITY, RESOLVER_WORK_TAB_ACCESSIBILITY,
- RESOLVER_CROSS_PROFILE_BLOCKED_TITLE, RESOLVER_CANT_SHARE_WITH_PERSONAL,
- RESOLVER_CANT_SHARE_WITH_WORK, RESOLVER_CANT_ACCESS_PERSONAL, RESOLVER_CANT_ACCESS_WORK,
- RESOLVER_WORK_PAUSED_TITLE, RESOLVER_NO_WORK_APPS, RESOLVER_NO_PERSONAL_APPS,
- CANT_ADD_ACCOUNT_MESSAGE, PACKAGE_INSTALLED_BY_DO, PACKAGE_UPDATED_BY_DO,
- PACKAGE_DELETED_BY_DO, UNLAUNCHABLE_APP_WORK_PAUSED_TITLE,
- UNLAUNCHABLE_APP_WORK_PAUSED_MESSAGE, PROFILE_ENCRYPTED_TITLE, PROFILE_ENCRYPTED_DETAIL,
- PROFILE_ENCRYPTED_MESSAGE, WORK_PROFILE_BADGED_LABEL,
-
- // DocsUi Strings
- WORK_PROFILE_OFF_ERROR_TITLE, WORK_PROFILE_OFF_ENABLE_BUTTON,
- CANT_SELECT_WORK_FILES_TITLE, CANT_SELECT_WORK_FILES_MESSAGE,
- CANT_SELECT_PERSONAL_FILES_TITLE, CANT_SELECT_PERSONAL_FILES_MESSAGE,
- CANT_SAVE_TO_WORK_TITLE, CANT_SAVE_TO_WORK_MESSAGE, CANT_SAVE_TO_PERSONAL_TITLE,
- CANT_SAVE_TO_PERSONAL_MESSAGE, CROSS_PROFILE_NOT_ALLOWED_TITLE,
- CROSS_PROFILE_NOT_ALLOWED_MESSAGE, PREVIEW_WORK_FILE_ACCESSIBILITY, PERSONAL_TAB,
- WORK_TAB, WORK_ACCESSIBILITY,
-
- // MediaProvider Strings
- SWITCH_TO_WORK_MESSAGE, SWITCH_TO_PERSONAL_MESSAGE, BLOCKED_BY_ADMIN_TITLE,
- BLOCKED_FROM_PERSONAL_MESSAGE, BLOCKED_FROM_PERSONAL_MESSAGE,
- BLOCKED_FROM_WORK_MESSAGE, Strings.MediaProvider.WORK_PROFILE_PAUSED_TITLE,
- WORK_PROFILE_PAUSED_MESSAGE,
-
- // Settings Strings
- FACE_SETTINGS_FOR_WORK_TITLE, WORK_PROFILE_FINGERPRINT_LAST_DELETE_MESSAGE,
- WORK_PROFILE_IT_ADMIN_CANT_RESET_SCREEN_LOCK, WORK_PROFILE_SCREEN_LOCK_SETUP_MESSAGE,
- WORK_PROFILE_SET_UNLOCK_LAUNCH_PICKER_TITLE,
- WORK_PROFILE_LAST_PATTERN_ATTEMPT_BEFORE_WIPE,
- WORK_PROFILE_LAST_PIN_ATTEMPT_BEFORE_WIPE,
- WORK_PROFILE_LAST_PASSWORD_ATTEMPT_BEFORE_WIPE, WORK_PROFILE_LOCK_ATTEMPTS_FAILED,
- ACCESSIBILITY_CATEGORY_WORK, ACCESSIBILITY_CATEGORY_PERSONAL,
- ACCESSIBILITY_WORK_ACCOUNT_TITLE, ACCESSIBILITY_PERSONAL_ACCOUNT_TITLE,
- WORK_PROFILE_LOCATION_SWITCH_TITLE, SET_WORK_PROFILE_PASSWORD_HEADER,
- SET_WORK_PROFILE_PIN_HEADER, SET_WORK_PROFILE_PATTERN_HEADER,
- CONFIRM_WORK_PROFILE_PASSWORD_HEADER, CONFIRM_WORK_PROFILE_PIN_HEADER,
- CONFIRM_WORK_PROFILE_PATTERN_HEADER, REENTER_WORK_PROFILE_PASSWORD_HEADER,
- REENTER_WORK_PROFILE_PIN_HEADER, WORK_PROFILE_CONFIRM_PATTERN, WORK_PROFILE_CONFIRM_PIN,
- WORK_PROFILE_PASSWORD_REQUIRED, WORK_PROFILE_SECURITY_TITLE,
- WORK_PROFILE_UNIFY_LOCKS_TITLE, WORK_PROFILE_UNIFY_LOCKS_SUMMARY,
- WORK_PROFILE_UNIFY_LOCKS_DETAIL, WORK_PROFILE_UNIFY_LOCKS_NONCOMPLIANT,
- WORK_PROFILE_KEYBOARDS_AND_TOOLS, WORK_PROFILE_NOT_AVAILABLE, WORK_PROFILE_SETTING,
- WORK_PROFILE_SETTING_ON_SUMMARY, WORK_PROFILE_SETTING_OFF_SUMMARY, REMOVE_WORK_PROFILE,
- DEVICE_OWNER_INSTALLED_CERTIFICATE_AUTHORITY_WARNING,
- WORK_PROFILE_INSTALLED_CERTIFICATE_AUTHORITY_WARNING, WORK_PROFILE_CONFIRM_REMOVE_TITLE,
- WORK_PROFILE_CONFIRM_REMOVE_MESSAGE, WORK_APPS_CANNOT_ACCESS_NOTIFICATION_SETTINGS,
- WORK_PROFILE_SOUND_SETTINGS_SECTION_HEADER, WORK_PROFILE_USE_PERSONAL_SOUNDS_TITLE,
- WORK_PROFILE_USE_PERSONAL_SOUNDS_SUMMARY, WORK_PROFILE_RINGTONE_TITLE,
- WORK_PROFILE_NOTIFICATION_RINGTONE_TITLE, WORK_PROFILE_ALARM_RINGTONE_TITLE,
- WORK_PROFILE_SYNC_WITH_PERSONAL_SOUNDS_ACTIVE_SUMMARY,
- ENABLE_WORK_PROFILE_SYNC_WITH_PERSONAL_SOUNDS_DIALOG_TITLE,
- ENABLE_WORK_PROFILE_SYNC_WITH_PERSONAL_SOUNDS_DIALOG_MESSAGE,
- WORK_PROFILE_NOTIFICATIONS_SECTION_HEADER, WORK_PROFILE_LOCKED_NOTIFICATION_TITLE,
- WORK_PROFILE_LOCK_SCREEN_REDACT_NOTIFICATION_TITLE,
- WORK_PROFILE_LOCK_SCREEN_REDACT_NOTIFICATION_SUMMARY,
- WORK_PROFILE_NOTIFICATION_LISTENER_BLOCKED, CONNECTED_WORK_AND_PERSONAL_APPS_TITLE,
- CONNECTED_APPS_SHARE_PERMISSIONS_AND_DATA, ONLY_CONNECT_TRUSTED_APPS,
- HOW_TO_DISCONNECT_APPS, CONNECT_APPS_DIALOG_TITLE, CONNECT_APPS_DIALOG_SUMMARY,
- APP_CAN_ACCESS_PERSONAL_DATA, APP_CAN_ACCESS_PERSONAL_PERMISSIONS,
- INSTALL_IN_WORK_PROFILE_TO_CONNECT_PROMPT,
- INSTALL_IN_PERSONAL_PROFILE_TO_CONNECT_PROMPT, WORK_PROFILE_MANAGED_BY, MANAGED_BY,
- WORK_PROFILE_DISABLE_USAGE_ACCESS_WARNING, DISABLED_BY_IT_ADMIN_TITLE,
- CONTACT_YOUR_IT_ADMIN, WORK_PROFILE_ADMIN_POLICIES_WARNING, USER_ADMIN_POLICIES_WARNING,
- DEVICE_ADMIN_POLICIES_WARNING, WORK_PROFILE_OFF_CONDITION_TITLE,
- MANAGED_PROFILE_SETTINGS_TITLE, WORK_PROFILE_CONTACT_SEARCH_TITLE,
- WORK_PROFILE_CONTACT_SEARCH_SUMMARY, CROSS_PROFILE_CALENDAR_TITLE,
- CROSS_PROFILE_CALENDAR_SUMMARY, ALWAYS_ON_VPN_PERSONAL_PROFILE, ALWAYS_ON_VPN_DEVICE,
- ALWAYS_ON_VPN_WORK_PROFILE, CA_CERTS_PERSONAL_PROFILE, CA_CERTS_WORK_PROFILE,
- CA_CERTS_DEVICE, ADMIN_CAN_LOCK_DEVICE, ADMIN_CAN_WIPE_DEVICE,
- ADMIN_CONFIGURED_FAILED_PASSWORD_WIPE_DEVICE,
- ADMIN_CONFIGURED_FAILED_PASSWORD_WIPE_WORK_PROFILE, DEVICE_MANAGED_WITHOUT_NAME,
- DEVICE_MANAGED_WITH_NAME, WORK_PROFILE_APP_SUBTEXT, PERSONAL_PROFILE_APP_SUBTEXT,
- FINGERPRINT_FOR_WORK, FACE_UNLOCK_DISABLED, FINGERPRINT_UNLOCK_DISABLED,
- FINGERPRINT_UNLOCK_DISABLED_EXPLANATION, PIN_RECENTLY_USED, PASSWORD_RECENTLY_USED,
- MANAGE_DEVICE_ADMIN_APPS, NUMBER_OF_DEVICE_ADMINS_NONE, NUMBER_OF_DEVICE_ADMINS,
- FORGOT_PASSWORD_TITLE, FORGOT_PASSWORD_TEXT, ERROR_MOVE_DEVICE_ADMIN,
- DEVICE_ADMIN_SETTINGS_TITLE, REMOVE_DEVICE_ADMIN, UNINSTALL_DEVICE_ADMIN,
- REMOVE_AND_UNINSTALL_DEVICE_ADMIN, SELECT_DEVICE_ADMIN_APPS, NO_DEVICE_ADMINS,
- ACTIVATE_DEVICE_ADMIN_APP, ACTIVATE_THIS_DEVICE_ADMIN_APP,
- ACTIVATE_DEVICE_ADMIN_APP_TITLE, NEW_DEVICE_ADMIN_WARNING,
- NEW_DEVICE_ADMIN_WARNING_SIMPLIFIED, ACTIVE_DEVICE_ADMIN_WARNING,
- SET_PROFILE_OWNER_TITLE, SET_PROFILE_OWNER_DIALOG_TITLE,
- SET_PROFILE_OWNER_POSTSETUP_WARNING, OTHER_OPTIONS_DISABLED_BY_ADMIN,
- REMOVE_ACCOUNT_FAILED_ADMIN_RESTRICTION, IT_ADMIN_POLICY_DISABLING_INFO_URL,
- SHARE_REMOTE_BUGREPORT_DIALOG_TITLE, SHARE_REMOTE_BUGREPORT_FINISHED_REQUEST_CONSENT,
- SHARE_REMOTE_BUGREPORT_NOT_FINISHED_REQUEST_CONSENT, SHARING_REMOTE_BUGREPORT_MESSAGE,
- MANAGED_DEVICE_INFO, MANAGED_DEVICE_INFO_SUMMARY, MANAGED_DEVICE_INFO_SUMMARY_WITH_NAME,
- ENTERPRISE_PRIVACY_HEADER, INFORMATION_YOUR_ORGANIZATION_CAN_SEE_TITLE,
- CHANGES_MADE_BY_YOUR_ORGANIZATION_ADMIN_TITLE, YOUR_ACCESS_TO_THIS_DEVICE_TITLE,
- ADMIN_CAN_SEE_WORK_DATA_WARNING, ADMIN_CAN_SEE_APPS_WARNING,
- ADMIN_CAN_SEE_USAGE_WARNING, ADMIN_CAN_SEE_NETWORK_LOGS_WARNING,
- ADMIN_CAN_SEE_BUG_REPORT_WARNING, ADMIN_CAN_SEE_SECURITY_LOGS_WARNING,
- ADMIN_ACTION_NONE, ADMIN_ACTION_APPS_INSTALLED, ADMIN_ACTION_APPS_COUNT_ESTIMATED,
- ADMIN_ACTIONS_APPS_COUNT_MINIMUM, ADMIN_ACTION_ACCESS_LOCATION,
- ADMIN_ACTION_ACCESS_MICROPHONE, ADMIN_ACTION_ACCESS_CAMERA,
- ADMIN_ACTION_SET_DEFAULT_APPS, ADMIN_ACTIONS_APPS_COUNT,
- ADMIN_ACTION_SET_CURRENT_INPUT_METHOD, ADMIN_ACTION_SET_INPUT_METHOD_NAME,
- ADMIN_ACTION_SET_HTTP_PROXY, WORK_PROFILE_PRIVACY_POLICY_INFO_SUMMARY,
- WORK_PROFILE_PRIVACY_POLICY_INFO, CONNECTED_APPS_SEARCH_KEYWORDS,
- WORK_PROFILE_UNIFICATION_SEARCH_KEYWORDS, ACCOUNTS_SEARCH_KEYWORDS,
- CONTROLLED_BY_ADMIN_SUMMARY, WORK_PROFILE_USER_LABEL, WORK_CATEGORY_HEADER,
- PERSONAL_CATEGORY_HEADER,
-
- // PermissionController Strings
- WORK_PROFILE_DEFAULT_APPS_TITLE, HOME_MISSING_WORK_PROFILE_SUPPORT_MESSAGE,
- BACKGROUND_ACCESS_DISABLED_BY_ADMIN_MESSAGE, BACKGROUND_ACCESS_ENABLED_BY_ADMIN_MESSAGE,
- BACKGROUND_ACCESS_ENABLED_BY_ADMIN_MESSAGE, FOREGROUND_ACCESS_ENABLED_BY_ADMIN_MESSAGE,
- LOCATION_AUTO_GRANTED_MESSAGE,
-
- // Dialer Strings
- NOTIFICATION_INCOMING_WORK_CALL_TITLE, NOTIFICATION_ONGOING_WORK_CALL_TITLE,
- NOTIFICATION_MISSED_WORK_CALL_TITLE, NOTIFICATION_WIFI_WORK_CALL_LABEL,
- })
- public @interface UpdatableStringId {
- }
-
- /**
- * Class containing the identifiers used to update device management-related system drawable.
- */
public static final class Drawables {
private Drawables() {
}
/**
- * An ID for any drawable that can't be updated.
- */
- public static final String UNDEFINED = "UNDEFINED";
-
- /**
* Specifically used to badge work profile app icons.
*/
public static final String WORK_PROFILE_ICON_BADGE = "WORK_PROFILE_ICON_BADGE";
@@ -562,20 +70,6 @@ public final class DevicePolicyResources {
public static final String WORK_PROFILE_USER_ICON = "WORK_PROFILE_USER_ICON";
/**
- * @hide
- */
- public static final Set<String> UPDATABLE_DRAWABLE_IDS = buildDrawablesSet();
-
- private static Set<String> buildDrawablesSet() {
- Set<String> drawables = new HashSet<>();
- drawables.add(WORK_PROFILE_ICON_BADGE);
- drawables.add(WORK_PROFILE_ICON);
- drawables.add(WORK_PROFILE_OFF_ICON);
- drawables.add(WORK_PROFILE_USER_ICON);
- return drawables;
- }
-
- /**
* Class containing the source identifiers used to update device management-related system
* drawable.
*/
@@ -585,12 +79,6 @@ public final class DevicePolicyResources {
}
/**
- * A source identifier indicating that the updatable resource is used in a generic
- * undefined location.
- */
- public static final String UNDEFINED = "UNDEFINED";
-
- /**
* A source identifier indicating that the updatable drawable is used in notifications.
*/
public static final String NOTIFICATION = "NOTIFICATION";
@@ -622,42 +110,18 @@ public final class DevicePolicyResources {
* A source identifier indicating that the updatable drawable is used in the status bar.
*/
public static final String STATUS_BAR = "STATUS_BAR";
-
- /**
- * @hide
- */
- public static final Set<String> UPDATABLE_DRAWABLE_SOURCES = buildSourcesSet();
-
- private static Set<String> buildSourcesSet() {
- Set<String> sources = new HashSet<>();
- sources.add(UNDEFINED);
- sources.add(NOTIFICATION);
- sources.add(PROFILE_SWITCH_ANIMATION);
- sources.add(HOME_WIDGET);
- sources.add(LAUNCHER_OFF_BUTTON);
- sources.add(QUICK_SETTINGS);
- sources.add(STATUS_BAR);
- return sources;
- }
}
/**
* Class containing the style identifiers used to update device management-related system
* drawable.
*/
- @SuppressLint("StaticUtils")
public static final class Style {
private Style() {
}
/**
- * A style identifier indicating that the updatable drawable should use the default
- * style.
- */
- public static final String DEFAULT = "DEFAULT";
-
- /**
* A style identifier indicating that the updatable drawable has a solid color fill.
*/
public static final String SOLID_COLORED = "SOLID_COLORED";
@@ -672,20 +136,6 @@ public final class DevicePolicyResources {
* A style identifier indicating that the updatable drawable is an outline.
*/
public static final String OUTLINE = "OUTLINE";
-
- /**
- * @hide
- */
- public static final Set<String> UPDATABLE_DRAWABLE_STYLES = buildStylesSet();
-
- private static Set<String> buildStylesSet() {
- Set<String> styles = new HashSet<>();
- styles.add(DEFAULT);
- styles.add(SOLID_COLORED);
- styles.add(SOLID_NOT_COLORED);
- styles.add(OUTLINE);
- return styles;
- }
}
}
@@ -701,29 +151,6 @@ public final class DevicePolicyResources {
}
/**
- * An ID for any string that can't be updated.
- */
- public static final String UNDEFINED = "UNDEFINED";
-
- /**
- * @hide
- */
- public static final Set<String> UPDATABLE_STRING_IDS = buildStringsSet();
-
- private static Set<String> buildStringsSet() {
- Set<String> strings = new HashSet<>();
- strings.addAll(Settings.buildStringsSet());
- strings.addAll(Launcher.buildStringsSet());
- strings.addAll(SystemUi.buildStringsSet());
- strings.addAll(Core.buildStringsSet());
- strings.addAll(DocumentsUi.buildStringsSet());
- strings.addAll(MediaProvider.buildStringsSet());
- strings.addAll(PermissionController.buildStringsSet());
- strings.addAll(Dialer.buildStringsSet());
- return strings;
- }
-
- /**
* Class containing the identifiers used to update device management-related system strings
* in the Settings package
*
@@ -1747,288 +1174,6 @@ public final class DevicePolicyResources {
* Header for items under the personal user
*/
public static final String PERSONAL_CATEGORY_HEADER = PREFIX + "category_personal";
-
- /**
- * @hide
- */
- static Set<String> buildStringsSet() {
- Set<String> strings = new HashSet<>();
- strings.add(FACE_SETTINGS_FOR_WORK_TITLE);
- strings.add(WORK_PROFILE_FINGERPRINT_LAST_DELETE_MESSAGE);
- strings.add(WORK_PROFILE_IT_ADMIN_CANT_RESET_SCREEN_LOCK);
- strings.add(WORK_PROFILE_SCREEN_LOCK_SETUP_MESSAGE);
- strings.add(WORK_PROFILE_SET_UNLOCK_LAUNCH_PICKER_TITLE);
- strings.add(WORK_PROFILE_LAST_PATTERN_ATTEMPT_BEFORE_WIPE);
- strings.add(WORK_PROFILE_LAST_PIN_ATTEMPT_BEFORE_WIPE);
- strings.add(WORK_PROFILE_LAST_PASSWORD_ATTEMPT_BEFORE_WIPE);
- strings.add(WORK_PROFILE_LOCK_ATTEMPTS_FAILED);
- strings.add(ACCESSIBILITY_CATEGORY_WORK);
- strings.add(ACCESSIBILITY_CATEGORY_PERSONAL);
- strings.add(ACCESSIBILITY_WORK_ACCOUNT_TITLE);
- strings.add(ACCESSIBILITY_PERSONAL_ACCOUNT_TITLE);
- strings.add(WORK_PROFILE_LOCATION_SWITCH_TITLE);
- strings.add(SET_WORK_PROFILE_PASSWORD_HEADER);
- strings.add(SET_WORK_PROFILE_PIN_HEADER);
- strings.add(SET_WORK_PROFILE_PATTERN_HEADER);
- strings.add(CONFIRM_WORK_PROFILE_PASSWORD_HEADER);
- strings.add(CONFIRM_WORK_PROFILE_PIN_HEADER);
- strings.add(CONFIRM_WORK_PROFILE_PATTERN_HEADER);
- strings.add(REENTER_WORK_PROFILE_PASSWORD_HEADER);
- strings.add(REENTER_WORK_PROFILE_PIN_HEADER);
- strings.add(WORK_PROFILE_CONFIRM_PATTERN);
- strings.add(WORK_PROFILE_CONFIRM_PIN);
- strings.add(WORK_PROFILE_PASSWORD_REQUIRED);
- strings.add(WORK_PROFILE_SECURITY_TITLE);
- strings.add(WORK_PROFILE_UNIFY_LOCKS_TITLE);
- strings.add(WORK_PROFILE_UNIFY_LOCKS_SUMMARY);
- strings.add(WORK_PROFILE_UNIFY_LOCKS_DETAIL);
- strings.add(WORK_PROFILE_UNIFY_LOCKS_NONCOMPLIANT);
- strings.add(WORK_PROFILE_KEYBOARDS_AND_TOOLS);
- strings.add(WORK_PROFILE_NOT_AVAILABLE);
- strings.add(WORK_PROFILE_SETTING);
- strings.add(WORK_PROFILE_SETTING_ON_SUMMARY);
- strings.add(WORK_PROFILE_SETTING_OFF_SUMMARY);
- strings.add(REMOVE_WORK_PROFILE);
- strings.add(DEVICE_OWNER_INSTALLED_CERTIFICATE_AUTHORITY_WARNING);
- strings.add(WORK_PROFILE_INSTALLED_CERTIFICATE_AUTHORITY_WARNING);
- strings.add(WORK_PROFILE_CONFIRM_REMOVE_TITLE);
- strings.add(WORK_PROFILE_CONFIRM_REMOVE_MESSAGE);
- strings.add(WORK_APPS_CANNOT_ACCESS_NOTIFICATION_SETTINGS);
- strings.add(WORK_PROFILE_SOUND_SETTINGS_SECTION_HEADER);
- strings.add(WORK_PROFILE_USE_PERSONAL_SOUNDS_TITLE);
- strings.add(WORK_PROFILE_USE_PERSONAL_SOUNDS_SUMMARY);
- strings.add(WORK_PROFILE_RINGTONE_TITLE);
- strings.add(WORK_PROFILE_NOTIFICATION_RINGTONE_TITLE);
- strings.add(WORK_PROFILE_ALARM_RINGTONE_TITLE);
- strings.add(WORK_PROFILE_SYNC_WITH_PERSONAL_SOUNDS_ACTIVE_SUMMARY);
- strings.add(ENABLE_WORK_PROFILE_SYNC_WITH_PERSONAL_SOUNDS_DIALOG_TITLE);
- strings.add(ENABLE_WORK_PROFILE_SYNC_WITH_PERSONAL_SOUNDS_DIALOG_MESSAGE);
- strings.add(WORK_PROFILE_NOTIFICATIONS_SECTION_HEADER);
- strings.add(WORK_PROFILE_LOCKED_NOTIFICATION_TITLE);
- strings.add(WORK_PROFILE_LOCK_SCREEN_REDACT_NOTIFICATION_TITLE);
- strings.add(WORK_PROFILE_LOCK_SCREEN_REDACT_NOTIFICATION_SUMMARY);
- strings.add(WORK_PROFILE_NOTIFICATION_LISTENER_BLOCKED);
- strings.add(CONNECTED_WORK_AND_PERSONAL_APPS_TITLE);
- strings.add(CONNECTED_APPS_SHARE_PERMISSIONS_AND_DATA);
- strings.add(ONLY_CONNECT_TRUSTED_APPS);
- strings.add(HOW_TO_DISCONNECT_APPS);
- strings.add(CONNECT_APPS_DIALOG_TITLE);
- strings.add(CONNECT_APPS_DIALOG_SUMMARY);
- strings.add(APP_CAN_ACCESS_PERSONAL_DATA);
- strings.add(APP_CAN_ACCESS_PERSONAL_PERMISSIONS);
- strings.add(INSTALL_IN_WORK_PROFILE_TO_CONNECT_PROMPT);
- strings.add(INSTALL_IN_PERSONAL_PROFILE_TO_CONNECT_PROMPT);
- strings.add(WORK_PROFILE_MANAGED_BY);
- strings.add(MANAGED_BY);
- strings.add(WORK_PROFILE_DISABLE_USAGE_ACCESS_WARNING);
- strings.add(DISABLED_BY_IT_ADMIN_TITLE);
- strings.add(CONTACT_YOUR_IT_ADMIN);
- strings.add(WORK_PROFILE_ADMIN_POLICIES_WARNING);
- strings.add(USER_ADMIN_POLICIES_WARNING);
- strings.add(DEVICE_ADMIN_POLICIES_WARNING);
- strings.add(WORK_PROFILE_OFF_CONDITION_TITLE);
- strings.add(MANAGED_PROFILE_SETTINGS_TITLE);
- strings.add(WORK_PROFILE_CONTACT_SEARCH_TITLE);
- strings.add(WORK_PROFILE_CONTACT_SEARCH_SUMMARY);
- strings.add(CROSS_PROFILE_CALENDAR_TITLE);
- strings.add(CROSS_PROFILE_CALENDAR_SUMMARY);
- strings.add(ALWAYS_ON_VPN_PERSONAL_PROFILE);
- strings.add(ALWAYS_ON_VPN_DEVICE);
- strings.add(ALWAYS_ON_VPN_WORK_PROFILE);
- strings.add(CA_CERTS_PERSONAL_PROFILE);
- strings.add(CA_CERTS_WORK_PROFILE);
- strings.add(CA_CERTS_DEVICE);
- strings.add(ADMIN_CAN_LOCK_DEVICE);
- strings.add(ADMIN_CAN_WIPE_DEVICE);
- strings.add(ADMIN_CONFIGURED_FAILED_PASSWORD_WIPE_DEVICE);
- strings.add(ADMIN_CONFIGURED_FAILED_PASSWORD_WIPE_WORK_PROFILE);
- strings.add(DEVICE_MANAGED_WITHOUT_NAME);
- strings.add(DEVICE_MANAGED_WITH_NAME);
- strings.add(WORK_PROFILE_APP_SUBTEXT);
- strings.add(PERSONAL_PROFILE_APP_SUBTEXT);
- strings.add(FINGERPRINT_FOR_WORK);
- strings.add(FACE_UNLOCK_DISABLED);
- strings.add(FINGERPRINT_UNLOCK_DISABLED);
- strings.add(FINGERPRINT_UNLOCK_DISABLED_EXPLANATION);
- strings.add(PIN_RECENTLY_USED);
- strings.add(PASSWORD_RECENTLY_USED);
- strings.add(MANAGE_DEVICE_ADMIN_APPS);
- strings.add(NUMBER_OF_DEVICE_ADMINS_NONE);
- strings.add(NUMBER_OF_DEVICE_ADMINS);
- strings.add(FORGOT_PASSWORD_TITLE);
- strings.add(FORGOT_PASSWORD_TEXT);
- strings.add(ERROR_MOVE_DEVICE_ADMIN);
- strings.add(DEVICE_ADMIN_SETTINGS_TITLE);
- strings.add(REMOVE_DEVICE_ADMIN);
- strings.add(UNINSTALL_DEVICE_ADMIN);
- strings.add(REMOVE_AND_UNINSTALL_DEVICE_ADMIN);
- strings.add(SELECT_DEVICE_ADMIN_APPS);
- strings.add(NO_DEVICE_ADMINS);
- strings.add(ACTIVATE_DEVICE_ADMIN_APP);
- strings.add(ACTIVATE_THIS_DEVICE_ADMIN_APP);
- strings.add(ACTIVATE_DEVICE_ADMIN_APP_TITLE);
- strings.add(NEW_DEVICE_ADMIN_WARNING);
- strings.add(NEW_DEVICE_ADMIN_WARNING_SIMPLIFIED);
- strings.add(ACTIVE_DEVICE_ADMIN_WARNING);
- strings.add(SET_PROFILE_OWNER_TITLE);
- strings.add(SET_PROFILE_OWNER_DIALOG_TITLE);
- strings.add(SET_PROFILE_OWNER_POSTSETUP_WARNING);
- strings.add(OTHER_OPTIONS_DISABLED_BY_ADMIN);
- strings.add(REMOVE_ACCOUNT_FAILED_ADMIN_RESTRICTION);
- strings.add(IT_ADMIN_POLICY_DISABLING_INFO_URL);
- strings.add(SHARE_REMOTE_BUGREPORT_DIALOG_TITLE);
- strings.add(SHARE_REMOTE_BUGREPORT_FINISHED_REQUEST_CONSENT);
- strings.add(SHARE_REMOTE_BUGREPORT_NOT_FINISHED_REQUEST_CONSENT);
- strings.add(SHARING_REMOTE_BUGREPORT_MESSAGE);
- strings.add(MANAGED_DEVICE_INFO);
- strings.add(MANAGED_DEVICE_INFO_SUMMARY);
- strings.add(MANAGED_DEVICE_INFO_SUMMARY_WITH_NAME);
- strings.add(ENTERPRISE_PRIVACY_HEADER);
- strings.add(INFORMATION_YOUR_ORGANIZATION_CAN_SEE_TITLE);
- strings.add(CHANGES_MADE_BY_YOUR_ORGANIZATION_ADMIN_TITLE);
- strings.add(YOUR_ACCESS_TO_THIS_DEVICE_TITLE);
- strings.add(ADMIN_CAN_SEE_WORK_DATA_WARNING);
- strings.add(ADMIN_CAN_SEE_APPS_WARNING);
- strings.add(ADMIN_CAN_SEE_USAGE_WARNING);
- strings.add(ADMIN_CAN_SEE_NETWORK_LOGS_WARNING);
- strings.add(ADMIN_CAN_SEE_BUG_REPORT_WARNING);
- strings.add(ADMIN_CAN_SEE_SECURITY_LOGS_WARNING);
- strings.add(ADMIN_ACTION_NONE);
- strings.add(ADMIN_ACTION_APPS_INSTALLED);
- strings.add(ADMIN_ACTION_APPS_COUNT_ESTIMATED);
- strings.add(ADMIN_ACTIONS_APPS_COUNT_MINIMUM);
- strings.add(ADMIN_ACTION_ACCESS_LOCATION);
- strings.add(ADMIN_ACTION_ACCESS_MICROPHONE);
- strings.add(ADMIN_ACTION_ACCESS_CAMERA);
- strings.add(ADMIN_ACTION_SET_DEFAULT_APPS);
- strings.add(ADMIN_ACTIONS_APPS_COUNT);
- strings.add(ADMIN_ACTION_SET_CURRENT_INPUT_METHOD);
- strings.add(ADMIN_ACTION_SET_INPUT_METHOD_NAME);
- strings.add(ADMIN_ACTION_SET_HTTP_PROXY);
- strings.add(WORK_PROFILE_PRIVACY_POLICY_INFO_SUMMARY);
- strings.add(WORK_PROFILE_PRIVACY_POLICY_INFO);
- strings.add(CONNECTED_APPS_SEARCH_KEYWORDS);
- strings.add(WORK_PROFILE_UNIFICATION_SEARCH_KEYWORDS);
- strings.add(ACCOUNTS_SEARCH_KEYWORDS);
- strings.add(CONTROLLED_BY_ADMIN_SUMMARY);
- strings.add(WORK_PROFILE_USER_LABEL);
- strings.add(WORK_CATEGORY_HEADER);
- strings.add(PERSONAL_CATEGORY_HEADER);
- return strings;
- }
- }
-
- /**
- * Class containing the identifiers used to update device management-related system strings
- * in the Launcher package.
- *
- * @hide
- */
- public static final class Launcher {
-
- private Launcher() {
- }
-
- private static final String PREFIX = "Launcher.";
-
- /**
- * User on-boarding title for work profile apps.
- */
- public static final String WORK_PROFILE_EDU = PREFIX + "WORK_PROFILE_EDU";
-
- /**
- * Action label to finish work profile edu.
- */
- public static final String WORK_PROFILE_EDU_ACCEPT = PREFIX + "WORK_PROFILE_EDU_ACCEPT";
-
- /**
- * Title shown when user opens work apps tab while work profile is paused.
- */
- public static final String WORK_PROFILE_PAUSED_TITLE =
- PREFIX + "WORK_PROFILE_PAUSED_TITLE";
-
- /**
- * Description shown when user opens work apps tab while work profile is paused.
- */
- public static final String WORK_PROFILE_PAUSED_DESCRIPTION =
- PREFIX + "WORK_PROFILE_PAUSED_DESCRIPTION";
-
- /**
- * Shown on the button to pause work profile.
- */
- public static final String WORK_PROFILE_PAUSE_BUTTON =
- PREFIX + "WORK_PROFILE_PAUSE_BUTTON";
-
- /**
- * Shown on the button to enable work profile.
- */
- public static final String WORK_PROFILE_ENABLE_BUTTON =
- PREFIX + "WORK_PROFILE_ENABLE_BUTTON";
-
- /**
- * Label on launcher tab to indicate work apps.
- */
- public static final String ALL_APPS_WORK_TAB = PREFIX + "ALL_APPS_WORK_TAB";
-
- /**
- * Label on launcher tab to indicate personal apps.
- */
- public static final String ALL_APPS_PERSONAL_TAB = PREFIX + "ALL_APPS_PERSONAL_TAB";
-
- /**
- * Accessibility description for launcher tab to indicate work apps.
- */
- public static final String ALL_APPS_WORK_TAB_ACCESSIBILITY =
- PREFIX + "ALL_APPS_WORK_TAB_ACCESSIBILITY";
-
- /**
- * Accessibility description for launcher tab to indicate personal apps.
- */
- public static final String ALL_APPS_PERSONAL_TAB_ACCESSIBILITY =
- PREFIX + "ALL_APPS_PERSONAL_TAB_ACCESSIBILITY";
-
- /**
- * Work folder name.
- */
- public static final String WORK_FOLDER_NAME = PREFIX + "WORK_FOLDER_NAME";
-
- /**
- * Label on widget tab to indicate work app widgets.
- */
- public static final String WIDGETS_WORK_TAB = PREFIX + "WIDGETS_WORK_TAB";
-
- /**
- * Label on widget tab to indicate personal app widgets.
- */
- public static final String WIDGETS_PERSONAL_TAB = PREFIX + "WIDGETS_PERSONAL_TAB";
-
- /**
- * Message shown when a feature is disabled by the admin (e.g. changing wallpaper).
- */
- public static final String DISABLED_BY_ADMIN_MESSAGE =
- PREFIX + "DISABLED_BY_ADMIN_MESSAGE";
-
- /**
- * @hide
- */
- static Set<String> buildStringsSet() {
- Set<String> strings = new HashSet<>();
- strings.add(WORK_PROFILE_EDU);
- strings.add(WORK_PROFILE_EDU_ACCEPT);
- strings.add(WORK_PROFILE_PAUSED_TITLE);
- strings.add(WORK_PROFILE_PAUSED_DESCRIPTION);
- strings.add(WORK_PROFILE_PAUSE_BUTTON);
- strings.add(WORK_PROFILE_ENABLE_BUTTON);
- strings.add(ALL_APPS_WORK_TAB);
- strings.add(ALL_APPS_PERSONAL_TAB);
- strings.add(ALL_APPS_PERSONAL_TAB_ACCESSIBILITY);
- strings.add(ALL_APPS_WORK_TAB_ACCESSIBILITY);
- strings.add(WORK_FOLDER_NAME);
- strings.add(WIDGETS_WORK_TAB);
- strings.add(WIDGETS_PERSONAL_TAB);
- strings.add(DISABLED_BY_ADMIN_MESSAGE);
- return strings;
- }
}
/**
@@ -2272,49 +1417,6 @@ public final class DevicePolicyResources {
* Content description for the work profile lock screen.
*/
public static final String WORK_LOCK_ACCESSIBILITY = PREFIX + "WORK_LOCK_ACCESSIBILITY";
-
- /**
- * @hide
- */
- static Set<String> buildStringsSet() {
- Set<String> strings = new HashSet<>();
- strings.add(QS_WORK_PROFILE_LABEL);
- strings.add(QS_MSG_MANAGEMENT);
- strings.add(QS_MSG_NAMED_MANAGEMENT);
- strings.add(QS_MSG_MANAGEMENT_MONITORING);
- strings.add(QS_MSG_NAMED_MANAGEMENT_MONITORING);
- strings.add(QS_MSG_MANAGEMENT_NAMED_VPN);
- strings.add(QS_MSG_NAMED_MANAGEMENT_NAMED_VPN);
- strings.add(QS_MSG_MANAGEMENT_MULTIPLE_VPNS);
- strings.add(QS_MSG_NAMED_MANAGEMENT_MULTIPLE_VPNS);
- strings.add(QS_MSG_WORK_PROFILE_MONITORING);
- strings.add(QS_MSG_NAMED_WORK_PROFILE_MONITORING);
- strings.add(QS_MSG_WORK_PROFILE_NETWORK);
- strings.add(QS_MSG_WORK_PROFILE_NAMED_VPN);
- strings.add(QS_MSG_PERSONAL_PROFILE_NAMED_VPN);
- strings.add(QS_DIALOG_MANAGEMENT_TITLE);
- strings.add(QS_DIALOG_VIEW_POLICIES);
- strings.add(QS_DIALOG_MANAGEMENT);
- strings.add(QS_DIALOG_NAMED_MANAGEMENT);
- strings.add(QS_DIALOG_MANAGEMENT_CA_CERT);
- strings.add(QS_DIALOG_WORK_PROFILE_CA_CERT);
- strings.add(QS_DIALOG_MANAGEMENT_NETWORK);
- strings.add(QS_DIALOG_WORK_PROFILE_NETWORK);
- strings.add(QS_DIALOG_MANAGEMENT_NAMED_VPN);
- strings.add(QS_DIALOG_MANAGEMENT_TWO_NAMED_VPN);
- strings.add(QS_DIALOG_WORK_PROFILE_NAMED_VPN);
- strings.add(QS_DIALOG_PERSONAL_PROFILE_NAMED_VPN);
- strings.add(BIOMETRIC_DIALOG_WORK_PIN_LAST_ATTEMPT);
- strings.add(BIOMETRIC_DIALOG_WORK_PATTERN_LAST_ATTEMPT);
- strings.add(BIOMETRIC_DIALOG_WORK_PASSWORD_LAST_ATTEMPT);
- strings.add(BIOMETRIC_DIALOG_WORK_LOCK_FAILED_ATTEMPTS);
- strings.add(STATUS_BAR_WORK_ICON_ACCESSIBILITY);
- strings.add(ONGOING_PRIVACY_DIALOG_WORK);
- strings.add(KEYGUARD_MANAGEMENT_DISCLOSURE);
- strings.add(KEYGUARD_NAMED_MANAGEMENT_DISCLOSURE);
- strings.add(WORK_LOCK_ACCESSIBILITY);
- return strings;
- }
}
/**
@@ -2614,278 +1716,35 @@ public final class DevicePolicyResources {
*/
public static final String WORK_PROFILE_BADGED_LABEL =
PREFIX + "WORK_PROFILE_BADGED_LABEL";
-
- /**
- * @hide
- */
- static Set<String> buildStringsSet() {
- Set<String> strings = new HashSet<>();
- strings.add(WORK_PROFILE_DELETED_TITLE);
- strings.add(WORK_PROFILE_DELETED_FAILED_PASSWORD_ATTEMPTS_MESSAGE);
- strings.add(WORK_PROFILE_DELETED_GENERIC_MESSAGE);
- strings.add(WORK_PROFILE_DELETED_ORG_OWNED_MESSAGE);
- strings.add(PERSONAL_APP_SUSPENSION_TITLE);
- strings.add(PERSONAL_APP_SUSPENSION_MESSAGE);
- strings.add(PERSONAL_APP_SUSPENSION_SOON_MESSAGE);
- strings.add(PERSONAL_APP_SUSPENSION_TURN_ON_PROFILE);
- strings.add(PRINTING_DISABLED_NAMED_ADMIN);
- strings.add(LOCATION_CHANGED_TITLE);
- strings.add(LOCATION_CHANGED_MESSAGE);
- strings.add(NETWORK_LOGGING_TITLE);
- strings.add(NETWORK_LOGGING_MESSAGE);
- strings.add(NOTIFICATION_WORK_PROFILE_CONTENT_DESCRIPTION);
- strings.add(NOTIFICATION_CHANNEL_DEVICE_ADMIN);
- strings.add(SWITCH_TO_WORK_LABEL);
- strings.add(SWITCH_TO_PERSONAL_LABEL);
- strings.add(FORWARD_INTENT_TO_WORK);
- strings.add(FORWARD_INTENT_TO_PERSONAL);
- strings.add(RESOLVER_WORK_PROFILE_NOT_SUPPORTED);
- strings.add(RESOLVER_PERSONAL_TAB);
- strings.add(RESOLVER_WORK_TAB);
- strings.add(RESOLVER_PERSONAL_TAB_ACCESSIBILITY);
- strings.add(RESOLVER_WORK_TAB_ACCESSIBILITY);
- strings.add(RESOLVER_CROSS_PROFILE_BLOCKED_TITLE);
- strings.add(RESOLVER_CANT_SHARE_WITH_PERSONAL);
- strings.add(RESOLVER_CANT_SHARE_WITH_WORK);
- strings.add(RESOLVER_CANT_ACCESS_PERSONAL);
- strings.add(RESOLVER_CANT_ACCESS_WORK);
- strings.add(RESOLVER_WORK_PAUSED_TITLE);
- strings.add(RESOLVER_NO_WORK_APPS);
- strings.add(RESOLVER_NO_PERSONAL_APPS);
- strings.add(CANT_ADD_ACCOUNT_MESSAGE);
- strings.add(PACKAGE_INSTALLED_BY_DO);
- strings.add(PACKAGE_UPDATED_BY_DO);
- strings.add(PACKAGE_DELETED_BY_DO);
- strings.add(UNLAUNCHABLE_APP_WORK_PAUSED_TITLE);
- strings.add(UNLAUNCHABLE_APP_WORK_PAUSED_MESSAGE);
- strings.add(PROFILE_ENCRYPTED_TITLE);
- strings.add(PROFILE_ENCRYPTED_DETAIL);
- strings.add(PROFILE_ENCRYPTED_MESSAGE);
- strings.add(WORK_PROFILE_BADGED_LABEL);
- return strings;
- }
- }
-
- /**
- * Class containing the identifiers used to update device management-related system strings
- * in the DocumentsUi package.
- */
- public static final class DocumentsUi {
-
- private DocumentsUi() {
- }
-
- private static final String PREFIX = "DocumentsUi.";
-
- /**
- * Title for error message shown when work profile is turned off.
- */
- public static final String WORK_PROFILE_OFF_ERROR_TITLE =
- PREFIX + "WORK_PROFILE_OFF_ERROR_TITLE";
-
- /**
- * Button text shown when work profile is turned off.
- */
- public static final String WORK_PROFILE_OFF_ENABLE_BUTTON =
- PREFIX + "WORK_PROFILE_OFF_ENABLE_BUTTON";
-
- /**
- * Title for error message shown when a user's IT admin does not allow the user to
- * select work files from a personal app.
- */
- public static final String CANT_SELECT_WORK_FILES_TITLE =
- PREFIX + "CANT_SELECT_WORK_FILES_TITLE";
-
- /**
- * Message shown when a user's IT admin does not allow the user to select work files
- * from a personal app.
- */
- public static final String CANT_SELECT_WORK_FILES_MESSAGE =
- PREFIX + "CANT_SELECT_WORK_FILES_MESSAGE";
-
- /**
- * Title for error message shown when a user's IT admin does not allow the user to
- * select personal files from a work app.
- */
- public static final String CANT_SELECT_PERSONAL_FILES_TITLE =
- PREFIX + "CANT_SELECT_PERSONAL_FILES_TITLE";
-
- /**
- * Message shown when a user's IT admin does not allow the user to select personal files
- * from a work app.
- */
- public static final String CANT_SELECT_PERSONAL_FILES_MESSAGE =
- PREFIX + "CANT_SELECT_PERSONAL_FILES_MESSAGE";
-
- /**
- * Title for error message shown when a user's IT admin does not allow the user to save
- * files from their personal profile to their work profile.
- */
- public static final String CANT_SAVE_TO_WORK_TITLE =
- PREFIX + "CANT_SAVE_TO_WORK_TITLE";
-
- /**
- * Message shown when a user's IT admin does not allow the user to save files from their
- * personal profile to their work profile.
- */
- public static final String CANT_SAVE_TO_WORK_MESSAGE =
- PREFIX + "CANT_SAVE_TO_WORK_MESSAGE";
-
- /**
- * Title for error message shown when a user's IT admin does not allow the user to save
- * files from their work profile to their personal profile.
- */
- public static final String CANT_SAVE_TO_PERSONAL_TITLE =
- PREFIX + "CANT_SAVE_TO_PERSONAL_TITLE";
-
- /**
- * Message shown when a user's IT admin does not allow the user to save files from their
- * work profile to their personal profile.
- */
- public static final String CANT_SAVE_TO_PERSONAL_MESSAGE =
- PREFIX + "CANT_SAVE_TO_PERSONAL_MESSAGE";
-
- /**
- * Title for error message shown when a user tries to do something on their work
- * device, but that action isn't allowed by their IT admin.
- */
- public static final String CROSS_PROFILE_NOT_ALLOWED_TITLE =
- PREFIX + "CROSS_PROFILE_NOT_ALLOWED_TITLE";
-
- /**
- * Message shown when a user tries to do something on their work device, but that action
- * isn't allowed by their IT admin.
- */
- public static final String CROSS_PROFILE_NOT_ALLOWED_MESSAGE =
- PREFIX + "CROSS_PROFILE_NOT_ALLOWED_MESSAGE";
-
- /**
- * Content description text that's spoken by a screen reader for previewing a work file
- * before opening it. Accepts file name as a param.
- */
- public static final String PREVIEW_WORK_FILE_ACCESSIBILITY =
- PREFIX + "PREVIEW_WORK_FILE_ACCESSIBILITY";
-
- /**
- * Label for tab and sidebar to indicate personal content.
- */
- public static final String PERSONAL_TAB = PREFIX + "PERSONAL_TAB";
-
- /**
- * Label for tab and sidebar tab to indicate work content
- */
- public static final String WORK_TAB = PREFIX + "WORK_TAB";
-
- /**
- * Accessibility label to indicate the subject(e.g. file/folder) is from work profile.
- */
- public static final String WORK_ACCESSIBILITY = PREFIX + "WORK_ACCESSIBILITY";
-
- /**
- * @hide
- */
- static Set<String> buildStringsSet() {
- Set<String> strings = new HashSet<>();
- strings.add(WORK_PROFILE_OFF_ERROR_TITLE);
- strings.add(WORK_PROFILE_OFF_ENABLE_BUTTON);
- strings.add(CANT_SELECT_WORK_FILES_TITLE);
- strings.add(CANT_SELECT_WORK_FILES_MESSAGE);
- strings.add(CANT_SELECT_PERSONAL_FILES_TITLE);
- strings.add(CANT_SELECT_PERSONAL_FILES_MESSAGE);
- strings.add(CANT_SAVE_TO_WORK_TITLE);
- strings.add(CANT_SAVE_TO_WORK_MESSAGE);
- strings.add(CANT_SAVE_TO_PERSONAL_TITLE);
- strings.add(CANT_SAVE_TO_PERSONAL_MESSAGE);
- strings.add(CROSS_PROFILE_NOT_ALLOWED_TITLE);
- strings.add(CROSS_PROFILE_NOT_ALLOWED_MESSAGE);
- strings.add(PREVIEW_WORK_FILE_ACCESSIBILITY);
- strings.add(PERSONAL_TAB);
- strings.add(WORK_TAB);
- strings.add(WORK_ACCESSIBILITY);
- return strings;
- }
}
/**
* Class containing the identifiers used to update device management-related system strings
- * in the MediaProvider module.
+ * in the Dialer app.
+ *
+ * @hide
*/
- public static final class MediaProvider {
+ public static final class Telecomm {
- private MediaProvider() {
+ private Telecomm() {
}
- private static final String PREFIX = "MediaProvider.";
+ private static final String PREFIX = "Telecomm.";
/**
- * The text shown to switch to the work profile in PhotoPicker.
- */
- public static final String SWITCH_TO_WORK_MESSAGE =
- PREFIX + "SWITCH_TO_WORK_MESSAGE";
-
- /**
- * The text shown to switch to the personal profile in PhotoPicker.
- */
- public static final String SWITCH_TO_PERSONAL_MESSAGE =
- PREFIX + "SWITCH_TO_PERSONAL_MESSAGE";
-
- /**
- * The title for error dialog in PhotoPicker when the admin blocks cross user
- * interaction for the intent.
- */
- public static final String BLOCKED_BY_ADMIN_TITLE =
- PREFIX + "BLOCKED_BY_ADMIN_TITLE";
-
- /**
- * The message for error dialog in PhotoPicker when the admin blocks cross user
- * interaction from the personal profile.
- */
- public static final String BLOCKED_FROM_PERSONAL_MESSAGE =
- PREFIX + "BLOCKED_FROM_PERSONAL_MESSAGE";
-
- /**
- * The message for error dialog in PhotoPicker when the admin blocks cross user
- * interaction from the work profile.
- */
- public static final String BLOCKED_FROM_WORK_MESSAGE =
- PREFIX + "BLOCKED_FROM_WORK_MESSAGE";
-
- /**
- * The title of the error dialog in PhotoPicker when the user tries to switch to work
- * content, but work profile is off.
- */
- public static final String WORK_PROFILE_PAUSED_TITLE =
- PREFIX + "WORK_PROFILE_PAUSED_TITLE";
-
- /**
- * The message of the error dialog in PhotoPicker when the user tries to switch to work
- * content, but work profile is off.
- */
- public static final String WORK_PROFILE_PAUSED_MESSAGE =
- PREFIX + "WORK_PROFILE_PAUSED_MESSAGE";
-
- /**
- * @hide
+ * Missed call notification label, used when there's exactly one missed call from work
+ * contact.
*/
- static Set<String> buildStringsSet() {
- Set<String> strings = new HashSet<>();
- strings.add(SWITCH_TO_WORK_MESSAGE);
- strings.add(SWITCH_TO_PERSONAL_MESSAGE);
- strings.add(BLOCKED_BY_ADMIN_TITLE);
- strings.add(BLOCKED_FROM_PERSONAL_MESSAGE);
- strings.add(BLOCKED_FROM_WORK_MESSAGE);
- strings.add(WORK_PROFILE_PAUSED_TITLE);
- strings.add(WORK_PROFILE_PAUSED_MESSAGE);
- return strings;
- }
+ public static final String NOTIFICATION_MISSED_WORK_CALL_TITLE =
+ PREFIX + "NOTIFICATION_MISSED_WORK_CALL_TITLE";
}
/**
* Class containing the identifiers used to update device management-related system strings
- * in the PermissionController module.
+ * in the Permissions module.
*/
public static final class PermissionController {
-
+
private PermissionController() {
}
@@ -2930,69 +1789,6 @@ public final class DevicePolicyResources {
*/
public static final String LOCATION_AUTO_GRANTED_MESSAGE =
PREFIX + "LOCATION_AUTO_GRANTED_MESSAGE";
-
- /**
- * @hide
- */
- static Set<String> buildStringsSet() {
- Set<String> strings = new HashSet<>();
- strings.add(WORK_PROFILE_DEFAULT_APPS_TITLE);
- strings.add(HOME_MISSING_WORK_PROFILE_SUPPORT_MESSAGE);
- strings.add(BACKGROUND_ACCESS_DISABLED_BY_ADMIN_MESSAGE);
- strings.add(BACKGROUND_ACCESS_ENABLED_BY_ADMIN_MESSAGE);
- strings.add(FOREGROUND_ACCESS_ENABLED_BY_ADMIN_MESSAGE);
- strings.add(LOCATION_AUTO_GRANTED_MESSAGE);
- return strings;
- }
- }
-
- /**
- * Class containing the identifiers used to update device management-related system strings
- * in the Dialer app.
- */
- public static final class Dialer {
-
- private Dialer() {
- }
-
- private static final String PREFIX = "Dialer.";
-
- /**
- * The title of the in-call notification for an incoming work call.
- */
- public static final String NOTIFICATION_INCOMING_WORK_CALL_TITLE =
- PREFIX + "NOTIFICATION_INCOMING_WORK_CALL_TITLE";
-
- /**
- * The title of the in-call notification for an ongoing work call.
- */
- public static final String NOTIFICATION_ONGOING_WORK_CALL_TITLE =
- PREFIX + "NOTIFICATION_ONGOING_WORK_CALL_TITLE";
-
- /**
- * Missed call notification label, used when there's exactly one missed call from work
- * contact.
- */
- public static final String NOTIFICATION_MISSED_WORK_CALL_TITLE =
- PREFIX + "NOTIFICATION_MISSED_WORK_CALL_TITLE";
-
- /**
- * Label for notification indicating that call is being made over wifi.
- */
- public static final String NOTIFICATION_WIFI_WORK_CALL_LABEL =
- PREFIX + "NOTIFICATION_WIFI_WORK_CALL_LABEL";
-
- /**
- * @hide
- */
- static Set<String> buildStringsSet() {
- Set<String> strings = new HashSet<>();
- strings.add(NOTIFICATION_INCOMING_WORK_CALL_TITLE);
- strings.add(NOTIFICATION_ONGOING_WORK_CALL_TITLE);
- strings.add(NOTIFICATION_MISSED_WORK_CALL_TITLE);
- strings.add(NOTIFICATION_WIFI_WORK_CALL_LABEL);
- return strings;
- }
}
}
}
diff --git a/core/java/android/app/admin/DevicePolicyResourcesManager.java b/core/java/android/app/admin/DevicePolicyResourcesManager.java
new file mode 100644
index 000000000000..06729222dea1
--- /dev/null
+++ b/core/java/android/app/admin/DevicePolicyResourcesManager.java
@@ -0,0 +1,528 @@
+/*
+ * 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.app.admin;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.annotation.SuppressLint;
+import android.annotation.SystemApi;
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Icon;
+import android.os.RemoteException;
+import android.util.DisplayMetrics;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.Objects;
+import java.util.Set;
+import java.util.function.Supplier;
+
+/**
+ * Class containing required APIs to set, reset, and get device policy related resources.
+ */
+public class DevicePolicyResourcesManager {
+ private static String TAG = "DevicePolicyResourcesManager";
+
+ private final Context mContext;
+ private final IDevicePolicyManager mService;
+
+ /**
+ * @hide
+ */
+ protected DevicePolicyResourcesManager(Context context, IDevicePolicyManager service) {
+ mContext = context;
+ mService = service;
+ }
+
+ /**
+ * For each {@link DevicePolicyDrawableResource} item in {@code drawables}, if
+ * {@link DevicePolicyDrawableResource#getDrawableSource()} is not set, it updates the drawable
+ * resource for the combination of {@link DevicePolicyDrawableResource#getDrawableId()} and
+ * {@link DevicePolicyDrawableResource#getDrawableStyle()} to the drawable with resource ID
+ * {@link DevicePolicyDrawableResource#getResourceIdInCallingPackage()},
+ * meaning any system UI surface calling {@link #getDrawable} with {@code drawableId} and
+ * {@code drawableStyle} will get the new resource after this API is called.
+ *
+ * <p>Otherwise, if {@link DevicePolicyDrawableResource#getDrawableSource()} is set, it
+ * overrides any drawables that was set for the same {@code drawableId} and
+ * {@code drawableStyle} for the provided source.
+ *
+ * <p>Sends a broadcast with action
+ * {@link DevicePolicyManager#ACTION_DEVICE_POLICY_RESOURCE_UPDATED} to registered receivers
+ * when a resource has been updated successfully.
+ *
+ * <p>Important notes to consider when using this API:
+ * <ul>
+ * <li>{@link #getDrawable} references the resource
+ * {@link DevicePolicyDrawableResource#getResourceIdInCallingPackage()} in the
+ * calling package each time it gets called. You have to ensure that the resource is always
+ * available in the calling package as long as it is used as an updated resource.
+ * <li>You still have to re-call {@code setDrawables} even if you only make changes to the
+ * content of the resource with ID
+ * {@link DevicePolicyDrawableResource#getResourceIdInCallingPackage()} as the content might be
+ * cached and would need updating.
+ * </ul>
+ *
+ * @param drawables The list of {@link DevicePolicyDrawableResource} to update.
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES)
+ public void setDrawables(@NonNull Set<DevicePolicyDrawableResource> drawables) {
+ if (mService != null) {
+ try {
+ mService.setDrawables(new ArrayList<>(drawables));
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ }
+
+ /**
+ * Removes all updated drawables for the list of {@code drawableIds} that was previously set by
+ * calling {@link #setDrawables}, meaning any subsequent calls to {@link #getDrawable} for the
+ * provided IDs with any {@code drawableStyle} and any {@code drawableSource} will return the
+ * default drawable from {@code defaultDrawableLoader}.
+ *
+ * <p>Sends a broadcast with action
+ * {@link DevicePolicyManager#ACTION_DEVICE_POLICY_RESOURCE_UPDATED} to registered receivers
+ * when a resource has been reset successfully.
+ *
+ * @param drawableIds The list of IDs to remove.
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES)
+ public void resetDrawables(@NonNull Set<String> drawableIds) {
+ if (mService != null) {
+ try {
+ mService.resetDrawables(new ArrayList<>(drawableIds));
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ }
+
+ /**
+ * Returns the appropriate updated drawable for the {@code drawableId} with style
+ * {@code drawableStyle} if one was set using {@code setDrawables}, otherwise returns the
+ * drawable from {@code defaultDrawableLoader}.
+ *
+ * <p>Also returns the drawable from {@code defaultDrawableLoader} if {@code drawableId}
+ * is {@link DevicePolicyResources#UNDEFINED}.
+ *
+ * <p>Calls to this API will not return {@code null} unless no updated drawable was found
+ * and the call to {@code defaultDrawableLoader} returned {@code null}.
+ *
+ * <p>This API uses the screen density returned from {@link Resources#getConfiguration()}, to
+ * set a different value use
+ * {@link #getDrawableForDensity(String, String, int, Supplier)}.
+ *
+ * <p>Callers should register for
+ * {@link DevicePolicyManager#ACTION_DEVICE_POLICY_RESOURCE_UPDATED} to get notified when a
+ * resource has been updated.
+ *
+ * <p>Note that each call to this API loads the resource from the package that called
+ * {@code setDrawables} to set the updated resource.
+ *
+ * @param drawableId The drawable ID to get the updated resource for.
+ * @param drawableStyle The drawable style to use.
+ * @param defaultDrawableLoader To get the default drawable if no updated drawable was set for
+ * the provided params.
+ */
+ @Nullable
+ public Drawable getDrawable(
+ @NonNull String drawableId,
+ @NonNull String drawableStyle,
+ @NonNull Supplier<Drawable> defaultDrawableLoader) {
+ return getDrawable(
+ drawableId, drawableStyle, DevicePolicyResources.UNDEFINED, defaultDrawableLoader);
+ }
+
+ /**
+ * Similar to {@link #getDrawable(String, String, Supplier)}, but also accepts
+ * a {@code drawableSource} which could result in returning a different drawable than
+ * {@link #getDrawable(String, String, Supplier)} if an override was set for that specific
+ * source.
+ *
+ * <p> If {@code drawableSource} is {@link DevicePolicyResources#UNDEFINED}, it returns the
+ * appropriate string for {@code drawableId} and {@code drawableStyle} similar to
+ * {@link #getDrawable(String, String, Supplier)}.
+ *
+ * <p>Calls to this API will not return {@code null} unless no updated drawable was found
+ * and the call to {@code defaultDrawableLoader} returned {@code null}.
+ *
+ * <p>Callers should register for
+ * {@link DevicePolicyManager#ACTION_DEVICE_POLICY_RESOURCE_UPDATED} to get notified when a
+ * resource has been updated.
+ *
+ * @param drawableId The drawable ID to get the updated resource for.
+ * @param drawableStyle The drawable style to use.
+ * @param drawableSource The source for the caller.
+ * @param defaultDrawableLoader To get the default drawable if no updated drawable was set for
+ * the provided params.
+ */
+ @Nullable
+ public Drawable getDrawable(
+ @NonNull String drawableId,
+ @NonNull String drawableStyle,
+ @NonNull String drawableSource,
+ @NonNull Supplier<Drawable> defaultDrawableLoader) {
+
+ Objects.requireNonNull(drawableId, "drawableId can't be null");
+ Objects.requireNonNull(drawableStyle, "drawableStyle can't be null");
+ Objects.requireNonNull(drawableSource, "drawableSource can't be null");
+ Objects.requireNonNull(defaultDrawableLoader, "defaultDrawableLoader can't be null");
+
+ if (drawableId.equals(DevicePolicyResources.UNDEFINED)) {
+ return ParcelableResource.loadDefaultDrawable(defaultDrawableLoader);
+ }
+ if (mService != null) {
+ try {
+ ParcelableResource resource = mService.getDrawable(
+ drawableId, drawableStyle, drawableSource);
+ if (resource == null) {
+ return ParcelableResource.loadDefaultDrawable(
+ defaultDrawableLoader);
+ }
+ return resource.getDrawable(
+ mContext,
+ /* density= */ 0,
+ defaultDrawableLoader);
+
+ } catch (RemoteException e) {
+ Log.e(
+ TAG,
+ "Error getting the updated drawable from DevicePolicyManagerService.",
+ e);
+ return ParcelableResource.loadDefaultDrawable(defaultDrawableLoader);
+ }
+ }
+ return ParcelableResource.loadDefaultDrawable(defaultDrawableLoader);
+ }
+
+ /**
+ * Similar to {@link #getDrawable(String, String, Supplier)}, but also accepts
+ * {@code density}. See {@link Resources#getDrawableForDensity(int, int, Resources.Theme)}.
+ *
+ * <p>Calls to this API will not return {@code null} unless no updated drawable was found
+ * and the call to {@code defaultDrawableLoader} returned {@code null}.
+ *
+ * <p>Callers should register for
+ * {@link DevicePolicyManager#ACTION_DEVICE_POLICY_RESOURCE_UPDATED} to get notified when a
+ * resource has been updated.
+ *
+ * @param drawableId The drawable ID to get the updated resource for.
+ * @param drawableStyle The drawable style to use.
+ * @param density The desired screen density indicated by the resource as
+ * found in {@link DisplayMetrics}. A value of 0 means to use the
+ * density returned from {@link Resources#getConfiguration()}.
+ * @param defaultDrawableLoader To get the default drawable if no updated drawable was set for
+ * the provided params.
+ */
+ @Nullable
+ public Drawable getDrawableForDensity(
+ @NonNull String drawableId,
+ @NonNull String drawableStyle,
+ int density,
+ @NonNull Supplier<Drawable> defaultDrawableLoader) {
+ return getDrawableForDensity(
+ drawableId,
+ drawableStyle,
+ DevicePolicyResources.UNDEFINED,
+ density,
+ defaultDrawableLoader);
+ }
+
+ /**
+ * Similar to {@link #getDrawable(String, String, String, Supplier)}, but also accepts
+ * {@code density}. See {@link Resources#getDrawableForDensity(int, int, Resources.Theme)}.
+ *
+ * <p>Calls to this API will not return {@code null} unless no updated drawable was found
+ * and the call to {@code defaultDrawableLoader} returned {@code null}.
+ *
+ * <p>Callers should register for
+ * {@link DevicePolicyManager#ACTION_DEVICE_POLICY_RESOURCE_UPDATED} to get notified when a
+ * resource has been updated.
+ *
+ * @param drawableId The drawable ID to get the updated resource for.
+ * @param drawableStyle The drawable style to use.
+ * @param drawableSource The source for the caller.
+ * @param density The desired screen density indicated by the resource as
+ * found in {@link DisplayMetrics}. A value of 0 means to use the
+ * density returned from {@link Resources#getConfiguration()}.
+ * @param defaultDrawableLoader To get the default drawable if no updated drawable was set for
+ * the provided params.
+ */
+ @Nullable
+ public Drawable getDrawableForDensity(
+ @NonNull String drawableId,
+ @NonNull String drawableStyle,
+ @NonNull String drawableSource,
+ int density,
+ @NonNull Supplier<Drawable> defaultDrawableLoader) {
+
+ Objects.requireNonNull(drawableId, "drawableId can't be null");
+ Objects.requireNonNull(drawableStyle, "drawableStyle can't be null");
+ Objects.requireNonNull(drawableSource, "drawableSource can't be null");
+ Objects.requireNonNull(defaultDrawableLoader, "defaultDrawableLoader can't be null");
+
+ if (drawableId.equals(DevicePolicyResources.UNDEFINED)) {
+ return ParcelableResource.loadDefaultDrawable(defaultDrawableLoader);
+ }
+ if (mService != null) {
+ try {
+ ParcelableResource resource = mService.getDrawable(
+ drawableId, drawableStyle, drawableSource);
+ if (resource == null) {
+ return ParcelableResource.loadDefaultDrawable(
+ defaultDrawableLoader);
+ }
+ return resource.getDrawable(mContext, density, defaultDrawableLoader);
+ } catch (RemoteException e) {
+ Log.e(
+ TAG,
+ "Error getting the updated drawable from DevicePolicyManagerService.",
+ e);
+ return ParcelableResource.loadDefaultDrawable(defaultDrawableLoader);
+ }
+ }
+ return ParcelableResource.loadDefaultDrawable(defaultDrawableLoader);
+ }
+
+ /**
+ * Similar to {@link #getDrawable(String, String, String, Supplier)} but returns an
+ * {@link Icon} instead of a {@link Drawable}.
+ *
+ * @param drawableId The drawable ID to get the updated resource for.
+ * @param drawableStyle The drawable style to use.
+ * @param drawableSource The source for the caller.
+ * @param defaultIcon Returned if no updated drawable was set for the provided params.
+ */
+ @Nullable
+ public Icon getDrawableAsIcon(
+ @NonNull String drawableId,
+ @NonNull String drawableStyle,
+ @NonNull String drawableSource,
+ @Nullable Icon defaultIcon) {
+ Objects.requireNonNull(drawableId, "drawableId can't be null");
+ Objects.requireNonNull(drawableStyle, "drawableStyle can't be null");
+ Objects.requireNonNull(drawableSource, "drawableSource can't be null");
+ Objects.requireNonNull(defaultIcon, "defaultIcon can't be null");
+
+ if (drawableId.equals(DevicePolicyResources.UNDEFINED)) {
+ return defaultIcon;
+ }
+ if (mService != null) {
+ try {
+ ParcelableResource resource = mService.getDrawable(
+ drawableId, drawableStyle, drawableSource);
+ if (resource == null) {
+ return defaultIcon;
+ }
+ return Icon.createWithResource(resource.getPackageName(), resource.getResourceId());
+ } catch (RemoteException e) {
+ Log.e(
+ TAG,
+ "Error getting the updated drawable from DevicePolicyManagerService.",
+ e);
+ return defaultIcon;
+ }
+ }
+ return defaultIcon;
+ }
+
+ /**
+ * Similar to {@link #getDrawable(String, String, Supplier)} but returns an {@link Icon}
+ * instead of a {@link Drawable}.
+ *
+ * @param drawableId The drawable ID to get the updated resource for.
+ * @param drawableStyle The drawable style to use.
+ * @param defaultIcon Returned if no updated drawable was set for the provided params.
+ */
+ @Nullable
+ public Icon getDrawableAsIcon(
+ @NonNull String drawableId,
+ @NonNull String drawableStyle,
+ @Nullable Icon defaultIcon) {
+ return getDrawableAsIcon(
+ drawableId, drawableStyle, DevicePolicyResources.UNDEFINED, defaultIcon);
+ }
+
+
+ /**
+ * For each {@link DevicePolicyStringResource} item in {@code strings}, it updates the string
+ * resource for {@link DevicePolicyStringResource#getStringId()} to the string with ID
+ * {@code callingPackageResourceId}, meaning any system UI surface calling {@link #getString}
+ * with {@code stringId} will get the new resource after this API is called.
+ *
+ * <p>Sends a broadcast with action
+ * {@link DevicePolicyManager#ACTION_DEVICE_POLICY_RESOURCE_UPDATED} to registered receivers
+ * when a resource has been updated successfully.
+ *
+ * <p>Important notes to consider when using this API:
+ * <ul>
+ * <li> {@link #getString} references the resource {@code callingPackageResourceId} in the
+ * calling package each time it gets called. You have to ensure that the resource is always
+ * available in the calling package as long as it is used as an updated resource.
+ * <li> You still have to re-call {@code setStrings} even if you only make changes to the
+ * content of the resource with ID {@code callingPackageResourceId} as the content might be
+ * cached and would need updating.
+ * </ul>
+ *
+ * @param strings The list of {@link DevicePolicyStringResource} to update.
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES)
+ public void setStrings(@NonNull Set<DevicePolicyStringResource> strings) {
+ if (mService != null) {
+ try {
+ mService.setStrings(new ArrayList<>(strings));
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ }
+
+ /**
+ * Removes the updated strings for the list of {@code stringIds} that was previously set by
+ * calling {@link #setStrings}, meaning any subsequent calls to {@link #getString} for the
+ * provided IDs will return the default string from {@code defaultStringLoader}.
+ *
+ * <p>Sends a broadcast with action
+ * {@link DevicePolicyManager#ACTION_DEVICE_POLICY_RESOURCE_UPDATED} to registered receivers
+ * when a resource has been reset successfully.
+ *
+ * @param stringIds The list of IDs to remove the updated resources for.
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES)
+ public void resetStrings(@NonNull Set<String> stringIds) {
+ if (mService != null) {
+ try {
+ mService.resetStrings(new ArrayList<>(stringIds));
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ }
+
+ /**
+ * Returns the appropriate updated string for the {@code stringId} (see
+ * {@link DevicePolicyResources.Strings}) if one was set using
+ * {@code setStrings}, otherwise returns the string from {@code defaultStringLoader}.
+ *
+ * <p>Also returns the string from {@code defaultStringLoader} if {@code stringId} is
+ * {@link DevicePolicyResources#UNDEFINED}.
+ *
+ * <p>Calls to this API will not return {@code null} unless no updated drawable was found
+ * and the call to {@code defaultStringLoader} returned {@code null}.
+ *
+ * <p>Callers should register for
+ * {@link DevicePolicyManager#ACTION_DEVICE_POLICY_RESOURCE_UPDATED} to get notified when a
+ * resource has been updated.
+ *
+ * <p>Note that each call to this API loads the resource from the package that called
+ * {@code setStrings} to set the updated resource.
+ *
+ * @param stringId The IDs to get the updated resource for.
+ * @param defaultStringLoader To get the default string if no updated string was set for
+ * {@code stringId}.
+ */
+ @Nullable
+ public String getString(
+ @NonNull String stringId,
+ @NonNull Supplier<String> defaultStringLoader) {
+
+ Objects.requireNonNull(stringId, "stringId can't be null");
+ Objects.requireNonNull(defaultStringLoader, "defaultStringLoader can't be null");
+
+ if (stringId.equals(DevicePolicyResources.UNDEFINED)) {
+ return ParcelableResource.loadDefaultString(defaultStringLoader);
+ }
+ if (mService != null) {
+ try {
+ ParcelableResource resource = mService.getString(stringId);
+ if (resource == null) {
+ return ParcelableResource.loadDefaultString(defaultStringLoader);
+ }
+ return resource.getString(mContext, defaultStringLoader);
+ } catch (RemoteException e) {
+ Log.e(
+ TAG,
+ "Error getting the updated string from DevicePolicyManagerService.",
+ e);
+ return ParcelableResource.loadDefaultString(defaultStringLoader);
+ }
+ }
+ return ParcelableResource.loadDefaultString(defaultStringLoader);
+ }
+
+ /**
+ * Similar to {@link #getString(String, Supplier)} but accepts {@code formatArgs} and returns a
+ * localized formatted string, substituting the format arguments as defined in
+ * {@link java.util.Formatter} and {@link java.lang.String#format}, (see
+ * {@link Resources#getString(int, Object...)}).
+ *
+ * <p>Calls to this API will not return {@code null} unless no updated drawable was found
+ * and the call to {@code defaultStringLoader} returned {@code null}.
+ *
+ * @param stringId The IDs to get the updated resource for.
+ * @param defaultStringLoader To get the default string if no updated string was set for
+ * {@code stringId}.
+ * @param formatArgs The format arguments that will be used for substitution.
+ */
+ @Nullable
+ @SuppressLint("SamShouldBeLast")
+ public String getString(
+ @NonNull String stringId,
+ @NonNull Supplier<String> defaultStringLoader,
+ @NonNull Object... formatArgs) {
+
+ Objects.requireNonNull(stringId, "stringId can't be null");
+ Objects.requireNonNull(defaultStringLoader, "defaultStringLoader can't be null");
+
+ if (stringId.equals(DevicePolicyResources.UNDEFINED)) {
+ return ParcelableResource.loadDefaultString(defaultStringLoader);
+ }
+ if (mService != null) {
+ try {
+ ParcelableResource resource = mService.getString(stringId);
+ if (resource == null) {
+ return ParcelableResource.loadDefaultString(defaultStringLoader);
+ }
+ return resource.getString(mContext, defaultStringLoader, formatArgs);
+ } catch (RemoteException e) {
+ Log.e(
+ TAG,
+ "Error getting the updated string from DevicePolicyManagerService.",
+ e);
+ return ParcelableResource.loadDefaultString(defaultStringLoader);
+ }
+ }
+ return ParcelableResource.loadDefaultString(defaultStringLoader);
+ }
+}
diff --git a/core/java/android/app/admin/DevicePolicyStringResource.java b/core/java/android/app/admin/DevicePolicyStringResource.java
index b36f140807aa..7e593406c87c 100644
--- a/core/java/android/app/admin/DevicePolicyStringResource.java
+++ b/core/java/android/app/admin/DevicePolicyStringResource.java
@@ -28,19 +28,19 @@ import java.util.Objects;
/**
* Used to pass in the required information for updating an enterprise string resource using
- * {@link DevicePolicyManager#setStrings}.
+ * {@link DevicePolicyResourcesManager#setStrings}.
*
* @hide
*/
@SystemApi
public final class DevicePolicyStringResource implements Parcelable {
- @NonNull private final @DevicePolicyResources.UpdatableStringId String mStringId;
+ @NonNull private final String mStringId;
private final @StringRes int mResourceIdInCallingPackage;
@NonNull private ParcelableResource mResource;
/**
* Creates an object containing the required information for updating an enterprise string
- * resource using {@link DevicePolicyManager#setStrings}.
+ * resource using {@link DevicePolicyResourcesManager#setStrings}.
*
* <p>It will be used to update the string defined by {@code stringId} to the string with ID
* {@code resourceIdInCallingPackage} in the calling package</p>
@@ -54,14 +54,14 @@ public final class DevicePolicyStringResource implements Parcelable {
*/
public DevicePolicyStringResource(
@NonNull Context context,
- @NonNull @DevicePolicyResources.UpdatableStringId String stringId,
+ @NonNull String stringId,
@StringRes int resourceIdInCallingPackage) {
this(stringId, resourceIdInCallingPackage, new ParcelableResource(
context, resourceIdInCallingPackage, ParcelableResource.RESOURCE_TYPE_STRING));
}
private DevicePolicyStringResource(
- @NonNull @DevicePolicyResources.UpdatableStringId String stringId,
+ @NonNull String stringId,
@StringRes int resourceIdInCallingPackage,
@NonNull ParcelableResource resource) {
Objects.requireNonNull(stringId, "stringId must be provided.");
@@ -75,7 +75,6 @@ public final class DevicePolicyStringResource implements Parcelable {
/**
* Returns the ID of the string to update.
*/
- @DevicePolicyResources.UpdatableStringId
@NonNull
public String getStringId() {
return mStringId;
diff --git a/core/java/android/app/admin/FactoryResetProtectionPolicy.java b/core/java/android/app/admin/FactoryResetProtectionPolicy.java
index 40ae1f0c11ea..7e951779d2a6 100644
--- a/core/java/android/app/admin/FactoryResetProtectionPolicy.java
+++ b/core/java/android/app/admin/FactoryResetProtectionPolicy.java
@@ -25,6 +25,7 @@ import android.annotation.Nullable;
import android.content.ComponentName;
import android.os.Parcel;
import android.os.Parcelable;
+import android.util.IndentingPrintWriter;
import android.util.Log;
import android.util.TypedXmlPullParser;
import android.util.TypedXmlSerializer;
@@ -254,4 +255,18 @@ public final class FactoryResetProtectionPolicy implements Parcelable {
return !mFactoryResetProtectionAccounts.isEmpty() && mFactoryResetProtectionEnabled;
}
+ /**
+ * @hide
+ */
+ public void dump(IndentingPrintWriter pw) {
+ pw.print("factoryResetProtectionEnabled=");
+ pw.println(mFactoryResetProtectionEnabled);
+
+ pw.print("factoryResetProtectionAccounts=");
+ pw.increaseIndent();
+ for (int i = 0; i < mFactoryResetProtectionAccounts.size(); i++) {
+ pw.println(mFactoryResetProtectionAccounts.get(i));
+ }
+ pw.decreaseIndent();
+ }
}
diff --git a/core/java/android/app/admin/FullyManagedDeviceProvisioningParams.java b/core/java/android/app/admin/FullyManagedDeviceProvisioningParams.java
index 1f7ae4ad35de..49992452df86 100644
--- a/core/java/android/app/admin/FullyManagedDeviceProvisioningParams.java
+++ b/core/java/android/app/admin/FullyManagedDeviceProvisioningParams.java
@@ -26,6 +26,7 @@ import android.content.ComponentName;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.PersistableBundle;
+import android.provider.Settings;
import android.stats.devicepolicy.DevicePolicyEnums;
import java.util.Locale;
@@ -44,6 +45,7 @@ public final class FullyManagedDeviceProvisioningParams implements Parcelable {
"CAN_DEVICE_OWNER_GRANT_SENSOR_PERMISSIONS";
private static final String TIME_ZONE_PROVIDED_PARAM = "TIME_ZONE_PROVIDED";
private static final String LOCALE_PROVIDED_PARAM = "LOCALE_PROVIDED";
+ private static final String DEMO_DEVICE = "DEMO_DEVICE";
@NonNull private final ComponentName mDeviceAdminComponentName;
@NonNull private final String mOwnerName;
@@ -54,6 +56,8 @@ public final class FullyManagedDeviceProvisioningParams implements Parcelable {
@Nullable private final Locale mLocale;
private final boolean mDeviceOwnerCanGrantSensorsPermissions;
@NonNull private final PersistableBundle mAdminExtras;
+ private final boolean mDemoDevice;
+
private FullyManagedDeviceProvisioningParams(
@NonNull ComponentName deviceAdminComponentName,
@@ -63,7 +67,8 @@ public final class FullyManagedDeviceProvisioningParams implements Parcelable {
long localTime,
@Nullable @SuppressLint("UseIcu") Locale locale,
boolean deviceOwnerCanGrantSensorsPermissions,
- @NonNull PersistableBundle adminExtras) {
+ @NonNull PersistableBundle adminExtras,
+ boolean demoDevice) {
this.mDeviceAdminComponentName = requireNonNull(deviceAdminComponentName);
this.mOwnerName = requireNonNull(ownerName);
this.mLeaveAllSystemAppsEnabled = leaveAllSystemAppsEnabled;
@@ -73,6 +78,7 @@ public final class FullyManagedDeviceProvisioningParams implements Parcelable {
this.mDeviceOwnerCanGrantSensorsPermissions =
deviceOwnerCanGrantSensorsPermissions;
this.mAdminExtras = adminExtras;
+ this.mDemoDevice = demoDevice;
}
private FullyManagedDeviceProvisioningParams(
@@ -83,7 +89,8 @@ public final class FullyManagedDeviceProvisioningParams implements Parcelable {
long localTime,
@Nullable String localeStr,
boolean deviceOwnerCanGrantSensorsPermissions,
- @Nullable PersistableBundle adminExtras) {
+ @Nullable PersistableBundle adminExtras,
+ boolean demoDevice) {
this(deviceAdminComponentName,
ownerName,
leaveAllSystemAppsEnabled,
@@ -91,7 +98,8 @@ public final class FullyManagedDeviceProvisioningParams implements Parcelable {
localTime,
getLocale(localeStr),
deviceOwnerCanGrantSensorsPermissions,
- adminExtras);
+ adminExtras,
+ demoDevice);
}
@Nullable
@@ -166,6 +174,14 @@ public final class FullyManagedDeviceProvisioningParams implements Parcelable {
}
/**
+ * @return true if this device is being setup as a retail demo device, see
+ * {@link Settings.Global#DEVICE_DEMO_MODE}.
+ */
+ public boolean isDemoDevice() {
+ return mDemoDevice;
+ }
+
+ /**
* Logs the provisioning params using {@link DevicePolicyEventLogger}.
*
* @hide
@@ -178,6 +194,7 @@ public final class FullyManagedDeviceProvisioningParams implements Parcelable {
mDeviceOwnerCanGrantSensorsPermissions);
logParam(callerPackage, TIME_ZONE_PROVIDED_PARAM, /* value= */ mTimeZone != null);
logParam(callerPackage, LOCALE_PROVIDED_PARAM, /* value= */ mLocale != null);
+ logParam(callerPackage, DEMO_DEVICE, mDemoDevice);
}
private void logParam(String callerPackage, String param, boolean value) {
@@ -204,6 +221,9 @@ public final class FullyManagedDeviceProvisioningParams implements Parcelable {
// Default to allowing control over sensor permission grants.
boolean mDeviceOwnerCanGrantSensorsPermissions = true;
@NonNull private PersistableBundle mAdminExtras;
+ // Default is normal user devices
+ boolean mDemoDevice = false;
+
/**
* Initialize a new {@link Builder} to construct a
@@ -289,6 +309,16 @@ public final class FullyManagedDeviceProvisioningParams implements Parcelable {
}
/**
+ * Marks the device as a demo device, see {@link Settings.Global#DEVICE_DEMO_MODE}. The
+ * default value if unset is {@code false}.
+ */
+ @NonNull
+ public Builder setDemoDevice(boolean demoDevice) {
+ this.mDemoDevice = demoDevice;
+ return this;
+ }
+
+ /**
* Combines all of the attributes that have been set on this {@code Builder}
*
* @return a new {@link FullyManagedDeviceProvisioningParams} object.
@@ -303,7 +333,8 @@ public final class FullyManagedDeviceProvisioningParams implements Parcelable {
mLocalTime,
mLocale,
mDeviceOwnerCanGrantSensorsPermissions,
- mAdminExtras);
+ mAdminExtras,
+ mDemoDevice);
}
}
@@ -327,6 +358,7 @@ public final class FullyManagedDeviceProvisioningParams implements Parcelable {
+ ", mDeviceOwnerCanGrantSensorsPermissions="
+ mDeviceOwnerCanGrantSensorsPermissions
+ ", mAdminExtras=" + mAdminExtras
+ + ", mDemoDevice=" + mDemoDevice
+ '}';
}
@@ -340,6 +372,7 @@ public final class FullyManagedDeviceProvisioningParams implements Parcelable {
dest.writeString(mLocale == null ? null : mLocale.toLanguageTag());
dest.writeBoolean(mDeviceOwnerCanGrantSensorsPermissions);
dest.writePersistableBundle(mAdminExtras);
+ dest.writeBoolean(mDemoDevice);
}
@NonNull
@@ -355,6 +388,7 @@ public final class FullyManagedDeviceProvisioningParams implements Parcelable {
String locale = in.readString();
boolean deviceOwnerCanGrantSensorsPermissions = in.readBoolean();
PersistableBundle adminExtras = in.readPersistableBundle();
+ boolean demoDevice = in.readBoolean();
return new FullyManagedDeviceProvisioningParams(
componentName,
@@ -364,7 +398,8 @@ public final class FullyManagedDeviceProvisioningParams implements Parcelable {
localtime,
locale,
deviceOwnerCanGrantSensorsPermissions,
- adminExtras);
+ adminExtras,
+ demoDevice);
}
@Override
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 9d28ddefda7b..8a9ef4bf9e0e 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -17,6 +17,7 @@
package android.app.admin;
+import android.accounts.Account;
import android.app.admin.DevicePolicyDrawableResource;
import android.app.admin.DevicePolicyStringResource;
import android.app.admin.ParcelableResource;
@@ -285,12 +286,9 @@ interface IDevicePolicyManager {
void setSecondaryLockscreenEnabled(in ComponentName who, boolean enabled);
boolean isSecondaryLockscreenEnabled(in UserHandle userHandle);
- void setPreferentialNetworkServiceEnabled(in boolean enabled);
- boolean isPreferentialNetworkServiceEnabled(int userHandle);
-
- void setPreferentialNetworkServiceConfig(
- in PreferentialNetworkServiceConfig preferentialNetworkServiceConfig);
- PreferentialNetworkServiceConfig getPreferentialNetworkServiceConfig();
+ void setPreferentialNetworkServiceConfigs(
+ in List<PreferentialNetworkServiceConfig> preferentialNetworkServiceConfigs);
+ List<PreferentialNetworkServiceConfig> getPreferentialNetworkServiceConfigs();
void setLockTaskPackages(in ComponentName who, in String[] packages);
String[] getLockTaskPackages(in ComponentName who);
@@ -479,7 +477,7 @@ interface IDevicePolicyManager {
int getGlobalPrivateDnsMode(in ComponentName admin);
String getGlobalPrivateDnsHost(in ComponentName admin);
- void markProfileOwnerOnOrganizationOwnedDevice(in ComponentName who, int userId);
+ void setProfileOwnerOnOrganizationOwnedDevice(in ComponentName who, int userId, boolean isProfileOwnerOnOrganizationOwnedDevice);
void installUpdateFromFile(in ComponentName admin, in ParcelFileDescriptor updateFileDescriptor, in StartInstallingUpdateCallback listener);
@@ -531,6 +529,8 @@ interface IDevicePolicyManager {
UserHandle createAndProvisionManagedProfile(in ManagedProfileProvisioningParams provisioningParams, in String callerPackage);
void provisionFullyManagedDevice(in FullyManagedDeviceProvisioningParams provisioningParams, in String callerPackage);
+ void finalizeWorkProfileProvisioning(in UserHandle managedProfileUser, in Account migratedAccount);
+
void setDeviceOwnerType(in ComponentName admin, in int deviceOwnerType);
int getDeviceOwnerType(in ComponentName admin);
@@ -552,13 +552,17 @@ interface IDevicePolicyManager {
List<UserHandle> listForegroundAffiliatedUsers();
void setDrawables(in List<DevicePolicyDrawableResource> drawables);
- void resetDrawables(in String[] drawableIds);
+ void resetDrawables(in List<String> drawableIds);
ParcelableResource getDrawable(String drawableId, String drawableStyle, String drawableSource);
boolean isDpcDownloaded();
void setDpcDownloaded(boolean downloaded);
void setStrings(in List<DevicePolicyStringResource> strings);
- void resetStrings(in String[] stringIds);
+ void resetStrings(in List<String> stringIds);
ParcelableResource getString(String stringId);
+
+ boolean shouldAllowBypassingDevicePolicyManagementRoleQualification();
+
+ List<UserHandle> getPolicyManagedProfiles(in UserHandle userHandle);
}
diff --git a/core/java/android/app/admin/ParcelableResource.java b/core/java/android/app/admin/ParcelableResource.java
index bcae2846ad42..a29766546551 100644
--- a/core/java/android/app/admin/ParcelableResource.java
+++ b/core/java/android/app/admin/ParcelableResource.java
@@ -43,7 +43,8 @@ import java.util.function.Supplier;
/**
* Used to store the required information to load a resource that was updated using
- * {@link DevicePolicyManager#setDrawables} and {@link DevicePolicyManager#setStrings}.
+ * {@link DevicePolicyResourcesManager#setDrawables} and
+ * {@link DevicePolicyResourcesManager#setStrings}.
*
* @hide
*/
diff --git a/core/java/android/app/admin/PreferentialNetworkServiceConfig.java b/core/java/android/app/admin/PreferentialNetworkServiceConfig.java
index 2849139c606b..54170a2a187f 100644
--- a/core/java/android/app/admin/PreferentialNetworkServiceConfig.java
+++ b/core/java/android/app/admin/PreferentialNetworkServiceConfig.java
@@ -28,7 +28,7 @@ import java.util.Objects;
/**
* Network configuration to be set for the user profile
- * {@see DevicePolicyManager#setPreferentialNetworkServiceConfig}.
+ * {@see DevicePolicyManager#setPreferentialNetworkServiceConfigs}.
*/
public final class PreferentialNetworkServiceConfig implements Parcelable {
final boolean mIsEnabled;
@@ -147,8 +147,6 @@ public final class PreferentialNetworkServiceConfig implements Parcelable {
/**
* @return preference enterprise identifier.
- * valid values starts from
- * {@link #PREFERENTIAL_NETWORK_ID_1} to {@link #PREFERENTIAL_NETWORK_ID_5}.
* preference identifier is applicable only if preference network service is enabled
*
*/
@@ -286,8 +284,6 @@ public final class PreferentialNetworkServiceConfig implements Parcelable {
/**
* Set the preferential network identifier.
- * Valid values starts from {@link #PREFERENTIAL_NETWORK_ID_1} to
- * {@link #PREFERENTIAL_NETWORK_ID_5}.
* preference identifier is applicable only if preferential network service is enabled.
* @param preferenceId preference Id
* @return The builder to facilitate chaining.
diff --git a/core/java/android/app/admin/SecurityLog.java b/core/java/android/app/admin/SecurityLog.java
index b170aa2a1325..b90408d4395e 100644
--- a/core/java/android/app/admin/SecurityLog.java
+++ b/core/java/android/app/admin/SecurityLog.java
@@ -517,14 +517,15 @@ public class SecurityLog {
public static final int TAG_PASSWORD_CHANGED = SecurityLogTags.SECURITY_PASSWORD_CHANGED;
/**
- * Indicates that the device attempts to connect to a WiFi network.
- * The log entry contains the following information about the
+ * Indicates that an event occurred as the device attempted to connect to
+ * a WiFi network. The log entry contains the following information about the
* event, encapsulated in an {@link Object} array and accessible via
* {@link SecurityEvent#getData()}:
- * <li> [0] The SSID of the network ({@code String})
- * <li> [1] The BSSID of the network ({@code String})
- * <li> [2] Whether the connection is successful ({@code Integer}, 1 if successful, 0 otherwise)
- * <li> [3] Optional human-readable failure reason, empty string if none ({@code String})
+ * <li> [0] Last 2 octets of the network BSSID ({@code String}, in the form "xx:xx:xx:xx:AA:BB")
+ * <li> [1] Type of event that occurred ({@code String}). Event types are CONNECTED,
+ * DISCONNECTED, ASSOCIATING, ASSOCIATED, EAP_METHOD_SELECTED, EAP_FAILURE,
+ * SSID_TEMP_DISABLED, and OPEN_SSL_FAILURE.
+ * <li> [2] Optional human-readable failure reason, empty string if none ({@code String})
*/
public static final int TAG_WIFI_CONNECTION = SecurityLogTags.SECURITY_WIFI_CONNECTION;
@@ -533,9 +534,8 @@ public class SecurityLog {
* The log entry contains the following information about the
* event, encapsulated in an {@link Object} array and accessible via
* {@link SecurityEvent#getData()}:
- * <li> [0] The SSID of the connected network ({@code String})
- * <li> [1] The BSSID of the connected network ({@code String})
- * <li> [2] Optional human-readable disconnection reason, empty string if none ({@code String})
+ * <li> [0] Last 2 octets of the network BSSID ({@code String}, in the form "xx:xx:xx:xx:AA:BB")
+ * <li> [1] Optional human-readable disconnection reason, empty string if none ({@code String})
*/
public static final int TAG_WIFI_DISCONNECTION = SecurityLogTags.SECURITY_WIFI_DISCONNECTION;
diff --git a/core/java/android/app/admin/SecurityLogTags.logtags b/core/java/android/app/admin/SecurityLogTags.logtags
index 5f41109600b2..b06e5a5849fd 100644
--- a/core/java/android/app/admin/SecurityLogTags.logtags
+++ b/core/java/android/app/admin/SecurityLogTags.logtags
@@ -41,7 +41,7 @@ option java_package android.app.admin
210034 security_camera_policy_set (package|3),(admin_user|1),(target_user|1),(disabled|1)
210035 security_password_complexity_required (package|3),(admin_user|1),(target_user|1),(complexity|1)
210036 security_password_changed (password_complexity|1),(target_user|1)
-210037 security_wifi_connection (ssid|3),(bssid|3),(success|1),(reason|3)
-210038 security_wifi_disconnection (ssid|3),(bssid|3),(reason|3)
+210037 security_wifi_connection (bssid|3),(event_type|3),(reason|3)
+210038 security_wifi_disconnection (bssid|3),(reason|3)
210039 security_bluetooth_connection (addr|3),(success|1),(reason|3)
210040 security_bluetooth_disconnection (addr|3),(reason|3) \ No newline at end of file
diff --git a/core/java/android/app/cloudsearch/SearchRequest.java b/core/java/android/app/cloudsearch/SearchRequest.java
index 4d6507abfd61..bf783255b3d9 100644
--- a/core/java/android/app/cloudsearch/SearchRequest.java
+++ b/core/java/android/app/cloudsearch/SearchRequest.java
@@ -100,7 +100,7 @@ public final class SearchRequest implements Parcelable {
*
*/
@NonNull
- private String mSource;
+ private String mCallerPackageName;
private SearchRequest(Parcel in) {
this.mQuery = in.readString();
@@ -109,17 +109,17 @@ public final class SearchRequest implements Parcelable {
this.mMaxLatencyMillis = in.readFloat();
this.mSearchConstraints = in.readBundle();
this.mId = in.readString();
- this.mSource = in.readString();
+ this.mCallerPackageName = in.readString();
}
private SearchRequest(String query, int resultOffset, int resultNumber, float maxLatencyMillis,
- Bundle searchConstraints, String source) {
+ Bundle searchConstraints, String callerPackageName) {
mQuery = query;
mResultOffset = resultOffset;
mResultNumber = resultNumber;
mMaxLatencyMillis = maxLatencyMillis;
mSearchConstraints = searchConstraints;
- mSource = source;
+ mCallerPackageName = callerPackageName;
}
/** Returns the original query. */
@@ -151,8 +151,8 @@ public final class SearchRequest implements Parcelable {
/** Gets the caller's package name. */
@NonNull
- public String getSource() {
- return mSource;
+ public String getCallerPackageName() {
+ return mCallerPackageName;
}
/** Returns the search request id, which is used to identify the request. */
@@ -169,8 +169,8 @@ public final class SearchRequest implements Parcelable {
*
* @hide
*/
- public void setSource(@NonNull String source) {
- this.mSource = source;
+ public void setCallerPackageName(@NonNull String callerPackageName) {
+ this.mCallerPackageName = callerPackageName;
}
private SearchRequest(Builder b) {
@@ -179,7 +179,7 @@ public final class SearchRequest implements Parcelable {
mResultNumber = b.mResultNumber;
mMaxLatencyMillis = b.mMaxLatencyMillis;
mSearchConstraints = requireNonNull(b.mSearchConstraints);
- mSource = requireNonNull(b.mSource);
+ mCallerPackageName = requireNonNull(b.mCallerPackageName);
}
/**
@@ -207,7 +207,7 @@ public final class SearchRequest implements Parcelable {
dest.writeFloat(this.mMaxLatencyMillis);
dest.writeBundle(this.mSearchConstraints);
dest.writeString(getRequestId());
- dest.writeString(this.mSource);
+ dest.writeString(this.mCallerPackageName);
}
@Override
@@ -231,7 +231,7 @@ public final class SearchRequest implements Parcelable {
&& mResultNumber == that.mResultNumber
&& mMaxLatencyMillis == that.mMaxLatencyMillis
&& Objects.equals(mSearchConstraints, that.mSearchConstraints)
- && Objects.equals(mSource, that.mSource);
+ && Objects.equals(mCallerPackageName, that.mCallerPackageName);
}
@Override
@@ -246,14 +246,15 @@ public final class SearchRequest implements Parcelable {
}
return String.format("SearchRequest: {query:%s,offset:%d;number:%d;max_latency:%f;"
- + "is_presubmit:%b;search_provider:%s;source:%s}", mQuery, mResultOffset,
- mResultNumber, mMaxLatencyMillis, isPresubmit, searchProvider, mSource);
+ + "is_presubmit:%b;search_provider:%s;callerPackageName:%s}", mQuery,
+ mResultOffset, mResultNumber, mMaxLatencyMillis, isPresubmit, searchProvider,
+ mCallerPackageName);
}
@Override
public int hashCode() {
return Objects.hash(mQuery, mResultOffset, mResultNumber, mMaxLatencyMillis,
- mSearchConstraints, mSource);
+ mSearchConstraints, mCallerPackageName);
}
/**
@@ -268,7 +269,7 @@ public final class SearchRequest implements Parcelable {
private int mResultNumber;
private float mMaxLatencyMillis;
private Bundle mSearchConstraints;
- private String mSource;
+ private String mCallerPackageName;
/**
*
@@ -284,7 +285,7 @@ public final class SearchRequest implements Parcelable {
mResultNumber = 10;
mMaxLatencyMillis = 200;
mSearchConstraints = Bundle.EMPTY;
- mSource = "DEFAULT_CALLER";
+ mCallerPackageName = "DEFAULT_CALLER";
}
/** Sets the input query. */
@@ -329,8 +330,8 @@ public final class SearchRequest implements Parcelable {
*/
@NonNull
@TestApi
- public Builder setSource(@NonNull String source) {
- this.mSource = source;
+ public Builder setCallerPackageName(@NonNull String callerPackageName) {
+ this.mCallerPackageName = callerPackageName;
return this;
}
@@ -343,7 +344,7 @@ public final class SearchRequest implements Parcelable {
}
return new SearchRequest(mQuery, mResultOffset, mResultNumber, mMaxLatencyMillis,
- mSearchConstraints, mSource);
+ mSearchConstraints, mCallerPackageName);
}
}
}
diff --git a/core/java/android/app/cloudsearch/SearchResult.java b/core/java/android/app/cloudsearch/SearchResult.java
index af8adacd4258..c6583b65f9c2 100644
--- a/core/java/android/app/cloudsearch/SearchResult.java
+++ b/core/java/android/app/cloudsearch/SearchResult.java
@@ -71,6 +71,10 @@ public final class SearchResult implements Parcelable {
EXTRAINFO_APP_BADGES,
EXTRAINFO_ACTION_BUTTON_TEXT_PREREGISTERING,
EXTRAINFO_ACTION_BUTTON_IMAGE_PREREGISTERING,
+ EXTRAINFO_ACTION_APP_CARD,
+ EXTRAINFO_ACTION_INSTALL_BUTTON,
+ EXTRAINFO_APP_PACKAGE_NAME,
+ EXTRAINFO_APP_INSTALL_COUNT,
EXTRAINFO_WEB_URL,
EXTRAINFO_WEB_ICON})
public @interface SearchResultExtraInfoKey {}
@@ -119,6 +123,20 @@ public final class SearchResult implements Parcelable {
@SuppressLint("IntentName")
public static final String EXTRAINFO_ACTION_BUTTON_IMAGE_PREREGISTERING =
"android.app.cloudsearch.ACTION_BUTTON_IMAGE";
+ /** Intent for tapping the app card, PendingIntent expected. */
+ @SuppressLint("IntentName")
+ public static final String EXTRAINFO_ACTION_APP_CARD =
+ "android.app.cloudsearch.ACTION_APP_CARD";
+ /** Intent for tapping the install button, PendingIntent expected. */
+ @SuppressLint("IntentName")
+ public static final String EXTRAINFO_ACTION_INSTALL_BUTTON =
+ "android.app.cloudsearch.ACTION_INSTALL_BUTTON";
+ /** App's package name, String value expected. */
+ public static final String EXTRAINFO_APP_PACKAGE_NAME =
+ "android.app.cloudsearch.APP_PACKAGE_NAME";
+ /** App's install count, double value expected. */
+ public static final String EXTRAINFO_APP_INSTALL_COUNT =
+ "android.app.cloudsearch.APP_INSTALL_COUNT";
/** Web content's URL, String value expected. */
public static final String EXTRAINFO_WEB_URL = "android.app.cloudsearch.WEB_URL";
/** Web content's domain icon, android.graphics.drawable.Icon expected. */
diff --git a/core/java/android/app/prediction/AppTargetEvent.java b/core/java/android/app/prediction/AppTargetEvent.java
index 51e3953ead4f..91da8ec71dae 100644
--- a/core/java/android/app/prediction/AppTargetEvent.java
+++ b/core/java/android/app/prediction/AppTargetEvent.java
@@ -60,6 +60,11 @@ public final class AppTargetEvent implements Parcelable {
*/
public static final int ACTION_UNPIN = 4;
+ /**
+ * Event type constant indicating an app target has been un-dismissed.
+ */
+ public static final int ACTION_UNDISMISS = 5;
+
private final AppTarget mTarget;
private final String mLocation;
private final int mAction;
diff --git a/core/java/android/app/servertransaction/ActivityTransactionItem.java b/core/java/android/app/servertransaction/ActivityTransactionItem.java
index 6a6d76d20259..469a9bfe59ef 100644
--- a/core/java/android/app/servertransaction/ActivityTransactionItem.java
+++ b/core/java/android/app/servertransaction/ActivityTransactionItem.java
@@ -64,11 +64,11 @@ public abstract class ActivityTransactionItem extends ClientTransactionItem {
final ActivityClientRecord r = client.getActivityClient(token);
if (r == null) {
throw new IllegalArgumentException("Activity client record must not be null to execute "
- + "transaction item");
+ + "transaction item: " + this);
}
if (client.getActivity(token) == null) {
throw new IllegalArgumentException("Activity must not be null to execute "
- + "transaction item");
+ + "transaction item: " + this);
}
return r;
}
diff --git a/core/java/android/app/servertransaction/LaunchActivityItem.java b/core/java/android/app/servertransaction/LaunchActivityItem.java
index abf1058f45a2..d7e09519bfb7 100644
--- a/core/java/android/app/servertransaction/LaunchActivityItem.java
+++ b/core/java/android/app/servertransaction/LaunchActivityItem.java
@@ -179,7 +179,7 @@ public class LaunchActivityItem extends ClientTransactionItem {
in.readPersistableBundle(getClass().getClassLoader()),
in.createTypedArrayList(ResultInfo.CREATOR),
in.createTypedArrayList(ReferrerIntent.CREATOR),
- readActivityOptions(in), in.readBoolean(),
+ ActivityOptions.fromBundle(in.readBundle()), in.readBoolean(),
in.readTypedObject(ProfilerInfo.CREATOR),
in.readStrongBinder(),
IActivityClientController.Stub.asInterface(in.readStrongBinder()),
@@ -187,11 +187,6 @@ public class LaunchActivityItem extends ClientTransactionItem {
in.readBoolean());
}
- private static ActivityOptions readActivityOptions(Parcel in) {
- Bundle bundle = in.readBundle();
- return bundle != null ? ActivityOptions.fromBundle(bundle) : null;
- }
-
public static final @NonNull Creator<LaunchActivityItem> CREATOR =
new Creator<LaunchActivityItem>() {
public LaunchActivityItem createFromParcel(Parcel in) {
diff --git a/core/java/android/app/servertransaction/StartActivityItem.java b/core/java/android/app/servertransaction/StartActivityItem.java
index f267060d1be6..15f65f6d9d26 100644
--- a/core/java/android/app/servertransaction/StartActivityItem.java
+++ b/core/java/android/app/servertransaction/StartActivityItem.java
@@ -23,7 +23,6 @@ import android.annotation.Nullable;
import android.app.ActivityOptions;
import android.app.ActivityThread.ActivityClientRecord;
import android.app.ClientTransactionHandler;
-import android.os.Bundle;
import android.os.Parcel;
import android.os.Trace;
@@ -84,8 +83,7 @@ public class StartActivityItem extends ActivityLifecycleItem {
/** Read from Parcel. */
private StartActivityItem(Parcel in) {
- Bundle bundle = in.readBundle();
- mActivityOptions = bundle != null ? ActivityOptions.fromBundle(bundle) : null;
+ mActivityOptions = ActivityOptions.fromBundle(in.readBundle());
}
public static final @NonNull Creator<StartActivityItem> CREATOR =
diff --git a/core/java/android/app/trust/ITrustManager.aidl b/core/java/android/app/trust/ITrustManager.aidl
index b786444faa8c..45146fd95104 100644
--- a/core/java/android/app/trust/ITrustManager.aidl
+++ b/core/java/android/app/trust/ITrustManager.aidl
@@ -26,7 +26,8 @@ import android.hardware.biometrics.BiometricSourceType;
*/
interface ITrustManager {
void reportUnlockAttempt(boolean successful, int userId);
- void reportUserRequestedUnlock(int userId);
+ void reportUserRequestedUnlock(int userId, boolean dismissKeyguard);
+ void reportUserMayRequestUnlock(int userId);
void reportUnlockLockout(int timeoutMs, int userId);
void reportEnabledTrustAgentsChanged(int userId);
void registerTrustListener(in ITrustListener trustListener);
diff --git a/core/java/android/app/trust/TEST_MAPPING b/core/java/android/app/trust/TEST_MAPPING
new file mode 100644
index 000000000000..b9c46bfbba8c
--- /dev/null
+++ b/core/java/android/app/trust/TEST_MAPPING
@@ -0,0 +1,15 @@
+{
+ "presubmit": [
+ {
+ "name": "TrustTests",
+ "options": [
+ {
+ "include-filter": "android.trust.test"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ }
+ ]
+ }
+ ]
+} \ No newline at end of file
diff --git a/core/java/android/app/trust/TrustManager.java b/core/java/android/app/trust/TrustManager.java
index 70b7de0767e4..9e825b7207e0 100644
--- a/core/java/android/app/trust/TrustManager.java
+++ b/core/java/android/app/trust/TrustManager.java
@@ -92,10 +92,25 @@ public class TrustManager {
* Reports that the user {@code userId} is likely interested in unlocking the device.
*
* Requires the {@link android.Manifest.permission#ACCESS_KEYGUARD_SECURE_STORAGE} permission.
+ *
+ * @param dismissKeyguard whether the user wants to dismiss keyguard
+ */
+ public void reportUserRequestedUnlock(int userId, boolean dismissKeyguard) {
+ try {
+ mService.reportUserRequestedUnlock(userId, dismissKeyguard);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Reports that the user {@code userId} may want to unlock the device soon.
+ *
+ * Requires the {@link android.Manifest.permission#ACCESS_KEYGUARD_SECURE_STORAGE} permission.
*/
- public void reportUserRequestedUnlock(int userId) {
+ public void reportUserMayRequestUnlock(int userId) {
try {
- mService.reportUserRequestedUnlock(userId);
+ mService.reportUserMayRequestUnlock(userId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/app/usage/BroadcastResponseStats.java b/core/java/android/app/usage/BroadcastResponseStats.java
index e1d37e1b1ae0..572c45355e42 100644
--- a/core/java/android/app/usage/BroadcastResponseStats.java
+++ b/core/java/android/app/usage/BroadcastResponseStats.java
@@ -29,6 +29,8 @@ import java.util.Objects;
* Class containing a collection of stats related to response events started from an app
* after receiving a broadcast.
*
+ * @see UsageStatsManager#queryBroadcastResponseStats(String, long)
+ * @see UsageStatsManager#clearBroadcastResponseStats(String, long)
* @hide
*/
@SystemApi
diff --git a/core/java/android/app/usage/IUsageStatsManager.aidl b/core/java/android/app/usage/IUsageStatsManager.aidl
index 2a2a9c6e703e..d4fbdc6850a4 100644
--- a/core/java/android/app/usage/IUsageStatsManager.aidl
+++ b/core/java/android/app/usage/IUsageStatsManager.aidl
@@ -74,12 +74,14 @@ interface IUsageStatsManager {
int getUsageSource();
void forceUsageSourceSettingRead();
long getLastTimeAnyComponentUsed(String packageName, String callingPackage);
- @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS)")
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.ACCESS_BROADCAST_RESPONSE_STATS)")
BroadcastResponseStatsList queryBroadcastResponseStats(
String packageName, long id, String callingPackage, int userId);
- @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS)")
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.ACCESS_BROADCAST_RESPONSE_STATS)")
void clearBroadcastResponseStats(String packageName, long id, String callingPackage,
int userId);
- @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS)")
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.ACCESS_BROADCAST_RESPONSE_STATS)")
void clearBroadcastEvents(String callingPackage, int userId);
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG)")
+ String getAppStandbyConstant(String key);
}
diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java
index 3a335f9d151b..c013fcd5adb9 100644
--- a/core/java/android/app/usage/UsageStatsManager.java
+++ b/core/java/android/app/usage/UsageStatsManager.java
@@ -16,6 +16,7 @@
package android.app.usage;
+import android.Manifest;
import android.annotation.CurrentTimeMillisLong;
import android.annotation.IntDef;
import android.annotation.IntRange;
@@ -1446,7 +1447,7 @@ public final class UsageStatsManager {
* @hide
*/
@SystemApi
- @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS)
+ @RequiresPermission(android.Manifest.permission.ACCESS_BROADCAST_RESPONSE_STATS)
@UserHandleAware
@NonNull
public List<BroadcastResponseStats> queryBroadcastResponseStats(
@@ -1479,7 +1480,7 @@ public final class UsageStatsManager {
* @hide
*/
@SystemApi
- @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS)
+ @RequiresPermission(android.Manifest.permission.ACCESS_BROADCAST_RESPONSE_STATS)
@UserHandleAware
public void clearBroadcastResponseStats(@Nullable String packageName,
@IntRange(from = 0) long id) {
@@ -1496,7 +1497,7 @@ public final class UsageStatsManager {
*
* @hide
*/
- @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS)
+ @RequiresPermission(android.Manifest.permission.ACCESS_BROADCAST_RESPONSE_STATS)
@UserHandleAware
public void clearBroadcastEvents() {
try {
@@ -1505,4 +1506,15 @@ public final class UsageStatsManager {
throw re.rethrowFromSystemServer();
}
}
+
+ /** @hide */
+ @RequiresPermission(Manifest.permission.READ_DEVICE_CONFIG)
+ @Nullable
+ public String getAppStandbyConstant(@NonNull String key) {
+ try {
+ return mService.getAppStandbyConstant(key);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
}
diff --git a/core/java/android/companion/CompanionDeviceManager.java b/core/java/android/companion/CompanionDeviceManager.java
index 15685000d6ba..56939f0ae650 100644
--- a/core/java/android/companion/CompanionDeviceManager.java
+++ b/core/java/android/companion/CompanionDeviceManager.java
@@ -76,6 +76,56 @@ public final class CompanionDeviceManager {
private static final String LOG_TAG = "CompanionDeviceManager";
/**
+ * The result code to propagate back to the originating activity, indicates the association
+ * dialog is explicitly declined by the users.
+ *
+ * @hide
+ */
+ public static final int RESULT_USER_REJECTED = 1;
+
+ /**
+ * The result code to propagate back to the originating activity, indicates the association
+ * dialog is dismissed if there's no device found after 20 seconds.
+ *
+ * @hide
+ */
+ public static final int RESULT_DISCOVERY_TIMEOUT = 2;
+
+ /**
+ * The result code to propagate back to the originating activity, indicates the internal error
+ * in CompanionDeviceManager.
+ *
+ * @hide
+ */
+ public static final int RESULT_INTERNAL_ERROR = 3;
+
+ /**
+ * Requesting applications will receive the String in {@link Callback#onFailure} if the
+ * association dialog is explicitly declined by the users. e.g. press the Don't allow button.
+ *
+ * @hide
+ */
+ public static final String REASON_USER_REJECTED = "user_rejected";
+
+ /**
+ * Requesting applications will receive the String in {@link Callback#onFailure} if there's
+ * no device found after 20 seconds.
+ *
+ * @hide
+ */
+ public static final String REASON_DISCOVERY_TIMEOUT = "discovery_timeout";
+
+ /**
+ * Requesting applications will receive the String in {@link Callback#onFailure} if the
+ * association dialog is in-explicitly declined by the users. e.g. phone is locked, switch to
+ * another app or press outside the dialog.
+ *
+ * @hide
+ */
+ public static final String REASON_CANCELED = "canceled";
+
+
+ /**
* A device, returned in the activity result of the {@link IntentSender} received in
* {@link Callback#onDeviceFound}
*
diff --git a/core/java/android/companion/virtual/VirtualDeviceParams.java b/core/java/android/companion/virtual/VirtualDeviceParams.java
index 41b1a1feae80..cbb51838507b 100644
--- a/core/java/android/companion/virtual/VirtualDeviceParams.java
+++ b/core/java/android/companion/virtual/VirtualDeviceParams.java
@@ -28,6 +28,8 @@ import android.os.Parcelable;
import android.os.UserHandle;
import android.util.ArraySet;
+import com.android.internal.util.Preconditions;
+
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -82,7 +84,7 @@ public final class VirtualDeviceParams implements Parcelable {
public static final int ACTIVITY_POLICY_DEFAULT_BLOCKED = 1;
private final int mLockState;
- private final ArraySet<UserHandle> mUsersWithMatchingAccounts;
+ @NonNull private final ArraySet<UserHandle> mUsersWithMatchingAccounts;
@NonNull private final ArraySet<ComponentName> mAllowedActivities;
@NonNull private final ArraySet<ComponentName> mBlockedActivities;
@ActivityPolicy
@@ -94,10 +96,14 @@ public final class VirtualDeviceParams implements Parcelable {
@NonNull Set<ComponentName> allowedActivities,
@NonNull Set<ComponentName> blockedActivities,
@ActivityPolicy int defaultActivityPolicy) {
+ Preconditions.checkNotNull(usersWithMatchingAccounts);
+ Preconditions.checkNotNull(allowedActivities);
+ Preconditions.checkNotNull(blockedActivities);
+
mLockState = lockState;
mUsersWithMatchingAccounts = new ArraySet<>(usersWithMatchingAccounts);
- mAllowedActivities = allowedActivities == null ? null : new ArraySet<>(allowedActivities);
- mBlockedActivities = blockedActivities == null ? null : new ArraySet<>(blockedActivities);
+ mAllowedActivities = new ArraySet<>(allowedActivities);
+ mBlockedActivities = new ArraySet<>(blockedActivities);
mDefaultActivityPolicy = defaultActivityPolicy;
}
@@ -130,30 +136,24 @@ public final class VirtualDeviceParams implements Parcelable {
}
/**
- * Returns the set of activities allowed to be streamed, or {@code null} if all activities are
+ * Returns the set of activities allowed to be streamed, or empty set if all activities are
* allowed, except the ones explicitly blocked.
*
* @see Builder#setAllowedActivities(Set)
*/
@NonNull
public Set<ComponentName> getAllowedActivities() {
- if (mAllowedActivities == null) {
- return Collections.emptySet();
- }
return Collections.unmodifiableSet(mAllowedActivities);
}
/**
- * Returns the set of activities that are blocked from streaming, or {@code null} to indicate
+ * Returns the set of activities that are blocked from streaming, or empty set to indicate
* that all activities in {@link #getAllowedActivities} are allowed.
*
* @see Builder#setBlockedActivities(Set)
*/
@NonNull
public Set<ComponentName> getBlockedActivities() {
- if (mBlockedActivities == null) {
- return Collections.emptySet();
- }
return Collections.unmodifiableSet(mBlockedActivities);
}
@@ -237,7 +237,7 @@ public final class VirtualDeviceParams implements Parcelable {
public static final class Builder {
private @LockState int mLockState = LOCK_STATE_DEFAULT;
- private Set<UserHandle> mUsersWithMatchingAccounts;
+ @NonNull private Set<UserHandle> mUsersWithMatchingAccounts = Collections.emptySet();;
@NonNull private Set<ComponentName> mBlockedActivities = Collections.emptySet();
@NonNull private Set<ComponentName> mAllowedActivities = Collections.emptySet();
@ActivityPolicy
@@ -282,6 +282,7 @@ public final class VirtualDeviceParams implements Parcelable {
@NonNull
public Builder setUsersWithMatchingAccounts(
@NonNull Set<UserHandle> usersWithMatchingAccounts) {
+ Preconditions.checkNotNull(usersWithMatchingAccounts);
mUsersWithMatchingAccounts = usersWithMatchingAccounts;
return this;
}
@@ -301,6 +302,7 @@ public final class VirtualDeviceParams implements Parcelable {
*/
@NonNull
public Builder setAllowedActivities(@NonNull Set<ComponentName> allowedActivities) {
+ Preconditions.checkNotNull(allowedActivities);
if (mDefaultActivityPolicyConfigured
&& mDefaultActivityPolicy != ACTIVITY_POLICY_DEFAULT_BLOCKED) {
throw new IllegalArgumentException(
@@ -327,6 +329,7 @@ public final class VirtualDeviceParams implements Parcelable {
*/
@NonNull
public Builder setBlockedActivities(@NonNull Set<ComponentName> blockedActivities) {
+ Preconditions.checkNotNull(blockedActivities);
if (mDefaultActivityPolicyConfigured
&& mDefaultActivityPolicy != ACTIVITY_POLICY_DEFAULT_ALLOWED) {
throw new IllegalArgumentException(
@@ -343,9 +346,6 @@ public final class VirtualDeviceParams implements Parcelable {
*/
@NonNull
public VirtualDeviceParams build() {
- if (mUsersWithMatchingAccounts == null) {
- mUsersWithMatchingAccounts = Collections.emptySet();
- }
return new VirtualDeviceParams(
mLockState,
mUsersWithMatchingAccounts,
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 2bda020192d5..24b1b6adb450 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -2011,9 +2011,9 @@ public abstract class Context {
* @hide
*/
@RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS)
- @UnsupportedAppUsage
- public void startActivityAsUser(@RequiresPermission Intent intent, @Nullable Bundle options,
- UserHandle userId) {
+ @SystemApi
+ public void startActivityAsUser(@RequiresPermission @NonNull Intent intent,
+ @Nullable Bundle options, @NonNull UserHandle userId) {
throw new RuntimeException("Not implemented. Must override in a subclass.");
}
@@ -6508,22 +6508,22 @@ public abstract class Context {
/**
- * Triggers the asynchronous revocation of a permission.
+ * Triggers the asynchronous revocation of a runtime permission. If the permission is not
+ * currently granted, nothing happens (even if later granted by the user).
*
* @param permName The name of the permission to be revoked.
- * @see #revokeOwnPermissionsOnKill(Collection)
+ * @see #revokeSelfPermissionsOnKill(Collection)
+ * @throws IllegalArgumentException if the permission is not a runtime permission
*/
- public void revokeOwnPermissionOnKill(@NonNull String permName) {
- revokeOwnPermissionsOnKill(Collections.singletonList(permName));
+ public void revokeSelfPermissionOnKill(@NonNull String permName) {
+ revokeSelfPermissionsOnKill(Collections.singletonList(permName));
}
/**
* Triggers the revocation of one or more permissions for the calling package. A package is only
- * able to revoke a permission under the following conditions:
- * <ul>
- * <li>Each permission in {@code permissions} must be granted to the calling package.
- * <li>Each permission in {@code permissions} must be a runtime permission.
- * </ul>
+ * able to revoke runtime permissions. If a permission is not currently granted, it is ignored
+ * and will not get revoked (even if later granted by the user). Ultimately, you should never
+ * make assumptions about a permission status as users may grant or revoke them at any time.
* <p>
* Background permissions which have no corresponding foreground permission still granted once
* the revocation is effective will also be revoked.
@@ -6549,8 +6549,9 @@ public abstract class Context {
* @param permissions Collection of permissions to be revoked.
* @see PackageManager#getGroupOfPlatformPermission(String, Executor, Consumer)
* @see PackageManager#getPlatformPermissionsForGroup(String, Executor, Consumer)
+ * @throws IllegalArgumentException if any of the permissions is not a runtime permission
*/
- public void revokeOwnPermissionsOnKill(@NonNull Collection<String> permissions) {
+ public void revokeSelfPermissionsOnKill(@NonNull Collection<String> permissions) {
throw new AbstractMethodError("Must be overridden in implementing class");
}
@@ -7145,8 +7146,9 @@ public abstract class Context {
}
/**
- * Returns token if the {@link Context} is a {@link android.app.WindowContext}. Returns
- * {@code null} otherwise.
+ * Returns the {@link IBinder} representing the associated
+ * {@link com.android.server.wm.WindowToken} if the {@link Context} is a
+ * {@link android.app.WindowContext}. Returns {@code null} otherwise.
*
* @hide
*/
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index 9adf17367039..4ecd7761ac4f 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -1036,8 +1036,8 @@ public class ContextWrapper extends Context {
}
@Override
- public void revokeOwnPermissionsOnKill(@NonNull Collection<String> permissions) {
- mBase.revokeOwnPermissionsOnKill(permissions);
+ public void revokeSelfPermissionsOnKill(@NonNull Collection<String> permissions) {
+ mBase.revokeSelfPermissionsOnKill(permissions);
}
@Override
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 478befd9c26d..a50ff3841da9 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -5987,22 +5987,6 @@ public class Intent implements Parcelable, Cloneable {
public static final String EXTRA_UID = "android.intent.extra.UID";
/**
- * Used as an optional int extra field in {@link android.content.Intent#ACTION_PACKAGE_ADDED}
- * intents to supply the previous uid the package had been assigned.
- * This would only be set when a package is leaving sharedUserId in an upgrade, or when a
- * system app upgrade that had left sharedUserId is getting uninstalled.
- */
- public static final String EXTRA_PREVIOUS_UID = "android.intent.extra.PREVIOUS_UID";
-
- /**
- * Used as an optional int extra field in {@link android.content.Intent#ACTION_PACKAGE_REMOVED}
- * intents to supply the new uid the package will be assigned.
- * This would only be set when a package is leaving sharedUserId in an upgrade, or when a
- * system app upgrade that had left sharedUserId is getting uninstalled.
- */
- public static final String EXTRA_NEW_UID = "android.intent.extra.NEW_UID";
-
- /**
* @hide String array of package names.
*/
@SystemApi
@@ -6034,16 +6018,6 @@ public class Intent implements Parcelable, Cloneable {
public static final String EXTRA_REPLACING = "android.intent.extra.REPLACING";
/**
- * Used as a boolean extra field in {@link android.content.Intent#ACTION_PACKAGE_REMOVED},
- * {@link android.content.Intent#ACTION_UID_REMOVED}, and
- * {@link android.content.Intent#ACTION_PACKAGE_ADDED}
- * intents to indicate that this package is changing its UID.
- * This would only be set when a package is leaving sharedUserId in an upgrade, or when a
- * system app upgrade that had left sharedUserId is getting uninstalled.
- */
- public static final String EXTRA_UID_CHANGING = "android.intent.extra.UID_CHANGING";
-
- /**
* Used as an int extra field in {@link android.app.AlarmManager} pending intents
* to tell the application being invoked how many pending alarms are being
* delivered with the intent. For one-shot alarms this will always be 1.
@@ -8903,8 +8877,12 @@ public class Intent implements Parcelable, Cloneable {
* @return the value of an item previously added with putExtra(),
* or null if no Parcelable value was found.
*
+ * @deprecated Use the type-safer {@link #getParcelableExtra(String, Class)} starting from
+ * Android {@link Build.VERSION_CODES#TIRAMISU}.
+ *
* @see #putExtra(String, Parcelable)
*/
+ @Deprecated
public @Nullable <T extends Parcelable> T getParcelableExtra(String name) {
return mExtras == null ? null : mExtras.<T>getParcelable(name);
}
@@ -8913,12 +8891,31 @@ public class Intent implements Parcelable, Cloneable {
* Retrieve extended data from the intent.
*
* @param name The name of the desired item.
+ * @param clazz The type of the object expected.
+ *
+ * @return the value of an item previously added with putExtra(),
+ * or null if no Parcelable value was found.
+ *
+ * @see #putExtra(String, Parcelable)
+ */
+ public @Nullable <T> T getParcelableExtra(@Nullable String name, @NonNull Class<T> clazz) {
+ return mExtras == null ? null : mExtras.getParcelable(name, clazz);
+ }
+
+ /**
+ * Retrieve extended data from the intent.
+ *
+ * @param name The name of the desired item.
*
* @return the value of an item previously added with putExtra(),
* or null if no Parcelable[] value was found.
*
+ * @deprecated Use the type-safer {@link #getParcelableArrayExtra(String, Class)} starting from
+ * Android {@link Build.VERSION_CODES#TIRAMISU}.
+ *
* @see #putExtra(String, Parcelable[])
*/
+ @Deprecated
public @Nullable Parcelable[] getParcelableArrayExtra(String name) {
return mExtras == null ? null : mExtras.getParcelableArray(name);
}
@@ -8927,13 +8924,34 @@ public class Intent implements Parcelable, Cloneable {
* Retrieve extended data from the intent.
*
* @param name The name of the desired item.
+ * @param clazz The type of the items inside the array. This is only verified when unparceling.
+ *
+ * @return the value of an item previously added with putExtra(),
+ * or null if no Parcelable[] value was found.
+ *
+ * @see #putExtra(String, Parcelable[])
+ */
+ @SuppressLint({"ArrayReturn", "NullableCollection"})
+ public @Nullable <T> T[] getParcelableArrayExtra(@Nullable String name,
+ @NonNull Class<T> clazz) {
+ return mExtras == null ? null : mExtras.getParcelableArray(name, clazz);
+ }
+
+ /**
+ * Retrieve extended data from the intent.
+ *
+ * @param name The name of the desired item.
*
* @return the value of an item previously added with
* putParcelableArrayListExtra(), or null if no
* ArrayList<Parcelable> value was found.
*
+ * @deprecated Use the type-safer {@link #getParcelableArrayListExtra(String, Class)} starting
+ * from Android {@link Build.VERSION_CODES#TIRAMISU}.
+ *
* @see #putParcelableArrayListExtra(String, ArrayList)
*/
+ @Deprecated
public @Nullable <T extends Parcelable> ArrayList<T> getParcelableArrayListExtra(String name) {
return mExtras == null ? null : mExtras.<T>getParcelableArrayList(name);
}
@@ -8942,10 +8960,32 @@ public class Intent implements Parcelable, Cloneable {
* Retrieve extended data from the intent.
*
* @param name The name of the desired item.
+ * @param clazz The type of the items inside the array list. This is only verified when
+ * unparceling.
+ *
+ * @return the value of an item previously added with
+ * putParcelableArrayListExtra(), or null if no
+ * ArrayList<Parcelable> value was found.
+ *
+ * @see #putParcelableArrayListExtra(String, ArrayList)
+ */
+ @SuppressLint({"ConcreteCollection", "NullableCollection"})
+ public @Nullable <T> ArrayList<T> getParcelableArrayListExtra(@Nullable String name,
+ @NonNull Class<? extends T> clazz) {
+ return mExtras == null ? null : mExtras.<T>getParcelableArrayList(name, clazz);
+ }
+
+ /**
+ * Retrieve extended data from the intent.
+ *
+ * @param name The name of the desired item.
*
* @return the value of an item previously added with putExtra(),
* or null if no Serializable value was found.
*
+ * @deprecated Use the type-safer {@link #getSerializableExtra(String, Class)} starting from
+ * Android {@link Build.VERSION_CODES#TIRAMISU}.
+ *
* @see #putExtra(String, Serializable)
*/
public @Nullable Serializable getSerializableExtra(String name) {
@@ -8956,6 +8996,22 @@ public class Intent implements Parcelable, Cloneable {
* Retrieve extended data from the intent.
*
* @param name The name of the desired item.
+ * @param clazz The type of the object expected.
+ *
+ * @return the value of an item previously added with putExtra(),
+ * or null if no Serializable value was found.
+ *
+ * @see #putExtra(String, Serializable)
+ */
+ public @Nullable <T extends Serializable> T getSerializableExtra(@Nullable String name,
+ @NonNull Class<T> clazz) {
+ return mExtras == null ? null : mExtras.getSerializable(name, clazz);
+ }
+
+ /**
+ * Retrieve extended data from the intent.
+ *
+ * @param name The name of the desired item.
*
* @return the value of an item previously added with
* putIntegerArrayListExtra(), or null if no
diff --git a/core/java/android/content/pm/AppSearchShortcutInfo.java b/core/java/android/content/pm/AppSearchShortcutInfo.java
index f20d1e62e8e7..1b84686bbfcf 100644
--- a/core/java/android/content/pm/AppSearchShortcutInfo.java
+++ b/core/java/android/content/pm/AppSearchShortcutInfo.java
@@ -349,7 +349,7 @@ public class AppSearchShortcutInfo extends GenericDocument {
.setDisabledReason(shortcutInfo.getDisabledReason())
.setPersons(shortcutInfo.getPersons())
.setLocusId(shortcutInfo.getLocusId())
- .setCapabilityBindings(shortcutInfo.getCapabilityBindings())
+ .setCapabilityBindings(shortcutInfo.getCapabilityBindingsInternal())
.setTtlMillis(SHORTCUT_TTL)
.build();
}
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 673127e9f808..2961b5505794 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -2084,7 +2084,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
splitNames = source.createString8Array();
splitSourceDirs = source.createString8Array();
splitPublicSourceDirs = source.createString8Array();
- splitDependencies = source.readSparseArray(null);
+ splitDependencies = source.readSparseArray(null, int[].class);
nativeLibraryDir = source.readString8();
secondaryNativeLibraryDir = source.readString8();
nativeLibraryRootDir = source.readString8();
diff --git a/core/java/android/content/pm/Capability.aidl b/core/java/android/content/pm/Capability.aidl
new file mode 100644
index 000000000000..df3b1be1ce31
--- /dev/null
+++ b/core/java/android/content/pm/Capability.aidl
@@ -0,0 +1,18 @@
+/*
+ * 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.content.pm;
+
+parcelable Capability; \ No newline at end of file
diff --git a/core/java/android/content/pm/Capability.java b/core/java/android/content/pm/Capability.java
new file mode 100644
index 000000000000..1597d31828a1
--- /dev/null
+++ b/core/java/android/content/pm/Capability.java
@@ -0,0 +1,143 @@
+/*
+ * 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.content.pm;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
+
+/**
+ * Represents a capability that can be performed by an app, also known as App Action.
+ * Capabilities can be associated with a {@link ShortcutInfo}.
+ *
+ * @see ShortcutInfo.Builder#addCapabilityBinding(Capability, CapabilityParams)
+ */
+public final class Capability implements Parcelable {
+
+ @NonNull
+ private final String mName;
+
+ /**
+ * Constructor.
+ * @param name Name of the capability, usually maps to a built-in intent,
+ * e.g. actions.intent.GET_MESSAGE. Note the character "/" is not permitted.
+ * @throws IllegalArgumentException If specified capability name contains the character "/".
+ *
+ * @hide
+ */
+ Capability(@NonNull final String name) {
+ Objects.requireNonNull(name);
+ if (name.contains("/")) {
+ throw new IllegalArgumentException("'/' is not permitted in the capability name");
+ }
+ mName = name;
+ }
+
+ /**
+ * Copy constructor.
+ *
+ * @hide
+ */
+ Capability(@NonNull final Capability orig) {
+ this(orig.mName);
+ }
+
+ private Capability(@NonNull final Builder builder) {
+ this(builder.mName);
+ }
+
+ private Capability(@NonNull final Parcel in) {
+ mName = in.readString();
+ }
+
+ /**
+ * Returns the name of the capability. e.g. actions.intent.GET_MESSAGE.
+ */
+ @NonNull
+ public String getName() {
+ return mName;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof Capability)) {
+ return false;
+ }
+ return mName.equals(((Capability) obj).mName);
+ }
+
+ @Override
+ public int hashCode() {
+ return mName.hashCode();
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeString(mName);
+ }
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @NonNull
+ public static final Parcelable.Creator<Capability> CREATOR =
+ new Parcelable.Creator<Capability>() {
+ @Override
+ public Capability[] newArray(int size) {
+ return new Capability[size];
+ }
+
+ @Override
+ public Capability createFromParcel(@NonNull Parcel in) {
+ return new Capability(in);
+ }
+ };
+
+ /**
+ * Builder class for {@link Capability}.
+ */
+ public static final class Builder {
+
+ @NonNull
+ private final String mName;
+
+ /**
+ * Constructor.
+ * @param name Name of the capability, usually maps to a built-in intent,
+ * e.g. actions.intent.GET_MESSAGE. Note the character "/" is not permitted.
+ * @throws IllegalArgumentException If specified capability name contains the character "/".
+ */
+ public Builder(@NonNull final String name) {
+ Objects.requireNonNull(name);
+ if (name.contains("/")) {
+ throw new IllegalArgumentException("'/' is not permitted in the capability name");
+ }
+ mName = name;
+ }
+
+ /**
+ * Creates an instance of {@link Capability}
+ */
+ @NonNull
+ public Capability build() {
+ return new Capability(this);
+ }
+ }
+}
diff --git a/core/java/android/content/pm/CapabilityParams.aidl b/core/java/android/content/pm/CapabilityParams.aidl
new file mode 100644
index 000000000000..39f12387404f
--- /dev/null
+++ b/core/java/android/content/pm/CapabilityParams.aidl
@@ -0,0 +1,18 @@
+/*
+ * 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.content.pm;
+
+parcelable CapabilityParams;
diff --git a/core/java/android/content/pm/CapabilityParams.java b/core/java/android/content/pm/CapabilityParams.java
new file mode 100644
index 000000000000..7239bacf1221
--- /dev/null
+++ b/core/java/android/content/pm/CapabilityParams.java
@@ -0,0 +1,215 @@
+/*
+ * 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.content.pm;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.TextUtils;
+import android.util.ArraySet;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * Represents the parameters and its matching names which can be associated with a
+ * {@link Capability}.
+ *
+ * @see ShortcutInfo.Builder#addCapabilityBinding(Capability, CapabilityParams)
+ */
+public final class CapabilityParams implements Parcelable {
+
+ @NonNull
+ private final String mName;
+ @NonNull
+ private final String mPrimaryValue;
+ @NonNull
+ private final List<String> mAliases;
+
+ /**
+ * Constructor.
+ * @param name Name of the capability parameter.
+ * Note the character "/" is not permitted.
+ * @param primaryValue The primary value of the parameter.
+ * @param aliases Alternative values of the parameter.
+ */
+ private CapabilityParams(@NonNull final String name,
+ @NonNull final String primaryValue, @Nullable final Collection<String> aliases) {
+ Objects.requireNonNull(name);
+ Objects.requireNonNull(primaryValue);
+ mName = name;
+ mPrimaryValue = primaryValue;
+ mAliases = aliases == null ? Collections.emptyList()
+ : Collections.unmodifiableList(new ArrayList<>(aliases));
+ }
+
+ /**
+ * Copy constructor.
+ * @hide
+ */
+ CapabilityParams(@NonNull final CapabilityParams orig) {
+ this(orig.mName, orig.mPrimaryValue, orig.mAliases);
+ }
+
+ private CapabilityParams(@NonNull final Builder builder) {
+ this(builder.mKey, builder.mPrimaryValue, builder.mAliases);
+ }
+
+ private CapabilityParams(@NonNull final Parcel in) {
+ mName = in.readString();
+ mPrimaryValue = in.readString();
+ final List<String> values = new ArrayList<>();
+ in.readStringList(values);
+ mAliases = Collections.unmodifiableList(values);
+ }
+
+ /**
+ * Name of the parameter.
+ */
+ @NonNull
+ public String getName() {
+ return mName;
+ }
+
+ /**
+ * Returns the primary name of values in this parameter.
+ */
+ @NonNull
+ public String getValue() {
+ return mPrimaryValue;
+ }
+
+ /**
+ * Returns the aliases of the values in ths parameter. Returns an empty list if there are no
+ * aliases.
+ */
+ @NonNull
+ public List<String> getAliases() {
+ return new ArrayList<>(mAliases);
+ }
+
+ /**
+ * A list of values for this parameter. The first value will be the primary name, while the
+ * rest will be alternative names.
+ * @hide
+ */
+ @NonNull
+ List<String> getValues() {
+ if (mAliases == null) {
+ return new ArrayList<>(Collections.singletonList(mPrimaryValue));
+ }
+ final List<String> ret = new ArrayList<>(mAliases.size() + 1);
+ ret.add(mPrimaryValue);
+ ret.addAll(mAliases);
+ return ret;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof CapabilityParams)) {
+ return false;
+ }
+ final CapabilityParams target = (CapabilityParams) obj;
+ return mName.equals(target.mName) && mPrimaryValue.equals(target.mPrimaryValue)
+ && mAliases.equals(target.mAliases);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mName, mPrimaryValue, mAliases);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeString(mName);
+ dest.writeString(mPrimaryValue);
+ dest.writeStringList(mAliases);
+ }
+
+ @NonNull
+ public static final Parcelable.Creator<CapabilityParams> CREATOR =
+ new Parcelable.Creator<CapabilityParams>() {
+ @Override
+ public CapabilityParams[] newArray(int size) {
+ return new CapabilityParams[size];
+ }
+
+ @Override
+ public CapabilityParams createFromParcel(@NonNull Parcel in) {
+ return new CapabilityParams(in);
+ }
+ };
+
+ /**
+ * Builder class for {@link CapabilityParams}.
+ */
+ public static final class Builder {
+
+ @NonNull
+ private final String mKey;
+ @NonNull
+ private String mPrimaryValue;
+ @NonNull
+ private Set<String> mAliases;
+
+ /**
+ * Constructor.
+ * @param key key of the capability parameter.
+ * Note the character "/" is not permitted.
+ * @param value The primary name of value in the {@link CapabilityParams}, cannot be empty.
+ */
+ public Builder(@NonNull final String key, @NonNull final String value) {
+ Objects.requireNonNull(key);
+ if (TextUtils.isEmpty(value)) {
+ throw new IllegalArgumentException("Primary value cannot be empty or null");
+ }
+ mPrimaryValue = value;
+ mKey = key;
+ }
+
+ /**
+ * Add an alias in the {@link CapabilityParams}.
+ */
+ @NonNull
+ public Builder addAlias(@NonNull final String alias) {
+ if (mAliases == null) {
+ mAliases = new ArraySet<>(1);
+ }
+ mAliases.add(alias);
+ return this;
+ }
+
+ /**
+ * Creates an instance of {@link CapabilityParams}
+ * @throws IllegalArgumentException If the specified value is empty.
+ */
+ @NonNull
+ public CapabilityParams build() {
+ return new CapabilityParams(this);
+ }
+ }
+}
diff --git a/core/java/android/content/pm/CrossProfileApps.java b/core/java/android/content/pm/CrossProfileApps.java
index 94f056110bf7..66c6c817e9ea 100644
--- a/core/java/android/content/pm/CrossProfileApps.java
+++ b/core/java/android/content/pm/CrossProfileApps.java
@@ -104,7 +104,44 @@ public class CrossProfileApps {
mContext.getAttributionTag(),
component,
targetUser.getIdentifier(),
- true);
+ true,
+ null,
+ null);
+ } catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Starts the specified main activity of the caller package in the specified profile, launching
+ * in the specified activity.
+ *
+ * @param component The ComponentName of the activity to launch, it must be exported and has
+ * action {@link android.content.Intent#ACTION_MAIN}, category
+ * {@link android.content.Intent#CATEGORY_LAUNCHER}. Otherwise, SecurityException will
+ * be thrown.
+ * @param targetUser The UserHandle of the profile, must be one of the users returned by
+ * {@link #getTargetUserProfiles()}, otherwise a {@link SecurityException} will
+ * be thrown.
+ * @param callingActivity The activity to start the new activity from for the purposes of
+ * deciding which task the new activity should belong to. If {@code null}, the activity
+ * will always be started in a new task.
+ * @param options The activity options or {@code null}. See {@link android.app.ActivityOptions}.
+ */
+ public void startMainActivity(@NonNull ComponentName component,
+ @NonNull UserHandle targetUser,
+ @Nullable Activity callingActivity,
+ @Nullable Bundle options) {
+ try {
+ mService.startActivityAsUser(
+ mContext.getIApplicationThread(),
+ mContext.getPackageName(),
+ mContext.getAttributionTag(),
+ component,
+ targetUser.getIdentifier(),
+ true,
+ callingActivity != null ? callingActivity.getActivityToken() : null,
+ options);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
@@ -191,6 +228,48 @@ public class CrossProfileApps {
* @param targetUser The UserHandle of the profile, must be one of the users returned by
* {@link #getTargetUserProfiles()}, otherwise a {@link SecurityException} will
* be thrown.
+ * @param callingActivity The activity to start the new activity from for the purposes of
+ * deciding which task the new activity should belong to. If {@code null}, the activity
+ * will always be started in a new task.
+ * @param options The activity options or {@code null}. See {@link android.app.ActivityOptions}.
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.INTERACT_ACROSS_PROFILES,
+ android.Manifest.permission.START_CROSS_PROFILE_ACTIVITIES})
+ public void startActivity(
+ @NonNull ComponentName component,
+ @NonNull UserHandle targetUser,
+ @Nullable Activity callingActivity,
+ @Nullable Bundle options) {
+ try {
+ mService.startActivityAsUser(
+ mContext.getIApplicationThread(),
+ mContext.getPackageName(),
+ mContext.getAttributionTag(),
+ component,
+ targetUser.getIdentifier(),
+ false,
+ callingActivity != null ? callingActivity.getActivityToken() : null,
+ options);
+ } catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Starts the specified activity of the caller package in the specified profile. Unlike
+ * {@link #startMainActivity}, this can start any activity of the caller package, not just
+ * the main activity.
+ * The caller must have the {@link android.Manifest.permission#INTERACT_ACROSS_PROFILES}
+ * or {@link android.Manifest.permission#START_CROSS_PROFILE_ACTIVITIES}
+ * permission and both the caller and target user profiles must be in the same profile group.
+ *
+ * @param component The ComponentName of the activity to launch. It must be exported.
+ * @param targetUser The UserHandle of the profile, must be one of the users returned by
+ * {@link #getTargetUserProfiles()}, otherwise a {@link SecurityException} will
+ * be thrown.
* @hide
*/
@SystemApi
@@ -201,7 +280,7 @@ public class CrossProfileApps {
try {
mService.startActivityAsUser(mContext.getIApplicationThread(),
mContext.getPackageName(), mContext.getAttributionTag(), component,
- targetUser.getIdentifier(), false);
+ targetUser.getIdentifier(), false, null, null);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
@@ -247,7 +326,7 @@ public class CrossProfileApps {
final boolean isManagedProfile = mUserManager.isManagedProfile(userHandle.getIdentifier());
final DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class);
- return dpm.getString(
+ return dpm.getResources().getString(
getUpdatableProfileSwitchingLabelId(isManagedProfile),
() -> getDefaultProfileSwitchingLabel(isManagedProfile));
}
diff --git a/core/java/android/content/pm/ICrossProfileApps.aidl b/core/java/android/content/pm/ICrossProfileApps.aidl
index e2850f111c4f..4f2c1069275e 100644
--- a/core/java/android/content/pm/ICrossProfileApps.aidl
+++ b/core/java/android/content/pm/ICrossProfileApps.aidl
@@ -29,7 +29,7 @@ import android.os.UserHandle;
interface ICrossProfileApps {
void startActivityAsUser(in IApplicationThread caller, in String callingPackage,
in String callingFeatureId, in ComponentName component, int userId,
- boolean launchMainActivity);
+ boolean launchMainActivity, in IBinder task, in Bundle options);
void startActivityAsUserByIntent(in IApplicationThread caller, in String callingPackage,
in String callingFeatureId, in Intent intent, int userId, in IBinder callingActivity,
in Bundle options);
diff --git a/core/java/android/content/pm/IPackageInstallerSession.aidl b/core/java/android/content/pm/IPackageInstallerSession.aidl
index 18e205f2e79e..8d6c8e8d9f62 100644
--- a/core/java/android/content/pm/IPackageInstallerSession.aidl
+++ b/core/java/android/content/pm/IPackageInstallerSession.aidl
@@ -57,4 +57,5 @@ interface IPackageInstallerSession {
int getParentSessionId();
boolean isStaged();
+ int getInstallFlags();
}
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index e9e6cd3a54c5..ca7d77b2c44a 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -497,21 +497,10 @@ interface IPackageManager {
void enterSafeMode();
@UnsupportedAppUsage
boolean isSafeMode();
- void systemReady();
@UnsupportedAppUsage
boolean hasSystemUidErrors();
/**
- * Ask the package manager to fstrim the disk if needed.
- */
- void performFstrimIfNeeded();
-
- /**
- * Ask the package manager to update packages if needed.
- */
- void updatePackagesIfNeeded();
-
- /**
* Notify the package manager that a package is going to be used and why.
*
* See PackageManager.NOTIFY_PACKAGE_USE_* for reasons.
@@ -792,7 +781,11 @@ interface IPackageManager {
boolean isAutoRevokeWhitelisted(String packageName);
- void grantImplicitAccess(int queryingUid, String visibleAuthority);
+ void makeProviderVisible(int recipientAppId, String visibleAuthority);
+
+ @JavaPassthrough(annotation = "@android.annotation.RequiresPermission(android.Manifest"
+ + ".permission.MAKE_UID_VISIBLE)")
+ void makeUidVisible(int recipientAppId, int visibleUid);
IBinder getHoldLockToken();
diff --git a/core/java/android/content/pm/PackageInfo.java b/core/java/android/content/pm/PackageInfo.java
index eefa63f5b8fa..f4de82946253 100644
--- a/core/java/android/content/pm/PackageInfo.java
+++ b/core/java/android/content/pm/PackageInfo.java
@@ -213,7 +213,8 @@ public class PackageInfo implements Parcelable {
* or null if there were none. This is only filled in if the flag
* {@link PackageManager#GET_PERMISSIONS} was set. Each value matches
* the corresponding entry in {@link #requestedPermissions}, and will have
- * the flag {@link #REQUESTED_PERMISSION_GRANTED} set as appropriate.
+ * the flags {@link #REQUESTED_PERMISSION_GRANTED} and
+ * {@link #REQUESTED_PERMISSION_NEVER_FOR_LOCATION} set as appropriate.
*/
public int[] requestedPermissionsFlags;
diff --git a/core/java/android/content/pm/PackageInfoLite.java b/core/java/android/content/pm/PackageInfoLite.java
index 410e106ce584..148eacc0c4d4 100644
--- a/core/java/android/content/pm/PackageInfoLite.java
+++ b/core/java/android/content/pm/PackageInfoLite.java
@@ -79,6 +79,11 @@ public class PackageInfoLite implements Parcelable {
public boolean debuggable;
/**
+ * Indicates if this apk is a sdk.
+ */
+ public boolean isSdkLibrary;
+
+ /**
* Specifies the recommended install location. Can be one of
* {@link InstallLocationUtils#RECOMMEND_INSTALL_INTERNAL} to install on internal storage,
* {@link InstallLocationUtils#RECOMMEND_INSTALL_EXTERNAL} to install on external media,
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 67a2dc84728d..450e09a307bf 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -1586,6 +1586,18 @@ public class PackageInstaller {
}
/**
+ * @return Session's {@link SessionParams#installFlags}.
+ * @hide
+ */
+ public int getInstallFlags() {
+ try {
+ return mSession.getInstallFlags();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* @return the session ID of the multi-package session that this belongs to or
* {@link SessionInfo#INVALID_ID} if it does not belong to a multi-package session.
*/
@@ -2421,15 +2433,6 @@ public class PackageInstaller {
/** {@hide} */
private static final int[] NO_SESSIONS = {};
- /** @hide */
- @IntDef(prefix = { "SESSION_" }, value = {
- SESSION_NO_ERROR,
- SESSION_VERIFICATION_FAILED,
- SESSION_ACTIVATION_FAILED,
- SESSION_UNKNOWN_ERROR,
- SESSION_CONFLICT})
- @Retention(RetentionPolicy.SOURCE)
- public @interface SessionErrorCode {}
/**
* @deprecated use {@link #SESSION_NO_ERROR}.
*/
@@ -3113,7 +3116,7 @@ public class PackageInstaller {
* If something went wrong with a staged session, clients can check this error code to
* understand which kind of failure happened. Only meaningful if {@code isStaged} is true.
*/
- public @SessionErrorCode int getStagedSessionErrorCode() {
+ public int getStagedSessionErrorCode() {
checkSessionIsStaged();
return mSessionErrorCode;
}
@@ -3128,7 +3131,7 @@ public class PackageInstaller {
}
/** {@hide} */
- public void setSessionErrorCode(@SessionErrorCode int errorCode, String errorMessage) {
+ public void setSessionErrorCode(int errorCode, String errorMessage) {
mSessionErrorCode = errorCode;
mSessionErrorMessage = errorMessage;
}
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index f4bc1616da2b..227ac1a02890 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -121,6 +121,9 @@ public abstract class PackageManager {
/** {@hide} */
public static final boolean APPLY_DEFAULT_TO_DEVICE_PROTECTED_STORAGE = true;
+ /** {@hide} */
+ public static final boolean ENABLE_SHARED_UID_MIGRATION = true;
+
/**
* This exception is thrown when a given package, application, or component
* name cannot be found.
@@ -2202,6 +2205,14 @@ public abstract class PackageManager {
*/
public static final int INSTALL_FAILED_BAD_PERMISSION_GROUP = -127;
+ /**
+ * Installation failed return code: an error occurred during the activation phase of this
+ * session.
+ *
+ * @hide
+ */
+ public static final int INSTALL_ACTIVATION_FAILED = -128;
+
/** @hide */
@IntDef(flag = true, prefix = { "DELETE_" }, value = {
DELETE_KEEP_DATA,
@@ -4076,6 +4087,28 @@ public abstract class PackageManager {
"android.software.incremental_delivery";
/**
+ * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: The device
+ * has the requisite kernel support for the EROFS filesystem present in 4.19 kernels as a
+ * staging driver, which lacks 0padding and big pcluster support.
+ *
+ * @hide
+ */
+ @SystemApi
+ @SdkConstant(SdkConstantType.FEATURE)
+ public static final String FEATURE_EROFS_LEGACY = "android.software.erofs_legacy";
+
+ /**
+ * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: The device
+ * has the requisite kernel support for the EROFS filesystem present in 5.10 kernels, which
+ * has 0padding, big pcluster, and chunked index support.
+ *
+ * @hide
+ */
+ @SystemApi
+ @SdkConstant(SdkConstantType.FEATURE)
+ public static final String FEATURE_EROFS = "android.software.erofs";
+
+ /**
* Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}:
* The device has tuner hardware to support tuner operations.
*
@@ -4251,8 +4284,9 @@ public abstract class PackageManager {
* for more details.
* @hide
*/
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public static final String EXTRA_VERIFICATION_ROOT_HASH =
- "android.content.pm.extra.EXTRA_VERIFICATION_ROOT_HASH";
+ "android.content.pm.extra.VERIFICATION_ROOT_HASH";
/**
* Extra field name for the ID of a intent filter pending verification.
@@ -4958,8 +4992,8 @@ public abstract class PackageManager {
* applications (which includes installed applications as well as
* applications with data directory i.e. applications which had been
* deleted with {@code DELETE_KEEP_DATA} flag set).
- * @throws NameNotFoundException if a package with the given name cannot be
- * found on the system.
+ * @throws NameNotFoundException if no such package is available to the
+ * caller.
* @deprecated Use {@link #getPackageInfo(String, PackageInfoFlags)} instead.
*/
@Deprecated
@@ -4995,8 +5029,8 @@ public abstract class PackageManager {
* applications (which includes installed applications as well as
* applications with data directory i.e. applications which had been
* deleted with {@code DELETE_KEEP_DATA} flag set).
- * @throws NameNotFoundException if a package with the given name cannot be
- * found on the system.
+ * @throws NameNotFoundException if no such package is available to the
+ * caller.
* @deprecated Use {@link #getPackageInfo(VersionedPackage, PackageInfoFlags)} instead.
*/
@Deprecated
@@ -5028,8 +5062,8 @@ public abstract class PackageManager {
* applications (which includes installed applications as well as
* applications with data directory i.e. applications which had been
* deleted with {@code DELETE_KEEP_DATA} flag set).
- * @throws NameNotFoundException if a package with the given name cannot be
- * found on the system.
+ * @throws NameNotFoundException if no such package is available to the
+ * caller.
* @deprecated Use {@link #getPackageInfoAsUser(String, PackageInfoFlags, int)} instead.
* @hide
*/
@@ -5154,8 +5188,8 @@ public abstract class PackageManager {
* desired package.
* @return Returns an int array of the assigned GIDs, or null if there are
* none.
- * @throws NameNotFoundException if a package with the given name cannot be
- * found on the system.
+ * @throws NameNotFoundException if no such package is available to the
+ * caller.
*/
public abstract int[] getPackageGids(@NonNull String packageName)
throws NameNotFoundException;
@@ -5171,8 +5205,8 @@ public abstract class PackageManager {
* desired package.
* @return Returns an int array of the assigned gids, or null if there are
* none.
- * @throws NameNotFoundException if a package with the given name cannot be
- * found on the system.
+ * @throws NameNotFoundException if no such package is available to the
+ * caller.
* @deprecated Use {@link #getPackageGids(String, PackageInfoFlags)} instead.
*/
@Deprecated
@@ -5198,8 +5232,8 @@ public abstract class PackageManager {
* @param packageName The full name (i.e. com.google.apps.contacts) of the
* desired package.
* @return Returns an integer UID who owns the given package name.
- * @throws NameNotFoundException if a package with the given name can not be
- * found on the system.
+ * @throws NameNotFoundException if no such package is available to the
+ * caller.
* @deprecated Use {@link #getPackageUid(String, PackageInfoFlags)} instead.
*/
@Deprecated
@@ -5225,8 +5259,8 @@ public abstract class PackageManager {
* desired package.
* @param userId The user handle identifier to look up the package under.
* @return Returns an integer UID who owns the given package name.
- * @throws NameNotFoundException if a package with the given name can not be
- * found on the system.
+ * @throws NameNotFoundException if no such package is available to the
+ * caller.
* @hide
*/
@SuppressWarnings("HiddenAbstractMethod")
@@ -5244,8 +5278,8 @@ public abstract class PackageManager {
* desired package.
* @param userId The user handle identifier to look up the package under.
* @return Returns an integer UID who owns the given package name.
- * @throws NameNotFoundException if a package with the given name can not be
- * found on the system.
+ * @throws NameNotFoundException if no such package is available to the
+ * caller.
* @deprecated Use {@link #getPackageUidAsUser(String, PackageInfoFlags, int)} instead.
* @hide
*/
@@ -10269,19 +10303,42 @@ public abstract class PackageManager {
}
/**
- * Grants implicit visibility of the package that provides an authority to a querying UID.
+ * Makes a package that provides an authority {@code visibleAuthority} become visible to the
+ * application {@code recipientUid}.
*
* @throws SecurityException when called by a package other than the contacts provider
* @hide
*/
- public void grantImplicitAccess(int queryingUid, String visibleAuthority) {
+ public void makeProviderVisible(int recipientUid, String visibleAuthority) {
try {
- ActivityThread.getPackageManager().grantImplicitAccess(queryingUid, visibleAuthority);
+ ActivityThread.getPackageManager().makeProviderVisible(recipientUid, visibleAuthority);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
+ /**
+ * Makes the package associated with the uid {@code visibleUid} become visible to the
+ * recipient application. The recipient application can receive the details about the
+ * visible package if successful.
+ * <p>
+ * Read <a href="/training/basics/intents/package-visibility">package visibility</a> for more
+ * information.
+ *
+ * @param recipientUid The uid of the application that is being given access to {@code
+ * visibleUid}
+ * @param visibleUid The uid of the application that is becoming accessible to {@code
+ * recipientAppId}
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.MAKE_UID_VISIBLE)
+ @TestApi
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public void makeUidVisible(int recipientUid, int visibleUid) {
+ throw new UnsupportedOperationException(
+ "makeUidVisible not implemented in subclass");
+ }
+
// Some of the flags don't affect the query result, but let's be conservative and cache
// each combination of flags separately.
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index e914432630f7..4d4a57db84be 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -1944,19 +1944,26 @@ public class PackageParser {
TypedArray sa = res.obtainAttributes(parser,
com.android.internal.R.styleable.AndroidManifest);
- String str = sa.getNonConfigurationString(
- com.android.internal.R.styleable.AndroidManifest_sharedUserId, 0);
- if (str != null && str.length() > 0) {
- String nameError = validateName(str, true, true);
- if (nameError != null && !"android".equals(pkg.packageName)) {
- outError[0] = "<manifest> specifies bad sharedUserId name \""
- + str + "\": " + nameError;
- mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID;
- return null;
+ int maxSdkVersion = 0;
+ if (PackageManager.ENABLE_SHARED_UID_MIGRATION) {
+ maxSdkVersion = sa.getInteger(
+ com.android.internal.R.styleable.AndroidManifest_sharedUserMaxSdkVersion, 0);
+ }
+ if (maxSdkVersion == 0 || maxSdkVersion >= Build.VERSION.RESOURCES_SDK_INT) {
+ String str = sa.getNonConfigurationString(
+ com.android.internal.R.styleable.AndroidManifest_sharedUserId, 0);
+ if (str != null && str.length() > 0) {
+ String nameError = validateName(str, true, true);
+ if (nameError != null && !"android".equals(pkg.packageName)) {
+ outError[0] = "<manifest> specifies bad sharedUserId name \""
+ + str + "\": " + nameError;
+ mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID;
+ return null;
+ }
+ pkg.mSharedUserId = str.intern();
+ pkg.mSharedUserLabel = sa.getResourceId(
+ com.android.internal.R.styleable.AndroidManifest_sharedUserLabel, 0);
}
- pkg.mSharedUserId = str.intern();
- pkg.mSharedUserLabel = sa.getResourceId(
- com.android.internal.R.styleable.AndroidManifest_sharedUserLabel, 0);
}
pkg.installLocation = sa.getInteger(
diff --git a/core/java/android/content/pm/SHORTCUT_OWNERS b/core/java/android/content/pm/SHORTCUT_OWNERS
index 3688d5a3a4c7..f8bba473336d 100644
--- a/core/java/android/content/pm/SHORTCUT_OWNERS
+++ b/core/java/android/content/pm/SHORTCUT_OWNERS
@@ -1,7 +1,6 @@
set noparent
+pinyaoting@google.com
+sunnygoyal@google.com
omakoto@google.com
yamasani@google.com
-sunnygoyal@google.com
-mett@google.com
-pinyaoting@google.com
diff --git a/core/java/android/content/pm/ShortcutInfo.java b/core/java/android/content/pm/ShortcutInfo.java
index 41dd5bb3f21d..56d092d8319d 100644
--- a/core/java/android/content/pm/ShortcutInfo.java
+++ b/core/java/android/content/pm/ShortcutInfo.java
@@ -52,7 +52,7 @@ import com.android.internal.util.Preconditions;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
-import java.util.Collection;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
@@ -60,7 +60,6 @@ import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
-import java.util.stream.Stream;
/**
* Represents a shortcut that can be published via {@link ShortcutManager}.
@@ -501,7 +500,8 @@ public final class ShortcutInfo implements Parcelable {
mRank = b.mRank;
mExtras = b.mExtras;
mLocusId = b.mLocusId;
- mCapabilityBindings = b.mCapabilityBindings;
+ mCapabilityBindings =
+ cloneCapabilityBindings(b.mCapabilityBindings);
mStartingThemeResName = b.mStartingThemeResId != 0
? b.mContext.getResources().getResourceName(b.mStartingThemeResId) : null;
updateTimestamp();
@@ -652,7 +652,8 @@ public final class ShortcutInfo implements Parcelable {
// Set this bit.
mFlags |= FLAG_KEY_FIELDS_ONLY;
}
- mCapabilityBindings = source.mCapabilityBindings;
+ mCapabilityBindings = cloneCapabilityBindings(
+ source.mCapabilityBindings);
mStartingThemeResName = source.mStartingThemeResName;
}
@@ -1003,7 +1004,8 @@ public final class ShortcutInfo implements Parcelable {
mStartingThemeResName = source.mStartingThemeResName;
}
if (source.mCapabilityBindings != null) {
- mCapabilityBindings = source.mCapabilityBindings;
+ mCapabilityBindings =
+ cloneCapabilityBindings(source.mCapabilityBindings);
}
}
@@ -1447,43 +1449,25 @@ public final class ShortcutInfo implements Parcelable {
* <P>This method can be called multiple times to add multiple parameters to the same
* capability.
*
- * @param capability capability associated with the shortcut. e.g. actions.intent
- * .START_EXERCISE.
- * @param parameterName name of the parameter associated with given capability.
- * e.g. exercise.name.
- * @param parameterValues a list of values for that parameters. The first value will be
- * the primary name, while the rest will be alternative names. If
- * the values are empty, then the parameter will not be saved in
- * the shortcut.
+ * @param capability {@link Capability} associated with the shortcut.
+ * @param capabilityParams Optional {@link CapabilityParams} associated with given
+ * capability.
*/
@NonNull
- public Builder addCapabilityBinding(@NonNull String capability,
- @Nullable String parameterName, @Nullable List<String> parameterValues) {
+ public Builder addCapabilityBinding(@NonNull final Capability capability,
+ @Nullable final CapabilityParams capabilityParams) {
Objects.requireNonNull(capability);
- if (capability.contains("/")) {
- throw new IllegalArgumentException("Illegal character '/' is found in capability");
- }
if (mCapabilityBindings == null) {
mCapabilityBindings = new ArrayMap<>(1);
}
- if (!mCapabilityBindings.containsKey(capability)) {
- mCapabilityBindings.put(capability, new ArrayMap<>(0));
- }
- if (parameterName == null || parameterValues == null || parameterValues.isEmpty()) {
- return this;
- }
- if (parameterName.contains("/")) {
- throw new IllegalArgumentException(
- "Illegal character '/' is found in parameter name");
+ if (!mCapabilityBindings.containsKey(capability.getName())) {
+ mCapabilityBindings.put(capability.getName(), new ArrayMap<>(0));
}
- final Map<String, List<String>> params = mCapabilityBindings.get(capability);
- if (!params.containsKey(parameterName)) {
- params.put(parameterName, parameterValues);
+ if (capabilityParams == null) {
return this;
}
- params.put(parameterName,
- Stream.of(params.get(parameterName), parameterValues)
- .flatMap(Collection::stream).collect(Collectors.toList()));
+ final Map<String, List<String>> params = mCapabilityBindings.get(capability.getName());
+ params.put(capabilityParams.getName(), capabilityParams.getValues());
return this;
}
@@ -2264,41 +2248,78 @@ public final class ShortcutInfo implements Parcelable {
}
/**
+ * Returns an immutable copy of the capability bindings using internal data structure.
* @hide
*/
- public Map<String, Map<String, List<String>>> getCapabilityBindings() {
- return mCapabilityBindings;
+ @Nullable
+ public Map<String, Map<String, List<String>>> getCapabilityBindingsInternal() {
+ return cloneCapabilityBindings(mCapabilityBindings);
+ }
+
+ @Nullable
+ private static Map<String, Map<String, List<String>>> cloneCapabilityBindings(
+ @Nullable final Map<String, Map<String, List<String>>> orig) {
+ if (orig == null) {
+ return null;
+ }
+ final Map<String, Map<String, List<String>>> ret = new ArrayMap<>();
+ for (String capability : orig.keySet()) {
+ final Map<String, List<String>> params = orig.get(capability);
+ final Map<String, List<String>> clone;
+ if (params == null) {
+ clone = null;
+ } else {
+ clone = new ArrayMap<>(params.size());
+ for (String paramName : params.keySet()) {
+ final List<String> paramValues = params.get(paramName);
+ clone.put(paramName, Collections.unmodifiableList(paramValues));
+ }
+ }
+ ret.put(capability, Collections.unmodifiableMap(clone));
+ }
+ return Collections.unmodifiableMap(ret);
}
/**
- * Return true if the shortcut is or can be used in specified capability.
+ * Return a list of {@link Capability} associated with the shortcut.
*/
- public boolean hasCapability(@NonNull String capability) {
- Objects.requireNonNull(capability);
- return mCapabilityBindings != null && mCapabilityBindings.containsKey(capability);
+ @NonNull
+ public List<Capability> getCapabilities() {
+ if (mCapabilityBindings == null) {
+ return new ArrayList<>(0);
+ }
+ return mCapabilityBindings.keySet().stream().map(Capability::new)
+ .collect(Collectors.toList());
}
/**
- * Returns the values of specified parameter in associated with given capability.
+ * Returns the {@link CapabilityParams} in associated with given capability.
*
- * @param capability capability associated with the shortcut. e.g. actions.intent
- * .START_EXERCISE.
- * @param parameterName name of the parameter associated with given capability.
- * e.g. exercise.name.
+ * @param capability {@link Capability} associated with the shortcut.
*/
@NonNull
- public List<String> getCapabilityParameterValues(
- @NonNull String capability, @NonNull String parameterName) {
+ public List<CapabilityParams> getCapabilityParams(@NonNull final Capability capability) {
Objects.requireNonNull(capability);
- Objects.requireNonNull(parameterName);
if (mCapabilityBindings == null) {
- return Collections.emptyList();
- }
- final Map<String, List<String>> param = mCapabilityBindings.get(capability);
- if (param == null || !param.containsKey(parameterName)) {
- return Collections.emptyList();
+ return new ArrayList<>(0);
+ }
+ final Map<String, List<String>> param = mCapabilityBindings.get(capability.getName());
+ if (param == null) {
+ return new ArrayList<>(0);
+ }
+ final List<CapabilityParams> ret = new ArrayList<>(param.size());
+ for (String key : param.keySet()) {
+ final List<String> values = param.get(key);
+ final String primaryValue = values.get(0);
+ final List<String> aliases = values.size() == 1
+ ? Collections.emptyList() : values.subList(1, values.size());
+ CapabilityParams.Builder builder = new CapabilityParams.Builder(key, primaryValue);
+ for (String alias : aliases) {
+ builder = builder.addAlias(alias);
+ }
+ ret.add(builder.build());
}
- return param.get(parameterName);
+ return ret;
}
private ShortcutInfo(Parcel source) {
@@ -2357,7 +2378,7 @@ public final class ShortcutInfo implements Parcelable {
final Map<String, Map<String, List<String>>> capabilityBindings =
new ArrayMap<>(rawCapabilityBindings.size());
rawCapabilityBindings.forEach(capabilityBindings::put);
- mCapabilityBindings = capabilityBindings;
+ mCapabilityBindings = cloneCapabilityBindings(capabilityBindings);
}
}
@@ -2695,6 +2716,6 @@ public final class ShortcutInfo implements Parcelable {
mPersons = persons;
mLocusId = locusId;
mStartingThemeResName = startingThemeResName;
- mCapabilityBindings = capabilityBindings;
+ mCapabilityBindings = cloneCapabilityBindings(capabilityBindings);
}
}
diff --git a/core/java/android/content/pm/Signature.java b/core/java/android/content/pm/Signature.java
index 3f5c5d21428e..d94b0d8f9072 100644
--- a/core/java/android/content/pm/Signature.java
+++ b/core/java/android/content/pm/Signature.java
@@ -312,7 +312,7 @@ public class Signature implements Parcelable {
* @hide
*/
public static boolean areExactMatch(Signature[] a, Signature[] b) {
- return (a.length == b.length) && ArrayUtils.containsAll(a, b)
+ return (ArrayUtils.size(a) == ArrayUtils.size(b)) && ArrayUtils.containsAll(a, b)
&& ArrayUtils.containsAll(b, a);
}
@@ -387,4 +387,4 @@ public class Signature implements Parcelable {
return sPrime;
}
-} \ No newline at end of file
+}
diff --git a/core/java/android/content/pm/SigningInfo.java b/core/java/android/content/pm/SigningInfo.java
index 7459a9029212..ee9aaca3ed43 100644
--- a/core/java/android/content/pm/SigningInfo.java
+++ b/core/java/android/content/pm/SigningInfo.java
@@ -72,9 +72,11 @@ public final class SigningInfo implements Parcelable {
/**
* Returns the signing certificates this package has proven it is authorized to use. This
* includes both the signing certificate associated with the signer of the package and the past
- * signing certificates it included as its proof of signing certificate rotation. This method
- * is the preferred replacement for the {@code GET_SIGNATURES} flag used with {@link
- * PackageManager#getPackageInfo(String, int)}. When determining if a package is signed by a
+ * signing certificates it included as its proof of signing certificate rotation. Signing
+ * certificates are returned in the order of rotation with the original signing certificate at
+ * index 0, and the current signing certificate at the last index. This method is the preferred
+ * replacement for the {@code GET_SIGNATURES} flag used with {@link
+ * PackageManager#getPackageInfo(String, int)}. When determining if a package is signed by a
* desired certificate, the returned array should be checked to determine if it is one of the
* entries.
*
diff --git a/core/java/android/content/pm/parsing/ApkLite.java b/core/java/android/content/pm/parsing/ApkLite.java
index 5ffb958082fb..269bec256282 100644
--- a/core/java/android/content/pm/parsing/ApkLite.java
+++ b/core/java/android/content/pm/parsing/ApkLite.java
@@ -133,6 +133,11 @@ public class ApkLite {
*/
private final boolean mHasDeviceAdminReceiver;
+ /**
+ * Indicates if this apk is a sdk.
+ */
+ private final boolean mIsSdkLibrary;
+
public ApkLite(String path, String packageName, String splitName, boolean isFeatureSplit,
String configForSplit, String usesSplitName, boolean isSplitRequired, int versionCode,
int versionCodeMajor, int revisionCode, int installLocation,
@@ -143,7 +148,7 @@ public class ApkLite {
String requiredSystemPropertyName, String requiredSystemPropertyValue,
int minSdkVersion, int targetSdkVersion, int rollbackDataPolicy,
Set<String> requiredSplitTypes, Set<String> splitTypes,
- boolean hasDeviceAdminReceiver) {
+ boolean hasDeviceAdminReceiver, boolean isSdkLibrary) {
mPath = path;
mPackageName = packageName;
mSplitName = splitName;
@@ -176,6 +181,7 @@ public class ApkLite {
mTargetSdkVersion = targetSdkVersion;
mRollbackDataPolicy = rollbackDataPolicy;
mHasDeviceAdminReceiver = hasDeviceAdminReceiver;
+ mIsSdkLibrary = isSdkLibrary;
}
/**
@@ -473,11 +479,19 @@ public class ApkLite {
return mHasDeviceAdminReceiver;
}
+ /**
+ * Indicates if this apk is a sdk.
+ */
+ @DataClass.Generated.Member
+ public boolean isIsSdkLibrary() {
+ return mIsSdkLibrary;
+ }
+
@DataClass.Generated(
- time = 1635266936769L,
+ time = 1643063342990L,
codegenVersion = "1.0.23",
sourceFile = "frameworks/base/core/java/android/content/pm/parsing/ApkLite.java",
- inputSignatures = "private final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.NonNull java.lang.String mPath\nprivate final @android.annotation.Nullable java.lang.String mSplitName\nprivate final @android.annotation.Nullable java.lang.String mUsesSplitName\nprivate final @android.annotation.Nullable java.lang.String mConfigForSplit\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String> mRequiredSplitTypes\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String> mSplitTypes\nprivate final int mVersionCodeMajor\nprivate final int mVersionCode\nprivate final int mRevisionCode\nprivate final int mInstallLocation\nprivate final int mMinSdkVersion\nprivate final int mTargetSdkVersion\nprivate final @android.annotation.NonNull android.content.pm.VerifierInfo[] mVerifiers\nprivate final @android.annotation.NonNull android.content.pm.SigningDetails mSigningDetails\nprivate final boolean mFeatureSplit\nprivate final boolean mIsolatedSplits\nprivate final boolean mSplitRequired\nprivate final boolean mCoreApp\nprivate final boolean mDebuggable\nprivate final boolean mProfileableByShell\nprivate final boolean mMultiArch\nprivate final boolean mUse32bitAbi\nprivate final boolean mExtractNativeLibs\nprivate final boolean mUseEmbeddedDex\nprivate final @android.annotation.Nullable java.lang.String mTargetPackageName\nprivate final boolean mOverlayIsStatic\nprivate final int mOverlayPriority\nprivate final @android.annotation.Nullable java.lang.String mRequiredSystemPropertyName\nprivate final @android.annotation.Nullable java.lang.String mRequiredSystemPropertyValue\nprivate final int mRollbackDataPolicy\nprivate final boolean mHasDeviceAdminReceiver\npublic long getLongVersionCode()\nprivate boolean hasAnyRequiredSplitTypes()\nclass ApkLite extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genConstDefs=false)")
+ inputSignatures = "private final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.NonNull java.lang.String mPath\nprivate final @android.annotation.Nullable java.lang.String mSplitName\nprivate final @android.annotation.Nullable java.lang.String mUsesSplitName\nprivate final @android.annotation.Nullable java.lang.String mConfigForSplit\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String> mRequiredSplitTypes\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String> mSplitTypes\nprivate final int mVersionCodeMajor\nprivate final int mVersionCode\nprivate final int mRevisionCode\nprivate final int mInstallLocation\nprivate final int mMinSdkVersion\nprivate final int mTargetSdkVersion\nprivate final @android.annotation.NonNull android.content.pm.VerifierInfo[] mVerifiers\nprivate final @android.annotation.NonNull android.content.pm.SigningDetails mSigningDetails\nprivate final boolean mFeatureSplit\nprivate final boolean mIsolatedSplits\nprivate final boolean mSplitRequired\nprivate final boolean mCoreApp\nprivate final boolean mDebuggable\nprivate final boolean mProfileableByShell\nprivate final boolean mMultiArch\nprivate final boolean mUse32bitAbi\nprivate final boolean mExtractNativeLibs\nprivate final boolean mUseEmbeddedDex\nprivate final @android.annotation.Nullable java.lang.String mTargetPackageName\nprivate final boolean mOverlayIsStatic\nprivate final int mOverlayPriority\nprivate final @android.annotation.Nullable java.lang.String mRequiredSystemPropertyName\nprivate final @android.annotation.Nullable java.lang.String mRequiredSystemPropertyValue\nprivate final int mRollbackDataPolicy\nprivate final boolean mHasDeviceAdminReceiver\nprivate final boolean mIsSdkLibrary\npublic long getLongVersionCode()\nprivate boolean hasAnyRequiredSplitTypes()\nclass ApkLite extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genConstDefs=false)")
@Deprecated
private void __metadata() {}
diff --git a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
index 165cae826187..5680bcd2e2e6 100644
--- a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
+++ b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
@@ -87,6 +87,7 @@ public class ApkLiteParseUtils {
private static final String TAG_USES_SDK = "uses-sdk";
private static final String TAG_USES_SPLIT = "uses-split";
private static final String TAG_MANIFEST = "manifest";
+ private static final String TAG_SDK_LIBRARY = "sdk-library";
private static final int SDK_VERSION = Build.VERSION.SDK_INT;
private static final String[] SDK_CODENAMES = Build.VERSION.ACTIVE_CODENAMES;
@@ -449,6 +450,8 @@ public class ApkLiteParseUtils {
boolean hasDeviceAdminReceiver = false;
+ boolean isSdkLibrary = false;
+
// Only search the tree when the tag is the direct child of <manifest> tag
int type;
final int searchDepth = parser.getDepth() + 1;
@@ -506,6 +509,8 @@ public class ApkLiteParseUtils {
} else if (TAG_RECEIVER.equals(parser.getName())) {
hasDeviceAdminReceiver |= isDeviceAdminReceiver(
parser, hasBindDeviceAdminPermission);
+ } else if (TAG_SDK_LIBRARY.equals(parser.getName())) {
+ isSdkLibrary = true;
}
}
} else if (TAG_OVERLAY.equals(parser.getName())) {
@@ -598,7 +603,7 @@ public class ApkLiteParseUtils {
overlayIsStatic, overlayPriority, requiredSystemPropertyName,
requiredSystemPropertyValue, minSdkVersion, targetSdkVersion,
rollbackDataPolicy, requiredSplitTypes.first, requiredSplitTypes.second,
- hasDeviceAdminReceiver));
+ hasDeviceAdminReceiver, isSdkLibrary));
}
private static boolean isDeviceAdminReceiver(
diff --git a/core/java/android/content/pm/parsing/FrameworkParsingPackageUtils.java b/core/java/android/content/pm/parsing/FrameworkParsingPackageUtils.java
index 8b86a16075e9..a65b6815f8ad 100644
--- a/core/java/android/content/pm/parsing/FrameworkParsingPackageUtils.java
+++ b/core/java/android/content/pm/parsing/FrameworkParsingPackageUtils.java
@@ -379,6 +379,30 @@ public class FrameworkParsingPackageUtils {
}
/**
+ * Computes the maxSdkVersion. If the package is not compatible with this platform, populates
+ * {@code outError[0]} with an error message.
+ * <p>
+ * {@code maxVers} is compared against {@code platformSdkVersion}. If {@code maxVers} is less
+ * than the {@code platformSdkVersion} then populates {@code outError[0]} with an error message.
+ * Otherwise, it returns {@code maxVers} unmodified.
+ *
+ * @param maxVers maxSdkVersion number, if specified in the application manifest, or {@code
+ * Integer.MAX_VALUE} otherwise
+ * @param platformSdkVersion platform SDK version number, typically Build.VERSION.SDK_INT
+ * @return the maxSdkVersion that was recognised or an error if the condition is not satisfied
+ */
+ public static ParseResult<Integer> computeMaxSdkVersion(@IntRange(from = 0) int maxVers,
+ @IntRange(from = 1) int platformSdkVersion, @NonNull ParseInput input) {
+ if (platformSdkVersion > maxVers) {
+ return input.error(PackageManager.INSTALL_FAILED_NEWER_SDK,
+ "Requires max SDK version " + maxVers + " but is "
+ + platformSdkVersion);
+ } else {
+ return input.success(maxVers);
+ }
+ }
+
+ /**
* Matches a given {@code targetCode} against a set of release codeNames. Target codes can
* either be of the form {@code [codename]}" (e.g {@code "Q"}) or of the form {@code
* [codename].[fingerprint]} (e.g {@code "Q.cafebc561"}).
diff --git a/core/java/android/content/pm/parsing/PackageLite.java b/core/java/android/content/pm/parsing/PackageLite.java
index 5f5e81253b31..e2789c93516f 100644
--- a/core/java/android/content/pm/parsing/PackageLite.java
+++ b/core/java/android/content/pm/parsing/PackageLite.java
@@ -105,6 +105,10 @@ public class PackageLite {
* or locally compiled variants.
*/
private final boolean mUseEmbeddedDex;
+ /**
+ * Indicates if this package is a sdk.
+ */
+ private final boolean mIsSdkLibrary;
public PackageLite(String path, String baseApkPath, ApkLite baseApk,
String[] splitNames, boolean[] isFeatureSplits, String[] usesSplitNames,
@@ -131,6 +135,7 @@ public class PackageLite {
mRequiredSplitTypes = requiredSplitTypes;
mSplitRequired = (baseApk.isSplitRequired() || hasAnyRequiredSplitTypes());
mProfileableByShell = baseApk.isProfileableByShell();
+ mIsSdkLibrary = baseApk.isIsSdkLibrary();
mSplitNames = splitNames;
mSplitTypes = splitTypes;
mIsFeatureSplits = isFeatureSplits;
@@ -401,11 +406,20 @@ public class PackageLite {
return mUseEmbeddedDex;
}
+ /**
+ * Indicates if this package is a sdk.
+ */
+ @DataClass.Generated.Member
+ public boolean isIsSdkLibrary() {
+ return mIsSdkLibrary;
+ }
+
@DataClass.Generated(
- time = 1628562559343L,
+ time = 1643132127068L,
codegenVersion = "1.0.23",
sourceFile = "frameworks/base/core/java/android/content/pm/parsing/PackageLite.java",
- inputSignatures = "private final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.NonNull java.lang.String mPath\nprivate final @android.annotation.NonNull java.lang.String mBaseApkPath\nprivate final @android.annotation.Nullable java.lang.String[] mSplitApkPaths\nprivate final @android.annotation.Nullable java.lang.String[] mSplitNames\nprivate final @android.annotation.Nullable java.lang.String[] mUsesSplitNames\nprivate final @android.annotation.Nullable java.lang.String[] mConfigForSplit\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String> mBaseRequiredSplitTypes\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String>[] mRequiredSplitTypes\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String>[] mSplitTypes\nprivate final int mVersionCodeMajor\nprivate final int mVersionCode\nprivate final int mTargetSdk\nprivate final int mBaseRevisionCode\nprivate final @android.annotation.Nullable int[] mSplitRevisionCodes\nprivate final int mInstallLocation\nprivate final @android.annotation.NonNull android.content.pm.VerifierInfo[] mVerifiers\nprivate final @android.annotation.Nullable boolean[] mIsFeatureSplits\nprivate final boolean mIsolatedSplits\nprivate final boolean mSplitRequired\nprivate final boolean mCoreApp\nprivate final boolean mDebuggable\nprivate final boolean mMultiArch\nprivate final boolean mUse32bitAbi\nprivate final boolean mExtractNativeLibs\nprivate final boolean mProfileableByShell\nprivate final boolean mUseEmbeddedDex\npublic java.util.List<java.lang.String> getAllApkPaths()\npublic long getLongVersionCode()\nprivate boolean hasAnyRequiredSplitTypes()\nclass PackageLite extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genConstDefs=false)")
+ inputSignatures =
+ "private final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.NonNull java.lang.String mPath\nprivate final @android.annotation.NonNull java.lang.String mBaseApkPath\nprivate final @android.annotation.Nullable java.lang.String[] mSplitApkPaths\nprivate final @android.annotation.Nullable java.lang.String[] mSplitNames\nprivate final @android.annotation.Nullable java.lang.String[] mUsesSplitNames\nprivate final @android.annotation.Nullable java.lang.String[] mConfigForSplit\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String> mBaseRequiredSplitTypes\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String>[] mRequiredSplitTypes\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String>[] mSplitTypes\nprivate final int mVersionCodeMajor\nprivate final int mVersionCode\nprivate final int mTargetSdk\nprivate final int mBaseRevisionCode\nprivate final @android.annotation.Nullable int[] mSplitRevisionCodes\nprivate final int mInstallLocation\nprivate final @android.annotation.NonNull android.content.pm.VerifierInfo[] mVerifiers\nprivate final @android.annotation.Nullable boolean[] mIsFeatureSplits\nprivate final boolean mIsolatedSplits\nprivate final boolean mSplitRequired\nprivate final boolean mCoreApp\nprivate final boolean mDebuggable\nprivate final boolean mMultiArch\nprivate final boolean mUse32bitAbi\nprivate final boolean mExtractNativeLibs\nprivate final boolean mProfileableByShell\nprivate final boolean mUseEmbeddedDex\nprivate final boolean mIsSdkLibrary\npublic java.util.List<java.lang.String> getAllApkPaths()\npublic long getLongVersionCode()\nprivate boolean hasAnyRequiredSplitTypes()\nclass PackageLite extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genConstDefs=false)")
@Deprecated
private void __metadata() {}
diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java
index a05f5c927b29..c8bbb0c1994d 100644
--- a/core/java/android/content/res/AssetManager.java
+++ b/core/java/android/content/res/AssetManager.java
@@ -79,6 +79,13 @@ public final class AssetManager implements AutoCloseable {
@GuardedBy("sSync") private static ArraySet<ApkAssets> sSystemApkAssetsSet;
/**
+ * Cookie value to use when the actual cookie is unknown. This value tells the system to search
+ * all the ApkAssets for the asset.
+ * @hide
+ */
+ public static final int COOKIE_UNKNOWN = -1;
+
+ /**
* Mode for {@link #open(String, int)}: no specific information about how
* data will be accessed.
*/
diff --git a/core/java/android/hardware/CameraSessionStats.java b/core/java/android/hardware/CameraSessionStats.java
index f34e2bf5ddc2..698cc76f6325 100644
--- a/core/java/android/hardware/CameraSessionStats.java
+++ b/core/java/android/hardware/CameraSessionStats.java
@@ -59,6 +59,7 @@ public class CameraSessionStats implements Parcelable {
private long mRequestCount;
private long mResultErrorCount;
private boolean mDeviceError;
+ private float mMaxPreviewFps;
private ArrayList<CameraStreamStats> mStreamStats;
public CameraSessionStats() {
@@ -67,6 +68,7 @@ public class CameraSessionStats implements Parcelable {
mApiLevel = -1;
mIsNdk = false;
mLatencyMs = -1;
+ mMaxPreviewFps = 0;
mSessionType = -1;
mInternalReconfigure = -1;
mRequestCount = 0;
@@ -77,7 +79,7 @@ public class CameraSessionStats implements Parcelable {
public CameraSessionStats(String cameraId, int facing, int newCameraState,
String clientName, int apiLevel, boolean isNdk, int creationDuration,
- int sessionType, int internalReconfigure) {
+ float maxPreviewFps, int sessionType, int internalReconfigure) {
mCameraId = cameraId;
mFacing = facing;
mNewCameraState = newCameraState;
@@ -85,6 +87,7 @@ public class CameraSessionStats implements Parcelable {
mApiLevel = apiLevel;
mIsNdk = isNdk;
mLatencyMs = creationDuration;
+ mMaxPreviewFps = maxPreviewFps;
mSessionType = sessionType;
mInternalReconfigure = internalReconfigure;
mStreamStats = new ArrayList<CameraStreamStats>();
@@ -121,6 +124,7 @@ public class CameraSessionStats implements Parcelable {
dest.writeInt(mApiLevel);
dest.writeBoolean(mIsNdk);
dest.writeInt(mLatencyMs);
+ dest.writeFloat(mMaxPreviewFps);
dest.writeInt(mSessionType);
dest.writeInt(mInternalReconfigure);
dest.writeLong(mRequestCount);
@@ -137,6 +141,7 @@ public class CameraSessionStats implements Parcelable {
mApiLevel = in.readInt();
mIsNdk = in.readBoolean();
mLatencyMs = in.readInt();
+ mMaxPreviewFps = in.readFloat();
mSessionType = in.readInt();
mInternalReconfigure = in.readInt();
mRequestCount = in.readLong();
@@ -176,6 +181,10 @@ public class CameraSessionStats implements Parcelable {
return mLatencyMs;
}
+ public float getMaxPreviewFps() {
+ return mMaxPreviewFps;
+ }
+
public int getSessionType() {
return mSessionType;
}
diff --git a/core/java/android/hardware/CameraStreamStats.java b/core/java/android/hardware/CameraStreamStats.java
index 823d454ee16b..3952467324fe 100644
--- a/core/java/android/hardware/CameraStreamStats.java
+++ b/core/java/android/hardware/CameraStreamStats.java
@@ -15,8 +15,8 @@
*/
package android.hardware;
-import android.hardware.camera2.params.DynamicRangeProfiles;
import android.hardware.camera2.CameraMetadata;
+import android.hardware.camera2.params.DynamicRangeProfiles;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Log;
@@ -37,6 +37,7 @@ public class CameraStreamStats implements Parcelable {
private int mWidth;
private int mHeight;
private int mFormat;
+ private float mMaxPreviewFps;
private int mDataSpace;
private long mUsage;
private long mRequestCount;
@@ -48,7 +49,7 @@ public class CameraStreamStats implements Parcelable {
private float[] mHistogramBins;
private long[] mHistogramCounts;
private long mDynamicRangeProfile;
- private int mStreamUseCase;
+ private long mStreamUseCase;
private static final String TAG = "CameraStreamStats";
@@ -56,6 +57,7 @@ public class CameraStreamStats implements Parcelable {
mWidth = 0;
mHeight = 0;
mFormat = 0;
+ mMaxPreviewFps = 0;
mDataSpace = 0;
mUsage = 0;
mRequestCount = 0;
@@ -68,13 +70,14 @@ public class CameraStreamStats implements Parcelable {
mStreamUseCase = CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT;
}
- public CameraStreamStats(int width, int height, int format,
+ public CameraStreamStats(int width, int height, int format, float maxPreviewFps,
int dataSpace, long usage, long requestCount, long errorCount,
int startLatencyMs, int maxHalBuffers, int maxAppBuffers, long dynamicRangeProfile,
- int streamUseCase) {
+ long streamUseCase) {
mWidth = width;
mHeight = height;
mFormat = format;
+ mMaxPreviewFps = maxPreviewFps;
mDataSpace = dataSpace;
mUsage = usage;
mRequestCount = requestCount;
@@ -120,6 +123,7 @@ public class CameraStreamStats implements Parcelable {
dest.writeInt(mWidth);
dest.writeInt(mHeight);
dest.writeInt(mFormat);
+ dest.writeFloat(mMaxPreviewFps);
dest.writeInt(mDataSpace);
dest.writeLong(mUsage);
dest.writeLong(mRequestCount);
@@ -131,13 +135,14 @@ public class CameraStreamStats implements Parcelable {
dest.writeFloatArray(mHistogramBins);
dest.writeLongArray(mHistogramCounts);
dest.writeLong(mDynamicRangeProfile);
- dest.writeInt(mStreamUseCase);
+ dest.writeLong(mStreamUseCase);
}
public void readFromParcel(Parcel in) {
mWidth = in.readInt();
mHeight = in.readInt();
mFormat = in.readInt();
+ mMaxPreviewFps = in.readFloat();
mDataSpace = in.readInt();
mUsage = in.readLong();
mRequestCount = in.readLong();
@@ -149,7 +154,7 @@ public class CameraStreamStats implements Parcelable {
mHistogramBins = in.createFloatArray();
mHistogramCounts = in.createLongArray();
mDynamicRangeProfile = in.readLong();
- mStreamUseCase = in.readInt();
+ mStreamUseCase = in.readLong();
}
public int getWidth() {
@@ -164,6 +169,10 @@ public class CameraStreamStats implements Parcelable {
return mFormat;
}
+ public float getMaxPreviewFps() {
+ return mMaxPreviewFps;
+ }
+
public int getDataSpace() {
return mDataSpace;
}
@@ -208,7 +217,7 @@ public class CameraStreamStats implements Parcelable {
return mDynamicRangeProfile;
}
- public int getStreamUseCase() {
+ public long getStreamUseCase() {
return mStreamUseCase;
}
}
diff --git a/core/java/android/hardware/SyncFence.java b/core/java/android/hardware/SyncFence.java
index cd4bf78f0879..166001347bd4 100644
--- a/core/java/android/hardware/SyncFence.java
+++ b/core/java/android/hardware/SyncFence.java
@@ -24,6 +24,7 @@ import android.opengl.EGLSync;
import android.os.Parcel;
import android.os.ParcelFileDescriptor;
import android.os.Parcelable;
+import android.os.SystemClock;
import libcore.util.NativeAllocationRegistry;
@@ -105,6 +106,21 @@ public final class SyncFence implements AutoCloseable, Parcelable {
}
}
+ /**
+ * Creates a SyncFence from a libui Fence*
+ * DOES NOT TAKE AN ADDITIONAL REFERENCE, the caller must incref if it intends to retain
+ * ownership (eg, when using sp<Fence>)
+ * @hide
+ */
+ public SyncFence(long nativeFencePtr) {
+ mNativePtr = nativeFencePtr;
+ if (nativeFencePtr != 0) {
+ mCloser = sRegistry.registerNativeAllocation(this, mNativePtr);
+ } else {
+ mCloser = () -> {};
+ }
+ }
+
private SyncFence() {
mCloser = () -> {};
}
@@ -194,7 +210,9 @@ public final class SyncFence implements AutoCloseable, Parcelable {
}
/**
- * Returns the time that the fence signaled in the CLOCK_MONOTONIC time domain.
+ * Returns the time in nanoseconds that the fence signaled in the CLOCK_MONOTONIC time domain.
+ * This corresponds to {@link System#nanoTime()} but may also be compared to
+ * {@link SystemClock#uptimeMillis()} after adjusting for milliseconds vs. nanoseconds.
*
* If the fence isn't valid, that is if {@link #isValid()} is false, then this returns
* {@link #SIGNAL_TIME_INVALID}. Similarly, if an error occurs while trying to access the
diff --git a/core/java/android/hardware/biometrics/BiometricFingerprintConstants.java b/core/java/android/hardware/biometrics/BiometricFingerprintConstants.java
index abdc64c56ead..d8ebb628452a 100644
--- a/core/java/android/hardware/biometrics/BiometricFingerprintConstants.java
+++ b/core/java/android/hardware/biometrics/BiometricFingerprintConstants.java
@@ -298,4 +298,33 @@ public interface BiometricFingerprintConstants {
* @hide
*/
int FINGERPRINT_ACQUIRED_VENDOR_BASE = 1000;
+
+ /**
+ * Whether the FingerprintAcquired message is a signal to turn off HBM
+ */
+ static boolean shouldTurnOffHbm(@FingerprintAcquired int acquiredInfo) {
+ switch (acquiredInfo) {
+ case FINGERPRINT_ACQUIRED_START:
+ // Authentication just began
+ return false;
+ case FINGERPRINT_ACQUIRED_GOOD:
+ // Good image captured. Turn off HBM. Success/Reject comes after, which is when
+ // hideUdfpsOverlay will be called.
+ return true;
+ case FINGERPRINT_ACQUIRED_PARTIAL:
+ case FINGERPRINT_ACQUIRED_INSUFFICIENT:
+ case FINGERPRINT_ACQUIRED_IMAGER_DIRTY:
+ case FINGERPRINT_ACQUIRED_TOO_SLOW:
+ case FINGERPRINT_ACQUIRED_TOO_FAST:
+ case FINGERPRINT_ACQUIRED_IMMOBILE:
+ case FINGERPRINT_ACQUIRED_TOO_BRIGHT:
+ case FINGERPRINT_ACQUIRED_VENDOR:
+ // Bad image captured. Turn off HBM. Matcher will not run, so there's no need to
+ // keep HBM on.
+ return true;
+ case FINGERPRINT_ACQUIRED_UNKNOWN:
+ default:
+ return false;
+ }
+ }
}
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 7bebe1ff14c3..b05e6d131957 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -3563,8 +3563,8 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
*/
@PublicKey
@NonNull
- public static final Key<int[]> SCALER_AVAILABLE_STREAM_USE_CASES =
- new Key<int[]>("android.scaler.availableStreamUseCases", int[].class);
+ public static final Key<long[]> SCALER_AVAILABLE_STREAM_USE_CASES =
+ new Key<long[]>("android.scaler.availableStreamUseCases", long[].class);
/**
* <p>An array of mandatory stream combinations with stream use cases.
diff --git a/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java b/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java
index 465abfb55540..a3bc66546a6a 100644
--- a/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java
+++ b/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java
@@ -66,7 +66,7 @@ public final class MandatoryStreamCombination {
private final boolean mIsUltraHighResolution;
private final boolean mIsMaximumSize;
private final boolean mIs10BitCapable;
- private final int mStreamUseCase;
+ private final long mStreamUseCase;
/**
* Create a new {@link MandatoryStreamInformation}.
@@ -168,7 +168,7 @@ public final class MandatoryStreamCombination {
*/
public MandatoryStreamInformation(@NonNull List<Size> availableSizes, @Format int format,
boolean isMaximumSize, boolean isInput, boolean isUltraHighResolution,
- boolean is10BitCapable, @StreamUseCase int streamUseCase) {
+ boolean is10BitCapable, @StreamUseCase long streamUseCase) {
if (availableSizes.isEmpty()) {
throw new IllegalArgumentException("No available sizes");
}
@@ -308,9 +308,9 @@ public final class MandatoryStreamCombination {
* For {@link MandatoryStreamInformation} belonging to other mandatory stream
* combinations, the return value will be DEFAULT. </p>
*
- * @return the integer stream use case.
+ * @return the long integer stream use case.
*/
- public @StreamUseCase int getStreamUseCase() {
+ public @StreamUseCase long getStreamUseCase() {
return mStreamUseCase;
}
@@ -365,15 +365,15 @@ public final class MandatoryStreamCombination {
/**
* Short hand for stream use cases
*/
- private static final int STREAM_USE_CASE_PREVIEW =
+ private static final long STREAM_USE_CASE_PREVIEW =
CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW;
- private static final int STREAM_USE_CASE_STILL_CAPTURE =
+ private static final long STREAM_USE_CASE_STILL_CAPTURE =
CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_STILL_CAPTURE;
- private static final int STREAM_USE_CASE_RECORD =
+ private static final long STREAM_USE_CASE_RECORD =
CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_RECORD;
- private static final int STREAM_USE_CASE_PREVIEW_VIDEO_STILL =
+ private static final long STREAM_USE_CASE_PREVIEW_VIDEO_STILL =
CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW_VIDEO_STILL;
- private static final int STREAM_USE_CASE_VIDEO_CALL =
+ private static final long STREAM_USE_CASE_VIDEO_CALL =
CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_CALL;
/**
@@ -471,12 +471,12 @@ public final class MandatoryStreamCombination {
private static final class StreamTemplate {
public int mFormat;
public SizeThreshold mSizeThreshold;
- public int mStreamUseCase;
+ public long mStreamUseCase;
public StreamTemplate(int format, SizeThreshold sizeThreshold) {
this(format, sizeThreshold, CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT);
}
public StreamTemplate(@Format int format, @NonNull SizeThreshold sizeThreshold,
- @StreamUseCase int streamUseCase) {
+ @StreamUseCase long streamUseCase) {
mFormat = format;
mSizeThreshold = sizeThreshold;
mStreamUseCase = streamUseCase;
diff --git a/core/java/android/hardware/camera2/params/OutputConfiguration.java b/core/java/android/hardware/camera2/params/OutputConfiguration.java
index 2350b7c7a481..39cb7f3ebddb 100644
--- a/core/java/android/hardware/camera2/params/OutputConfiguration.java
+++ b/core/java/android/hardware/camera2/params/OutputConfiguration.java
@@ -918,9 +918,9 @@ public final class OutputConfiguration implements Parcelable {
* @throws IllegalArgumentException If the streamUseCase isn't within the range of valid
* values.
*/
- public void setStreamUseCase(@StreamUseCase int streamUseCase) {
+ public void setStreamUseCase(@StreamUseCase long streamUseCase) {
// Verify that the value is in range
- int maxUseCaseValue = CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_CALL;
+ long maxUseCaseValue = CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_CALL;
if (streamUseCase > maxUseCaseValue &&
streamUseCase < CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_VENDOR_START) {
throw new IllegalArgumentException("Not a valid stream use case value " +
@@ -938,7 +938,7 @@ public final class OutputConfiguration implements Parcelable {
*
* @return the currently set stream use case
*/
- public int getStreamUseCase() {
+ public long getStreamUseCase() {
return mStreamUseCase;
}
@@ -1067,7 +1067,7 @@ public final class OutputConfiguration implements Parcelable {
String physicalCameraId = source.readString();
boolean isMultiResolutionOutput = source.readInt() == 1;
int[] sensorPixelModesUsed = source.createIntArray();
- int streamUseCase = source.readInt();
+ long streamUseCase = source.readLong();
checkArgumentInRange(rotation, ROTATION_0, ROTATION_270, "Rotation constant");
long dynamicRangeProfile = source.readLong();
@@ -1218,7 +1218,7 @@ public final class OutputConfiguration implements Parcelable {
// writeList doesn't seem to work well with Integer list.
dest.writeIntArray(convertIntegerToIntList(mSensorPixelModesUsed));
dest.writeLong(mDynamicRangeProfile);
- dest.writeInt(mStreamUseCase);
+ dest.writeLong(mStreamUseCase);
dest.writeInt(mTimestampBase);
dest.writeInt(mMirrorMode);
}
@@ -1337,7 +1337,7 @@ public final class OutputConfiguration implements Parcelable {
// Dynamic range profile
private long mDynamicRangeProfile;
// Stream use case
- private int mStreamUseCase;
+ private long mStreamUseCase;
// Timestamp base
private int mTimestampBase;
// Mirroring mode
diff --git a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
index d9734b493471..5981d279227d 100644
--- a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
+++ b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
@@ -781,10 +781,11 @@ public final class StreamConfigurationMap {
* <li>The fpsMin and fpsMax will be a multiple 30fps.</li>
* <li>The fpsMin will be no less than 30fps, the fpsMax will be no less than 120fps.</li>
* <li>At least one range will be a fixed FPS range where fpsMin == fpsMax.</li>
- * <li>For each fixed FPS range, there will be one corresponding variable FPS range [30,
- * fps_max]. These kinds of FPS ranges are suitable for preview-only use cases where the
- * application doesn't want the camera device always produce higher frame rate than the display
- * refresh rate.</li>
+ * <li>For each fixed FPS range, there will be one corresponding variable FPS range
+ * [30, fps_max] or [60, fps_max]. These kinds of FPS ranges are suitable for preview-only
+ * use cases where the application doesn't want the camera device always produce higher frame
+ * rate than the display refresh rate. Both 30fps and 60fps preview rate will not be
+ * supported for the same recording rate.</li>
* </p>
*
* @return an array of supported high speed video recording FPS ranges The upper bound of
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index 7e070bc06056..29221b801ef6 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -923,14 +923,15 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
* @hide
*/
@RequiresPermission(USE_BIOMETRIC_INTERNAL)
- public void onPointerDown(int sensorId, int x, int y, float minor, float major) {
+ public void onPointerDown(long requestId, int sensorId, int x, int y,
+ float minor, float major) {
if (mService == null) {
Slog.w(TAG, "onFingerDown: no fingerprint service");
return;
}
try {
- mService.onPointerDown(sensorId, x, y, minor, major);
+ mService.onPointerDown(requestId, sensorId, x, y, minor, major);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -940,14 +941,14 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
* @hide
*/
@RequiresPermission(USE_BIOMETRIC_INTERNAL)
- public void onPointerUp(int sensorId) {
+ public void onPointerUp(long requestId, int sensorId) {
if (mService == null) {
Slog.w(TAG, "onFingerDown: no fingerprint service");
return;
}
try {
- mService.onPointerUp(sensorId);
+ mService.onPointerUp(requestId, sensorId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -957,14 +958,14 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
* @hide
*/
@RequiresPermission(USE_BIOMETRIC_INTERNAL)
- public void onUiReady(int sensorId) {
+ public void onUiReady(long requestId, int sensorId) {
if (mService == null) {
Slog.w(TAG, "onUiReady: no fingerprint service");
return;
}
try {
- mService.onUiReady(sensorId);
+ mService.onUiReady(requestId, sensorId);
} 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 cbff8b11a72a..12114aa3fa33 100644
--- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
@@ -155,13 +155,13 @@ interface IFingerprintService {
void addAuthenticatorsRegisteredCallback(IFingerprintAuthenticatorsRegisteredCallback callback);
// Notifies about a finger touching the sensor area.
- void onPointerDown(int sensorId, int x, int y, float minor, float major);
+ void onPointerDown(long requestId, int sensorId, int x, int y, float minor, float major);
// Notifies about a finger leaving the sensor area.
- void onPointerUp(int sensorId);
+ void onPointerUp(long requestId, int sensorId);
// Notifies about the fingerprint UI being ready (e.g. HBM illumination is enabled).
- void onUiReady(int sensorId);
+ void onUiReady(long requestId, int sensorId);
// Sets the controller for managing the UDFPS overlay.
void setUdfpsOverlayController(in IUdfpsOverlayController controller);
diff --git a/core/java/android/hardware/fingerprint/IUdfpsOverlayController.aidl b/core/java/android/hardware/fingerprint/IUdfpsOverlayController.aidl
index 648edda62171..dbb8e40f3a71 100644
--- a/core/java/android/hardware/fingerprint/IUdfpsOverlayController.aidl
+++ b/core/java/android/hardware/fingerprint/IUdfpsOverlayController.aidl
@@ -23,14 +23,15 @@ import android.hardware.fingerprint.IUdfpsOverlayControllerCallback;
*/
oneway interface IUdfpsOverlayController {
// Shows the overlay for the given sensor with a reason from BiometricOverlayConstants.
- void showUdfpsOverlay(int sensorId, int reason, IUdfpsOverlayControllerCallback callback);
+ void showUdfpsOverlay(long requestId, int sensorId, int reason, IUdfpsOverlayControllerCallback callback);
// Hides the overlay.
void hideUdfpsOverlay(int sensorId);
- // Good image captured. Turn off HBM. Success/Reject comes after, which is when hideUdfpsOverlay
- // will be called.
- void onAcquiredGood(int sensorId);
+ // Check acquiredInfo for the acquired type (BiometricFingerprintConstants#FingerprintAcquired).
+ // Check BiometricFingerprintConstants#shouldTurnOffHbm for whether the acquiredInfo
+ // should turn off HBM.
+ void onAcquired(int sensorId, int acquiredInfo);
// Notifies of enrollment progress changes.
void onEnrollmentProgress(int sensorId, int remaining);
diff --git a/core/java/android/hardware/location/GeofenceHardwareRequestParcelable.java b/core/java/android/hardware/location/GeofenceHardwareRequestParcelable.java
index df13ade2bf5e..bd25b8f2ad88 100644
--- a/core/java/android/hardware/location/GeofenceHardwareRequestParcelable.java
+++ b/core/java/android/hardware/location/GeofenceHardwareRequestParcelable.java
@@ -16,9 +16,9 @@
package android.hardware.location;
+import android.os.BadParcelableException;
import android.os.Parcel;
import android.os.Parcelable;
-import android.util.Log;
/**
* Geofence Hardware Request used for internal location services communication.
@@ -139,11 +139,8 @@ public final class GeofenceHardwareRequestParcelable implements Parcelable {
@Override
public GeofenceHardwareRequestParcelable createFromParcel(Parcel parcel) {
int geofenceType = parcel.readInt();
- if(geofenceType != GeofenceHardwareRequest.GEOFENCE_TYPE_CIRCLE) {
- Log.e(
- "GeofenceHardwareRequest",
- String.format("Invalid Geofence type: %d", geofenceType));
- return null;
+ if (geofenceType != GeofenceHardwareRequest.GEOFENCE_TYPE_CIRCLE) {
+ throw new BadParcelableException("Invalid Geofence type: " + geofenceType);
}
GeofenceHardwareRequest request = GeofenceHardwareRequest.createCircularGeofence(
diff --git a/core/java/android/inputmethodservice/IInputMethodWrapper.java b/core/java/android/inputmethodservice/IInputMethodWrapper.java
index af57f793bf73..f9ed0e3db499 100644
--- a/core/java/android/inputmethodservice/IInputMethodWrapper.java
+++ b/core/java/android/inputmethodservice/IInputMethodWrapper.java
@@ -40,6 +40,7 @@ import android.view.inputmethod.InputMethodSubtype;
import com.android.internal.inputmethod.CancellationGroup;
import com.android.internal.inputmethod.IInputMethodPrivilegedOperations;
+import com.android.internal.inputmethod.InputMethodNavButtonFlags;
import com.android.internal.os.HandlerCaller;
import com.android.internal.os.SomeArgs;
import com.android.internal.view.IInlineSuggestionsRequestCallback;
@@ -70,7 +71,7 @@ class IInputMethodWrapper extends IInputMethod.Stub
private static final int DO_SET_INPUT_CONTEXT = 20;
private static final int DO_UNSET_INPUT_CONTEXT = 30;
private static final int DO_START_INPUT = 32;
- private static final int DO_ON_SHOULD_SHOW_IME_SWITCHER_WHEN_IME_IS_SHOWN_CHANGED = 35;
+ private static final int DO_ON_NAV_BUTTON_FLAGS_CHANGED = 35;
private static final int DO_CREATE_SESSION = 40;
private static final int DO_SET_SESSION_ENABLED = 45;
private static final int DO_SHOW_SOFT_INPUT = 60;
@@ -80,6 +81,7 @@ class IInputMethodWrapper extends IInputMethod.Stub
private static final int DO_CAN_START_STYLUS_HANDWRITING = 100;
private static final int DO_START_STYLUS_HANDWRITING = 110;
private static final int DO_INIT_INK_WINDOW = 120;
+ private static final int DO_FINISH_STYLUS_HANDWRITING = 130;
final WeakReference<InputMethodServiceInternal> mTarget;
final Context mContext;
@@ -176,7 +178,7 @@ class IInputMethodWrapper extends IInputMethod.Stub
try {
inputMethod.initializeInternal((IBinder) args.arg1,
(IInputMethodPrivilegedOperations) args.arg2, msg.arg1,
- (boolean) args.arg3, msg.arg2 != 0);
+ (boolean) args.arg3, msg.arg2);
} finally {
args.recycle();
}
@@ -196,22 +198,20 @@ class IInputMethodWrapper extends IInputMethod.Stub
final EditorInfo info = (EditorInfo) args.arg3;
final CancellationGroup cancellationGroup = (CancellationGroup) args.arg4;
final boolean restarting = args.argi5 == 1;
- final boolean shouldShowImeSwitcherWhenImeIsShown = args.argi6 != 0;
+ @InputMethodNavButtonFlags
+ final int navButtonFlags = args.argi6;
final InputConnection ic = inputContext != null
? new RemoteInputConnection(mTarget, inputContext, cancellationGroup)
: null;
info.makeCompatible(mTargetSdkVersion);
inputMethod.dispatchStartInputWithToken(ic, info, restarting, startInputToken,
- shouldShowImeSwitcherWhenImeIsShown);
+ navButtonFlags);
args.recycle();
return;
}
- case DO_ON_SHOULD_SHOW_IME_SWITCHER_WHEN_IME_IS_SHOWN_CHANGED: {
- final boolean shouldShowImeSwitcherWhenImeIsShown = msg.arg1 != 0;
- inputMethod.onShouldShowImeSwitcherWhenImeIsShownChanged(
- shouldShowImeSwitcherWhenImeIsShown);
+ case DO_ON_NAV_BUTTON_FLAGS_CHANGED:
+ inputMethod.onNavButtonFlagsChanged(msg.arg1);
return;
- }
case DO_CREATE_SESSION: {
SomeArgs args = (SomeArgs)msg.obj;
inputMethod.createSession(new InputMethodSessionCallbackWrapper(
@@ -264,6 +264,10 @@ class IInputMethodWrapper extends IInputMethod.Stub
inputMethod.initInkWindow();
return;
}
+ case DO_FINISH_STYLUS_HANDWRITING: {
+ inputMethod.finishStylusHandwriting();
+ return;
+ }
}
Log.w(TAG, "Unhandled message code: " + msg.what);
@@ -301,10 +305,9 @@ class IInputMethodWrapper extends IInputMethod.Stub
@Override
public void initializeInternal(IBinder token, IInputMethodPrivilegedOperations privOps,
int configChanges, boolean stylusHwSupported,
- boolean shouldShowImeSwitcherWhenImeIsShown) {
+ @InputMethodNavButtonFlags int navButtonFlags) {
mCaller.executeOrSendMessage(mCaller.obtainMessageIIOOO(DO_INITIALIZE_INTERNAL,
- configChanges, shouldShowImeSwitcherWhenImeIsShown ? 1 : 0, token, privOps,
- stylusHwSupported));
+ configChanges, navButtonFlags, token, privOps, stylusHwSupported));
}
@BinderThread
@@ -344,23 +347,21 @@ class IInputMethodWrapper extends IInputMethod.Stub
@BinderThread
@Override
public void startInput(IBinder startInputToken, IInputContext inputContext,
- EditorInfo attribute, boolean restarting, boolean shouldShowImeSwitcherWhenImeIsShown) {
+ EditorInfo attribute, boolean restarting,
+ @InputMethodNavButtonFlags int navButtonFlags) {
if (mCancellationGroup == null) {
Log.e(TAG, "startInput must be called after bindInput.");
mCancellationGroup = new CancellationGroup();
}
mCaller.executeOrSendMessage(mCaller.obtainMessageOOOOII(DO_START_INPUT, startInputToken,
- inputContext, attribute, mCancellationGroup, restarting ? 1 : 0,
- shouldShowImeSwitcherWhenImeIsShown ? 1 : 0));
+ inputContext, attribute, mCancellationGroup, restarting ? 1 : 0, navButtonFlags));
}
@BinderThread
@Override
- public void onShouldShowImeSwitcherWhenImeIsShownChanged(
- boolean shouldShowImeSwitcherWhenImeIsShown) {
- mCaller.executeOrSendMessage(mCaller.obtainMessageI(
- DO_ON_SHOULD_SHOW_IME_SWITCHER_WHEN_IME_IS_SHOWN_CHANGED,
- shouldShowImeSwitcherWhenImeIsShown ? 1 : 0));
+ public void onNavButtonFlagsChanged(@InputMethodNavButtonFlags int navButtonFlags) {
+ mCaller.executeOrSendMessage(
+ mCaller.obtainMessageI(DO_ON_NAV_BUTTON_FLAGS_CHANGED, navButtonFlags));
}
@BinderThread
@@ -431,4 +432,10 @@ class IInputMethodWrapper extends IInputMethod.Stub
public void initInkWindow() {
mCaller.executeOrSendMessage(mCaller.obtainMessage(DO_INIT_INK_WINDOW));
}
+
+ @BinderThread
+ @Override
+ public void finishStylusHandwriting() {
+ mCaller.executeOrSendMessage(mCaller.obtainMessage(DO_FINISH_STYLUS_HANDWRITING));
+ }
}
diff --git a/core/java/android/inputmethodservice/ImsConfigurationTracker.java b/core/java/android/inputmethodservice/ImsConfigurationTracker.java
index 3c788884371b..30ef0a2a6f7f 100644
--- a/core/java/android/inputmethodservice/ImsConfigurationTracker.java
+++ b/core/java/android/inputmethodservice/ImsConfigurationTracker.java
@@ -63,8 +63,9 @@ public final class ImsConfigurationTracker {
*/
@MainThread
public void onBindInput(@Nullable Resources resources) {
- Preconditions.checkState(mInitialized,
- "onBindInput can be called only after onInitialize().");
+ if (!mInitialized) {
+ return;
+ }
if (mLastKnownConfig == null && resources != null) {
mLastKnownConfig = new Configuration(resources.getConfiguration());
}
diff --git a/core/java/android/inputmethodservice/InkWindow.java b/core/java/android/inputmethodservice/InkWindow.java
index 499634ae5bec..8289c268d4c6 100644
--- a/core/java/android/inputmethodservice/InkWindow.java
+++ b/core/java/android/inputmethodservice/InkWindow.java
@@ -27,6 +27,8 @@ import android.content.Context;
import android.os.IBinder;
import android.util.Slog;
import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
import android.view.WindowManager;
import com.android.internal.policy.PhoneWindow;
@@ -40,6 +42,9 @@ final class InkWindow extends PhoneWindow {
private final WindowManager mWindowManager;
private boolean mIsViewAdded;
+ private View mInkView;
+ private InkVisibilityListener mInkViewVisibilityListener;
+ private ViewTreeObserver.OnGlobalLayoutListener mGlobalLayoutListener;
public InkWindow(@NonNull Context context) {
super(context);
@@ -102,4 +107,77 @@ final class InkWindow extends PhoneWindow {
lp.token = token;
setAttributes(lp);
}
+
+ @Override
+ public void addContentView(View view, ViewGroup.LayoutParams params) {
+ if (mInkView == null) {
+ mInkView = view;
+ } else if (mInkView != view) {
+ throw new IllegalStateException("Only one Child Inking view is permitted.");
+ }
+ super.addContentView(view, params);
+ initInkViewVisibilityListener();
+ }
+
+ @Override
+ public void setContentView(View view, ViewGroup.LayoutParams params) {
+ mInkView = view;
+ super.setContentView(view, params);
+ initInkViewVisibilityListener();
+ }
+
+ @Override
+ public void setContentView(View view) {
+ mInkView = view;
+ super.setContentView(view);
+ initInkViewVisibilityListener();
+ }
+
+ @Override
+ public void clearContentView() {
+ if (mGlobalLayoutListener != null && mInkView != null) {
+ mInkView.getViewTreeObserver().removeOnGlobalLayoutListener(mGlobalLayoutListener);
+ }
+ mGlobalLayoutListener = null;
+ mInkView = null;
+ super.clearContentView();
+ }
+
+ /**
+ * Listener used by InkWindow to time the dispatching of {@link MotionEvent}s to Ink view, once
+ * it is visible to user.
+ */
+ interface InkVisibilityListener {
+ void onInkViewVisible();
+ }
+
+ void setInkViewVisibilityListener(InkVisibilityListener listener) {
+ mInkViewVisibilityListener = listener;
+ initInkViewVisibilityListener();
+ }
+
+ void initInkViewVisibilityListener() {
+ if (mInkView == null || mInkViewVisibilityListener == null
+ || mGlobalLayoutListener != null) {
+ return;
+ }
+ mGlobalLayoutListener = new ViewTreeObserver.OnGlobalLayoutListener() {
+ @Override
+ public void onGlobalLayout() {
+ if (mInkView.isVisibleToUser()) {
+ if (mInkViewVisibilityListener != null) {
+ mInkViewVisibilityListener.onInkViewVisible();
+ }
+ mInkView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
+ mGlobalLayoutListener = null;
+ }
+ }
+ };
+ mInkView.getViewTreeObserver().addOnGlobalLayoutListener(mGlobalLayoutListener);
+ }
+
+ boolean isInkViewVisible() {
+ return getDecorView().getVisibility() == View.VISIBLE
+ && mInkView != null && mInkView.isVisibleToUser();
+ }
}
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index fbc0732affe1..4fdd53425328 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -140,8 +140,10 @@ import com.android.internal.annotations.GuardedBy;
import com.android.internal.inputmethod.IInputContentUriToken;
import com.android.internal.inputmethod.IInputMethodPrivilegedOperations;
import com.android.internal.inputmethod.ImeTracing;
+import com.android.internal.inputmethod.InputMethodNavButtonFlags;
import com.android.internal.inputmethod.InputMethodPrivilegedOperations;
import com.android.internal.inputmethod.InputMethodPrivilegedOperationsRegistry;
+import com.android.internal.util.RingBuffer;
import com.android.internal.view.IInlineSuggestionsRequestCallback;
import com.android.internal.view.IInputContext;
import com.android.internal.view.InlineSuggestionsRequestInfo;
@@ -333,6 +335,17 @@ public class InputMethodService extends AbstractInputMethodService {
"persist.sys.ime.can_render_gestural_nav_buttons";
/**
+ * Number of {@link MotionEvent} to buffer if IME is not ready with Ink view.
+ * This number may be configured eventually based on device's touch sampling frequency.
+ */
+ private static final int MAX_EVENTS_BUFFER = 500;
+
+ /**
+ * A circular buffer of size MAX_EVENTS_BUFFER in case IME is taking too long to add ink view.
+ **/
+ private RingBuffer<MotionEvent> mPendingEvents;
+
+ /**
* Returns whether {@link InputMethodService} is responsible for rendering the back button and
* the IME switcher button or not when the gestural navigation is enabled.
*
@@ -347,7 +360,7 @@ public class InputMethodService extends AbstractInputMethodService {
*/
@AnyThread
public static boolean canImeRenderGesturalNavButtons() {
- return SystemProperties.getBoolean(PROP_CAN_RENDER_GESTURAL_NAV_BUTTONS, false);
+ return SystemProperties.getBoolean(PROP_CAN_RENDER_GESTURAL_NAV_BUTTONS, true);
}
/**
@@ -660,7 +673,7 @@ public class InputMethodService extends AbstractInputMethodService {
@Override
public final void initializeInternal(@NonNull IBinder token,
IInputMethodPrivilegedOperations privilegedOperations, int configChanges,
- boolean stylusHwSupported, boolean shouldShowImeSwitcherWhenImeIsShown) {
+ boolean stylusHwSupported, @InputMethodNavButtonFlags int navButtonFlags) {
if (mDestroyed) {
Log.i(TAG, "The InputMethodService has already onDestroyed()."
+ "Ignore the initialization.");
@@ -673,8 +686,7 @@ public class InputMethodService extends AbstractInputMethodService {
if (stylusHwSupported) {
mInkWindow = new InkWindow(mWindow.getContext());
}
- mNavigationBarController.setShouldShowImeSwitcherWhenImeIsShown(
- shouldShowImeSwitcherWhenImeIsShown);
+ mNavigationBarController.onNavButtonFlagsChanged(navButtonFlags);
attachToken(token);
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
@@ -784,10 +796,9 @@ public class InputMethodService extends AbstractInputMethodService {
@Override
public final void dispatchStartInputWithToken(@Nullable InputConnection inputConnection,
@NonNull EditorInfo editorInfo, boolean restarting,
- @NonNull IBinder startInputToken, boolean shouldShowImeSwitcherWhenImeIsShown) {
+ @NonNull IBinder startInputToken, @InputMethodNavButtonFlags int navButtonFlags) {
mPrivOps.reportStartInputAsync(startInputToken);
- mNavigationBarController.setShouldShowImeSwitcherWhenImeIsShown(
- shouldShowImeSwitcherWhenImeIsShown);
+ mNavigationBarController.onNavButtonFlagsChanged(navButtonFlags);
if (restarting) {
restartInput(inputConnection, editorInfo);
} else {
@@ -801,10 +812,8 @@ public class InputMethodService extends AbstractInputMethodService {
*/
@MainThread
@Override
- public void onShouldShowImeSwitcherWhenImeIsShownChanged(
- boolean shouldShowImeSwitcherWhenImeIsShown) {
- mNavigationBarController.setShouldShowImeSwitcherWhenImeIsShown(
- shouldShowImeSwitcherWhenImeIsShown);
+ public void onNavButtonFlagsChanged(@InputMethodNavButtonFlags int navButtonFlags) {
+ mNavigationBarController.onNavButtonFlagsChanged(navButtonFlags);
}
/**
@@ -957,7 +966,8 @@ public class InputMethodService extends AbstractInputMethodService {
mInkWindow.show();
// deliver previous @param stylusEvents
- stylusEvents.forEach(mInkWindow.getDecorView()::dispatchTouchEvent);
+ stylusEvents.forEach(InputMethodService.this::onStylusHandwritingMotionEvent);
+
// create receiver for channel
mHandwritingEventReceiver = new SimpleBatchedInputEventReceiver(
channel,
@@ -966,11 +976,11 @@ public class InputMethodService extends AbstractInputMethodService {
if (!(event instanceof MotionEvent)) {
return false;
}
- return mInkWindow.getDecorView().dispatchTouchEvent((MotionEvent) event);
+ onStylusHandwritingMotionEvent((MotionEvent) event);
+ return true;
});
}
-
/**
* {@inheritDoc}
* @hide
@@ -984,6 +994,15 @@ public class InputMethodService extends AbstractInputMethodService {
/**
* {@inheritDoc}
+ * @hide
+ */
+ @Override
+ public void finishStylusHandwriting() {
+ InputMethodService.this.finishStylusHandwriting();
+ }
+
+ /**
+ * {@inheritDoc}
*/
@MainThread
@Override
@@ -2360,7 +2379,8 @@ public class InputMethodService extends AbstractInputMethodService {
*
* If the IME supports handwriting for the current input, it should return {@code true},
* ensure its inking views are attached to the {@link #getStylusHandwritingWindow()}, and handle
- * stylus input received on the ink window via {@link #getCurrentInputConnection()}.
+ * stylus input received from {@link #onStylusHandwritingMotionEvent(MotionEvent)} on the
+ * {@link #getStylusHandwritingWindow()} via {@link #getCurrentInputConnection()}.
* @return {@code true} if IME can honor the request, {@code false} if IME cannot at this time.
*/
public boolean onStartStylusHandwriting() {
@@ -2369,6 +2389,33 @@ public class InputMethodService extends AbstractInputMethodService {
}
/**
+ * Called after {@link #onStartStylusHandwriting()} returns {@code true} for every Stylus
+ * {@link MotionEvent}.
+ * By default, this method forwards all {@link MotionEvent}s to the
+ * {@link #getStylusHandwritingWindow()} once its visible, however IME can override it to
+ * receive them sooner.
+ * @param motionEvent {@link MotionEvent} from stylus.
+ */
+ public void onStylusHandwritingMotionEvent(@NonNull MotionEvent motionEvent) {
+ if (mInkWindow.isInkViewVisible()) {
+ mInkWindow.getDecorView().dispatchTouchEvent(motionEvent);
+ } else {
+ if (mPendingEvents == null) {
+ mPendingEvents = new RingBuffer(MotionEvent.class, MAX_EVENTS_BUFFER);
+ }
+ mPendingEvents.append(motionEvent);
+ mInkWindow.setInkViewVisibilityListener(() -> {
+ if (mPendingEvents != null && !mPendingEvents.isEmpty()) {
+ for (MotionEvent event : mPendingEvents.toArray()) {
+ mInkWindow.getDecorView().dispatchTouchEvent(event);
+ }
+ mPendingEvents.clear();
+ }
+ });
+ }
+ }
+
+ /**
* Called when the current stylus handwriting session was finished (either by the system or
* via {@link #finishStylusHandwriting()}.
*
@@ -2423,7 +2470,7 @@ public class InputMethodService extends AbstractInputMethodService {
mHandwritingEventReceiver = null;
mInkWindow.hide(false /* remove */);
- mPrivOps.finishStylusHandwriting(requestId);
+ mPrivOps.resetStylusHandwriting(requestId);
mOnPreparedStylusHwCalled = false;
onFinishStylusHandwriting();
}
diff --git a/core/java/android/inputmethodservice/NavigationBarController.java b/core/java/android/inputmethodservice/NavigationBarController.java
index 19fa01de4a5f..03d11515c0a8 100644
--- a/core/java/android/inputmethodservice/NavigationBarController.java
+++ b/core/java/android/inputmethodservice/NavigationBarController.java
@@ -16,7 +16,6 @@
package android.inputmethodservice;
-import static android.content.Intent.ACTION_OVERLAY_CHANGED;
import static android.view.WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS;
import android.animation.ValueAnimator;
@@ -24,18 +23,12 @@ import android.annotation.FloatRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.StatusBarManager;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.Insets;
import android.graphics.Rect;
import android.graphics.Region;
import android.inputmethodservice.navigationbar.NavigationBarFrame;
import android.inputmethodservice.navigationbar.NavigationBarView;
-import android.os.PatternMatcher;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
@@ -49,6 +42,8 @@ import android.view.animation.Interpolator;
import android.view.animation.PathInterpolator;
import android.widget.FrameLayout;
+import com.android.internal.inputmethod.InputMethodNavButtonFlags;
+
import java.util.Objects;
/**
@@ -77,8 +72,7 @@ final class NavigationBarController {
default void onDestroy() {
}
- default void setShouldShowImeSwitcherWhenImeIsShown(
- boolean shouldShowImeSwitcherWhenImeIsShown) {
+ default void onNavButtonFlagsChanged(@InputMethodNavButtonFlags int navButtonFlags) {
}
default String toDebugString() {
@@ -117,8 +111,8 @@ final class NavigationBarController {
mImpl.onDestroy();
}
- void setShouldShowImeSwitcherWhenImeIsShown(boolean shouldShowImeSwitcherWhenImeIsShown) {
- mImpl.setShouldShowImeSwitcherWhenImeIsShown(shouldShowImeSwitcherWhenImeIsShown);
+ void onNavButtonFlagsChanged(@InputMethodNavButtonFlags int navButtonFlags) {
+ mImpl.onNavButtonFlagsChanged(navButtonFlags);
}
String toDebugString() {
@@ -144,9 +138,6 @@ final class NavigationBarController {
@Nullable
Insets mLastInsets;
- @Nullable
- private BroadcastReceiver mSystemOverlayChangedReceiver;
-
private boolean mShouldShowImeSwitcherWhenImeIsShown;
@Appearance
@@ -303,8 +294,8 @@ final class NavigationBarController {
dest.setTouchableInsets(
ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
- // TODO(b/205803355): See if we can use View#OnLayoutChangeListener().
- // TODO(b/205803355): See if we can replace DecorView#mNavigationColorViewState.view
+ // TODO(b/215443343): See if we can use View#OnLayoutChangeListener().
+ // TODO(b/215443343): See if we can replace DecorView#mNavigationColorViewState.view
boolean zOrderChanged = false;
if (decor instanceof ViewGroup) {
ViewGroup decorGroup = (ViewGroup) decor;
@@ -359,14 +350,6 @@ final class NavigationBarController {
});
}
- private boolean imeDrawsImeNavBar() {
- final Resources resources = mService.getResources();
- if (resources == null) {
- return false;
- }
- return resources.getBoolean(com.android.internal.R.bool.config_imeDrawsImeNavBar);
- }
-
@Override
public void onSoftInputWindowCreated(@NonNull SoftInputWindow softInputWindow) {
final Window window = softInputWindow.getWindow();
@@ -379,27 +362,6 @@ final class NavigationBarController {
if (mDestroyed) {
return;
}
- mImeDrawsImeNavBar = imeDrawsImeNavBar();
- if (mSystemOverlayChangedReceiver == null) {
- final IntentFilter intentFilter = new IntentFilter(ACTION_OVERLAY_CHANGED);
- intentFilter.addDataScheme(IntentFilter.SCHEME_PACKAGE);
- intentFilter.addDataSchemeSpecificPart("android", PatternMatcher.PATTERN_LITERAL);
- mSystemOverlayChangedReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (mDestroyed) {
- return;
- }
- mImeDrawsImeNavBar = imeDrawsImeNavBar();
- if (mImeDrawsImeNavBar) {
- installNavigationBarFrameIfNecessary();
- } else {
- uninstallNavigationBarFrameIfNecessary();
- }
- }
- };
- mService.registerReceiver(mSystemOverlayChangedReceiver, intentFilter);
- }
installNavigationBarFrameIfNecessary();
}
@@ -412,10 +374,6 @@ final class NavigationBarController {
mTintAnimator.cancel();
mTintAnimator = null;
}
- if (mSystemOverlayChangedReceiver != null) {
- mService.unregisterReceiver(mSystemOverlayChangedReceiver);
- mSystemOverlayChangedReceiver = null;
- }
mDestroyed = true;
}
@@ -448,28 +406,43 @@ final class NavigationBarController {
}
@Override
- public void setShouldShowImeSwitcherWhenImeIsShown(
- boolean shouldShowImeSwitcherWhenImeIsShown) {
+ public void onNavButtonFlagsChanged(@InputMethodNavButtonFlags int navButtonFlags) {
if (mDestroyed) {
return;
}
- if (mShouldShowImeSwitcherWhenImeIsShown == shouldShowImeSwitcherWhenImeIsShown) {
- return;
- }
+
+ final boolean imeDrawsImeNavBar =
+ (navButtonFlags & InputMethodNavButtonFlags.IME_DRAWS_IME_NAV_BAR) != 0;
+ final boolean shouldShowImeSwitcherWhenImeIsShown =
+ (navButtonFlags & InputMethodNavButtonFlags.SHOW_IME_SWITCHER_WHEN_IME_IS_SHOWN)
+ != 0;
+
+ mImeDrawsImeNavBar = imeDrawsImeNavBar;
+ final boolean prevShouldShowImeSwitcherWhenImeIsShown =
+ mShouldShowImeSwitcherWhenImeIsShown;
mShouldShowImeSwitcherWhenImeIsShown = shouldShowImeSwitcherWhenImeIsShown;
- if (mNavigationBarFrame == null) {
- return;
- }
- final NavigationBarView navigationBarView =
- mNavigationBarFrame.findViewByPredicate(NavigationBarView.class::isInstance);
- if (navigationBarView == null) {
- return;
+ if (imeDrawsImeNavBar) {
+ installNavigationBarFrameIfNecessary();
+ if (mNavigationBarFrame == null) {
+ return;
+ }
+ if (mShouldShowImeSwitcherWhenImeIsShown
+ == prevShouldShowImeSwitcherWhenImeIsShown) {
+ return;
+ }
+ final NavigationBarView navigationBarView = mNavigationBarFrame.findViewByPredicate(
+ NavigationBarView.class::isInstance);
+ if (navigationBarView == null) {
+ return;
+ }
+ final int hints = StatusBarManager.NAVIGATION_HINT_BACK_ALT
+ | (shouldShowImeSwitcherWhenImeIsShown
+ ? StatusBarManager.NAVIGATION_HINT_IME_SWITCHER_SHOWN : 0);
+ navigationBarView.setNavigationIconHints(hints);
+ } else {
+ uninstallNavigationBarFrameIfNecessary();
}
- final int hints = StatusBarManager.NAVIGATION_HINT_BACK_ALT
- | (shouldShowImeSwitcherWhenImeIsShown
- ? StatusBarManager.NAVIGATION_HINT_IME_SWITCHER_SHOWN : 0);
- navigationBarView.setNavigationIconHints(hints);
}
@Override
diff --git a/core/java/android/inputmethodservice/navigationbar/ButtonDispatcher.java b/core/java/android/inputmethodservice/navigationbar/ButtonDispatcher.java
index 3f26fa461097..6b2db7d01a54 100644
--- a/core/java/android/inputmethodservice/navigationbar/ButtonDispatcher.java
+++ b/core/java/android/inputmethodservice/navigationbar/ButtonDispatcher.java
@@ -67,7 +67,7 @@ final class ButtonDispatcher {
}
};
- public ButtonDispatcher(int id) {
+ ButtonDispatcher(int id) {
mId = id;
}
@@ -125,8 +125,8 @@ final class ButtonDispatcher {
public void setImageDrawable(KeyButtonDrawable drawable) {
mImageDrawable = drawable;
- final int N = mViews.size();
- for (int i = 0; i < N; i++) {
+ final int numViews = mViews.size();
+ for (int i = 0; i < numViews; i++) {
if (mViews.get(i) instanceof ButtonInterface) {
((ButtonInterface) mViews.get(i)).setImageDrawable(mImageDrawable);
}
@@ -143,8 +143,8 @@ final class ButtonDispatcher {
}
mVisibility = visibility;
- final int N = mViews.size();
- for (int i = 0; i < N; i++) {
+ final int numViews = mViews.size();
+ for (int i = 0; i < numViews; i++) {
mViews.get(i).setVisibility(mVisibility);
}
}
@@ -188,8 +188,8 @@ final class ButtonDispatcher {
int nextAlpha = (int) (alpha * 255);
if (prevAlpha != nextAlpha) {
mAlpha = nextAlpha / 255f;
- final int N = mViews.size();
- for (int i = 0; i < N; i++) {
+ final int numViews = mViews.size();
+ for (int i = 0; i < numViews; i++) {
mViews.get(i).setAlpha(mAlpha);
}
}
@@ -198,8 +198,8 @@ final class ButtonDispatcher {
public void setDarkIntensity(float darkIntensity) {
mDarkIntensity = darkIntensity;
- final int N = mViews.size();
- for (int i = 0; i < N; i++) {
+ final int numViews = mViews.size();
+ for (int i = 0; i < numViews; i++) {
if (mViews.get(i) instanceof ButtonInterface) {
((ButtonInterface) mViews.get(i)).setDarkIntensity(darkIntensity);
}
@@ -208,8 +208,8 @@ final class ButtonDispatcher {
public void setDelayTouchFeedback(boolean delay) {
mDelayTouchFeedback = delay;
- final int N = mViews.size();
- for (int i = 0; i < N; i++) {
+ final int numViews = mViews.size();
+ for (int i = 0; i < numViews; i++) {
if (mViews.get(i) instanceof ButtonInterface) {
((ButtonInterface) mViews.get(i)).setDelayTouchFeedback(delay);
}
@@ -218,55 +218,55 @@ final class ButtonDispatcher {
public void setOnClickListener(View.OnClickListener clickListener) {
mClickListener = clickListener;
- final int N = mViews.size();
- for (int i = 0; i < N; i++) {
+ final int numViews = mViews.size();
+ for (int i = 0; i < numViews; i++) {
mViews.get(i).setOnClickListener(mClickListener);
}
}
public void setOnTouchListener(View.OnTouchListener touchListener) {
mTouchListener = touchListener;
- final int N = mViews.size();
- for (int i = 0; i < N; i++) {
+ final int numViews = mViews.size();
+ for (int i = 0; i < numViews; i++) {
mViews.get(i).setOnTouchListener(mTouchListener);
}
}
public void setLongClickable(boolean isLongClickable) {
mLongClickable = isLongClickable;
- final int N = mViews.size();
- for (int i = 0; i < N; i++) {
+ final int numViews = mViews.size();
+ for (int i = 0; i < numViews; i++) {
mViews.get(i).setLongClickable(mLongClickable);
}
}
public void setOnLongClickListener(View.OnLongClickListener longClickListener) {
mLongClickListener = longClickListener;
- final int N = mViews.size();
- for (int i = 0; i < N; i++) {
+ final int numViews = mViews.size();
+ for (int i = 0; i < numViews; i++) {
mViews.get(i).setOnLongClickListener(mLongClickListener);
}
}
public void setOnHoverListener(View.OnHoverListener hoverListener) {
mOnHoverListener = hoverListener;
- final int N = mViews.size();
- for (int i = 0; i < N; i++) {
+ final int numViews = mViews.size();
+ for (int i = 0; i < numViews; i++) {
mViews.get(i).setOnHoverListener(mOnHoverListener);
}
}
public void setAccessibilityDelegate(AccessibilityDelegate delegate) {
mAccessibilityDelegate = delegate;
- final int N = mViews.size();
- for (int i = 0; i < N; i++) {
+ final int numViews = mViews.size();
+ for (int i = 0; i < numViews; i++) {
mViews.get(i).setAccessibilityDelegate(delegate);
}
}
public void setTranslation(int x, int y, int z) {
- final int N = mViews.size();
- for (int i = 0; i < N; i++) {
+ final int numViews = mViews.size();
+ for (int i = 0; i < numViews; i++) {
final View view = mViews.get(i);
view.setTranslationX(x);
view.setTranslationY(y);
diff --git a/core/java/android/inputmethodservice/navigationbar/DeadZone.java b/core/java/android/inputmethodservice/navigationbar/DeadZone.java
index 4adc84bf0b6f..382b6b074962 100644
--- a/core/java/android/inputmethodservice/navigationbar/DeadZone.java
+++ b/core/java/android/inputmethodservice/navigationbar/DeadZone.java
@@ -82,7 +82,7 @@ final class DeadZone {
}
};
- public DeadZone(NavigationBarView view) {
+ DeadZone(NavigationBarView view) {
mNavigationBarView = view;
onConfigurationChanged(Surface.ROTATION_0);
}
@@ -92,13 +92,15 @@ final class DeadZone {
}
private float getSize(long now) {
- if (mSizeMax == 0)
+ if (mSizeMax == 0) {
return 0;
+ }
long dt = (now - mLastPokeTime);
- if (dt > mHold + mDecay)
+ if (dt > mHold + mDecay) {
return mSizeMin;
- if (dt < mHold)
+ } else if (dt < mHold) {
return mSizeMax;
+ }
return (int) lerp(mSizeMax, mSizeMin, (float) (dt - mHold) / mDecay);
}
@@ -146,7 +148,7 @@ final class DeadZone {
if (DEBUG) {
Log.v(TAG, this + " ACTION_DOWN: " + event.getX() + "," + event.getY());
}
- //TODO(b/205803355): call mNavBarController.touchAutoDim(mDisplayId); here
+ //TODO(b/215443343): call mNavBarController.touchAutoDim(mDisplayId); here
int size = (int) getSize(event.getEventTime());
// In the vertical orientation consume taps along the left edge.
// In horizontal orientation consume taps along the top edge.
@@ -177,8 +179,9 @@ final class DeadZone {
private void poke(MotionEvent event) {
mLastPokeTime = event.getEventTime();
- if (DEBUG)
+ if (DEBUG) {
Log.v(TAG, "poked! size=" + getSize(mLastPokeTime));
+ }
if (mShouldFlash) mNavigationBarView.postInvalidate();
}
diff --git a/core/java/android/inputmethodservice/navigationbar/KeyButtonDrawable.java b/core/java/android/inputmethodservice/navigationbar/KeyButtonDrawable.java
index 25a443de916b..45c8a186117d 100644
--- a/core/java/android/inputmethodservice/navigationbar/KeyButtonDrawable.java
+++ b/core/java/android/inputmethodservice/navigationbar/KeyButtonDrawable.java
@@ -54,30 +54,30 @@ import android.view.View;
final class KeyButtonDrawable extends Drawable {
public static final FloatProperty<KeyButtonDrawable> KEY_DRAWABLE_ROTATE =
- new FloatProperty<KeyButtonDrawable>("KeyButtonRotation") {
- @Override
- public void setValue(KeyButtonDrawable drawable, float degree) {
- drawable.setRotation(degree);
- }
+ new FloatProperty<KeyButtonDrawable>("KeyButtonRotation") {
+ @Override
+ public void setValue(KeyButtonDrawable drawable, float degree) {
+ drawable.setRotation(degree);
+ }
- @Override
- public Float get(KeyButtonDrawable drawable) {
- return drawable.getRotation();
- }
- };
+ @Override
+ public Float get(KeyButtonDrawable drawable) {
+ return drawable.getRotation();
+ }
+ };
public static final FloatProperty<KeyButtonDrawable> KEY_DRAWABLE_TRANSLATE_Y =
- new FloatProperty<KeyButtonDrawable>("KeyButtonTranslateY") {
- @Override
- public void setValue(KeyButtonDrawable drawable, float y) {
- drawable.setTranslationY(y);
- }
+ new FloatProperty<KeyButtonDrawable>("KeyButtonTranslateY") {
+ @Override
+ public void setValue(KeyButtonDrawable drawable, float y) {
+ drawable.setTranslationY(y);
+ }
- @Override
- public Float get(KeyButtonDrawable drawable) {
- return drawable.getTranslationY();
- }
- };
+ @Override
+ public Float get(KeyButtonDrawable drawable) {
+ return drawable.getTranslationY();
+ }
+ };
private final Paint mIconPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
private final Paint mShadowPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
@@ -100,7 +100,7 @@ final class KeyButtonDrawable extends Drawable {
}
};
- public KeyButtonDrawable(Drawable d, @ColorInt int lightColor, @ColorInt int darkColor,
+ KeyButtonDrawable(Drawable d, @ColorInt int lightColor, @ColorInt int darkColor,
boolean horizontalFlip, Color ovalBackgroundColor) {
this(d, new ShadowDrawableState(lightColor, darkColor,
d instanceof AnimatedVectorDrawable, horizontalFlip, ovalBackgroundColor));
@@ -433,8 +433,8 @@ final class KeyButtonDrawable extends Drawable {
final boolean mSupportsAnimation;
final Color mOvalBackgroundColor;
- public ShadowDrawableState(@ColorInt int lightColor, @ColorInt int darkColor,
- boolean animated, boolean horizontalFlip, Color ovalBackgroundColor) {
+ ShadowDrawableState(@ColorInt int lightColor, @ColorInt int darkColor, boolean animated,
+ boolean horizontalFlip, Color ovalBackgroundColor) {
mLightColor = lightColor;
mDarkColor = darkColor;
mSupportsAnimation = animated;
diff --git a/core/java/android/inputmethodservice/navigationbar/KeyButtonRipple.java b/core/java/android/inputmethodservice/navigationbar/KeyButtonRipple.java
index 38a63b661ac0..cf77c8989858 100644
--- a/core/java/android/inputmethodservice/navigationbar/KeyButtonRipple.java
+++ b/core/java/android/inputmethodservice/navigationbar/KeyButtonRipple.java
@@ -90,7 +90,7 @@ final class KeyButtonRipple extends Drawable {
private Type mType = Type.ROUNDED_RECT;
- public KeyButtonRipple(Context ctx, View targetView, @DimenRes int maxWidthResource) {
+ KeyButtonRipple(Context ctx, View targetView, @DimenRes int maxWidthResource) {
mMaxWidthResource = maxWidthResource;
mMaxWidth = ctx.getResources().getDimensionPixelSize(maxWidthResource);
mTargetView = targetView;
@@ -126,7 +126,7 @@ final class KeyButtonRipple extends Drawable {
private void drawSoftware(Canvas canvas) {
if (mGlowAlpha > 0f) {
final Paint p = getRipplePaint();
- p.setAlpha((int)(mGlowAlpha * 255f));
+ p.setAlpha((int) (mGlowAlpha * 255f));
final float w = getBounds().width();
final float h = getBounds().height();
@@ -412,7 +412,7 @@ final class KeyButtonRipple extends Drawable {
mDrawingHardwareGlow = true;
setExtendStart(CanvasProperty.createFloat(getExtendSize() / 2));
final RenderNodeAnimator startAnim = new RenderNodeAnimator(getExtendStart(),
- getExtendSize()/2 - GLOW_MAX_SCALE_FACTOR * getRippleSize()/2);
+ getExtendSize() / 2 - GLOW_MAX_SCALE_FACTOR * getRippleSize() / 2);
startAnim.setDuration(ANIMATION_DURATION_SCALE);
startAnim.setInterpolator(mInterpolator);
startAnim.addListener(mAnimatorListener);
@@ -420,7 +420,7 @@ final class KeyButtonRipple extends Drawable {
setExtendEnd(CanvasProperty.createFloat(getExtendSize() / 2));
final RenderNodeAnimator endAnim = new RenderNodeAnimator(getExtendEnd(),
- getExtendSize()/2 + GLOW_MAX_SCALE_FACTOR * getRippleSize()/2);
+ getExtendSize() / 2 + GLOW_MAX_SCALE_FACTOR * getRippleSize() / 2);
endAnim.setDuration(ANIMATION_DURATION_SCALE);
endAnim.setInterpolator(mInterpolator);
endAnim.addListener(mAnimatorListener);
@@ -430,13 +430,13 @@ final class KeyButtonRipple extends Drawable {
if (isHorizontal()) {
mTopProp = CanvasProperty.createFloat(0f);
mBottomProp = CanvasProperty.createFloat(getBounds().height());
- mRxProp = CanvasProperty.createFloat(getBounds().height()/2);
- mRyProp = CanvasProperty.createFloat(getBounds().height()/2);
+ mRxProp = CanvasProperty.createFloat(getBounds().height() / 2);
+ mRyProp = CanvasProperty.createFloat(getBounds().height() / 2);
} else {
mLeftProp = CanvasProperty.createFloat(0f);
mRightProp = CanvasProperty.createFloat(getBounds().width());
- mRxProp = CanvasProperty.createFloat(getBounds().width()/2);
- mRyProp = CanvasProperty.createFloat(getBounds().width()/2);
+ mRxProp = CanvasProperty.createFloat(getBounds().width() / 2);
+ mRyProp = CanvasProperty.createFloat(getBounds().width() / 2);
}
mGlowScale = GLOW_MAX_SCALE_FACTOR;
diff --git a/core/java/android/inputmethodservice/navigationbar/KeyButtonView.java b/core/java/android/inputmethodservice/navigationbar/KeyButtonView.java
index 74d30f8f8806..92d358fe1663 100644
--- a/core/java/android/inputmethodservice/navigationbar/KeyButtonView.java
+++ b/core/java/android/inputmethodservice/navigationbar/KeyButtonView.java
@@ -89,7 +89,7 @@ public class KeyButtonView extends ImageView implements ButtonInterface {
public KeyButtonView(Context context, AttributeSet attrs) {
super(context, attrs);
- // TODO(b/205803355): Figure out better place to set this.
+ // TODO(b/215443343): Figure out better place to set this.
switch (getId()) {
case com.android.internal.R.id.input_method_nav_back:
mCode = KEYCODE_BACK;
@@ -200,8 +200,8 @@ public class KeyButtonView extends ImageView implements ButtonInterface {
postDelayed(mCheckLongPress, ViewConfiguration.getLongPressTimeout());
break;
case MotionEvent.ACTION_MOVE:
- x = (int)ev.getRawX();
- y = (int)ev.getRawY();
+ x = (int) ev.getRawX();
+ y = (int) ev.getRawY();
float slop = getQuickStepTouchSlopPx(getContext());
if (Math.abs(x - mTouchDownX) > slop || Math.abs(y - mTouchDownY) > slop) {
@@ -272,23 +272,24 @@ public class KeyButtonView extends ImageView implements ButtonInterface {
: KeyButtonRipple.Type.ROUNDED_RECT);
}
+ @Override
public void playSoundEffect(int soundConstant) {
if (!mPlaySounds) return;
mAudioManager.playSoundEffect(soundConstant);
}
- public void sendEvent(int action, int flags) {
+ private void sendEvent(int action, int flags) {
sendEvent(action, flags, SystemClock.uptimeMillis());
}
private void sendEvent(int action, int flags, long when) {
if (mCode == KeyEvent.KEYCODE_BACK && flags != KeyEvent.FLAG_LONG_PRESS) {
if (action == MotionEvent.ACTION_UP) {
- // TODO(b/205803355): Implement notifyBackAction();
+ // TODO(b/215443343): Implement notifyBackAction();
}
}
- // TODO(b/205803355): Consolidate this logic to somewhere else.
+ // TODO(b/215443343): Consolidate this logic to somewhere else.
if (mContext instanceof InputMethodService) {
final int repeatCount = (flags & KeyEvent.FLAG_LONG_PRESS) != 0 ? 1 : 0;
final KeyEvent ev = new KeyEvent(mDownTime, when, action, mCode, repeatCount,
@@ -309,8 +310,8 @@ public class KeyButtonView extends ImageView implements ButtonInterface {
switch (action) {
case KeyEvent.ACTION_DOWN:
handled = ims.onKeyDown(ev.getKeyCode(), ev);
- mTracking = handled && ev.getRepeatCount() == 0 &&
- (ev.getFlags() & KeyEvent.FLAG_START_TRACKING) != 0;
+ mTracking = handled && ev.getRepeatCount() == 0
+ && (ev.getFlags() & KeyEvent.FLAG_START_TRACKING) != 0;
break;
case KeyEvent.ACTION_UP:
handled = ims.onKeyUp(ev.getKeyCode(), ev);
diff --git a/core/java/android/inputmethodservice/navigationbar/NavigationBarFrame.java b/core/java/android/inputmethodservice/navigationbar/NavigationBarFrame.java
index f01173e0fdae..a270675239ee 100644
--- a/core/java/android/inputmethodservice/navigationbar/NavigationBarFrame.java
+++ b/core/java/android/inputmethodservice/navigationbar/NavigationBarFrame.java
@@ -59,4 +59,4 @@ public final class NavigationBarFrame extends FrameLayout {
}
return super.dispatchTouchEvent(event);
}
-} \ No newline at end of file
+}
diff --git a/core/java/android/inputmethodservice/navigationbar/NavigationBarInflaterView.java b/core/java/android/inputmethodservice/navigationbar/NavigationBarInflaterView.java
index d488890b27d4..e93bda2fa939 100644
--- a/core/java/android/inputmethodservice/navigationbar/NavigationBarInflaterView.java
+++ b/core/java/android/inputmethodservice/navigationbar/NavigationBarInflaterView.java
@@ -121,7 +121,7 @@ public final class NavigationBarInflaterView extends FrameLayout {
return CONFIG_NAV_BAR_LAYOUT_HANDLE;
}
- public void setButtonDispatchers(SparseArray<ButtonDispatcher> buttonDispatchers) {
+ void setButtonDispatchers(SparseArray<ButtonDispatcher> buttonDispatchers) {
mButtonDispatchers = buttonDispatchers;
for (int i = 0; i < buttonDispatchers.size(); i++) {
initiallyFill(buttonDispatchers.valueAt(i));
@@ -376,7 +376,7 @@ public final class NavigationBarInflaterView extends FrameLayout {
}
*/
- public static String extractSize(String buttonSpec) {
+ private static String extractSize(String buttonSpec) {
if (!buttonSpec.contains(SIZE_MOD_START)) {
return null;
}
@@ -384,7 +384,7 @@ public final class NavigationBarInflaterView extends FrameLayout {
return buttonSpec.substring(sizeStart + 1, buttonSpec.indexOf(SIZE_MOD_END));
}
- public static String extractButton(String buttonSpec) {
+ private static String extractButton(String buttonSpec) {
if (!buttonSpec.contains(SIZE_MOD_START)) {
return buttonSpec;
}
@@ -398,9 +398,9 @@ public final class NavigationBarInflaterView extends FrameLayout {
mButtonDispatchers.valueAt(indexOfKey).addView(v);
}
if (v instanceof ViewGroup) {
- final ViewGroup viewGroup = (ViewGroup)v;
- final int N = viewGroup.getChildCount();
- for (int i = 0; i < N; i++) {
+ final ViewGroup viewGroup = (ViewGroup) v;
+ final int numChildViews = viewGroup.getChildCount();
+ for (int i = 0; i < numChildViews; i++) {
addToDispatchers(viewGroup.getChildAt(i));
}
}
diff --git a/core/java/android/inputmethodservice/navigationbar/NavigationBarView.java b/core/java/android/inputmethodservice/navigationbar/NavigationBarView.java
index a2d71054c65d..510b14e7acd4 100644
--- a/core/java/android/inputmethodservice/navigationbar/NavigationBarView.java
+++ b/core/java/android/inputmethodservice/navigationbar/NavigationBarView.java
@@ -48,8 +48,8 @@ import java.util.function.Consumer;
* @hide
*/
public final class NavigationBarView extends FrameLayout {
- final static boolean DEBUG = false;
- final static String TAG = "NavBarView";
+ private static final boolean DEBUG = false;
+ private static final String TAG = "NavBarView";
// Copied from com.android.systemui.animation.Interpolators#FAST_OUT_SLOW_IN
private static final Interpolator FAST_OUT_SLOW_IN = new PathInterpolator(0.4f, 0f, 0.2f, 1f);
@@ -139,7 +139,7 @@ public final class NavigationBarView extends FrameLayout {
}
/**
- * Applies {@param consumer} to each of the nav bar views.
+ * Applies {@code consumer} to each of the nav bar views.
*/
public void forEachView(Consumer<View> consumer) {
if (mHorizontal != null) {
@@ -181,7 +181,7 @@ public final class NavigationBarView extends FrameLayout {
}
}
- public KeyButtonDrawable getBackDrawable() {
+ private KeyButtonDrawable getBackDrawable() {
KeyButtonDrawable drawable = getDrawable(com.android.internal.R.drawable.ic_ime_nav_back);
orientBackButton(drawable);
return drawable;
@@ -211,7 +211,7 @@ public final class NavigationBarView extends FrameLayout {
// Animate the back button's rotation to the new degrees and only in portrait move up the
// back button to line up with the other buttons
float targetY = useAltBack
- ? - dpToPx(NAVBAR_BACK_BUTTON_IME_OFFSET, getResources())
+ ? -dpToPx(NAVBAR_BACK_BUTTON_IME_OFFSET, getResources())
: 0;
ObjectAnimator navBarAnimator = ObjectAnimator.ofPropertyValuesHolder(drawable,
PropertyValuesHolder.ofFloat(KeyButtonDrawable.KEY_DRAWABLE_ROTATE, degrees),
@@ -233,6 +233,11 @@ public final class NavigationBarView extends FrameLayout {
super.setLayoutDirection(layoutDirection);
}
+ /**
+ * Updates the navigation icons based on {@code hints}.
+ *
+ * @param hints bit flags defined in {@link StatusBarManager}.
+ */
public void setNavigationIconHints(int hints) {
if (hints == mNavigationIconHints) return;
final boolean newBackAlt = (hints & StatusBarManager.NAVIGATION_HINT_BACK_ALT) != 0;
@@ -250,15 +255,7 @@ public final class NavigationBarView extends FrameLayout {
updateNavButtonIcons();
}
- public void setDisabledFlags(int disabledFlags) {
- if (mDisabledFlags == disabledFlags) return;
-
- mDisabledFlags = disabledFlags;
-
- updateNavButtonIcons();
- }
-
- public void updateNavButtonIcons() {
+ private void updateNavButtonIcons() {
// We have to replace or restore the back and home button icons when exiting or entering
// carmode, respectively. Recents are not available in CarMode in nav bar so change
// to recent icon is not required.
@@ -319,7 +316,7 @@ public final class NavigationBarView extends FrameLayout {
mHorizontal.setVisibility(View.GONE);
}
- public void reorient() {
+ private void reorient() {
updateCurrentView();
final android.inputmethodservice.navigationbar.NavigationBarFrame frame =
@@ -372,6 +369,11 @@ public final class NavigationBarView extends FrameLayout {
}
}
+ /**
+ * Updates the dark intensity.
+ *
+ * @param intensity The intensity of darkness from {@code 0.0f} to {@code 1.0f}.
+ */
public void setDarkIntensity(@FloatRange(from = 0.0f, to = 1.0f) float intensity) {
for (int i = 0; i < mButtonDispatchers.size(); ++i) {
mButtonDispatchers.valueAt(i).setDarkIntensity(intensity);
diff --git a/core/java/android/inputmethodservice/navigationbar/ReverseLinearLayout.java b/core/java/android/inputmethodservice/navigationbar/ReverseLinearLayout.java
index 68163c35f784..9b36cc54b657 100644
--- a/core/java/android/inputmethodservice/navigationbar/ReverseLinearLayout.java
+++ b/core/java/android/inputmethodservice/navigationbar/ReverseLinearLayout.java
@@ -30,9 +30,8 @@ import java.util.ArrayList;
/**
* Automatically reverses the order of children as they are added.
* Also reverse the width and height values of layout params
- * @hide
*/
-public class ReverseLinearLayout extends LinearLayout {
+class ReverseLinearLayout extends LinearLayout {
/** If true, the layout is reversed vs. a regular linear layout */
private boolean mIsLayoutReverse;
@@ -40,7 +39,7 @@ public class ReverseLinearLayout extends LinearLayout {
/** If true, the layout is opposite to it's natural reversity from the layout direction */
private boolean mIsAlternativeOrder;
- public ReverseLinearLayout(Context context, @Nullable AttributeSet attrs) {
+ ReverseLinearLayout(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
@@ -129,7 +128,7 @@ public class ReverseLinearLayout extends LinearLayout {
public static class ReverseRelativeLayout extends RelativeLayout implements Reversible {
- public ReverseRelativeLayout(Context context) {
+ ReverseRelativeLayout(Context context) {
super(context);
}
diff --git a/core/java/android/net/IVpnManager.aidl b/core/java/android/net/IVpnManager.aidl
index 070efa363cc0..b4647cabe1bc 100644
--- a/core/java/android/net/IVpnManager.aidl
+++ b/core/java/android/net/IVpnManager.aidl
@@ -17,6 +17,7 @@
package android.net;
import android.net.Network;
+import android.net.VpnProfileState;
import com.android.internal.net.LegacyVpnInfo;
import com.android.internal.net.VpnConfig;
@@ -40,6 +41,7 @@ interface IVpnManager {
void deleteVpnProfile(String packageName);
String startVpnProfile(String packageName);
void stopVpnProfile(String packageName);
+ VpnProfileState getProvisionedVpnProfileState(String packageName);
/** Always-on VPN APIs */
boolean isAlwaysOnVpnPackageSupported(int userId, String packageName);
diff --git a/core/java/android/net/Ikev2VpnProfile.java b/core/java/android/net/Ikev2VpnProfile.java
index 0fd3e034291b..3abe83bd3373 100644
--- a/core/java/android/net/Ikev2VpnProfile.java
+++ b/core/java/android/net/Ikev2VpnProfile.java
@@ -142,6 +142,7 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile {
private final boolean mIsMetered; // Defaults in builder
private final int mMaxMtu; // Defaults in builder
private final boolean mIsRestrictedToTestNetworks;
+ @Nullable private final IkeTunnelConnectionParams mIkeTunConnParams;
private Ikev2VpnProfile(
int type,
@@ -160,7 +161,8 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile {
int maxMtu,
boolean restrictToTestNetworks,
boolean excludeLocalRoutes,
- boolean requiresInternetValidation) {
+ boolean requiresInternetValidation,
+ @Nullable IkeTunnelConnectionParams ikeTunConnParams) {
super(type, excludeLocalRoutes, requiresInternetValidation);
checkNotNull(serverAddr, MISSING_PARAM_MSG_TMPL, "Server address");
@@ -190,6 +192,8 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile {
mMaxMtu = maxMtu;
mIsRestrictedToTestNetworks = restrictToTestNetworks;
+ mIkeTunConnParams = ikeTunConnParams;
+
validate();
}
@@ -375,6 +379,12 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile {
return mMaxMtu;
}
+ /** Retrieves the ikeTunnelConnectionParams contains IKEv2 configurations, if any was set. */
+ @Nullable
+ public IkeTunnelConnectionParams getIkeTunnelConnectionParams() {
+ return mIkeTunConnParams;
+ }
+
/**
* Returns whether or not this VPN profile is restricted to test networks.
*
@@ -403,7 +413,8 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile {
mMaxMtu,
mIsRestrictedToTestNetworks,
mExcludeLocalRoutes,
- mRequiresInternetValidation);
+ mRequiresInternetValidation,
+ mIkeTunConnParams);
}
@Override
@@ -429,7 +440,8 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile {
&& mMaxMtu == other.mMaxMtu
&& mIsRestrictedToTestNetworks == other.mIsRestrictedToTestNetworks
&& mExcludeLocalRoutes == other.mExcludeLocalRoutes
- && mRequiresInternetValidation == other.mRequiresInternetValidation;
+ && mRequiresInternetValidation == other.mRequiresInternetValidation
+ && Objects.equals(mIkeTunConnParams, other.mIkeTunConnParams);
}
/**
@@ -504,6 +516,7 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile {
@NonNull
public static Ikev2VpnProfile fromVpnProfile(@NonNull VpnProfile profile)
throws GeneralSecurityException {
+ // TODO: Build the VpnProfile from mIkeTunConnParams if it exists.
final Builder builder = new Builder(profile.server, profile.ipsecIdentifier);
builder.setProxy(profile.proxy);
builder.setAllowedAlgorithms(profile.getAllowedAlgorithms());
@@ -788,7 +801,7 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile {
private int mMaxMtu = PlatformVpnProfile.MAX_MTU_DEFAULT;
private boolean mIsRestrictedToTestNetworks = false;
private boolean mExcludeLocalRoutes = false;
- @Nullable private IkeTunnelConnectionParams mIkeTunConnParams;
+ @Nullable private final IkeTunnelConnectionParams mIkeTunConnParams;
/**
* Creates a new builder with the basic parameters of an IKEv2/IPsec VPN.
@@ -803,6 +816,8 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile {
mServerAddr = serverAddr;
mUserIdentity = identity;
+
+ mIkeTunConnParams = null;
}
/**
@@ -1135,7 +1150,8 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile {
mMaxMtu,
mIsRestrictedToTestNetworks,
mExcludeLocalRoutes,
- mRequiresInternetValidation);
+ mRequiresInternetValidation,
+ mIkeTunConnParams);
}
}
}
diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java
index 18ec8f57ad3a..2c2a703b16e2 100644
--- a/core/java/android/net/NetworkPolicyManager.java
+++ b/core/java/android/net/NetworkPolicyManager.java
@@ -580,6 +580,24 @@ public class NetworkPolicyManager {
}
/**
+ * Notifies that the specified {@link NetworkStatsProvider} has reached its warning threshold
+ * which was set through {@link NetworkStatsProvider#onSetWarningAndLimit(String, long, long)}.
+ *
+ * @hide
+ */
+ @RequiresPermission(anyOf = {
+ NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
+ android.Manifest.permission.NETWORK_STACK})
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public void notifyStatsProviderWarningReached() {
+ try {
+ mService.notifyStatsProviderWarningOrLimitReached();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Notifies that the specified {@link NetworkStatsProvider} has reached its quota
* which was set through {@link NetworkStatsProvider#onSetLimit(String, long)} or
* {@link NetworkStatsProvider#onSetWarningAndLimit(String, long, long)}.
@@ -590,7 +608,7 @@ public class NetworkPolicyManager {
NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
android.Manifest.permission.NETWORK_STACK})
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
- public void notifyStatsProviderWarningOrLimitReached() {
+ public void notifyStatsProviderLimitReached() {
try {
mService.notifyStatsProviderWarningOrLimitReached();
} catch (RemoteException e) {
diff --git a/core/java/android/net/SntpClient.java b/core/java/android/net/SntpClient.java
index 0eb4cf3ecadf..b05f7cf241e3 100644
--- a/core/java/android/net/SntpClient.java
+++ b/core/java/android/net/SntpClient.java
@@ -60,7 +60,7 @@ public class SntpClient {
private static final int TRANSMIT_TIME_OFFSET = 40;
private static final int NTP_PACKET_SIZE = 48;
- private static final int NTP_PORT = 123;
+ public static final int STANDARD_NTP_PORT = 123;
private static final int NTP_MODE_CLIENT = 3;
private static final int NTP_MODE_SERVER = 4;
private static final int NTP_MODE_BROADCAST = 5;
@@ -108,18 +108,21 @@ public class SntpClient {
* Sends an SNTP request to the given host and processes the response.
*
* @param host host name of the server.
+ * @param port port of the server.
* @param timeout network timeout in milliseconds. the timeout doesn't include the DNS lookup
* time, and it applies to each individual query to the resolved addresses of
* the NTP server.
* @param network network over which to send the request.
* @return true if the transaction was successful.
*/
- public boolean requestTime(String host, int timeout, Network network) {
+ public boolean requestTime(String host, int port, int timeout, Network network) {
final Network networkForResolv = network.getPrivateDnsBypassingCopy();
try {
final InetAddress[] addresses = networkForResolv.getAllByName(host);
for (int i = 0; i < addresses.length; i++) {
- if (requestTime(addresses[i], NTP_PORT, timeout, networkForResolv)) return true;
+ if (requestTime(addresses[i], port, timeout, networkForResolv)) {
+ return true;
+ }
}
} catch (UnknownHostException e) {
Log.w(TAG, "Unknown host: " + host);
diff --git a/core/java/android/net/VpnManager.java b/core/java/android/net/VpnManager.java
index c51444cd31b6..ae7d91f92cb7 100644
--- a/core/java/android/net/VpnManager.java
+++ b/core/java/android/net/VpnManager.java
@@ -161,6 +161,23 @@ public class VpnManager {
"android.net.category.EVENT_DEACTIVATED_BY_USER";
/**
+ * The always-on state of this VPN was changed
+ *
+ * <p>This may be the result of a user changing VPN settings, or a Device Policy Manager app
+ * having changed the VPN policy.
+ */
+ @SdkConstant(SdkConstant.SdkConstantType.INTENT_CATEGORY)
+ public static final String CATEGORY_EVENT_ALWAYS_ON_STATE_CHANGED =
+ "android.net.category.EVENT_ALWAYS_ON_STATE_CHANGED";
+
+ /**
+ * The VpnProfileState at the time that this event occurred.
+ *
+ * <p>This extra may be null if the VPN was revoked by the user, or the profile was deleted.
+ */
+ public static final String EXTRA_VPN_PROFILE_STATE = "android.net.extra.VPN_PROFILE_STATE";
+
+ /**
* The key of the session that experienced this event, as a {@code String}.
*
* This is the same key that was returned by {@link #startProvisionedVpnProfileSession}.
@@ -403,6 +420,21 @@ public class VpnManager {
}
/**
+ * Retrieve the VpnProfileState for the profile provisioned by the calling package.
+ *
+ * @return the VpnProfileState with current information, or null if there was no profile
+ * provisioned by the calling package.
+ */
+ @Nullable
+ public VpnProfileState getProvisionedVpnProfileState() {
+ try {
+ return mService.getProvisionedVpnProfileState(mContext.getOpPackageName());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Resets all VPN settings back to factory defaults.
* @hide
*/
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SysUISubcomponentModule.java b/core/java/android/net/VpnProfileState.aidl
index aacc6939cf74..add6386eda75 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SysUISubcomponentModule.java
+++ b/core/java/android/net/VpnProfileState.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 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.
@@ -14,13 +14,6 @@
* limitations under the License.
*/
-package com.android.systemui.dagger;
+package android.net;
-import dagger.Module;
-
-/**
- * Dagger module for including the WMComponent.
- */
-@Module(subcomponents = {SysUIComponent.class})
-public abstract class SysUISubcomponentModule {
-}
+parcelable VpnProfileState; \ No newline at end of file
diff --git a/core/java/android/net/VpnProfileState.java b/core/java/android/net/VpnProfileState.java
new file mode 100644
index 000000000000..c69ea1a8c220
--- /dev/null
+++ b/core/java/android/net/VpnProfileState.java
@@ -0,0 +1,153 @@
+/*
+ * 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.net;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Describe the state of VPN.
+ */
+public final class VpnProfileState implements Parcelable {
+ /** The VPN has not been started, or some other VPN is active. */
+ public static final int STATE_DISCONNECTED = 0;
+ /** The VPN is attempting to connect, potentially after a failure. */
+ public static final int STATE_CONNECTING = 1;
+ /** The VPN was established successfully. */
+ public static final int STATE_CONNECTED = 2;
+ /** A non-recoverable error has occurred, and will not be retried. */
+ public static final int STATE_FAILED = 3;
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"STATE_"}, value = {
+ STATE_CONNECTED,
+ STATE_CONNECTING,
+ STATE_DISCONNECTED,
+ STATE_FAILED,
+ })
+ public @interface State {}
+
+ @State private final int mState;
+ private final String mSessionKey;
+ private final boolean mAlwaysOn;
+ private final boolean mLockdown;
+
+ public VpnProfileState(@State int state, @Nullable String sessionKey, boolean alwaysOn,
+ boolean lockdown) {
+ mState = state;
+ mSessionKey = sessionKey;
+ mAlwaysOn = alwaysOn;
+ mLockdown = lockdown;
+ }
+
+ /**
+ * Returns the state of the Platform VPN
+ *
+ * <p>This state represents the internal connection state of the VPN. This state may diverge
+ * from the VPN Network's state during error and recovery handling.
+ */
+ @State public int getState() {
+ return mState;
+ }
+
+ /**
+ * Retrieves the Session Key
+ *
+ * <p>The session key is an ephemeral key uniquely identifying the session for a Platform VPN.
+ * The lifetime of this key is tied to the lifetime of the VPN session. In other words,
+ * reprovisioning of the VPN profile, restarting of the device, or manually restarting the
+ * platform VPN session will result in a new VPN session, and a new key.
+ *
+ * @return the unique key for the platform VPN session, or null if it is not running.
+ */
+ @Nullable
+ public String getSessionId() {
+ return mSessionKey;
+ }
+
+ /**
+ * Returns the always-on status of the PlatformVpnProfile.
+ *
+ * <p>If the PlatformVpnProfile is set to be running in always-on mode, the system will ensure
+ * that the profile is always started, and restarting it when necessary (e.g. after reboot).
+ *
+ * <p>Always-on can be set by an appropriately privileged user via the Settings VPN menus, or by
+ * the Device Policy Manager app programmatically.
+ *
+ * See DevicePolicyManager#setAlwaysOnVpnPackage(ComponentName, String, boolean, Set)
+ */
+ public boolean isAlwaysOn() {
+ return mAlwaysOn;
+ }
+
+ /**
+ * Returns the lockdown mode status of the PlatformVpnProfile.
+ *
+ * <p>In lockdown mode, the system will ensure that apps are not allowed to bypass the VPN,
+ * including during startup or failure of the VPN.
+ *
+ * <p>Lockdown mode can be set by an appropriately privileged user via the Settings VPN menus,
+ * or by the Device Policy Manager app programmatically.
+ *
+ * See DevicePolicyManager#setAlwaysOnVpnPackage(ComponentName, String, boolean, Set)
+ */
+ public boolean isLockdownEnabled() {
+ return mLockdown;
+ }
+
+ /**
+ * Implement the Parcelable interface
+ */
+ public int describeContents() {
+ return 0;
+ }
+
+ /**
+ * Implement the Parcelable interface
+ */
+ public void writeToParcel(@NonNull Parcel out, int flags) {
+ out.writeInt(mState);
+ out.writeString(mSessionKey);
+ out.writeBoolean(mAlwaysOn);
+ out.writeBoolean(mLockdown);
+ }
+
+ @NonNull
+ public static final Parcelable.Creator<VpnProfileState> CREATOR =
+ new Parcelable.Creator<VpnProfileState>() {
+ public VpnProfileState createFromParcel(Parcel in) {
+ return new VpnProfileState(in);
+ }
+
+ public VpnProfileState[] newArray(int size) {
+ return new VpnProfileState[size];
+ }
+ };
+
+ private VpnProfileState(Parcel in) {
+ mState = in.readInt();
+ mSessionKey = in.readString();
+ mAlwaysOn = in.readBoolean();
+ mLockdown = in.readBoolean();
+ }
+}
diff --git a/core/java/android/net/netstats/NetworkStatsDataMigrationUtils.java b/core/java/android/net/netstats/NetworkStatsDataMigrationUtils.java
index 2dd3aaa1f55a..5c9989e9d981 100644
--- a/core/java/android/net/netstats/NetworkStatsDataMigrationUtils.java
+++ b/core/java/android/net/netstats/NetworkStatsDataMigrationUtils.java
@@ -27,6 +27,7 @@ import static android.net.NetworkStats.TAG_NONE;
import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
import android.annotation.NonNull;
+import android.annotation.StringDef;
import android.annotation.SystemApi;
import android.net.NetworkIdentity;
import android.net.NetworkStatsCollection;
@@ -47,6 +48,8 @@ import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.net.ProtocolException;
import java.util.ArrayList;
import java.util.HashMap;
@@ -76,6 +79,15 @@ public class NetworkStatsDataMigrationUtils {
*/
public static final String PREFIX_UID_TAG = "uid_tag";
+ /** @hide */
+ @StringDef(prefix = {"PREFIX_"}, value = {
+ PREFIX_XT,
+ PREFIX_UID,
+ PREFIX_UID_TAG,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Prefix {}
+
private static final HashMap<String, String> sPrefixLegacyFileNameMap =
new HashMap<String, String>() {{
put(PREFIX_XT, "netstats_xt.bin");
@@ -141,13 +153,13 @@ public class NetworkStatsDataMigrationUtils {
// Get /data/system/netstats_*.bin legacy files. Does not check for existence.
@NonNull
- private static File getLegacyBinFileForPrefix(@NonNull String prefix) {
+ private static File getLegacyBinFileForPrefix(@NonNull @Prefix String prefix) {
return new File(getPlatformSystemDir(), sPrefixLegacyFileNameMap.get(prefix));
}
// List /data/system/netstats/[xt|uid|uid_tag].<start>-<end> legacy files.
@NonNull
- private static ArrayList<File> getPlatformFileListForPrefix(@NonNull String prefix) {
+ private static ArrayList<File> getPlatformFileListForPrefix(@NonNull @Prefix String prefix) {
final ArrayList<File> list = new ArrayList<>();
final File platformFiles = new File(getPlatformBaseDir(), "netstats");
if (platformFiles.exists()) {
@@ -207,7 +219,7 @@ public class NetworkStatsDataMigrationUtils {
*/
@NonNull
public static NetworkStatsCollection readPlatformCollection(
- @NonNull String prefix, long bucketDuration) throws IOException {
+ @NonNull @Prefix String prefix, long bucketDuration) throws IOException {
final NetworkStatsCollection.Builder builder =
new NetworkStatsCollection.Builder(bucketDuration);
diff --git a/core/java/android/nfc/Tag.java b/core/java/android/nfc/Tag.java
index 0ce9c70569b5..731d1ba78299 100644
--- a/core/java/android/nfc/Tag.java
+++ b/core/java/android/nfc/Tag.java
@@ -142,9 +142,13 @@ public final class Tag implements Parcelable {
mTagService = tagService;
mConnectedTechnology = -1;
+ mCookie = SystemClock.elapsedRealtime();
+
+ if (tagService == null) {
+ return;
+ }
try {
- mCookie = SystemClock.elapsedRealtime();
tagService.setTagUpToDate(mCookie);
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
@@ -370,6 +374,10 @@ public final class Tag implements Parcelable {
/** @hide */
@UnsupportedAppUsage
public INfcTag getTagService() {
+ if (mTagService == null) {
+ return null;
+ }
+
try {
if (!mTagService.isTagUpToDate(mCookie)) {
String id_str = "";
diff --git a/core/java/android/os/BatteryConsumer.java b/core/java/android/os/BatteryConsumer.java
index de76c8fab69b..f4ca1b50fe86 100644
--- a/core/java/android/os/BatteryConsumer.java
+++ b/core/java/android/os/BatteryConsumer.java
@@ -165,6 +165,7 @@ public abstract class BatteryConsumer {
PROCESS_STATE_FOREGROUND,
PROCESS_STATE_BACKGROUND,
PROCESS_STATE_FOREGROUND_SERVICE,
+ PROCESS_STATE_CACHED,
})
@Retention(RetentionPolicy.SOURCE)
public @interface ProcessState {
@@ -175,8 +176,9 @@ public abstract class BatteryConsumer {
public static final int PROCESS_STATE_FOREGROUND = 1;
public static final int PROCESS_STATE_BACKGROUND = 2;
public static final int PROCESS_STATE_FOREGROUND_SERVICE = 3;
+ public static final int PROCESS_STATE_CACHED = 4;
- public static final int PROCESS_STATE_COUNT = 4;
+ public static final int PROCESS_STATE_COUNT = 5;
private static final String[] sProcessStateNames = new String[PROCESS_STATE_COUNT];
@@ -186,6 +188,7 @@ public abstract class BatteryConsumer {
sProcessStateNames[PROCESS_STATE_FOREGROUND] = "fg";
sProcessStateNames[PROCESS_STATE_BACKGROUND] = "bg";
sProcessStateNames[PROCESS_STATE_FOREGROUND_SERVICE] = "fgs";
+ sProcessStateNames[PROCESS_STATE_CACHED] = "cached";
}
private static final int[] SUPPORTED_POWER_COMPONENTS_PER_PROCESS_STATE = {
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index de1dc8091b2a..06c35b5bec5d 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -680,6 +680,8 @@ public abstract class BatteryStats implements Parcelable {
return BatteryConsumer.PROCESS_STATE_BACKGROUND;
case BatteryStats.Uid.PROCESS_STATE_FOREGROUND_SERVICE:
return BatteryConsumer.PROCESS_STATE_FOREGROUND_SERVICE;
+ case BatteryStats.Uid.PROCESS_STATE_CACHED:
+ return BatteryConsumer.PROCESS_STATE_CACHED;
default:
return BatteryConsumer.PROCESS_STATE_UNSPECIFIED;
}
@@ -2681,7 +2683,7 @@ public abstract class BatteryStats implements Parcelable {
public static final String[] RADIO_ACCESS_TECHNOLOGY_NAMES = {"Other", "LTE", "NR"};
/**
- * Returns the time in microseconds that the mobile radio has been active on a
+ * Returns the time in milliseconds that the mobile radio has been active on a
* given Radio Access Technology (RAT), at a given frequency (NR RAT only), for a given
* transmission power level.
*
@@ -2700,6 +2702,46 @@ public abstract class BatteryStats implements Parcelable {
@ServiceState.FrequencyRange int frequencyRange, int signalStrength,
long elapsedRealtimeMs);
+ /**
+ * Returns the time in milliseconds that the mobile radio has been actively transmitting data on
+ * a given Radio Access Technology (RAT), at a given frequency (NR RAT only), for a given
+ * transmission power level.
+ *
+ * @param rat Radio Access Technology {@see RadioAccessTechnology}
+ * @param frequencyRange frequency range {@see ServiceState.FrequencyRange}, only needed for
+ * RADIO_ACCESS_TECHNOLOGY_NR. Use
+ * {@link ServiceState.FREQUENCY_RANGE_UNKNOWN} for other Radio Access
+ * Technologies.
+ * @param signalStrength the cellular signal strength. {@see CellSignalStrength#getLevel()}
+ * @param elapsedRealtimeMs current elapsed realtime
+ * @return time (in milliseconds) the mobile radio spent actively transmitting data in the
+ * specified state, while on battery. Returns {@link DURATION_UNAVAILABLE} if
+ * data unavailable.
+ * @hide
+ */
+ public abstract long getActiveTxRadioDurationMs(@RadioAccessTechnology int rat,
+ @ServiceState.FrequencyRange int frequencyRange, int signalStrength,
+ long elapsedRealtimeMs);
+
+ /**
+ * Returns the time in milliseconds that the mobile radio has been actively receiving data on a
+ * given Radio Access Technology (RAT), at a given frequency (NR RAT only), for a given
+ * transmission power level.
+ *
+ * @param rat Radio Access Technology {@see RadioAccessTechnology}
+ * @param frequencyRange frequency range {@see ServiceState.FrequencyRange}, only needed for
+ * RADIO_ACCESS_TECHNOLOGY_NR. Use
+ * {@link ServiceState.FREQUENCY_RANGE_UNKNOWN} for other Radio Access
+ * Technologies.
+ * @param elapsedRealtimeMs current elapsed realtime
+ * @return time (in milliseconds) the mobile radio spent actively receiving data in the
+ * specified state, while on battery. Returns {@link DURATION_UNAVAILABLE} if
+ * data unavailable.
+ * @hide
+ */
+ public abstract long getActiveRxRadioDurationMs(@RadioAccessTechnology int rat,
+ @ServiceState.FrequencyRange int frequencyRange, long elapsedRealtimeMs);
+
static final String[] WIFI_SUPPL_STATE_NAMES = {
"invalid", "disconn", "disabled", "inactive", "scanning",
"authenticating", "associating", "associated", "4-way-handshake",
@@ -2720,6 +2762,13 @@ public abstract class BatteryStats implements Parcelable {
public static final long POWER_DATA_UNAVAILABLE = -1L;
/**
+ * Returned value if duration data is unavailable.
+ *
+ * {@hide}
+ */
+ public static final long DURATION_UNAVAILABLE = -1L;
+
+ /**
* Returns the battery consumption (in microcoulombs) of bluetooth, derived from on
* device power measurement data.
* Will return {@link #POWER_DATA_UNAVAILABLE} if data is unavailable.
@@ -4093,6 +4142,10 @@ public abstract class BatteryStats implements Parcelable {
" Mmwave frequency (greater than 6GHz):\n"};
final String signalStrengthHeader =
" Signal Strength Time:\n";
+ final String txHeader =
+ " Tx Time:\n";
+ final String rxHeader =
+ " Rx Time: ";
final String[] signalStrengthDescription = new String[]{
" unknown: ",
" poor: ",
@@ -4144,6 +4197,29 @@ public abstract class BatteryStats implements Parcelable {
sb.append(")\n");
}
+ sb.append(prefix);
+ sb.append(txHeader);
+ for (int strength = 0; strength < numSignalStrength; strength++) {
+ final long timeMs = getActiveTxRadioDurationMs(rat, freqLvl, strength,
+ rawRealtimeMs);
+ if (timeMs <= 0) continue;
+ hasFreqData = true;
+ sb.append(prefix);
+ sb.append(signalStrengthDescription[strength]);
+ formatTimeMs(sb, timeMs);
+ sb.append("(");
+ sb.append(formatRatioLocked(timeMs, totalActiveTimesMs));
+ sb.append(")\n");
+ }
+
+ sb.append(prefix);
+ sb.append(rxHeader);
+ final long rxTimeMs = getActiveRxRadioDurationMs(rat, freqLvl, rawRealtimeMs);
+ formatTimeMs(sb, rxTimeMs);
+ sb.append("(");
+ sb.append(formatRatioLocked(rxTimeMs, totalActiveTimesMs));
+ sb.append(")\n");
+
if (hasFreqData) {
hasData = true;
pw.print(sb);
@@ -5655,6 +5731,7 @@ public abstract class BatteryStats implements Parcelable {
.setMaxStatsAgeMs(0)
.includePowerModels()
.includeProcessStateData()
+ .includeVirtualUids()
.build());
stats.dump(pw, prefix);
diff --git a/core/java/android/os/BatteryUsageStatsQuery.java b/core/java/android/os/BatteryUsageStatsQuery.java
index 37bd51bb66c5..b3f4d9874f4e 100644
--- a/core/java/android/os/BatteryUsageStatsQuery.java
+++ b/core/java/android/os/BatteryUsageStatsQuery.java
@@ -42,6 +42,7 @@ public final class BatteryUsageStatsQuery implements Parcelable {
FLAG_BATTERY_USAGE_STATS_POWER_PROFILE_MODEL,
FLAG_BATTERY_USAGE_STATS_INCLUDE_HISTORY,
FLAG_BATTERY_USAGE_STATS_INCLUDE_PROCESS_STATE_DATA,
+ FLAG_BATTERY_USAGE_STATS_INCLUDE_VIRTUAL_UIDS,
})
@Retention(RetentionPolicy.SOURCE)
public @interface BatteryUsageStatsFlags {}
@@ -69,6 +70,8 @@ public final class BatteryUsageStatsQuery implements Parcelable {
public static final int FLAG_BATTERY_USAGE_STATS_INCLUDE_PROCESS_STATE_DATA = 0x0008;
+ public static final int FLAG_BATTERY_USAGE_STATS_INCLUDE_VIRTUAL_UIDS = 0x0010;
+
private static final long DEFAULT_MAX_STATS_AGE_MS = 5 * 60 * 1000;
private final int mFlags;
@@ -271,6 +274,15 @@ public final class BatteryUsageStatsQuery implements Parcelable {
}
/**
+ * Requests to return attribution data for virtual UIDs such as
+ * {@link Process#SDK_SANDBOX_VIRTUAL_UID}.
+ */
+ public Builder includeVirtualUids() {
+ mFlags |= BatteryUsageStatsQuery.FLAG_BATTERY_USAGE_STATS_INCLUDE_VIRTUAL_UIDS;
+ return this;
+ }
+
+ /**
* Requests to aggregate stored snapshots between the two supplied timestamps
* @param fromTimestamp Exclusive starting timestamp, as per System.currentTimeMillis()
* @param toTimestamp Inclusive ending timestamp, as per System.currentTimeMillis()
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 1c85f692b232..42e6ac4df8af 100755
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -406,7 +406,7 @@ public class Build {
public static final String CODENAME = getString("ro.build.version.codename");
/**
- * All known codenames starting from {@link VERSION_CODES.Q}.
+ * All known codenames that are present in {@link VERSION_CODES}.
*
* <p>This includes in development codenames as well, i.e. if {@link #CODENAME} is not "REL"
* then the value of that is present in this set.
diff --git a/core/java/android/os/Bundle.java b/core/java/android/os/Bundle.java
index a19b51b7811b..cf28c1639fac 100644
--- a/core/java/android/os/Bundle.java
+++ b/core/java/android/os/Bundle.java
@@ -989,7 +989,7 @@ public final class Bundle extends BaseBundle implements Cloneable, Parcelable {
* Otherwise, this method might throw an exception or return {@code null}.
*
* @param key a String, or {@code null}
- * @param clazz The type of the items inside the array
+ * @param clazz The type of the items inside the array. This is only verified when unparceling.
* @return a Parcelable[] value, or {@code null}
*/
@SuppressLint({"ArrayReturn", "NullableCollection"})
@@ -1053,7 +1053,8 @@ public final class Bundle extends BaseBundle implements Cloneable, Parcelable {
* Otherwise, this method might throw an exception or return {@code null}.
*
* @param key a String, or {@code null}
- * @param clazz The type of the items inside the array list
+ * @param clazz The type of the items inside the array list. This is only verified when
+ * unparceling.
* @return an ArrayList<T> value, or {@code null}
*/
@SuppressLint("NullableCollection")
@@ -1103,6 +1104,8 @@ public final class Bundle extends BaseBundle implements Cloneable, Parcelable {
* </ul>
*
* @param key a String, or null
+ * @param clazz The type of the items inside the sparse array. This is only verified when
+ * unparceling.
* @return a SparseArray of T values, or null
*/
@SuppressWarnings("unchecked")
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index 0a7a40798d71..ecdc803c0074 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -478,10 +478,20 @@ public class Environment {
}
/** {@hide} */
+ public static File getDataMiscCeSharedSdkSandboxDirectory(int userId, String packageName) {
+ return buildPath(getDataMiscCeDirectory(userId), "sdksandbox", packageName, "shared");
+ }
+
+ /** {@hide} */
public static File getDataMiscDeDirectory(int userId) {
return buildPath(getDataDirectory(), "misc_de", String.valueOf(userId));
}
+ /** {@hide} */
+ public static File getDataMiscDeSharedSdkSandboxDirectory(int userId, String packageName) {
+ return buildPath(getDataMiscDeDirectory(userId), "sdksandbox", packageName, "shared");
+ }
+
private static File getDataProfilesDeDirectory(int userId) {
return buildPath(getDataDirectory(), "misc", "profiles", "cur", String.valueOf(userId));
}
diff --git a/core/java/android/os/ExternalVibration.java b/core/java/android/os/ExternalVibration.java
index 4e0995fb8792..db5bc7024e0b 100644
--- a/core/java/android/os/ExternalVibration.java
+++ b/core/java/android/os/ExternalVibration.java
@@ -47,7 +47,13 @@ public class ExternalVibration implements Parcelable {
this(uid, pkg, attrs, controller, new Binder());
}
- private ExternalVibration(int uid, @NonNull String pkg, @NonNull AudioAttributes attrs,
+ /**
+ * Full constructor, but exposed to construct the ExternalVibration with an explicit binder
+ * token (for mocks).
+ *
+ * @hide
+ */
+ public ExternalVibration(int uid, @NonNull String pkg, @NonNull AudioAttributes attrs,
@NonNull IExternalVibrationController controller, @NonNull IBinder token) {
mUid = uid;
mPkg = Preconditions.checkNotNull(pkg);
@@ -166,7 +172,7 @@ public class ExternalVibration implements Parcelable {
+ "pkg=" + mPkg + ", "
+ "attrs=" + mAttrs + ", "
+ "controller=" + mController
- + "token=" + mController
+ + "token=" + mToken
+ "}";
}
diff --git a/core/java/android/os/IBinder.java b/core/java/android/os/IBinder.java
index 010459d06e8d..9e47a708162d 100644
--- a/core/java/android/os/IBinder.java
+++ b/core/java/android/os/IBinder.java
@@ -293,7 +293,10 @@ public interface IBinder {
*
* @return Returns the result from {@link Binder#onTransact}. A successful call
* generally returns true; false generally means the transaction code was not
- * understood.
+ * understood. For a oneway call to a different process false should never be
+ * returned. If a oneway call is made to code in the same process (usually to
+ * a C++ or Rust implementation), then there are no oneway semantics, and
+ * false can still be returned.
*/
public boolean transact(int code, @NonNull Parcel data, @Nullable Parcel reply, int flags)
throws RemoteException;
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index 39ca596f9181..3cde0319efd3 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -109,7 +109,7 @@ interface IUserManager {
boolean someUserHasAccount(in String accountName, in String accountType);
String getProfileType(int userId);
boolean isMediaSharedWithParent(int userId);
- boolean isCredentialSharedWithParent(int userId);
+ boolean isCredentialSharableWithParent(int userId);
boolean isDemoUser(int userId);
boolean isPreCreated(int userId);
UserInfo createProfileForUserEvenWhenDisallowedWithThrow(in String name, in String userType, int flags,
diff --git a/core/java/android/os/IpcDataCache.java b/core/java/android/os/IpcDataCache.java
new file mode 100644
index 000000000000..0efa34cdc47f
--- /dev/null
+++ b/core/java/android/os/IpcDataCache.java
@@ -0,0 +1,385 @@
+/*
+ * 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.os;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.StringDef;
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
+import android.app.PropertyInvalidatedCache;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.FastPrintWriter;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Random;
+import java.util.Set;
+import java.util.WeakHashMap;
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * LRU cache that's invalidated when an opaque value in a property changes. Self-synchronizing,
+ * but doesn't hold a lock across data fetches on query misses.
+ *
+ * The intended use case is caching frequently-read, seldom-changed information normally retrieved
+ * across interprocess communication. Imagine that you've written a user birthday information
+ * daemon called "birthdayd" that exposes an {@code IUserBirthdayService} interface over
+ * binder. That binder interface looks something like this:
+ *
+ * <pre>
+ * parcelable Birthday {
+ * int month;
+ * int day;
+ * }
+ * interface IUserBirthdayService {
+ * Birthday getUserBirthday(int userId);
+ * }
+ * </pre>
+ *
+ * Suppose the service implementation itself looks like this...
+ *
+ * <pre>
+ * public class UserBirthdayServiceImpl implements IUserBirthdayService {
+ * private final HashMap&lt;Integer, Birthday%&gt; mUidToBirthday;
+ * {@literal @}Override
+ * public synchronized Birthday getUserBirthday(int userId) {
+ * return mUidToBirthday.get(userId);
+ * }
+ * private synchronized void updateBirthdays(Map&lt;Integer, Birthday%&gt; uidToBirthday) {
+ * mUidToBirthday.clear();
+ * mUidToBirthday.putAll(uidToBirthday);
+ * }
+ * }
+ * </pre>
+ *
+ * ... and we have a client in frameworks (loaded into every app process) that looks like this:
+ *
+ * <pre>
+ * public class ActivityThread {
+ * ...
+ * public Birthday getUserBirthday(int userId) {
+ * return GetService("birthdayd").getUserBirthday(userId);
+ * }
+ * ...
+ * }
+ * </pre>
+ *
+ * With this code, every time an app calls {@code getUserBirthday(uid)}, we make a binder call to
+ * the birthdayd process and consult its database of birthdays. If we query user birthdays
+ * frequently, we do a lot of work that we don't have to do, since user birthdays change
+ * infrequently.
+ *
+ * IpcDataCache is part of a pattern for optimizing this kind of information-querying code. Using
+ * {@code IpcDataCache}, you'd write the client this way:
+ *
+ * <pre>
+ * public class ActivityThread {
+ * ...
+ * private final IpcDataCache.QueryHandler&lt;Integer, Birthday&gt; mBirthdayQuery =
+ * new IpcDataCache.QueryHandler&lt;Integer, Birthday&gt;() {
+ * {@literal @}Override
+ * public Birthday apply(Integer) {
+ * return GetService("birthdayd").getUserBirthday(userId);
+ * }
+ * };
+ * private static final int BDAY_CACHE_MAX = 8; // Maximum birthdays to cache
+ * private static final String BDAY_API = "getUserBirthday";
+ * private final IpcDataCache&lt;Integer, Birthday%&gt; mBirthdayCache = new
+ * IpcDataCache&lt;Integer, Birthday%&gt;(
+ * BDAY_CACHE_MAX, MODULE_SYSTEM, BDAY_API, BDAY_API, mBirthdayQuery);
+ *
+ * public void disableUserBirthdayCache() {
+ * mBirthdayCache.disableForCurrentProcess();
+ * }
+ * public void invalidateUserBirthdayCache() {
+ * mBirthdayCache.invalidateCache();
+ * }
+ * public Birthday getUserBirthday(int userId) {
+ * return mBirthdayCache.query(userId);
+ * }
+ * ...
+ * }
+ * </pre>
+ *
+ * With this cache, clients perform a binder call to birthdayd if asking for a user's birthday
+ * for the first time; on subsequent queries, we return the already-known Birthday object.
+ *
+ * The second parameter to the IpcDataCache constructor is a string that identifies the "module"
+ * that owns the cache. There are some well-known modules (such as {@code MODULE_SYSTEM} but any
+ * string is permitted. The third parameters is the name of the API being cached; this, too, can
+ * any value. The fourth is the name of the cache. The cache is usually named after th API.
+ * Some things you must know about the three strings:
+ * <list>
+ * <ul> The system property that controls the cache is named {@code cache_key.<module>.<api>}.
+ * Usually, the SELinux rules permit a process to write a system property (and therefore
+ * invalidate a cache) based on the wildcard {@code cache_key.<module>.*}. This means that
+ * although the cache can be constructed with any module string, whatever string is chosen must be
+ * consistent with the SELinux configuration.
+ * <ul> The API name can be any string of alphanumeric characters. All caches with the same API
+ * are invalidated at the same time. If a server supports several caches and all are invalidated
+ * in common, then it is most efficient to assign the same API string to every cache.
+ * <ul> The cache name can be any string. In debug output, the name is used to distiguish between
+ * caches with the same API name. The cache name is also used when disabling caches in the
+ * current process. So, invalidation is based on the module+api but disabling (which is generally
+ * a once-per-process operation) is based on the cache name.
+ * </list>
+ *
+ * User birthdays do occasionally change, so we have to modify the server to invalidate this
+ * cache when necessary. That invalidation code looks like this:
+ *
+ * <pre>
+ * public class UserBirthdayServiceImpl {
+ * ...
+ * public UserBirthdayServiceImpl() {
+ * ...
+ * ActivityThread.currentActivityThread().disableUserBirthdayCache();
+ * ActivityThread.currentActivityThread().invalidateUserBirthdayCache();
+ * }
+ *
+ * private synchronized void updateBirthdays(Map&lt;Integer, Birthday%&gt; uidToBirthday) {
+ * mUidToBirthday.clear();
+ * mUidToBirthday.putAll(uidToBirthday);
+ * ActivityThread.currentActivityThread().invalidateUserBirthdayCache();
+ * }
+ * ...
+ * }
+ * </pre>
+ *
+ * The call to {@code IpcDataCache.invalidateCache()} guarantees that all clients will re-fetch
+ * birthdays from binder during consequent calls to
+ * {@code ActivityThread.getUserBirthday()}. Because the invalidate call happens with the lock
+ * held, we maintain consistency between different client views of the birthday state. The use of
+ * IpcDataCache in this idiomatic way introduces no new race conditions.
+ *
+ * IpcDataCache has a few other features for doing things like incremental enhancement of cached
+ * values and invalidation of multiple caches (that all share the same property key) at once.
+ *
+ * {@code BDAY_CACHE_KEY} is the name of a property that we set to an opaque unique value each
+ * time we update the cache. SELinux configuration must allow everyone to read this property
+ * and it must allow any process that needs to invalidate the cache (here, birthdayd) to write
+ * the property. (These properties conventionally begin with the "cache_key." prefix.)
+ *
+ * The {@code UserBirthdayServiceImpl} constructor calls {@code disableUserBirthdayCache()} so
+ * that calls to {@code getUserBirthday} from inside birthdayd don't go through the cache. In this
+ * local case, there's no IPC, so use of the cache is (depending on exact circumstance)
+ * unnecessary.
+ *
+ * There may be queries for which it is more efficient to bypass the cache than to cache the
+ * result. This would be true, for example, if some queries would require frequent cache
+ * invalidation while other queries require infrequent invalidation. To expand on the birthday
+ * example, suppose that there is a userId that signifies "the next birthday". When passed this
+ * userId, the server returns the next birthday among all users - this value changes as time
+ * advances. The userId value can be cached, but the cache must be invalidated whenever a
+ * birthday occurs, and this invalidates all birthdays. If there is a large number of users,
+ * invalidation will happen so often that the cache provides no value.
+ *
+ * The class provides a bypass mechanism to handle this situation.
+ * <pre>
+ * public class ActivityThread {
+ * ...
+ * private final IpcDataCache.QueryHandler&lt;Integer, Birthday&gt; mBirthdayQuery =
+ * new IpcDataCache.QueryHandler&lt;Integer, Birthday&gt;() {
+ * {@literal @}Override
+ * public Birthday apply(Integer) {
+ * return GetService("birthdayd").getUserBirthday(userId);
+ * }
+ * {@literal @}Override
+ * public boolean shouldBypassQuery(Integer userId) {
+ * return userId == NEXT_BIRTHDAY;
+ * }
+ * };
+ * ...
+ * }
+ * </pre>
+ *
+ * If the {@code shouldBypassQuery()} method returns true then the cache is not used for that
+ * particular query. The {@code shouldBypassQuery()} method is not abstract and the default
+ * implementation returns false.
+ *
+ * For security, there is a allowlist of processes that are allowed to invalidate a cache. The
+ * allowlist includes normal runtime processes but does not include test processes. Test
+ * processes must call {@code IpcDataCache.disableForTestMode()} to disable all cache activity in
+ * that process.
+ *
+ * Caching can be disabled completely by initializing {@code sEnabled} to false and rebuilding.
+ *
+ * To test a binder cache, create one or more tests that exercise the binder method. This should
+ * be done twice: once with production code and once with a special image that sets {@code DEBUG}
+ * and {@code VERIFY} true. In the latter case, verify that no cache inconsistencies are
+ * reported. If a cache inconsistency is reported, however, it might be a false positive. This
+ * happens if the server side data can be read and written non-atomically with respect to cache
+ * invalidation.
+ *
+ * @param <Query> The class used to index cache entries: must be hashable and comparable
+ * @param <Result> The class holding cache entries; use a boxed primitive if possible
+ * @hide
+ */
+@TestApi
+@SystemApi(client=SystemApi.Client.MODULE_LIBRARIES)
+public class IpcDataCache<Query, Result> extends PropertyInvalidatedCache<Query, Result> {
+ /**
+ * {@inheritDoc}
+ * @hide
+ */
+ @SystemApi(client=SystemApi.Client.MODULE_LIBRARIES)
+ @TestApi
+ public static abstract class QueryHandler<Q,R>
+ extends PropertyInvalidatedCache.QueryHandler<Q,R> {
+ /**
+ * Compute a result given a query. The semantics are those of Functor.
+ */
+ public abstract @Nullable R apply(@NonNull Q query);
+
+ /**
+ * Return true if a query should not use the cache. The default implementation
+ * always uses the cache.
+ */
+ public boolean shouldBypassCache(@NonNull Q query) {
+ return false;
+ }
+ };
+
+ /**
+ * The list of cache namespaces. Each namespace corresponds to an sepolicy domain. A
+ * namespace is owned by a single process, although a single process can have more
+ * than one namespace (system_server, as an example).
+ * @hide
+ */
+ @StringDef(
+ prefix = { "MODULE_"
+ },
+ value = {
+ MODULE_TEST,
+ MODULE_SYSTEM,
+ MODULE_BLUETOOTH,
+ MODULE_TELEPHONY
+ }
+ )
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface IpcDataCacheModule { }
+
+ /**
+ * The module used for unit tests and cts tests. It is expected that no process in
+ * the system has permissions to write properties with this module.
+ * @hide
+ */
+ @TestApi
+ public static final String MODULE_TEST = PropertyInvalidatedCache.MODULE_TEST;
+
+ /**
+ * The module used for system server/framework caches. This is not visible outside
+ * the system processes.
+ * @hide
+ */
+ @TestApi
+ public static final String MODULE_SYSTEM = PropertyInvalidatedCache.MODULE_SYSTEM;
+
+ /**
+ * The module used for bluetooth caches.
+ * @hide
+ */
+ @SystemApi(client=SystemApi.Client.MODULE_LIBRARIES)
+ @TestApi
+ public static final String MODULE_BLUETOOTH = PropertyInvalidatedCache.MODULE_BLUETOOTH;
+
+ /**
+ * Make a new property invalidated cache. The key is computed from the module and api
+ * parameters.
+ *
+ * @param maxEntries Maximum number of entries to cache; LRU discard
+ * @param module The module under which the cache key should be placed.
+ * @param api The api this cache front-ends. The api must be a Java identifier but
+ * need not be an actual api.
+ * @param cacheName Name of this cache in debug and dumpsys
+ * @param computer The code to compute values that are not in the cache.
+ * @hide
+ */
+ @SystemApi(client=SystemApi.Client.MODULE_LIBRARIES)
+ @TestApi
+ public IpcDataCache(int maxEntries, @NonNull @IpcDataCacheModule String module,
+ @NonNull String api,
+ @NonNull String cacheName, @NonNull QueryHandler<Query, Result> computer) {
+ super(maxEntries, module, api, cacheName, computer);
+ }
+
+ /**
+ * {@inheritDoc}
+ * @hide
+ */
+ @SystemApi(client=SystemApi.Client.MODULE_LIBRARIES)
+ @TestApi
+ @Override
+ public void disableForCurrentProcess() {
+ super.disableForCurrentProcess();
+ }
+
+ /**
+ * {@inheritDoc}
+ * @hide
+ */
+ @SystemApi(client=SystemApi.Client.MODULE_LIBRARIES)
+ @TestApi
+ public static void disableForCurrentProcess(@NonNull String cacheName) {
+ PropertyInvalidatedCache.disableForCurrentProcess(cacheName);
+ }
+
+ /**
+ * {@inheritDoc}
+ * @hide
+ */
+ @SystemApi(client=SystemApi.Client.MODULE_LIBRARIES)
+ @TestApi
+ @Override
+ public @Nullable Result query(@NonNull Query query) {
+ return super.query(query);
+ }
+
+ /**
+ * {@inheritDoc}
+ * @hide
+ */
+ @SystemApi(client=SystemApi.Client.MODULE_LIBRARIES)
+ @TestApi
+ @Override
+ public void invalidateCache() {
+ super.invalidateCache();
+ }
+
+ /**
+ * Invalidate caches in all processes that are keyed for the module and api.
+ * @hide
+ */
+ @SystemApi(client=SystemApi.Client.MODULE_LIBRARIES)
+ @TestApi
+ public static void invalidateCache(@NonNull @IpcDataCacheModule String module,
+ @NonNull String api) {
+ PropertyInvalidatedCache.invalidateCache(module, api);
+ }
+}
diff --git a/core/java/android/os/ParcelableHolder.java b/core/java/android/os/ParcelableHolder.java
index 368ee2d91172..a739ba3dd438 100644
--- a/core/java/android/os/ParcelableHolder.java
+++ b/core/java/android/os/ParcelableHolder.java
@@ -179,7 +179,11 @@ public final class ParcelableHolder implements Parcelable {
* Read ParcelableHolder from a parcel.
*/
public void readFromParcel(@NonNull Parcel parcel) {
- this.mStability = parcel.readInt();
+ int wireStability = parcel.readInt();
+ if (this.mStability != wireStability) {
+ throw new IllegalArgumentException("Expected stability " + this.mStability
+ + " but got " + wireStability);
+ }
mParcelable = null;
diff --git a/core/java/android/os/PowerComponents.java b/core/java/android/os/PowerComponents.java
index 605171208fc1..522807b83d04 100644
--- a/core/java/android/os/PowerComponents.java
+++ b/core/java/android/os/PowerComponents.java
@@ -292,6 +292,10 @@ class PowerComponents {
procState = BatteryUsageStatsAtomsProto.BatteryConsumerData.PowerComponentUsageSlice
.FOREGROUND_SERVICE;
break;
+ case BatteryConsumer.PROCESS_STATE_CACHED:
+ procState = BatteryUsageStatsAtomsProto.BatteryConsumerData.PowerComponentUsageSlice
+ .CACHED;
+ break;
default:
throw new IllegalArgumentException("Unknown process state: " + processState);
}
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 9428ac965f84..e06e7326a860 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -257,6 +257,14 @@ public class Process {
public static final int UWB_UID = 1083;
/**
+ * Defines a virtual UID that is used to aggregate data related to SDK sandbox UIDs.
+ * {@see SdkSandboxManager}
+ * @hide
+ */
+ @TestApi
+ public static final int SDK_SANDBOX_VIRTUAL_UID = 1090;
+
+ /**
* GID that corresponds to the INTERNET permission.
* Must match the value of AID_INET.
* @hide
@@ -920,7 +928,7 @@ public class Process {
*/
@SystemApi(client = MODULE_LIBRARIES)
@TestApi
- public static final int sdkSandboxToAppUid(int uid) {
+ public static final int getAppUidForSdkSandboxUid(int uid) {
return uid - (FIRST_SDK_SANDBOX_UID - FIRST_APPLICATION_UID);
}
diff --git a/core/java/android/os/UidBatteryConsumer.java b/core/java/android/os/UidBatteryConsumer.java
index a1ff923e3b94..91d231eb1c39 100644
--- a/core/java/android/os/UidBatteryConsumer.java
+++ b/core/java/android/os/UidBatteryConsumer.java
@@ -119,6 +119,8 @@ public final class UidBatteryConsumer extends BatteryConsumer {
skipEmptyComponents);
appendProcessStateData(sb, BatteryConsumer.PROCESS_STATE_FOREGROUND_SERVICE,
skipEmptyComponents);
+ appendProcessStateData(sb, BatteryConsumer.PROCESS_STATE_CACHED,
+ skipEmptyComponents);
pw.print(sb);
}
@@ -202,20 +204,24 @@ public final class UidBatteryConsumer extends BatteryConsumer {
private static final String PACKAGE_NAME_UNINITIALIZED = "";
private final BatteryStats.Uid mBatteryStatsUid;
private final int mUid;
+ private final boolean mIsVirtualUid;
private String mPackageWithHighestDrain = PACKAGE_NAME_UNINITIALIZED;
private boolean mExcludeFromBatteryUsageStats;
public Builder(BatteryConsumerData data, @NonNull BatteryStats.Uid batteryStatsUid) {
- super(data, CONSUMER_TYPE_UID);
- mBatteryStatsUid = batteryStatsUid;
- mUid = batteryStatsUid.getUid();
- data.putLong(COLUMN_INDEX_UID, mUid);
+ this(data, batteryStatsUid, batteryStatsUid.getUid());
}
public Builder(BatteryConsumerData data, int uid) {
+ this(data, null, uid);
+ }
+
+ private Builder(BatteryConsumerData data, @Nullable BatteryStats.Uid batteryStatsUid,
+ int uid) {
super(data, CONSUMER_TYPE_UID);
- mBatteryStatsUid = null;
+ mBatteryStatsUid = batteryStatsUid;
mUid = uid;
+ mIsVirtualUid = mUid == Process.SDK_SANDBOX_VIRTUAL_UID;
data.putLong(COLUMN_INDEX_UID, mUid);
}
@@ -232,6 +238,10 @@ public final class UidBatteryConsumer extends BatteryConsumer {
return mUid;
}
+ public boolean isVirtualUid() {
+ return mIsVirtualUid;
+ }
+
/**
* Sets the name of the package owned by this UID that consumed the highest amount
* of power since BatteryStats reset.
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index a715c6961359..608c424451b7 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -17,7 +17,7 @@
package android.os;
import static android.app.admin.DevicePolicyResources.Strings.Core.WORK_PROFILE_BADGED_LABEL;
-import static android.app.admin.DevicePolicyResources.Strings.UNDEFINED;
+import static android.app.admin.DevicePolicyResources.UNDEFINED;
import android.Manifest;
import android.accounts.AccountManager;
@@ -1703,12 +1703,40 @@ public class UserManager {
/**
* A response code from {@link #removeUserWhenPossible(UserHandle, boolean)} indicating that
- * an error occurred that prevented the user from being removed or set as ephemeral.
+ * an unknown error occurred that prevented the user from being removed or set as ephemeral.
*
* @hide
*/
@SystemApi
- public static final int REMOVE_RESULT_ERROR = 3;
+ public static final int REMOVE_RESULT_ERROR_UNKNOWN = -1;
+
+ /**
+ * A response code from {@link #removeUserWhenPossible(UserHandle, boolean)} indicating that
+ * the user could not be removed due to a {@link #DISALLOW_REMOVE_MANAGED_PROFILE} or
+ * {@link #DISALLOW_REMOVE_USER} user restriction.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int REMOVE_RESULT_ERROR_USER_RESTRICTION = -2;
+
+ /**
+ * A response code from {@link #removeUserWhenPossible(UserHandle, boolean)} indicating that
+ * user being removed does not exist.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int REMOVE_RESULT_ERROR_USER_NOT_FOUND = -3;
+
+ /**
+ * A response code from {@link #removeUserWhenPossible(UserHandle, boolean)} indicating that
+ * user being removed is a {@link UserHandle#SYSTEM} user which can't be removed.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int REMOVE_RESULT_ERROR_SYSTEM_USER = -4;
/**
* Possible response codes from {@link #removeUserWhenPossible(UserHandle, boolean)}.
@@ -1719,7 +1747,10 @@ public class UserManager {
REMOVE_RESULT_REMOVED,
REMOVE_RESULT_DEFERRED,
REMOVE_RESULT_ALREADY_BEING_REMOVED,
- REMOVE_RESULT_ERROR,
+ REMOVE_RESULT_ERROR_USER_RESTRICTION,
+ REMOVE_RESULT_ERROR_USER_NOT_FOUND,
+ REMOVE_RESULT_ERROR_SYSTEM_USER,
+ REMOVE_RESULT_ERROR_UNKNOWN,
})
@Retention(RetentionPolicy.SOURCE)
public @interface RemoveResult {}
@@ -4718,7 +4749,7 @@ public class UserManager {
return label;
}
DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class);
- return dpm.getString(
+ return dpm.getResources().getString(
getUpdatableUserBadgedLabelId(userId),
() -> getDefaultUserBadgedLabel(label, userId),
/* formatArgs= */ label);
@@ -4763,7 +4794,7 @@ public class UserManager {
}
/**
- * Returns {@code true} if the user shares lock settings credential with its parent user
+ * Returns whether the user can have shared lockscreen credential with its parent user.
*
* This API only works for {@link UserManager#isProfile() profiles}
* and will always return false for any other user type.
@@ -4776,9 +4807,9 @@ public class UserManager {
Manifest.permission.MANAGE_USERS,
Manifest.permission.INTERACT_ACROSS_USERS})
@SuppressAutoDoc
- public boolean isCredentialSharedWithParent() {
+ public boolean isCredentialSharableWithParent() {
try {
- return mService.isCredentialSharedWithParent(mUserId);
+ return mService.isCredentialSharableWithParent(mUserId);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
@@ -4846,8 +4877,10 @@ public class UserManager {
* the {@link #DISALLOW_REMOVE_USER} or {@link #DISALLOW_REMOVE_MANAGED_PROFILE} restriction
*
* @return the {@link RemoveResult} code: {@link #REMOVE_RESULT_REMOVED},
- * {@link #REMOVE_RESULT_DEFERRED}, {@link #REMOVE_RESULT_ALREADY_BEING_REMOVED}, or
- * {@link #REMOVE_RESULT_ERROR}.
+ * {@link #REMOVE_RESULT_DEFERRED}, {@link #REMOVE_RESULT_ALREADY_BEING_REMOVED},
+ * {@link #REMOVE_RESULT_ERROR_USER_RESTRICTION}, {@link #REMOVE_RESULT_ERROR_USER_NOT_FOUND},
+ * {@link #REMOVE_RESULT_ERROR_SYSTEM_USER}, or {@link #REMOVE_RESULT_ERROR_UNKNOWN}. All error
+ * codes have negative values.
*
* @hide
*/
@@ -4864,6 +4897,19 @@ public class UserManager {
}
/**
+ * Check if {@link #removeUserWhenPossible} returned a success code which means that the user
+ * has been removed or is slated for removal.
+ *
+ * @param result is {@link #RemoveResult} code return by {@link #removeUserWhenPossible}.
+ * @return {@code true} if it is a success code.
+ * @hide
+ */
+ @SystemApi
+ public static boolean isRemoveResultSuccessful(@RemoveResult int result) {
+ return result >= 0;
+ }
+
+ /**
* Updates the user's name.
*
* @param userId the user's integer id
diff --git a/core/java/android/os/storage/IStorageManager.aidl b/core/java/android/os/storage/IStorageManager.aidl
index 722cdbc620a7..a0f6598640ba 100644
--- a/core/java/android/os/storage/IStorageManager.aidl
+++ b/core/java/android/os/storage/IStorageManager.aidl
@@ -54,13 +54,13 @@ interface IStorageManager {
*/
void shutdown(IStorageShutdownObserver observer) = 19;
/**
- * Mounts an Opaque Binary Blob (OBB) with the specified decryption key and
- * only allows the calling process's UID access to the contents.
- * StorageManagerService will call back to the supplied IObbActionListener to inform
- * it of the terminal state of the call.
+ * Mounts an Opaque Binary Blob (OBB). Only allows the calling process's UID
+ * access to the contents. StorageManagerService will call back to the
+ * supplied IObbActionListener to inform it of the terminal state of the
+ * call.
*/
- void mountObb(in String rawPath, in String canonicalPath, in String key,
- IObbActionListener token, int nonce, in ObbInfo obbInfo) = 21;
+ void mountObb(in String rawPath, in String canonicalPath, IObbActionListener token,
+ int nonce, in ObbInfo obbInfo) = 21;
/**
* Unmounts an Opaque Binary Blob (OBB). When the force flag is specified,
* any program using it will be forcibly killed to unmount the image.
@@ -78,37 +78,10 @@ interface IStorageManager {
*/
String getMountedObbPath(in String rawPath) = 24;
/**
- * Decrypts any encrypted volumes.
- */
- int decryptStorage(in String password) = 26;
- /**
- * Encrypts storage.
- */
- int encryptStorage(int type, in String password) = 27;
- /**
- * Changes the encryption password.
- */
- int changeEncryptionPassword(int type, in String password) = 28;
- /**
* Returns list of all mountable volumes for the specified userId
*/
StorageVolume[] getVolumeList(int userId, in String callingPackage, int flags) = 29;
/**
- * Determines the encryption state of the volume.
- * @return a numerical value. See {@code ENCRYPTION_STATE_*} for possible
- * values.
- * Note that this has been replaced in most cases by the APIs in
- * StorageManager (see isEncryptable and below)
- * This is still useful to get the error state when encryption has failed
- * and CryptKeeper needs to throw up a screen advising the user what to do
- */
- int getEncryptionState() = 31;
- /**
- * Verify the encryption password against the stored volume. This method
- * may only be called by the system process.
- */
- int verifyEncryptionPassword(in String password) = 32;
- /**
* Ensure that all directories along given path exist, creating parent
* directories as needed. Validates that given path is absolute and that it
* contains no relative "." or ".." paths or symlinks. Also ensures that
@@ -117,32 +90,6 @@ interface IStorageManager {
*/
void mkdirs(in String callingPkg, in String path) = 34;
/**
- * Determines the type of the encryption password
- * @return PasswordType
- */
- int getPasswordType() = 35;
- /**
- * Get password from vold
- * @return password or empty string
- */
- String getPassword() = 36;
- /**
- * Securely clear password from vold
- */
- oneway void clearPassword() = 37;
- /**
- * Set a field in the crypto header.
- * @param field field to set
- * @param contents contents to set in field
- */
- oneway void setField(in String field, in String contents) = 38;
- /**
- * Gets a field from the crypto header.
- * @param field field to get
- * @return contents of field
- */
- String getField(in String field) = 39;
- /**
* Report the time of the last maintenance operation such as fstrim.
* @return Timestamp of the last maintenance operation, in the
* System.currentTimeMillis() time base
@@ -178,7 +125,6 @@ interface IStorageManager {
boolean isUserKeyUnlocked(int userId) = 65;
void prepareUserStorage(in String volumeUuid, int userId, int serialNumber, int flags) = 66;
void destroyUserStorage(in String volumeUuid, int userId, int flags) = 67;
- boolean isConvertibleToFBE() = 68;
void addUserKeyAuth(int userId, int serialNumber, in byte[] secret) = 70;
void fixateNewestUserKeyAuth(int userId) = 71;
void fstrim(int flags, IVoldTaskListener listener) = 72;
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 48e2827f19e1..9971cbcfa586 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -83,7 +83,6 @@ import android.os.UserHandle;
import android.provider.DeviceConfig;
import android.provider.MediaStore;
import android.provider.Settings;
-import android.sysprop.VoldProperties;
import android.system.ErrnoException;
import android.system.Os;
import android.system.OsConstants;
@@ -273,12 +272,15 @@ public class StorageManager {
public static final int FLAG_STORAGE_CE = IInstalld.FLAG_STORAGE_CE;
/** {@hide} */
public static final int FLAG_STORAGE_EXTERNAL = IInstalld.FLAG_STORAGE_EXTERNAL;
+ /** @hide */
+ public static final int FLAG_STORAGE_SDK = IInstalld.FLAG_STORAGE_SDK;
/** {@hide} */
@IntDef(prefix = "FLAG_STORAGE_", value = {
FLAG_STORAGE_DE,
FLAG_STORAGE_CE,
- FLAG_STORAGE_EXTERNAL
+ FLAG_STORAGE_EXTERNAL,
+ FLAG_STORAGE_SDK,
})
@Retention(RetentionPolicy.SOURCE)
public @interface StorageFlags {}
@@ -677,9 +679,7 @@ public class StorageManager {
}
/**
- * Mount an Opaque Binary Blob (OBB) file. If a <code>key</code> is
- * specified, it is supplied to the mounting process to be used in any
- * encryption used in the OBB.
+ * Mount an Opaque Binary Blob (OBB) file.
* <p>
* The OBB will remain mounted for as long as the StorageManager reference
* is held by the application. As soon as this reference is lost, the OBBs
@@ -692,19 +692,22 @@ public class StorageManager {
* application's OBB that shares its UID.
*
* @param rawPath the path to the OBB file
- * @param key secret used to encrypt the OBB; may be <code>null</code> if no
- * encryption was used on the OBB.
+ * @param key must be <code>null</code>. Previously, some Android device
+ * implementations accepted a non-<code>null</code> key to mount
+ * an encrypted OBB file. However, this never worked reliably and
+ * is no longer supported.
* @param listener will receive the success or failure of the operation
* @return whether the mount call was successfully queued or not
*/
public boolean mountObb(String rawPath, String key, OnObbStateChangeListener listener) {
Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
+ Preconditions.checkArgument(key == null, "mounting encrypted OBBs is no longer supported");
Preconditions.checkNotNull(listener, "listener cannot be null");
try {
final String canonicalPath = new File(rawPath).getCanonicalPath();
final int nonce = mObbActionListener.addListener(listener);
- mStorageManager.mountObb(rawPath, canonicalPath, key, mObbActionListener, nonce,
+ mStorageManager.mountObb(rawPath, canonicalPath, mObbActionListener, nonce,
getObbInfo(canonicalPath));
return true;
} catch (IOException e) {
@@ -1735,10 +1738,7 @@ public class StorageManager {
* false not encrypted or file encrypted
*/
public static boolean isBlockEncrypted() {
- if (!isEncrypted()) {
- return false;
- }
- return RoSystemProperties.CRYPTO_BLOCK_ENCRYPTED;
+ return false;
}
/** {@hide}
@@ -1748,18 +1748,7 @@ public class StorageManager {
* false not encrypted, file encrypted or default block encrypted
*/
public static boolean isNonDefaultBlockEncrypted() {
- if (!isBlockEncrypted()) {
- return false;
- }
-
- try {
- IStorageManager storageManager = IStorageManager.Stub.asInterface(
- ServiceManager.getService("mount"));
- return storageManager.getPasswordType() != CRYPT_TYPE_DEFAULT;
- } catch (RemoteException e) {
- Log.e(TAG, "Error getting encryption type");
- return false;
- }
+ return false;
}
/** {@hide}
@@ -1773,8 +1762,7 @@ public class StorageManager {
* framework, so no service needs to check for changes during their lifespan
*/
public static boolean isBlockEncrypting() {
- final String state = VoldProperties.encrypt_progress().orElse("");
- return !"".equalsIgnoreCase(state);
+ return false;
}
/** {@hide}
@@ -1789,8 +1777,7 @@ public class StorageManager {
* framework, so no service needs to check for changes during their lifespan
*/
public static boolean inCryptKeeperBounce() {
- final String status = VoldProperties.decrypt().orElse("");
- return "trigger_restart_min_framework".equals(status);
+ return false;
}
/** {@hide} */
@@ -3057,14 +3044,4 @@ public class StorageManager {
public static final int CRYPT_TYPE_PATTERN = IVold.PASSWORD_TYPE_PATTERN;
/** @hide */
public static final int CRYPT_TYPE_PIN = IVold.PASSWORD_TYPE_PIN;
-
- // Constants for the data available via StorageManagerService.getField.
- /** @hide */
- public static final String SYSTEM_LOCALE_KEY = "SystemLocale";
- /** @hide */
- public static final String OWNER_INFO_KEY = "OwnerInfo";
- /** @hide */
- public static final String PATTERN_VISIBLE_KEY = "PatternVisible";
- /** @hide */
- public static final String PASSWORD_VISIBLE_KEY = "PasswordVisible";
}
diff --git a/core/java/android/permission/IPermissionController.aidl b/core/java/android/permission/IPermissionController.aidl
index c9dd06cfaa43..e3f02e73a41f 100644
--- a/core/java/android/permission/IPermissionController.aidl
+++ b/core/java/android/permission/IPermissionController.aidl
@@ -59,6 +59,6 @@ oneway interface IPermissionController {
void getHibernationEligibility(
in String packageName,
in AndroidFuture callback);
- void revokeOwnPermissionsOnKill(in String packageName, in List<String> permissions,
+ void revokeSelfPermissionsOnKill(in String packageName, in List<String> permissions,
in AndroidFuture callback);
}
diff --git a/core/java/android/permission/IPermissionManager.aidl b/core/java/android/permission/IPermissionManager.aidl
index 619c8705ddae..6a93b354f4da 100644
--- a/core/java/android/permission/IPermissionManager.aidl
+++ b/core/java/android/permission/IPermissionManager.aidl
@@ -76,8 +76,6 @@ interface IPermissionManager {
List<SplitPermissionInfoParcelable> getSplitPermissions();
- void revokeOwnPermissionsOnKill(String packageName, in List<String> permissions);
-
void startOneTimePermissionSession(String packageName, int userId, long timeout,
long revokeAfterKilledDelay, int importanceToResetTimer,
int importanceToKeepSessionAlive);
diff --git a/core/java/android/permission/PermissionControllerManager.java b/core/java/android/permission/PermissionControllerManager.java
index a005ab4e6ac7..3c2c7f03761b 100644
--- a/core/java/android/permission/PermissionControllerManager.java
+++ b/core/java/android/permission/PermissionControllerManager.java
@@ -916,15 +916,15 @@ public final class PermissionControllerManager {
* @param packageName The name of the package for which the permissions will be revoked.
* @param permissions List of permissions to be revoked.
*
- * @see Context#revokeOwnPermissionsOnKill(java.util.Collection)
+ * @see Context#revokeSelfPermissionsOnKill(java.util.Collection)
*
* @hide
*/
- public void revokeOwnPermissionsOnKill(@NonNull String packageName,
+ public void revokeSelfPermissionsOnKill(@NonNull String packageName,
@NonNull List<String> permissions) {
mRemoteService.postAsync(service -> {
AndroidFuture<Void> callback = new AndroidFuture<>();
- service.revokeOwnPermissionsOnKill(packageName, permissions, callback);
+ service.revokeSelfPermissionsOnKill(packageName, permissions, callback);
return callback;
}).whenComplete((result, err) -> {
if (err != null) {
diff --git a/core/java/android/permission/PermissionControllerService.java b/core/java/android/permission/PermissionControllerService.java
index 3292e7110ee5..4efffc5a11ef 100644
--- a/core/java/android/permission/PermissionControllerService.java
+++ b/core/java/android/permission/PermissionControllerService.java
@@ -40,6 +40,7 @@ import android.compat.annotation.Disabled;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
+import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.os.ParcelFileDescriptor;
@@ -339,10 +340,10 @@ public abstract class PermissionControllerService extends Service {
* @param permissions List of permissions to be revoked.
* @param callback Callback waiting for operation to be complete.
*
- * @see PermissionManager#revokeOwnPermissionsOnKill(java.util.Collection)
+ * @see android.content.Context#revokeSelfPermissionsOnKill(java.util.Collection)
*/
@BinderThread
- public void onRevokeOwnPermissionsOnKill(@NonNull String packageName,
+ public void onRevokeSelfPermissionsOnKill(@NonNull String packageName,
@NonNull List<String> permissions, @NonNull Runnable callback) {
throw new AbstractMethodError("Must be overridden in implementing class");
}
@@ -703,13 +704,19 @@ public abstract class PermissionControllerService extends Service {
}
@Override
- public void revokeOwnPermissionsOnKill(@NonNull String packageName,
+ public void revokeSelfPermissionsOnKill(@NonNull String packageName,
@NonNull List<String> permissions, @NonNull AndroidFuture callback) {
try {
- enforceSomePermissionsGrantedToCaller(
- Manifest.permission.REVOKE_RUNTIME_PERMISSIONS);
Objects.requireNonNull(callback);
- onRevokeOwnPermissionsOnKill(packageName, permissions,
+
+ final int callingUid = Binder.getCallingUid();
+ int targetPackageUid = getPackageManager().getPackageUid(packageName,
+ PackageManager.PackageInfoFlags.of(0));
+ if (targetPackageUid != callingUid) {
+ enforceSomePermissionsGrantedToCaller(
+ Manifest.permission.REVOKE_RUNTIME_PERMISSIONS);
+ }
+ onRevokeSelfPermissionsOnKill(packageName, permissions,
() -> callback.complete(null));
} catch (Throwable t) {
callback.completeExceptionally(t);
diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java
index c509de6bb5e1..69728756d745 100644
--- a/core/java/android/permission/PermissionManager.java
+++ b/core/java/android/permission/PermissionManager.java
@@ -76,7 +76,6 @@ import com.android.internal.annotations.Immutable;
import com.android.internal.util.CollectionUtils;
import java.util.ArrayList;
-import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
@@ -251,6 +250,10 @@ public final class PermissionManager {
* will evaluate the permission access based on the current fg/bg state of the app and
* leave a record that the data was accessed.
*
+ * <p>Requires the start of the AttributionSource chain to have the UPDATE_APP_OPS_STATS
+ * permission for the app op accesses to be given the TRUSTED_PROXY/PROXIED flags, otherwise the
+ * accesses will have the UNTRUSTED flags.
+ *
* @param permission The permission to check.
* @param attributionSource the permission identity
* @param message A message describing the reason the permission was checked
@@ -260,6 +263,7 @@ public final class PermissionManager {
* @see #checkPermissionForPreflight(String, AttributionSource)
*/
@PermissionCheckerManager.PermissionResult
+ @RequiresPermission(value = Manifest.permission.UPDATE_APP_OPS_STATS, conditional = true)
public int checkPermissionForDataDelivery(@NonNull String permission,
@NonNull AttributionSource attributionSource, @Nullable String message) {
return PermissionChecker.checkPermissionForDataDelivery(mContext, permission,
@@ -279,9 +283,14 @@ public final class PermissionManager {
* @return The permission check result which is either {@link #PERMISSION_GRANTED}
* or {@link #PERMISSION_SOFT_DENIED} or {@link #PERMISSION_HARD_DENIED}.
*
+ * <p>Requires the start of the AttributionSource chain to have the UPDATE_APP_OPS_STATS
+ * permission for the app op accesses to be given the TRUSTED_PROXY/PROXIED flags, otherwise the
+ * accesses will have the UNTRUSTED flags.
+ *
* @see #checkPermissionForDataDelivery(String, AttributionSource, String)
*/
@PermissionCheckerManager.PermissionResult
+ @RequiresPermission(value = Manifest.permission.UPDATE_APP_OPS_STATS, conditional = true)
public int checkPermissionForStartDataDelivery(@NonNull String permission,
@NonNull AttributionSource attributionSource, @Nullable String message) {
return PermissionChecker.checkPermissionForDataDelivery(mContext, permission,
@@ -321,6 +330,10 @@ public final class PermissionManager {
* will evaluate the permission access based on the current fg/bg state of the app and
* leave a record that the data was accessed.
*
+ * <p>Requires the start of the AttributionSource chain to have the UPDATE_APP_OPS_STATS
+ * permission for the app op accesses to be given the TRUSTED_PROXY/PROXIED flags, otherwise the
+ * accesses will have the UNTRUSTED flags.
+ *
* @param permission The permission to check.
* @param attributionSource the permission identity
* @param message A message describing the reason the permission was checked
@@ -330,6 +343,7 @@ public final class PermissionManager {
* @see #checkPermissionForPreflight(String, AttributionSource)
*/
@PermissionCheckerManager.PermissionResult
+ @RequiresPermission(value = Manifest.permission.UPDATE_APP_OPS_STATS, conditional = true)
public int checkPermissionForDataDeliveryFromDataSource(@NonNull String permission,
@NonNull AttributionSource attributionSource, @Nullable String message) {
return PermissionChecker.checkPermissionForDataDeliveryFromDataSource(mContext, permission,
@@ -626,19 +640,6 @@ public final class PermissionManager {
}
/**
- * @see Context#revokeOwnPermissionsOnKill(Collection)
- * @hide
- */
- public void revokeOwnPermissionsOnKill(@NonNull Collection<String> permissions) {
- try {
- mPermissionManager.revokeOwnPermissionsOnKill(mContext.getPackageName(),
- new ArrayList<String>(permissions));
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
* Gets the state flags associated with a permission.
*
* @param packageName the package name for which to get the flags
diff --git a/core/java/android/permission/PermissionUsageHelper.java b/core/java/android/permission/PermissionUsageHelper.java
index 0b57842cde11..4ed939c48bd7 100644
--- a/core/java/android/permission/PermissionUsageHelper.java
+++ b/core/java/android/permission/PermissionUsageHelper.java
@@ -47,6 +47,7 @@ import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.icu.text.ListFormatter;
+import android.location.LocationManager;
import android.media.AudioManager;
import android.os.Process;
import android.os.UserHandle;
@@ -411,10 +412,13 @@ public class PermissionUsageHelper implements AppOpsManager.OnOpActiveChangedLis
}
/**
- * Returns true if the app supports subattribution.
+ * Returns true if the app satisfies subattribution policies and supports it
*/
private boolean isSubattributionSupported(String packageName, int uid) {
try {
+ if (!isLocationProvider(packageName)) {
+ return false;
+ }
PackageManager userPkgManager =
getUserContext(UserHandle.getUserHandleForUid(uid)).getPackageManager();
ApplicationInfo appInfo = userPkgManager.getApplicationInfoAsUser(packageName,
@@ -430,6 +434,15 @@ public class PermissionUsageHelper implements AppOpsManager.OnOpActiveChangedLis
}
/**
+ * @param packageName
+ * @return If the package is location provider
+ */
+ private boolean isLocationProvider(String packageName) {
+ return Objects.requireNonNull(
+ mContext.getSystemService(LocationManager.class)).isProviderPackage(packageName);
+ }
+
+ /**
* Get the raw usages from the system, and then parse out the ones that are not recent enough,
* determine which permission group each belongs in, and removes duplicates (if the same app
* uses multiple permissions of the same group). Stores the package name, attribution tag, user,
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index 052e4d0538f2..47315047b6c4 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -74,6 +74,13 @@ public final class DeviceConfig {
public static final String NAMESPACE_ACTIVITY_MANAGER = "activity_manager";
/**
+ * Namespace for activity manager, specific to the "component alias" feature. We needed a
+ * different namespace in order to avoid phonetype from resetting it.
+ * @hide
+ */
+ public static final String NAMESPACE_ACTIVITY_MANAGER_COMPONENT_ALIAS = "activity_manager_ca";
+
+ /**
* Namespace for all activity manager related features that are used at the native level.
* These features are applied at reboot.
*
@@ -322,6 +329,13 @@ public final class DeviceConfig {
public static final String NAMESPACE_NNAPI_NATIVE = "nnapi_native";
/**
+ * Namespace for all OnDevicePersonalization related feature.
+ * @hide
+ */
+ @SystemApi
+ public static final String NAMESPACE_ON_DEVICE_PERSONALIZATION = "on_device_personalization";
+
+ /**
* Namespace for features related to the Package Manager Service.
*
* @hide
@@ -586,6 +600,13 @@ public final class DeviceConfig {
public static final String NAMESPACE_SELECTION_TOOLBAR = "selection_toolbar";
/**
+ * Definitions for voice interaction related functions.
+ *
+ * @hide
+ */
+ public static final String NAMESPACE_VOICE_INTERACTION = "voice_interaction";
+
+ /**
* List of namespaces which can be read without READ_DEVICE_CONFIG permission
*
* @hide
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index f2137b30350a..5191c9583379 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -85,8 +85,10 @@ import android.util.ArraySet;
import android.util.Log;
import android.util.MemoryIntArray;
import android.view.Display;
+import android.view.MotionEvent;
import android.view.Window;
import android.view.WindowManager.LayoutParams;
+import android.widget.Editor;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.Preconditions;
@@ -2141,10 +2143,10 @@ public final class Settings {
/**
* Intent extra: The id of a setting restricted by supervisors.
* <p>
- * Type: Integer with a value from the SupervisorVerificationSetting annotation below.
+ * Type: Integer with a value from the one of the SUPERVISOR_VERIFICATION_* constants below.
* <ul>
- * <li>{@link #SUPERVISOR_VERIFICATION_SETTING_UNKNOWN}
- * <li>{@link #SUPERVISOR_VERIFICATION_SETTING_BIOMETRICS}
+ * <li>{@see #SUPERVISOR_VERIFICATION_SETTING_UNKNOWN}
+ * <li>{@see #SUPERVISOR_VERIFICATION_SETTING_BIOMETRICS}
* </ul>
* </p>
*/
@@ -2152,12 +2154,14 @@ public final class Settings {
"android.provider.extra.SUPERVISOR_RESTRICTED_SETTING_KEY";
/**
- * Unknown setting.
+ * The unknown setting can usually be ignored and is used for compatibility with future
+ * supervisor settings.
*/
public static final int SUPERVISOR_VERIFICATION_SETTING_UNKNOWN = 0;
/**
- * Biometric settings for supervisors.
+ * Settings for supervisors to control what kinds of biometric sensors, such a face and
+ * fingerprint scanners, can be used on the device.
*/
public static final int SUPERVISOR_VERIFICATION_SETTING_BIOMETRICS = 1;
@@ -10727,14 +10731,6 @@ public final class Settings {
"communal_mode_trusted_networks";
/**
- * Setting to allow Fast Pair scans to be enabled.
- * @hide
- */
- @SystemApi
- @Readable
- public static final String FAST_PAIR_SCAN_ENABLED = "fast_pair_scan_enabled";
-
- /**
* Setting to store denylisted system languages by the CEC {@code <Set Menu Language>}
* confirmation dialog.
*
@@ -15518,6 +15514,17 @@ public final class Settings {
public static final String AUTOFILL_MAX_VISIBLE_DATASETS = "autofill_max_visible_datasets";
/**
+ * Toggle for enabling stylus handwriting. When enabled, current Input method receives
+ * stylus {@link MotionEvent}s if an {@link Editor} is focused.
+ *
+ * @hide
+ */
+ @TestApi
+ @Readable
+ @SuppressLint("NoSettingsProvider")
+ public static final String STYLUS_HANDWRITING_ENABLED = "stylus_handwriting_enabled";
+
+ /**
* Exemptions to the hidden API blacklist.
*
* @hide
diff --git a/core/java/android/service/ambientcontext/AmbientContextDetectionResult.java b/core/java/android/service/ambientcontext/AmbientContextDetectionResult.java
index 227194e60a7e..a216ed501687 100644
--- a/core/java/android/service/ambientcontext/AmbientContextDetectionResult.java
+++ b/core/java/android/service/ambientcontext/AmbientContextDetectionResult.java
@@ -26,6 +26,7 @@ import com.android.internal.util.AnnotationValidations;
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
/**
* Represents a {@code AmbientContextEvent} detection result reported by the detection service.
@@ -127,7 +128,9 @@ public final class AmbientContextDetectionResult implements Parcelable {
private @NonNull String mPackageName;
private long mBuilderFieldsSet = 0L;
- public Builder() {
+ public Builder(@NonNull String packageName) {
+ Objects.requireNonNull(packageName);
+ mPackageName = packageName;
}
/**
@@ -144,26 +147,37 @@ public final class AmbientContextDetectionResult implements Parcelable {
}
/**
- * The package to deliver the response to.
+ * Adds a list of events to the builder.
*/
- public @NonNull Builder setPackageName(@NonNull String value) {
+ public @NonNull Builder addEvents(@NonNull List<AmbientContextEvent> values) {
checkNotUsed();
- mBuilderFieldsSet |= 0x2;
- mPackageName = value;
+ if (mEvents == null) {
+ mBuilderFieldsSet |= 0x1;
+ mEvents = new ArrayList<>();
+ }
+ mEvents.addAll(values);
+ return this;
+ }
+
+ /**
+ * Clears all events from the builder.
+ */
+ public @NonNull Builder clearEvents() {
+ checkNotUsed();
+ if (mEvents != null) {
+ mEvents.clear();
+ }
return this;
}
/** Builds the instance. This builder should not be touched after calling this! */
public @NonNull AmbientContextDetectionResult build() {
checkNotUsed();
- mBuilderFieldsSet |= 0x4; // Mark builder used
+ mBuilderFieldsSet |= 0x2; // Mark builder used
if ((mBuilderFieldsSet & 0x1) == 0) {
mEvents = new ArrayList<>();
}
- if ((mBuilderFieldsSet & 0x2) == 0) {
- mPackageName = "";
- }
AmbientContextDetectionResult o = new AmbientContextDetectionResult(
mEvents,
mPackageName);
@@ -171,7 +185,7 @@ public final class AmbientContextDetectionResult implements Parcelable {
}
private void checkNotUsed() {
- if ((mBuilderFieldsSet & 0x4) != 0) {
+ if ((mBuilderFieldsSet & 0x2) != 0) {
throw new IllegalStateException(
"This Builder should not be reused. Use a new Builder instance instead");
}
diff --git a/core/java/android/service/ambientcontext/AmbientContextDetectionService.java b/core/java/android/service/ambientcontext/AmbientContextDetectionService.java
index 6224aa1d102e..8cf34115c6c4 100644
--- a/core/java/android/service/ambientcontext/AmbientContextDetectionService.java
+++ b/core/java/android/service/ambientcontext/AmbientContextDetectionService.java
@@ -134,12 +134,18 @@ public abstract class AmbientContextDetectionService extends Service {
}
/**
- * Starts detection and provides detected events to the statusConsumer. The ongoing detection
- * will keep running, until onStopDetection is called. If there were previously requested
- * detection from the same package, the previous request will be replaced with the new request.
- * The implementation should keep track of whether the user consented each requested
- * AmbientContextEvent for the app. If not consented, the statusConsumer should get a response
- * with STATUS_ACCESS_DENIED.
+ * Called when a client app requests starting detection of the events in the request. The
+ * implementation should keep track of whether the user has explicitly consented to detecting
+ * the events using on-going ambient sensor (e.g. microphone), and agreed to share the
+ * detection results with this client app. If the user has not consented, the detection
+ * should not start, and the statusConsumer should get a response with STATUS_ACCESS_DENIED.
+ * If the user has made the consent and the underlying services are available, the
+ * implementation should start detection and provide detected events to the
+ * detectionResultConsumer. If the type of event needs immediate attention, the implementation
+ * should send result as soon as detected. Otherwise, the implementation can bulk send response.
+ * The ongoing detection will keep running, until onStopDetection is called. If there were
+ * previously requested detection from the same package, regardless of the type of events in
+ * the request, the previous request will be replaced with the new request.
*
* @param request The request with events to detect.
* @param packageName the requesting app's package name
diff --git a/core/java/android/service/ambientcontext/AmbientContextDetectionServiceStatus.java b/core/java/android/service/ambientcontext/AmbientContextDetectionServiceStatus.java
index 3e92f39893de..199e674e4b54 100644
--- a/core/java/android/service/ambientcontext/AmbientContextDetectionServiceStatus.java
+++ b/core/java/android/service/ambientcontext/AmbientContextDetectionServiceStatus.java
@@ -24,6 +24,8 @@ import android.os.Parcelable;
import com.android.internal.util.AnnotationValidations;
+import java.util.Objects;
+
/**
* Represents a status for the {@code AmbientContextDetectionService}.
*
@@ -121,7 +123,9 @@ public final class AmbientContextDetectionServiceStatus implements Parcelable {
private @NonNull String mPackageName;
private long mBuilderFieldsSet = 0L;
- public Builder() {
+ public Builder(@NonNull String packageName) {
+ Objects.requireNonNull(packageName);
+ mPackageName = packageName;
}
/**
@@ -134,27 +138,14 @@ public final class AmbientContextDetectionServiceStatus implements Parcelable {
return this;
}
- /**
- * The package to deliver the response to.
- */
- public @NonNull Builder setPackageName(@NonNull String value) {
- checkNotUsed();
- mBuilderFieldsSet |= 0x2;
- mPackageName = value;
- return this;
- }
-
/** Builds the instance. This builder should not be touched after calling this! */
public @NonNull AmbientContextDetectionServiceStatus build() {
checkNotUsed();
- mBuilderFieldsSet |= 0x4; // Mark builder used
+ mBuilderFieldsSet |= 0x2; // Mark builder used
if ((mBuilderFieldsSet & 0x1) == 0) {
mStatusCode = AmbientContextManager.STATUS_UNKNOWN;
}
- if ((mBuilderFieldsSet & 0x2) == 0) {
- mPackageName = "";
- }
AmbientContextDetectionServiceStatus o = new AmbientContextDetectionServiceStatus(
mStatusCode,
mPackageName);
@@ -162,7 +153,7 @@ public final class AmbientContextDetectionServiceStatus implements Parcelable {
}
private void checkNotUsed() {
- if ((mBuilderFieldsSet & 0x4) != 0) {
+ if ((mBuilderFieldsSet & 0x2) != 0) {
throw new IllegalStateException(
"This Builder should not be reused. Use a new Builder instance instead");
}
diff --git a/core/java/android/service/autofill/FillEventHistory.java b/core/java/android/service/autofill/FillEventHistory.java
index 7a8f6f415fbf..0fb9f57f5f57 100644
--- a/core/java/android/service/autofill/FillEventHistory.java
+++ b/core/java/android/service/autofill/FillEventHistory.java
@@ -160,6 +160,7 @@ public final class FillEventHistory implements Parcelable {
event.mDetectedFieldClassifications);
}
parcel.writeInt(event.mSaveDialogNotShowReason);
+ parcel.writeInt(event.mUiType);
}
}
}
@@ -278,6 +279,29 @@ public final class FillEventHistory implements Parcelable {
@Retention(RetentionPolicy.SOURCE)
public @interface NoSaveReason{}
+ /** The autofill suggestion presentation is unknown, this will be set for the event
+ * that is unrelated to fill Ui presentation */
+ public static final int UI_TYPE_UNKNOWN = 0;
+
+ /** The autofill suggestion is shown as a menu popup presentation. */
+ public static final int UI_TYPE_MENU = 1;
+
+ /** The autofill suggestion is shown as a keyboard inline presentation. */
+ public static final int UI_TYPE_INLINE = 2;
+
+ /** The autofill suggestion is shown as a dialog presentation. */
+ public static final int UI_TYPE_DIALOG = 3;
+
+ /** @hide */
+ @IntDef(prefix = { "UI_TYPE_" }, value = {
+ UI_TYPE_UNKNOWN,
+ UI_TYPE_MENU,
+ UI_TYPE_INLINE,
+ UI_TYPE_DIALOG
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface UiType {}
+
@EventIds private final int mEventType;
@Nullable private final String mDatasetId;
@Nullable private final Bundle mClientState;
@@ -298,6 +322,10 @@ public final class FillEventHistory implements Parcelable {
@NoSaveReason private final int mSaveDialogNotShowReason;
+
+ @UiType
+ private final int mUiType;
+
/**
* Returns the type of the event.
*
@@ -498,6 +526,21 @@ public final class FillEventHistory implements Parcelable {
}
/**
+ * Returns fill suggestion ui presentation type which corresponds to types
+ * defined in {@link android.service.autofill.Presentations).
+ *
+ * <p><b>Note: </b>Only set on events of type {@link #TYPE_DATASETS_SHOWN} and
+ * {@link #TYPE_DATASET_SELECTED}. For the other event types, the type is set to
+ * {@link #UI_TYPE_UNKNOWN }.
+ *
+ * @return The ui presentation type shown for user.
+ */
+ @UiType
+ public int getUiType() {
+ return mUiType;
+ }
+
+ /**
* Creates a new event.
*
* @param eventType The type of the event
@@ -573,6 +616,49 @@ public final class FillEventHistory implements Parcelable {
@Nullable AutofillId[] detectedFieldIds,
@Nullable FieldClassification[] detectedFieldClassifications,
int saveDialogNotShowReason) {
+ this(eventType, datasetId, clientState, selectedDatasetIds, ignoredDatasetIds,
+ changedFieldIds, changedDatasetIds, manuallyFilledFieldIds,
+ manuallyFilledDatasetIds, detectedFieldIds, detectedFieldClassifications,
+ saveDialogNotShowReason, UI_TYPE_UNKNOWN);
+ }
+
+ /**
+ * Creates a new event.
+ *
+ * @param eventType The type of the event
+ * @param datasetId The dataset the event was on, or {@code null} if the event was on the
+ * whole response.
+ * @param clientState The client state associated with the event.
+ * @param selectedDatasetIds The ids of datasets selected by the user.
+ * @param ignoredDatasetIds The ids of datasets NOT select by the user.
+ * @param changedFieldIds The ids of fields changed by the user.
+ * @param changedDatasetIds The ids of the datasets that havd values matching the
+ * respective entry on {@code changedFieldIds}.
+ * @param manuallyFilledFieldIds The ids of fields that were manually entered by the user
+ * and belonged to datasets.
+ * @param manuallyFilledDatasetIds The ids of datasets that had values matching the
+ * respective entry on {@code manuallyFilledFieldIds}.
+ * @param detectedFieldClassifications the field classification matches.
+ * @param saveDialogNotShowReason The reason why a save dialog was not shown.
+ * @param uiType The ui presentation type for fill suggestion.
+ *
+ * @throws IllegalArgumentException If the length of {@code changedFieldIds} and
+ * {@code changedDatasetIds} doesn't match.
+ * @throws IllegalArgumentException If the length of {@code manuallyFilledFieldIds} and
+ * {@code manuallyFilledDatasetIds} doesn't match.
+ *
+ * @hide
+ */
+ public Event(int eventType, @Nullable String datasetId, @Nullable Bundle clientState,
+ @Nullable List<String> selectedDatasetIds,
+ @Nullable ArraySet<String> ignoredDatasetIds,
+ @Nullable ArrayList<AutofillId> changedFieldIds,
+ @Nullable ArrayList<String> changedDatasetIds,
+ @Nullable ArrayList<AutofillId> manuallyFilledFieldIds,
+ @Nullable ArrayList<ArrayList<String>> manuallyFilledDatasetIds,
+ @Nullable AutofillId[] detectedFieldIds,
+ @Nullable FieldClassification[] detectedFieldClassifications,
+ int saveDialogNotShowReason, int uiType) {
mEventType = Preconditions.checkArgumentInRange(eventType, 0, TYPE_DATASETS_SHOWN,
"eventType");
mDatasetId = datasetId;
@@ -581,16 +667,16 @@ public final class FillEventHistory implements Parcelable {
mIgnoredDatasetIds = ignoredDatasetIds;
if (changedFieldIds != null) {
Preconditions.checkArgument(!ArrayUtils.isEmpty(changedFieldIds)
- && changedDatasetIds != null
- && changedFieldIds.size() == changedDatasetIds.size(),
+ && changedDatasetIds != null
+ && changedFieldIds.size() == changedDatasetIds.size(),
"changed ids must have same length and not be empty");
}
mChangedFieldIds = changedFieldIds;
mChangedDatasetIds = changedDatasetIds;
if (manuallyFilledFieldIds != null) {
Preconditions.checkArgument(!ArrayUtils.isEmpty(manuallyFilledFieldIds)
- && manuallyFilledDatasetIds != null
- && manuallyFilledFieldIds.size() == manuallyFilledDatasetIds.size(),
+ && manuallyFilledDatasetIds != null
+ && manuallyFilledFieldIds.size() == manuallyFilledDatasetIds.size(),
"manually filled ids must have same length and not be empty");
}
mManuallyFilledFieldIds = manuallyFilledFieldIds;
@@ -602,12 +688,14 @@ public final class FillEventHistory implements Parcelable {
mSaveDialogNotShowReason = Preconditions.checkArgumentInRange(saveDialogNotShowReason,
NO_SAVE_UI_REASON_NONE, NO_SAVE_UI_REASON_DATASET_MATCH,
"saveDialogNotShowReason");
+ mUiType = uiType;
}
@Override
public String toString() {
return "FillEvent [datasetId=" + mDatasetId
- + ", type=" + mEventType
+ + ", type=" + eventToString(mEventType)
+ + ", uiType=" + uiTypeToString(mUiType)
+ ", selectedDatasets=" + mSelectedDatasetIds
+ ", ignoredDatasetIds=" + mIgnoredDatasetIds
+ ", changedFieldIds=" + mChangedFieldIds
@@ -620,6 +708,38 @@ public final class FillEventHistory implements Parcelable {
+ ", saveDialogNotShowReason=" + mSaveDialogNotShowReason
+ "]";
}
+
+ private static String eventToString(int eventType) {
+ switch (eventType) {
+ case TYPE_DATASET_SELECTED:
+ return "TYPE_DATASET_SELECTED";
+ case TYPE_DATASET_AUTHENTICATION_SELECTED:
+ return "TYPE_DATASET_AUTHENTICATION_SELECTED";
+ case TYPE_AUTHENTICATION_SELECTED:
+ return "TYPE_AUTHENTICATION_SELECTED";
+ case TYPE_SAVE_SHOWN:
+ return "TYPE_SAVE_SHOWN";
+ case TYPE_CONTEXT_COMMITTED:
+ return "TYPE_CONTEXT_COMMITTED";
+ case TYPE_DATASETS_SHOWN:
+ return "TYPE_DATASETS_SHOWN";
+ default:
+ return "TYPE_UNKNOWN";
+ }
+ }
+
+ private static String uiTypeToString(int uiType) {
+ switch (uiType) {
+ case UI_TYPE_MENU:
+ return "UI_TYPE_MENU";
+ case UI_TYPE_INLINE:
+ return "UI_TYPE_INLINE";
+ case UI_TYPE_DIALOG:
+ return "UI_TYPE_FILL_DIALOG";
+ default:
+ return "UI_TYPE_UNKNOWN";
+ }
+ }
}
public static final @android.annotation.NonNull Parcelable.Creator<FillEventHistory> CREATOR =
@@ -660,13 +780,14 @@ public final class FillEventHistory implements Parcelable {
? FieldClassification.readArrayFromParcel(parcel)
: null;
final int saveDialogNotShowReason = parcel.readInt();
+ final int uiType = parcel.readInt();
selection.addEvent(new Event(eventType, datasetId, clientState,
selectedDatasetIds, ignoredDatasets,
changedFieldIds, changedDatasetIds,
manuallyFilledFieldIds, manuallyFilledDatasetIds,
detectedFieldIds, detectedFieldClassifications,
- saveDialogNotShowReason));
+ saveDialogNotShowReason, uiType));
}
return selection;
}
diff --git a/core/java/android/service/autofill/FillRequest.java b/core/java/android/service/autofill/FillRequest.java
index e4d3732361ed..c73ebed3c368 100644
--- a/core/java/android/service/autofill/FillRequest.java
+++ b/core/java/android/service/autofill/FillRequest.java
@@ -100,10 +100,10 @@ public final class FillRequest implements Parcelable {
// The flag value 0x20 has been defined in AutofillManager.
/**
- * Indicates the request is coming from the activity just started.
- * @hide
+ * Indicates the request supports fill dialog presentation for the fields, the
+ * system will send the request when the activity just started.
*/
- public static final @RequestFlags int FLAG_ACTIVITY_START = 0x40;
+ public static final @RequestFlags int FLAG_SUPPORTS_FILL_DIALOG = 0x40;
/** @hide */
public static final int INVALID_REQUEST_ID = Integer.MIN_VALUE;
@@ -140,8 +140,10 @@ public final class FillRequest implements Parcelable {
/**
* Gets the flags associated with this request.
*
- * @return any combination of {@link #FLAG_MANUAL_REQUEST} and
+ * @return any combination of {@link #FLAG_MANUAL_REQUEST},
+ * {@link #FLAG_SUPPORTS_FILL_DIALOG} and
* {@link #FLAG_COMPATIBILITY_MODE_REQUEST}.
+ *
*/
private final @RequestFlags int mFlags;
@@ -199,7 +201,7 @@ public final class FillRequest implements Parcelable {
FLAG_COMPATIBILITY_MODE_REQUEST,
FLAG_PASSWORD_INPUT_TYPE,
FLAG_VIEW_NOT_FOCUSED,
- FLAG_ACTIVITY_START
+ FLAG_SUPPORTS_FILL_DIALOG
})
@Retention(RetentionPolicy.SOURCE)
@DataClass.Generated.Member
@@ -223,8 +225,8 @@ public final class FillRequest implements Parcelable {
return "FLAG_PASSWORD_INPUT_TYPE";
case FLAG_VIEW_NOT_FOCUSED:
return "FLAG_VIEW_NOT_FOCUSED";
- case FLAG_ACTIVITY_START:
- return "FLAG_ACTIVITY_START";
+ case FLAG_SUPPORTS_FILL_DIALOG:
+ return "FLAG_SUPPORTS_FILL_DIALOG";
default: return Integer.toHexString(value);
}
}
@@ -253,7 +255,8 @@ public final class FillRequest implements Parcelable {
* @param flags
* Gets the flags associated with this request.
*
- * @return any combination of {@link #FLAG_MANUAL_REQUEST} and
+ * @return any combination of {@link #FLAG_MANUAL_REQUEST},
+ * {@link #FLAG_SUPPORTS_FILL_DIALOG} and
* {@link #FLAG_COMPATIBILITY_MODE_REQUEST}.
* @param inlineSuggestionsRequest
* Gets the {@link InlineSuggestionsRequest} associated
@@ -299,7 +302,7 @@ public final class FillRequest implements Parcelable {
| FLAG_COMPATIBILITY_MODE_REQUEST
| FLAG_PASSWORD_INPUT_TYPE
| FLAG_VIEW_NOT_FOCUSED
- | FLAG_ACTIVITY_START);
+ | FLAG_SUPPORTS_FILL_DIALOG);
this.mInlineSuggestionsRequest = inlineSuggestionsRequest;
this.mDelayedFillIntentSender = delayedFillIntentSender;
@@ -347,7 +350,8 @@ public final class FillRequest implements Parcelable {
/**
* Gets the flags associated with this request.
*
- * @return any combination of {@link #FLAG_MANUAL_REQUEST} and
+ * @return any combination of {@link #FLAG_MANUAL_REQUEST},
+ * {@link #FLAG_SUPPORTS_FILL_DIALOG} and
* {@link #FLAG_COMPATIBILITY_MODE_REQUEST}.
*/
@DataClass.Generated.Member
@@ -458,7 +462,7 @@ public final class FillRequest implements Parcelable {
| FLAG_COMPATIBILITY_MODE_REQUEST
| FLAG_PASSWORD_INPUT_TYPE
| FLAG_VIEW_NOT_FOCUSED
- | FLAG_ACTIVITY_START);
+ | FLAG_SUPPORTS_FILL_DIALOG);
this.mInlineSuggestionsRequest = inlineSuggestionsRequest;
this.mDelayedFillIntentSender = delayedFillIntentSender;
@@ -480,10 +484,10 @@ public final class FillRequest implements Parcelable {
};
@DataClass.Generated(
- time = 1643386870464L,
+ time = 1647644111186L,
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_ACTIVITY_START\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 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/service/displayhash/DisplayHashingService.java b/core/java/android/service/displayhash/DisplayHashingService.java
index f22d40ea4d5e..3fac23b61a4b 100644
--- a/core/java/android/service/displayhash/DisplayHashingService.java
+++ b/core/java/android/service/displayhash/DisplayHashingService.java
@@ -68,9 +68,6 @@ public abstract class DisplayHashingService extends Service {
private DisplayHashingServiceWrapper mWrapper;
private Handler mHandler;
- public DisplayHashingService() {
- }
-
@Override
public void onCreate() {
super.onCreate();
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index 86707598255d..001707d228b6 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -1341,7 +1341,9 @@ public class DreamService extends Service implements Window.Callback {
public void onViewDetachedFromWindow(View v) {
if (mActivity == null || !mActivity.isChangingConfigurations()) {
// Only stop the dream if the view is not detached by relaunching
- // activity for configuration changes.
+ // activity for configuration changes. It is important to also clear
+ // the window reference in order to fully release the DreamActivity.
+ mWindow = null;
mActivity = null;
finish();
}
diff --git a/core/java/android/service/dreams/OWNERS b/core/java/android/service/dreams/OWNERS
index f8318054ddfc..489a5f62b49d 100644
--- a/core/java/android/service/dreams/OWNERS
+++ b/core/java/android/service/dreams/OWNERS
@@ -1,3 +1,8 @@
# Bug component: 78010
+brycelee@google.com
dsandler@google.com
+galinap@google.com
+jjaggi@google.com
+michaelwr@google.com
+santoscordon@google.com
diff --git a/core/java/android/service/games/GameScreenshotResult.java b/core/java/android/service/games/GameScreenshotResult.java
index ae76e08c7971..5490aef0e225 100644
--- a/core/java/android/service/games/GameScreenshotResult.java
+++ b/core/java/android/service/games/GameScreenshotResult.java
@@ -18,8 +18,6 @@ package android.service.games;
import android.annotation.IntDef;
import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.graphics.Bitmap;
import android.os.Parcel;
import android.os.Parcelable;
@@ -30,9 +28,7 @@ import java.util.Objects;
/**
* Result object for calls to {@link IGameSessionController#takeScreenshot}.
*
- * It includes a status (see {@link #getStatus}) and, if the status is
- * {@link #GAME_SCREENSHOT_SUCCESS} an {@link android.graphics.Bitmap} result (see {@link
- * #getBitmap}).
+ * It includes a status only (see {@link #getStatus}).
*
* @hide
*/
@@ -54,8 +50,7 @@ public final class GameScreenshotResult implements Parcelable {
/**
* Indicates that the result of a call to {@link IGameSessionController#takeScreenshot} was
- * successful and an {@link android.graphics.Bitmap} result should be available by calling
- * {@link #getBitmap}.
+ * successful.
*
* @hide
*/
@@ -81,9 +76,7 @@ public final class GameScreenshotResult implements Parcelable {
new Parcelable.Creator<GameScreenshotResult>() {
@Override
public GameScreenshotResult createFromParcel(Parcel source) {
- return new GameScreenshotResult(
- source.readInt(),
- source.readParcelable(null, Bitmap.class));
+ return new GameScreenshotResult(source.readInt());
}
@Override
@@ -95,14 +88,11 @@ public final class GameScreenshotResult implements Parcelable {
@GameScreenshotStatus
private final int mStatus;
- @Nullable
- private final Bitmap mBitmap;
-
/**
- * Creates a successful {@link GameScreenshotResult} with the provided bitmap.
+ * Creates a successful {@link GameScreenshotResult}.
*/
- public static GameScreenshotResult createSuccessResult(@NonNull Bitmap bitmap) {
- return new GameScreenshotResult(GAME_SCREENSHOT_SUCCESS, bitmap);
+ public static GameScreenshotResult createSuccessResult() {
+ return new GameScreenshotResult(GAME_SCREENSHOT_SUCCESS);
}
/**
@@ -110,12 +100,11 @@ public final class GameScreenshotResult implements Parcelable {
* {@link #GAME_SCREENSHOT_ERROR_INTERNAL_ERROR} status.
*/
public static GameScreenshotResult createInternalErrorResult() {
- return new GameScreenshotResult(GAME_SCREENSHOT_ERROR_INTERNAL_ERROR, null);
+ return new GameScreenshotResult(GAME_SCREENSHOT_ERROR_INTERNAL_ERROR);
}
- private GameScreenshotResult(@GameScreenshotStatus int status, @Nullable Bitmap bitmap) {
+ private GameScreenshotResult(@GameScreenshotStatus int status) {
this.mStatus = status;
- this.mBitmap = bitmap;
}
@Override
@@ -126,7 +115,6 @@ public final class GameScreenshotResult implements Parcelable {
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeInt(mStatus);
- dest.writeParcelable(mBitmap, flags);
}
@GameScreenshotStatus
@@ -134,29 +122,12 @@ public final class GameScreenshotResult implements Parcelable {
return mStatus;
}
- /**
- * Gets the {@link Bitmap} result from a successful screenshot attempt.
- *
- * @return The bitmap.
- * @throws IllegalStateException if this method is called when {@link #getStatus} does not
- * return {@link #GAME_SCREENSHOT_SUCCESS}.
- */
- @NonNull
- public Bitmap getBitmap() {
- if (mBitmap == null) {
- throw new IllegalStateException("Bitmap not available for failed screenshot result");
- }
- return mBitmap;
- }
-
@Override
public String toString() {
return "GameScreenshotResult{"
+ "mStatus="
+ mStatus
- + ", has bitmap='"
- + mBitmap != null ? "yes" : "no"
- + "\'}";
+ + "}";
}
@Override
@@ -170,12 +141,11 @@ public final class GameScreenshotResult implements Parcelable {
}
GameScreenshotResult that = (GameScreenshotResult) o;
- return mStatus == that.mStatus
- && Objects.equals(mBitmap, that.mBitmap);
+ return mStatus == that.mStatus;
}
@Override
public int hashCode() {
- return Objects.hash(mStatus, mBitmap);
+ return Objects.hash(mStatus);
}
}
diff --git a/core/java/android/service/games/GameSession.java b/core/java/android/service/games/GameSession.java
index 468e087c941b..01152943efe3 100644
--- a/core/java/android/service/games/GameSession.java
+++ b/core/java/android/service/games/GameSession.java
@@ -29,7 +29,6 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
-import android.graphics.Bitmap;
import android.graphics.Rect;
import android.os.Binder;
import android.os.Bundle;
@@ -367,7 +366,7 @@ public abstract class GameSession {
}
/**
- * Interface for returning screenshot outcome from calls to {@link #takeScreenshot}.
+ * Interface for handling result of {@link #takeScreenshot}.
*/
public interface ScreenshotCallback {
@@ -402,18 +401,16 @@ public abstract class GameSession {
/**
* Called when taking the screenshot succeeded.
- *
- * @param bitmap The screenshot.
*/
- void onSuccess(@NonNull Bitmap bitmap);
+ void onSuccess();
}
/**
* Takes a screenshot of the associated game. For this call to succeed, the device screen
* must be turned on and the game task must be visible.
*
- * If the callback is called with {@link ScreenshotCallback#onSuccess}, the provided {@link
- * Bitmap} may be used.
+ * If the callback is called with {@link ScreenshotCallback#onSuccess}, the screenshot is
+ * taken successfully.
*
* If the callback is called with {@link ScreenshotCallback#onFailure}, the provided status
* code should be checked.
@@ -429,6 +426,7 @@ public abstract class GameSession {
* or failed.
* @throws IllegalStateException if this method is called prior to {@link #onCreate}.
*/
+ @RequiresPermission(android.Manifest.permission.MANAGE_GAME_ACTIVITY)
public void takeScreenshot(@NonNull Executor executor, @NonNull ScreenshotCallback callback) {
if (mGameSessionController == null) {
throw new IllegalStateException("Can not call before onCreate()");
@@ -460,7 +458,7 @@ public abstract class GameSession {
@GameScreenshotResult.GameScreenshotStatus int status = result.getStatus();
switch (status) {
case GameScreenshotResult.GAME_SCREENSHOT_SUCCESS:
- callback.onSuccess(result.getBitmap());
+ callback.onSuccess();
break;
case GameScreenshotResult.GAME_SCREENSHOT_ERROR_INTERNAL_ERROR:
Slog.w(TAG, "Error taking screenshot");
diff --git a/core/java/android/service/gatekeeper/GateKeeperResponse.java b/core/java/android/service/gatekeeper/GateKeeperResponse.java
index 7ed733cb4f4c..9d648a6995fb 100644
--- a/core/java/android/service/gatekeeper/GateKeeperResponse.java
+++ b/core/java/android/service/gatekeeper/GateKeeperResponse.java
@@ -105,7 +105,7 @@ public final class GateKeeperResponse implements Parcelable {
dest.writeInt(mTimeout);
} else if (mResponseCode == RESPONSE_OK) {
dest.writeInt(mShouldReEnroll ? 1 : 0);
- if (mPayload != null) {
+ if (mPayload != null && mPayload.length > 0) {
dest.writeInt(mPayload.length);
dest.writeByteArray(mPayload);
} else {
diff --git a/core/java/android/service/quicksettings/TileService.java b/core/java/android/service/quicksettings/TileService.java
index b507328d21a1..0829d2813c83 100644
--- a/core/java/android/service/quicksettings/TileService.java
+++ b/core/java/android/service/quicksettings/TileService.java
@@ -15,18 +15,19 @@
*/
package android.service.quicksettings;
-import android.Manifest;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.app.Dialog;
import android.app.Service;
+import android.app.StatusBarManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.graphics.drawable.Icon;
+import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
@@ -147,13 +148,6 @@ public class TileService extends Service {
"android.service.quicksettings.TOGGLEABLE_TILE";
/**
- * Used to notify SysUI that Listening has be requested.
- * @hide
- */
- public static final String ACTION_REQUEST_LISTENING =
- "android.service.quicksettings.action.REQUEST_LISTENING";
-
- /**
* @hide
*/
public static final String EXTRA_SERVICE = "service";
@@ -482,14 +476,24 @@ public class TileService extends Service {
*
* This method is only applicable to tiles that have {@link #META_DATA_ACTIVE_TILE} defined
* as true on their TileService Manifest declaration, and will do nothing otherwise.
+ *
+ * For apps targeting {@link Build.VERSION_CODES#TIRAMISU} or later, this call may throw
+ * the following exceptions if the request is not valid:
+ * <ul>
+ * <li> {@link NullPointerException} if {@code component} is {@code null}.</li>
+ * <li> {@link SecurityException} if the package of {@code component} does not match
+ * the calling package or if the calling user cannot act on behalf of the user from the
+ * {@code context}.</li>
+ * <li> {@link IllegalArgumentException} if the user of the {@code context} is not the
+ * current user.</li>
+ * </ul>
*/
public static final void requestListeningState(Context context, ComponentName component) {
- final ComponentName sysuiComponent = ComponentName.unflattenFromString(
- context.getResources().getString(
- com.android.internal.R.string.config_systemUIServiceComponent));
- Intent intent = new Intent(ACTION_REQUEST_LISTENING);
- intent.putExtra(Intent.EXTRA_COMPONENT_NAME, component);
- intent.setPackage(sysuiComponent.getPackageName());
- context.sendBroadcast(intent, Manifest.permission.BIND_QUICK_SETTINGS_TILE);
+ StatusBarManager sbm = context.getSystemService(StatusBarManager.class);
+ if (sbm == null) {
+ Log.e(TAG, "No StatusBarManager service found");
+ return;
+ }
+ sbm.requestTileServiceListeningState(component);
}
}
diff --git a/core/java/android/service/trust/GrantTrustResult.aidl b/core/java/android/service/trust/GrantTrustResult.aidl
new file mode 100644
index 000000000000..d24a6bc62f17
--- /dev/null
+++ b/core/java/android/service/trust/GrantTrustResult.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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.service.trust;
+
+parcelable GrantTrustResult;
diff --git a/core/java/android/service/trust/GrantTrustResult.java b/core/java/android/service/trust/GrantTrustResult.java
new file mode 100644
index 000000000000..7cf708a3d6e3
--- /dev/null
+++ b/core/java/android/service/trust/GrantTrustResult.java
@@ -0,0 +1,179 @@
+/*
+ * 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.service.trust;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcelable;
+
+import com.android.internal.util.DataClass;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Result type for a callback in a call to
+ * {@link TrustAgentService#grantTrust(CharSequence, long, int)}.
+ *
+ * @hide
+ */
+@DataClass(genHiddenConstructor = true)
+@SystemApi
+public final class GrantTrustResult implements Parcelable {
+
+ /** Result status is unknown to this version of the SDK. */
+ public static final int STATUS_UNKNOWN = 0;
+
+ /** The device went from locked to unlocked as a result of the call. */
+ public static final int STATUS_UNLOCKED_BY_GRANT = 1;
+
+ @Status
+ private int mStatus;
+
+ /** Returns a new {@link GrantTrustResult} with the specified status. */
+ @NonNull
+ public static GrantTrustResult withStatus(@Status int status) {
+ return new GrantTrustResult(status);
+ }
+
+
+
+ // Code below generated by codegen v1.0.23.
+ //
+ // DO NOT MODIFY!
+ // CHECKSTYLE:OFF Generated code
+ //
+ // To regenerate run:
+ // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/service/trust/GrantTrustResult.java
+ //
+ // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+ // Settings > Editor > Code Style > Formatter Control
+ //@formatter:off
+
+
+ /** @hide */
+ @IntDef(prefix = "STATUS_", value = {
+ STATUS_UNKNOWN,
+ STATUS_UNLOCKED_BY_GRANT
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @DataClass.Generated.Member
+ public @interface Status {}
+
+ @NonNull
+ @DataClass.Generated.Member
+ public static String statusToString(@Status int value) {
+ switch (value) {
+ case STATUS_UNKNOWN:
+ return "STATUS_UNKNOWN";
+ case STATUS_UNLOCKED_BY_GRANT:
+ return "STATUS_UNLOCKED_BY_GRANT";
+ default: return Integer.toHexString(value);
+ }
+ }
+
+ /**
+ * Creates a new GrantTrustResult.
+ *
+ * @hide
+ */
+ @DataClass.Generated.Member
+ public GrantTrustResult(
+ @Status int status) {
+ this.mStatus = status;
+
+ if (!(mStatus == STATUS_UNKNOWN)
+ && !(mStatus == STATUS_UNLOCKED_BY_GRANT)) {
+ throw new java.lang.IllegalArgumentException(
+ "status was " + mStatus + " but must be one of: "
+ + "STATUS_UNKNOWN(" + STATUS_UNKNOWN + "), "
+ + "STATUS_UNLOCKED_BY_GRANT(" + STATUS_UNLOCKED_BY_GRANT + ")");
+ }
+
+
+ // onConstructed(); // You can define this method to get a callback
+ }
+
+ @DataClass.Generated.Member
+ public @Status int getStatus() {
+ return mStatus;
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public void writeToParcel(@NonNull android.os.Parcel dest, int flags) {
+ // You can override field parcelling by defining methods like:
+ // void parcelFieldName(Parcel dest, int flags) { ... }
+
+ dest.writeInt(mStatus);
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public int describeContents() { return 0; }
+
+ /** @hide */
+ @SuppressWarnings({"unchecked", "RedundantCast"})
+ @DataClass.Generated.Member
+ /* package-private */ GrantTrustResult(@NonNull android.os.Parcel in) {
+ // You can override field unparcelling by defining methods like:
+ // static FieldType unparcelFieldName(Parcel in) { ... }
+
+ int status = in.readInt();
+
+ this.mStatus = status;
+
+ if (!(mStatus == STATUS_UNKNOWN)
+ && !(mStatus == STATUS_UNLOCKED_BY_GRANT)) {
+ throw new java.lang.IllegalArgumentException(
+ "status was " + mStatus + " but must be one of: "
+ + "STATUS_UNKNOWN(" + STATUS_UNKNOWN + "), "
+ + "STATUS_UNLOCKED_BY_GRANT(" + STATUS_UNLOCKED_BY_GRANT + ")");
+ }
+
+
+ // onConstructed(); // You can define this method to get a callback
+ }
+
+ @DataClass.Generated.Member
+ public static final @NonNull Parcelable.Creator<GrantTrustResult> CREATOR
+ = new Parcelable.Creator<GrantTrustResult>() {
+ @Override
+ public GrantTrustResult[] newArray(int size) {
+ return new GrantTrustResult[size];
+ }
+
+ @Override
+ public GrantTrustResult createFromParcel(@NonNull android.os.Parcel in) {
+ return new GrantTrustResult(in);
+ }
+ };
+
+ @DataClass.Generated(
+ time = 1647878197834L,
+ codegenVersion = "1.0.23",
+ sourceFile = "frameworks/base/core/java/android/service/trust/GrantTrustResult.java",
+ inputSignatures = "public static final int STATUS_UNKNOWN\npublic static final int STATUS_UNLOCKED_BY_GRANT\nprivate @android.service.trust.GrantTrustResult.Status int mStatus\npublic static @android.annotation.NonNull android.service.trust.GrantTrustResult withStatus(int)\nclass GrantTrustResult extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genHiddenConstructor=true)")
+ @Deprecated
+ private void __metadata() {}
+
+
+ //@formatter:on
+ // End of generated code
+
+}
diff --git a/core/java/android/service/trust/ITrustAgentService.aidl b/core/java/android/service/trust/ITrustAgentService.aidl
index ec3b8575ed36..70c29a682cd1 100644
--- a/core/java/android/service/trust/ITrustAgentService.aidl
+++ b/core/java/android/service/trust/ITrustAgentService.aidl
@@ -25,7 +25,8 @@ import android.service.trust.ITrustAgentServiceCallback;
*/
interface ITrustAgentService {
oneway void onUnlockAttempt(boolean successful);
- oneway void onUserRequestedUnlock();
+ oneway void onUserRequestedUnlock(boolean dismissKeyguard);
+ oneway void onUserMayRequestUnlock();
oneway void onUnlockLockout(int timeoutMs);
oneway void onTrustTimeout();
oneway void onDeviceLocked();
diff --git a/core/java/android/service/trust/ITrustAgentServiceCallback.aidl b/core/java/android/service/trust/ITrustAgentServiceCallback.aidl
index 6b11e7463abc..e9e40c0175ac 100644
--- a/core/java/android/service/trust/ITrustAgentServiceCallback.aidl
+++ b/core/java/android/service/trust/ITrustAgentServiceCallback.aidl
@@ -18,13 +18,15 @@ package android.service.trust;
import android.os.Bundle;
import android.os.IBinder;
import android.os.UserHandle;
+import com.android.internal.infra.AndroidFuture;
/**
* Communication channel from the TrustAgentService back to TrustManagerService.
* @hide
*/
oneway interface ITrustAgentServiceCallback {
- void grantTrust(CharSequence message, long durationMs, int flags);
+ void grantTrust(
+ CharSequence message, long durationMs, int flags, in AndroidFuture resultCallback);
void revokeTrust();
void lockUser();
void setManagingTrust(boolean managingTrust);
diff --git a/core/java/android/service/trust/TrustAgentService.java b/core/java/android/service/trust/TrustAgentService.java
index 8f6e1e00c3f4..559313a30dfa 100644
--- a/core/java/android/service/trust/TrustAgentService.java
+++ b/core/java/android/service/trust/TrustAgentService.java
@@ -19,6 +19,7 @@ package android.service.trust;
import android.Manifest;
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.SdkConstant;
import android.annotation.SystemApi;
import android.app.Service;
@@ -39,9 +40,12 @@ import android.os.UserManager;
import android.util.Log;
import android.util.Slog;
+import com.android.internal.infra.AndroidFuture;
+
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.List;
+import java.util.function.Consumer;
/**
* A service that notifies the system about whether it believes the environment of the device
@@ -183,6 +187,7 @@ public class TrustAgentService extends Service {
private static final int MSG_ESCROW_TOKEN_STATE_RECEIVED = 8;
private static final int MSG_ESCROW_TOKEN_REMOVED = 9;
private static final int MSG_USER_REQUESTED_UNLOCK = 10;
+ private static final int MSG_USER_MAY_REQUEST_UNLOCK = 11;
private static final String EXTRA_TOKEN = "token";
private static final String EXTRA_TOKEN_HANDLE = "token_handle";
@@ -217,7 +222,10 @@ public class TrustAgentService extends Service {
onUnlockAttempt(msg.arg1 != 0);
break;
case MSG_USER_REQUESTED_UNLOCK:
- onUserRequestedUnlock();
+ onUserRequestedUnlock(msg.arg1 != 0);
+ break;
+ case MSG_USER_MAY_REQUEST_UNLOCK:
+ onUserMayRequestUnlock();
break;
case MSG_UNLOCK_LOCKOUT:
onDeviceUnlockLockout(msg.arg1);
@@ -297,16 +305,37 @@ public class TrustAgentService extends Service {
}
/**
+ * Called when the user has interacted with the locked device such that they are likely to want
+ * it to be unlocked soon. This approximates the timing when, for example, the platform would
+ * check for face authentication to unlock the device.
+ *
+ * This signal can be used for the agent to make preparations to quickly unlock the device
+ * with {@link #onUserRequestedUnlock}. Agents should not unlock the device based solely on this
+ * signal. There is no guarantee that this method will be called before
+ * {@link #onUserRequestedUnlock(boolean)}.
+ */
+ public void onUserMayRequestUnlock() {
+ }
+
+ /**
* Called when the user has interacted with the locked device such that they likely want it
- * to be unlocked. This approximates the timing when, for example, the platform would check for
- * face authentication to unlock the device.
+ * to be unlocked.
+ *
+ * When this is called, there is a high probability that the user wants to unlock the device and
+ * that a biometric method is either not available or not the optimal method at this time. For
+ * example, this may be called after some kinds of biometric authentication failure.
+ *
+ * A call to this method may be preceded by a call to {@link #onUserMayRequestUnlock} which
+ * the agent can use as a signal to prepare for a subsequent call to this method.
*
* To attempt to unlock the device, the agent needs to call
* {@link #grantTrust(CharSequence, long, int)}.
*
+ * @param dismissKeyguard true when the user wants keyguard dismissed
+ *
* @see #FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE
*/
- public void onUserRequestedUnlock() {
+ public void onUserRequestedUnlock(boolean dismissKeyguard) {
}
/**
@@ -399,26 +428,10 @@ public class TrustAgentService extends Service {
}
/**
- * Call to grant trust on the device.
- *
- * @param message describes why the device is trusted, e.g. "Trusted by location".
- * @param durationMs amount of time in milliseconds to keep the device in a trusted state.
- * Trust for this agent will automatically be revoked when the timeout expires unless
- * extended by a subsequent call to this function. The timeout is measured from the
- * invocation of this function as dictated by {@link SystemClock#elapsedRealtime())}.
- * For security reasons, the value should be no larger than necessary.
- * The value may be adjusted by the system as necessary to comply with a policy controlled
- * by the system or {@link DevicePolicyManager} restrictions. See {@link #onTrustTimeout()}
- * for determining when trust expires.
- * @param initiatedByUser this is a hint to the system that trust is being granted as the
- * direct result of user action - such as solving a security challenge. The hint is used
- * by the system to optimize the experience. Behavior may vary by device and release, so
- * one should only set this parameter if it meets the above criteria rather than relying on
- * the behavior of any particular device or release. Corresponds to
- * {@link #FLAG_GRANT_TRUST_INITIATED_BY_USER}.
- * @throws IllegalStateException if the agent is not currently managing trust.
+ * Attempts to grant trust on the device.
*
- * @deprecated use {@link #grantTrust(CharSequence, long, int)} instead.
+ * @param initiatedByUser see {@link #FLAG_GRANT_TRUST_INITIATED_BY_USER}
+ * @deprecated use {@link #grantTrust(CharSequence, long, int, Consumer)} instead.
*/
@Deprecated
public final void grantTrust(
@@ -427,7 +440,17 @@ public class TrustAgentService extends Service {
}
/**
- * Call to grant trust on the device.
+ * Attempts to grant trust on the device.
+ * @deprecated use {@link #grantTrust(CharSequence, long, int, Consumer)} instead.
+ */
+ @Deprecated
+ public final void grantTrust(
+ final CharSequence message, final long durationMs, @GrantTrustFlags final int flags) {
+ grantTrust(message, durationMs, flags, null);
+ }
+
+ /**
+ * Attempts to grant trust on the device.
*
* @param message describes why the device is trusted, e.g. "Trusted by location".
* @param durationMs amount of time in milliseconds to keep the device in a trusted state.
@@ -438,19 +461,36 @@ public class TrustAgentService extends Service {
* The value may be adjusted by the system as necessary to comply with a policy controlled
* by the system or {@link DevicePolicyManager} restrictions. See {@link #onTrustTimeout()}
* for determining when trust expires.
- * @param flags TBDocumented
+ * @param flags flags to control call: see constants prefixed by {@code FLAG_GRANT_TRUST_}.
+ * @param resultCallback may be called with the results of the grant
* @throws IllegalStateException if the agent is not currently managing trust.
+ *
+ * See {@link GrantTrustResult} for the cases where {@code resultCallback} will be called.
*/
public final void grantTrust(
- final CharSequence message, final long durationMs, @GrantTrustFlags final int flags) {
+ @NonNull final CharSequence message,
+ final long durationMs,
+ @GrantTrustFlags final int flags,
+ @Nullable final Consumer<GrantTrustResult> resultCallback) {
synchronized (mLock) {
if (!mManagingTrust) {
throw new IllegalStateException("Cannot grant trust if agent is not managing trust."
+ " Call setManagingTrust(true) first.");
}
+
+ // Prepare future for the IPC
+ AndroidFuture<GrantTrustResult> future = new AndroidFuture<>();
+ future.thenAccept(result -> {
+ if (resultCallback != null) {
+ // Instead of taking an explicit executor, we post this to mHandler to be
+ // consistent with the other event methods in this class.
+ mHandler.post(() -> resultCallback.accept(result));
+ }
+ });
+
if (mCallback != null) {
try {
- mCallback.grantTrust(message.toString(), durationMs, flags);
+ mCallback.grantTrust(message.toString(), durationMs, flags, future);
} catch (RemoteException e) {
onError("calling enableTrust()");
}
@@ -460,7 +500,7 @@ public class TrustAgentService extends Service {
mPendingGrantTrustTask = new Runnable() {
@Override
public void run() {
- grantTrust(message, durationMs, flags);
+ grantTrust(message, durationMs, flags, resultCallback);
}
};
}
@@ -666,8 +706,14 @@ public class TrustAgentService extends Service {
}
@Override
- public void onUserRequestedUnlock() {
- mHandler.obtainMessage(MSG_USER_REQUESTED_UNLOCK).sendToTarget();
+ public void onUserRequestedUnlock(boolean dismissKeyguard) {
+ mHandler.obtainMessage(MSG_USER_REQUESTED_UNLOCK, dismissKeyguard ? 1 : 0, 0)
+ .sendToTarget();
+ }
+
+ @Override
+ public void onUserMayRequestUnlock() {
+ mHandler.obtainMessage(MSG_USER_MAY_REQUEST_UNLOCK).sendToTarget();
}
@Override
diff --git a/core/java/android/service/voice/AlwaysOnHotwordDetector.java b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
index bec5d1be57fd..bc42da6b4c97 100644
--- a/core/java/android/service/voice/AlwaysOnHotwordDetector.java
+++ b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
@@ -851,7 +851,8 @@ public class AlwaysOnHotwordDetector extends AbstractHotwordDetector {
@RequiresPermission(allOf = {RECORD_AUDIO, CAPTURE_AUDIO_HOTWORD})
public void triggerHardwareRecognitionEventForTest(int status, int soundModelHandle,
boolean captureAvailable, int captureSession, int captureDelayMs, int capturePreambleMs,
- boolean triggerInData, @NonNull AudioFormat captureFormat, @Nullable byte[] data) {
+ boolean triggerInData, @NonNull AudioFormat captureFormat, @Nullable byte[] data,
+ @NonNull List<KeyphraseRecognitionExtra> keyphraseRecognitionExtras) {
Log.d(TAG, "triggerHardwareRecognitionEventForTest()");
synchronized (mLock) {
if (mAvailability == STATE_INVALID || mAvailability == STATE_ERROR) {
@@ -862,7 +863,8 @@ public class AlwaysOnHotwordDetector extends AbstractHotwordDetector {
mModelManagementService.triggerHardwareRecognitionEventForTest(
new KeyphraseRecognitionEvent(status, soundModelHandle, captureAvailable,
captureSession, captureDelayMs, capturePreambleMs, triggerInData,
- captureFormat, data, null /* keyphraseExtras */),
+ captureFormat, data, keyphraseRecognitionExtras.toArray(
+ new KeyphraseRecognitionExtra[0])),
mInternalCallback);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index a2938a8783eb..317408387526 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -252,6 +252,7 @@ public abstract class WallpaperService extends Service {
final InsetsVisibilities mRequestedVisibilities = new InsetsVisibilities();
final InsetsSourceControl[] mTempControls = new InsetsSourceControl[0];
final MergedConfiguration mMergedConfiguration = new MergedConfiguration();
+ final Bundle mSyncSeqIdBundle = new Bundle();
private final Point mSurfaceSize = new Point();
private final Point mLastSurfaceSize = new Point();
private final Matrix mTmpMatrix = new Matrix();
@@ -391,7 +392,7 @@ public abstract class WallpaperService extends Service {
@Override
public void resized(ClientWindowFrames frames, boolean reportDraw,
MergedConfiguration mergedConfiguration, boolean forceLayout,
- boolean alwaysConsumeSystemBars, int displayId) {
+ boolean alwaysConsumeSystemBars, int displayId, int syncSeqId, int resizeMode) {
Message msg = mCaller.obtainMessageIO(MSG_WINDOW_RESIZED,
reportDraw ? 1 : 0,
mergedConfiguration);
@@ -1151,7 +1152,7 @@ public abstract class WallpaperService extends Service {
final int relayoutResult = mSession.relayout(
mWindow, mLayout, mWidth, mHeight,
View.VISIBLE, 0, mWinFrames, mMergedConfiguration, mSurfaceControl,
- mInsetsState, mTempControls);
+ mInsetsState, mTempControls, mSyncSeqIdBundle);
final int transformHint = SurfaceControl.rotationToBufferTransform(
(mDisplayInstallOrientation + mDisplay.getRotation()) % 4);
@@ -1338,7 +1339,8 @@ public abstract class WallpaperService extends Service {
mSurfaceCreated = true;
if (redrawNeeded) {
resetWindowPages();
- mSession.finishDrawing(mWindow, null /* postDrawTransaction */);
+ mSession.finishDrawing(mWindow, null /* postDrawTransaction */,
+ Integer.MAX_VALUE);
processLocalColors(mPendingXOffset, mPendingXOffsetStep);
notifyColorsChanged();
}
diff --git a/core/java/android/telephony/TelephonyRegistryManager.java b/core/java/android/telephony/TelephonyRegistryManager.java
index c1fcd664f6fa..f8445921d3b0 100644
--- a/core/java/android/telephony/TelephonyRegistryManager.java
+++ b/core/java/android/telephony/TelephonyRegistryManager.java
@@ -27,6 +27,7 @@ import android.os.Binder;
import android.os.Build;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.service.carrier.CarrierService;
import android.telephony.Annotation.CallState;
import android.telephony.Annotation.DataActivityType;
import android.telephony.Annotation.DisconnectCauses;
@@ -36,6 +37,7 @@ import android.telephony.Annotation.PreciseDisconnectCauses;
import android.telephony.Annotation.RadioPowerState;
import android.telephony.Annotation.SimActivationState;
import android.telephony.Annotation.SrvccState;
+import android.telephony.TelephonyManager.CarrierPrivilegesCallback;
import android.telephony.TelephonyManager.CarrierPrivilegesListener;
import android.telephony.emergency.EmergencyNumber;
import android.telephony.ims.ImsReasonInfo;
@@ -44,17 +46,19 @@ import android.util.Log;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.listeners.ListenerExecutor;
-import com.android.internal.telephony.ICarrierPrivilegesListener;
+import com.android.internal.telephony.ICarrierPrivilegesCallback;
import com.android.internal.telephony.IOnSubscriptionsChangedListener;
import com.android.internal.telephony.ITelephonyRegistry;
import java.lang.ref.WeakReference;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;
import java.util.concurrent.Executor;
+import java.util.stream.Collectors;
/**
* A centralized place to notify telephony related status changes, e.g, {@link ServiceState} update
@@ -1260,34 +1264,78 @@ public class TelephonyRegistryManager {
pkgName, attributionTag, callback, new int[0], notifyNow);
}
- private static class CarrierPrivilegesListenerWrapper extends ICarrierPrivilegesListener.Stub
+ // TODO(b/216549778): Remove listener logic once all clients switch to CarrierPrivilegesCallback
+ private static class CarrierPrivilegesCallbackWrapper extends ICarrierPrivilegesCallback.Stub
implements ListenerExecutor {
- private final WeakReference<CarrierPrivilegesListener> mListener;
- private final Executor mExecutor;
+ // Either mListener or mCallback may be null, never both
+ @Nullable private final WeakReference<CarrierPrivilegesListener> mListener;
+ @Nullable private final WeakReference<CarrierPrivilegesCallback> mCallback;
+ @NonNull private final Executor mExecutor;
+
+ CarrierPrivilegesCallbackWrapper(
+ @NonNull CarrierPrivilegesCallback callback, @NonNull Executor executor) {
+ mListener = null;
+ mCallback = new WeakReference<>(callback);
+ mExecutor = executor;
+ }
- CarrierPrivilegesListenerWrapper(CarrierPrivilegesListener listener, Executor executor) {
+ CarrierPrivilegesCallbackWrapper(
+ @NonNull CarrierPrivilegesListener listener, @NonNull Executor executor) {
mListener = new WeakReference<>(listener);
+ mCallback = null;
mExecutor = executor;
}
@Override
public void onCarrierPrivilegesChanged(
- List<String> privilegedPackageNames, int[] privilegedUids) {
- Binder.withCleanCallingIdentity(
- () ->
- executeSafely(
- mExecutor,
- mListener::get,
- cpl ->
- cpl.onCarrierPrivilegesChanged(
- privilegedPackageNames, privilegedUids)));
+ @NonNull List<String> privilegedPackageNames, @NonNull int[] privilegedUids) {
+ if (mListener != null) {
+ Binder.withCleanCallingIdentity(
+ () ->
+ executeSafely(
+ mExecutor,
+ mListener::get,
+ cpl ->
+ cpl.onCarrierPrivilegesChanged(
+ privilegedPackageNames, privilegedUids)));
+ }
+
+ if (mCallback != null) {
+ // AIDL interface does not support Set, keep the List/Array and translate them here
+ Set<String> privilegedPkgNamesSet = Set.copyOf(privilegedPackageNames);
+ Set<Integer> privilegedUidsSet = Arrays.stream(privilegedUids).boxed().collect(
+ Collectors.toSet());
+ Binder.withCleanCallingIdentity(
+ () ->
+ executeSafely(
+ mExecutor,
+ mCallback::get,
+ cpc ->
+ cpc.onCarrierPrivilegesChanged(
+ privilegedPkgNamesSet, privilegedUidsSet)));
+ }
+ }
+
+ @Override
+ public void onCarrierServiceChanged(@Nullable String packageName, int uid) {
+ if (mCallback != null) {
+ Binder.withCleanCallingIdentity(
+ () ->
+ executeSafely(
+ mExecutor,
+ mCallback::get,
+ cpc -> cpc.onCarrierServiceChanged(packageName, uid)));
+ }
}
}
- @GuardedBy("sCarrierPrivilegeListeners")
- private static final WeakHashMap<
- CarrierPrivilegesListener, WeakReference<CarrierPrivilegesListenerWrapper>>
- sCarrierPrivilegeListeners = new WeakHashMap<>();
+ // TODO(b/216549778): Change the map key to CarrierPrivilegesCallback once all clients switch to
+ // CarrierPrivilegesCallback. Before that, the key is either CarrierPrivilegesCallback or
+ // CarrierPrivilegesListener, no logic actually depends on the type.
+ @NonNull
+ @GuardedBy("sCarrierPrivilegeCallbacks")
+ private static final WeakHashMap<Object, WeakReference<CarrierPrivilegesCallbackWrapper>>
+ sCarrierPrivilegeCallbacks = new WeakHashMap<>();
/**
* Registers a {@link CarrierPrivilegesListener} on the given {@code logicalSlotIndex} to
@@ -1297,7 +1345,11 @@ public class TelephonyRegistryManager {
* @param logicalSlotIndex The SIM slot to listen on
* @param executor The executor where {@code listener} will be invoked
* @param listener The callback to register
+ *
+ * @deprecated Use {@link #addCarrierPrivilegesCallback} instead. This API will be removed
+ * prior to API finalization.
*/
+ @Deprecated
public void addCarrierPrivilegesListener(
int logicalSlotIndex,
@NonNull @CallbackExecutor Executor executor,
@@ -1305,18 +1357,18 @@ public class TelephonyRegistryManager {
if (listener == null || executor == null) {
throw new IllegalArgumentException("listener and executor must be non-null");
}
- synchronized (sCarrierPrivilegeListeners) {
- WeakReference<CarrierPrivilegesListenerWrapper> existing =
- sCarrierPrivilegeListeners.get(listener);
+ synchronized (sCarrierPrivilegeCallbacks) {
+ WeakReference<CarrierPrivilegesCallbackWrapper> existing =
+ sCarrierPrivilegeCallbacks.get(listener);
if (existing != null && existing.get() != null) {
Log.d(TAG, "addCarrierPrivilegesListener: listener already registered");
return;
}
- CarrierPrivilegesListenerWrapper wrapper =
- new CarrierPrivilegesListenerWrapper(listener, executor);
- sCarrierPrivilegeListeners.put(listener, new WeakReference<>(wrapper));
+ CarrierPrivilegesCallbackWrapper wrapper =
+ new CarrierPrivilegesCallbackWrapper(listener, executor);
+ sCarrierPrivilegeCallbacks.put(listener, new WeakReference<>(wrapper));
try {
- sRegistry.addCarrierPrivilegesListener(
+ sRegistry.addCarrierPrivilegesCallback(
logicalSlotIndex,
wrapper,
mContext.getOpPackageName(),
@@ -1331,19 +1383,84 @@ public class TelephonyRegistryManager {
* Unregisters a {@link CarrierPrivilegesListener}.
*
* @param listener The callback to unregister
+ *
+ * @deprecated Use {@link #removeCarrierPrivilegesCallback} instead. The callback will prior
+ * to API finalization.
*/
+ @Deprecated
public void removeCarrierPrivilegesListener(@NonNull CarrierPrivilegesListener listener) {
if (listener == null) {
throw new IllegalArgumentException("listener must be non-null");
}
- synchronized (sCarrierPrivilegeListeners) {
- WeakReference<CarrierPrivilegesListenerWrapper> ref =
- sCarrierPrivilegeListeners.remove(listener);
+ synchronized (sCarrierPrivilegeCallbacks) {
+ WeakReference<CarrierPrivilegesCallbackWrapper> ref =
+ sCarrierPrivilegeCallbacks.remove(listener);
if (ref == null) return;
- CarrierPrivilegesListenerWrapper wrapper = ref.get();
+ CarrierPrivilegesCallbackWrapper wrapper = ref.get();
if (wrapper == null) return;
try {
- sRegistry.removeCarrierPrivilegesListener(wrapper, mContext.getOpPackageName());
+ sRegistry.removeCarrierPrivilegesCallback(wrapper, mContext.getOpPackageName());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ }
+
+ /**
+ * Registers a {@link CarrierPrivilegesCallback} on the given {@code logicalSlotIndex} to
+ * receive callbacks when the set of packages with carrier privileges changes. The callback will
+ * immediately be called with the latest state.
+ *
+ * @param logicalSlotIndex The SIM slot to listen on
+ * @param executor The executor where {@code listener} will be invoked
+ * @param callback The callback to register
+ */
+ public void addCarrierPrivilegesCallback(
+ int logicalSlotIndex,
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull CarrierPrivilegesCallback callback) {
+ if (callback == null || executor == null) {
+ throw new IllegalArgumentException("callback and executor must be non-null");
+ }
+ synchronized (sCarrierPrivilegeCallbacks) {
+ WeakReference<CarrierPrivilegesCallbackWrapper> existing =
+ sCarrierPrivilegeCallbacks.get(callback);
+ if (existing != null && existing.get() != null) {
+ Log.d(TAG, "addCarrierPrivilegesCallback: callback already registered");
+ return;
+ }
+ CarrierPrivilegesCallbackWrapper wrapper =
+ new CarrierPrivilegesCallbackWrapper(callback, executor);
+ sCarrierPrivilegeCallbacks.put(callback, new WeakReference<>(wrapper));
+ try {
+ sRegistry.addCarrierPrivilegesCallback(
+ logicalSlotIndex,
+ wrapper,
+ mContext.getOpPackageName(),
+ mContext.getAttributionTag());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ }
+
+ /**
+ * Unregisters a {@link CarrierPrivilegesCallback}.
+ *
+ * @param callback The callback to unregister
+ */
+ public void removeCarrierPrivilegesCallback(@NonNull CarrierPrivilegesCallback callback) {
+ if (callback == null) {
+ throw new IllegalArgumentException("listener must be non-null");
+ }
+ synchronized (sCarrierPrivilegeCallbacks) {
+ WeakReference<CarrierPrivilegesCallbackWrapper> ref =
+ sCarrierPrivilegeCallbacks.remove(callback);
+ if (ref == null) return;
+ CarrierPrivilegesCallbackWrapper wrapper = ref.get();
+ if (wrapper == null) return;
+ try {
+ sRegistry.removeCarrierPrivilegesCallback(wrapper, mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1359,15 +1476,33 @@ public class TelephonyRegistryManager {
*/
public void notifyCarrierPrivilegesChanged(
int logicalSlotIndex,
- @NonNull List<String> privilegedPackageNames,
- @NonNull int[] privilegedUids) {
+ @NonNull Set<String> privilegedPackageNames,
+ @NonNull Set<Integer> privilegedUids) {
if (privilegedPackageNames == null || privilegedUids == null) {
throw new IllegalArgumentException(
"privilegedPackageNames and privilegedUids must be non-null");
}
try {
- sRegistry.notifyCarrierPrivilegesChanged(
- logicalSlotIndex, privilegedPackageNames, privilegedUids);
+ // AIDL doesn't support Set yet. Convert Set to List/Array
+ List<String> pkgList = List.copyOf(privilegedPackageNames);
+ int[] uids = privilegedUids.stream().mapToInt(Number::intValue).toArray();
+ sRegistry.notifyCarrierPrivilegesChanged(logicalSlotIndex, pkgList, uids);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Notify listeners that the {@link CarrierService} for current user has changed.
+ *
+ * @param logicalSlotIndex the SIM slot the change occurred on
+ * @param packageName the package name of the changed {@link CarrierService}
+ * @param uid the UID of the changed {@link CarrierService}
+ */
+ public void notifyCarrierServiceChanged(int logicalSlotIndex, @Nullable String packageName,
+ int uid) {
+ try {
+ sRegistry.notifyCarrierServiceChanged(logicalSlotIndex, packageName, uid);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/text/PrecomputedText.java b/core/java/android/text/PrecomputedText.java
index 9307e566b5c3..f31a690c7774 100644
--- a/core/java/android/text/PrecomputedText.java
+++ b/core/java/android/text/PrecomputedText.java
@@ -99,7 +99,7 @@ public class PrecomputedText implements Spannable {
private final @Layout.HyphenationFrequency int mHyphenationFrequency;
// The line break configuration for calculating text wrapping.
- private final @Nullable LineBreakConfig mLineBreakConfig;
+ private final @NonNull LineBreakConfig mLineBreakConfig;
/**
* A builder for creating {@link Params}.
@@ -119,7 +119,7 @@ public class PrecomputedText implements Spannable {
Layout.HYPHENATION_FREQUENCY_NORMAL;
// The line break configuration for calculating text wrapping.
- private @Nullable LineBreakConfig mLineBreakConfig;
+ private @NonNull LineBreakConfig mLineBreakConfig = LineBreakConfig.NONE;
/**
* Builder constructor.
@@ -212,7 +212,7 @@ public class PrecomputedText implements Spannable {
// For the external developers, use Builder instead.
/** @hide */
public Params(@NonNull TextPaint paint,
- @Nullable LineBreakConfig lineBreakConfig,
+ @NonNull LineBreakConfig lineBreakConfig,
@NonNull TextDirectionHeuristic textDir,
@Layout.BreakStrategy int strategy,
@Layout.HyphenationFrequency int frequency) {
@@ -260,11 +260,12 @@ public class PrecomputedText implements Spannable {
}
/**
- * Return the line break configuration for this text.
+ * Returns the {@link LineBreakConfig} for this text.
*
- * @return the current line break configuration, null if no line break configuration is set.
+ * @return the current line break configuration. The {@link LineBreakConfig} with default
+ * values will be returned if no line break configuration is set.
*/
- public @Nullable LineBreakConfig getLineBreakConfig() {
+ public @NonNull LineBreakConfig getLineBreakConfig() {
return mLineBreakConfig;
}
@@ -297,9 +298,9 @@ public class PrecomputedText implements Spannable {
/** @hide */
public @CheckResultUsableResult int checkResultUsable(@NonNull TextPaint paint,
@NonNull TextDirectionHeuristic textDir, @Layout.BreakStrategy int strategy,
- @Layout.HyphenationFrequency int frequency, @Nullable LineBreakConfig lbConfig) {
+ @Layout.HyphenationFrequency int frequency, @NonNull LineBreakConfig lbConfig) {
if (mBreakStrategy == strategy && mHyphenationFrequency == frequency
- && isLineBreakEquals(mLineBreakConfig, lbConfig)
+ && mLineBreakConfig.equals(lbConfig)
&& mPaint.equalsForTextMeasurement(paint)) {
return mTextDir == textDir ? USABLE : NEED_RECOMPUTE;
} else {
@@ -308,29 +309,6 @@ public class PrecomputedText implements Spannable {
}
/**
- * Check the two LineBreakConfig instances are equal.
- * This method assumes they are equal if one parameter is null and the other parameter has
- * a LineBreakStyle value of LineBreakConfig.LINE_BREAK_STYLE_NONE.
- *
- * @param o1 the first LineBreakConfig instance.
- * @param o2 the second LineBreakConfig instance.
- * @return true if the two LineBreakConfig instances are equal.
- */
- private boolean isLineBreakEquals(LineBreakConfig o1, LineBreakConfig o2) {
- if (Objects.equals(o1, o2)) {
- return true;
- }
- if (o1 == null && (o2 != null
- && o2.getLineBreakStyle() == LineBreakConfig.LINE_BREAK_STYLE_NONE)) {
- return true;
- } else if (o2 == null && (o1 != null
- && o1.getLineBreakStyle() == LineBreakConfig.LINE_BREAK_STYLE_NONE)) {
- return true;
- }
- return false;
- }
-
- /**
* Check if the same text layout.
*
* @return true if this and the given param result in the same text layout
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index b10fc37bff2f..2f85d2b63840 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -112,6 +112,7 @@ public class StaticLayout extends Layout {
b.mBreakStrategy = Layout.BREAK_STRATEGY_SIMPLE;
b.mHyphenationFrequency = Layout.HYPHENATION_FREQUENCY_NONE;
b.mJustificationMode = Layout.JUSTIFICATION_MODE_NONE;
+ b.mLineBreakConfig = LineBreakConfig.NONE;
return b;
}
@@ -410,7 +411,8 @@ public class StaticLayout extends Layout {
*
* @param lineBreakConfig the line break configuration for text wrapping.
* @return this builder, useful for chaining.
- * @see android.widget.TextView#setLineBreakConfig
+ * @see android.widget.TextView#setLineBreakStyle
+ * @see android.widget.TextView#setLineBreakWordStyle
*/
@NonNull
public Builder setLineBreakConfig(@NonNull LineBreakConfig lineBreakConfig) {
@@ -454,7 +456,7 @@ public class StaticLayout extends Layout {
@Nullable private int[] mRightIndents;
private int mJustificationMode;
private boolean mAddLastLineLineSpacing;
- private LineBreakConfig mLineBreakConfig;
+ private LineBreakConfig mLineBreakConfig = LineBreakConfig.NONE;
private final Paint.FontMetricsInt mFontMetricsInt = new Paint.FontMetricsInt();
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index 4541f3afa428..fe6ae78ccf2d 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -71,8 +71,8 @@ public class FeatureFlagUtils {
* Hide back key in the Settings two pane design.
* @hide
*/
- public static final String SETTINGS_HIDE_SECONDARY_PAGE_BACK_BUTTON_IN_TWO_PANE =
- "settings_hide_secondary_page_back_button_in_two_pane";
+ public static final String SETTINGS_HIDE_SECOND_LAYER_PAGE_NAVIGATE_UP_BUTTON_IN_TWO_PANE =
+ "settings_hide_second_layer_page_navigate_up_button_in_two_pane";
private static final Map<String, String> DEFAULT_FLAGS;
@@ -99,7 +99,7 @@ public class FeatureFlagUtils {
DEFAULT_FLAGS.put(SETTINGS_APP_LANGUAGE_SELECTION, "true");
DEFAULT_FLAGS.put(SETTINGS_ENABLE_MONITOR_PHANTOM_PROCS, "true");
DEFAULT_FLAGS.put(SETTINGS_APP_ALLOW_DARK_THEME_ACTIVATION_AT_BEDTIME, "false");
- DEFAULT_FLAGS.put(SETTINGS_HIDE_SECONDARY_PAGE_BACK_BUTTON_IN_TWO_PANE, "true");
+ DEFAULT_FLAGS.put(SETTINGS_HIDE_SECOND_LAYER_PAGE_NAVIGATE_UP_BUTTON_IN_TWO_PANE, "true");
}
private static final Set<String> PERSISTENT_FLAGS;
@@ -109,7 +109,7 @@ public class FeatureFlagUtils {
PERSISTENT_FLAGS.add(SETTINGS_SUPPORT_LARGE_SCREEN);
PERSISTENT_FLAGS.add(SETTINGS_ENABLE_MONITOR_PHANTOM_PROCS);
PERSISTENT_FLAGS.add(SETTINGS_APP_ALLOW_DARK_THEME_ACTIVATION_AT_BEDTIME);
- PERSISTENT_FLAGS.add(SETTINGS_HIDE_SECONDARY_PAGE_BACK_BUTTON_IN_TWO_PANE);
+ PERSISTENT_FLAGS.add(SETTINGS_HIDE_SECOND_LAYER_PAGE_NAVIGATE_UP_BUTTON_IN_TWO_PANE);
}
/**
diff --git a/core/java/android/util/IconDrawableFactory.java b/core/java/android/util/IconDrawableFactory.java
index 5bb263a1f463..e3bc510b8e40 100644
--- a/core/java/android/util/IconDrawableFactory.java
+++ b/core/java/android/util/IconDrawableFactory.java
@@ -16,8 +16,8 @@
package android.util;
import static android.app.admin.DevicePolicyResources.Drawables.Style.SOLID_COLORED;
-import static android.app.admin.DevicePolicyResources.Drawables.UNDEFINED;
import static android.app.admin.DevicePolicyResources.Drawables.WORK_PROFILE_ICON_BADGE;
+import static android.app.admin.DevicePolicyResources.UNDEFINED;
import android.annotation.UserIdInt;
import android.app.admin.DevicePolicyManager;
@@ -88,7 +88,7 @@ public class IconDrawableFactory {
}
if (mUm.hasBadge(userId)) {
- Drawable badge = mDpm.getDrawable(
+ Drawable badge = mDpm.getResources().getDrawable(
getUpdatableUserIconBadgeId(userId),
SOLID_COLORED,
() -> getDefaultUserIconBadge(userId));
diff --git a/core/java/android/util/NtpTrustedTime.java b/core/java/android/util/NtpTrustedTime.java
index 40beab323576..01a037ae3495 100644
--- a/core/java/android/util/NtpTrustedTime.java
+++ b/core/java/android/util/NtpTrustedTime.java
@@ -33,6 +33,9 @@ import android.text.TextUtils;
import com.android.internal.annotations.GuardedBy;
+import java.io.PrintWriter;
+import java.time.Duration;
+import java.time.Instant;
import java.util.Objects;
import java.util.function.Supplier;
@@ -96,8 +99,8 @@ public class NtpTrustedTime implements TrustedTime {
@Override
public String toString() {
return "TimeResult{"
- + "mTimeMillis=" + mTimeMillis
- + ", mElapsedRealtimeMillis=" + mElapsedRealtimeMillis
+ + "mTimeMillis=" + Instant.ofEpochMilli(mTimeMillis)
+ + ", mElapsedRealtimeMillis=" + Duration.ofMillis(mElapsedRealtimeMillis)
+ ", mCertaintyMillis=" + mCertaintyMillis
+ '}';
}
@@ -131,6 +134,18 @@ public class NtpTrustedTime implements TrustedTime {
}
};
+ /** An in-memory config override for use during tests. */
+ @Nullable
+ private String mHostnameForTests;
+
+ /** An in-memory config override for use during tests. */
+ @Nullable
+ private Integer mPortForTests;
+
+ /** An in-memory config override for use during tests. */
+ @Nullable
+ private Duration mTimeoutForTests;
+
// Declared volatile and accessed outside of synchronized blocks to avoid blocking reads during
// forceRefresh().
private volatile TimeResult mTimeResult;
@@ -148,12 +163,25 @@ public class NtpTrustedTime implements TrustedTime {
return sSingleton;
}
+ /**
+ * Overrides the NTP server config for tests. Passing {@code null} to a parameter clears the
+ * test value, i.e. so the normal value will be used next time.
+ */
+ public void setServerConfigForTests(
+ @Nullable String hostname, @Nullable Integer port, @Nullable Duration timeout) {
+ synchronized (this) {
+ mHostnameForTests = hostname;
+ mPortForTests = port;
+ mTimeoutForTests = timeout;
+ }
+ }
+
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public boolean forceRefresh() {
synchronized (this) {
NtpConnectionInfo connectionInfo = getNtpConnectionInfo();
if (connectionInfo == null) {
- // missing server config, so no trusted time available
+ // missing server config, so no NTP time available
if (LOGD) Log.d(TAG, "forceRefresh: invalid server config");
return false;
}
@@ -173,8 +201,9 @@ public class NtpTrustedTime implements TrustedTime {
if (LOGD) Log.d(TAG, "forceRefresh() from cache miss");
final SntpClient client = new SntpClient();
final String serverName = connectionInfo.getServer();
+ final int port = connectionInfo.getPort();
final int timeoutMillis = connectionInfo.getTimeoutMillis();
- if (client.requestTime(serverName, timeoutMillis, network)) {
+ if (client.requestTime(serverName, port, timeoutMillis, network)) {
long ntpCertainty = client.getRoundTripTime() / 2;
mTimeResult = new TimeResult(
client.getNtpTime(), client.getNtpTimeReference(), ntpCertainty);
@@ -275,10 +304,12 @@ public class NtpTrustedTime implements TrustedTime {
private static class NtpConnectionInfo {
@NonNull private final String mServer;
+ private final int mPort;
private final int mTimeoutMillis;
- NtpConnectionInfo(@NonNull String server, int timeoutMillis) {
+ NtpConnectionInfo(@NonNull String server, int port, int timeoutMillis) {
mServer = Objects.requireNonNull(server);
+ mPort = port;
mTimeoutMillis = timeoutMillis;
}
@@ -287,9 +318,23 @@ public class NtpTrustedTime implements TrustedTime {
return mServer;
}
+ @NonNull
+ public int getPort() {
+ return mPort;
+ }
+
int getTimeoutMillis() {
return mTimeoutMillis;
}
+
+ @Override
+ public String toString() {
+ return "NtpConnectionInfo{"
+ + "mServer='" + mServer + '\''
+ + ", mPort='" + mPort + '\''
+ + ", mTimeoutMillis=" + mTimeoutMillis
+ + '}';
+ }
}
@GuardedBy("this")
@@ -297,17 +342,49 @@ public class NtpTrustedTime implements TrustedTime {
final ContentResolver resolver = mContext.getContentResolver();
final Resources res = mContext.getResources();
- final String defaultServer = res.getString(
- com.android.internal.R.string.config_ntpServer);
- final int defaultTimeoutMillis = res.getInteger(
- com.android.internal.R.integer.config_ntpTimeout);
-
- final String secureServer = Settings.Global.getString(
- resolver, Settings.Global.NTP_SERVER);
- final int timeoutMillis = Settings.Global.getInt(
- resolver, Settings.Global.NTP_TIMEOUT, defaultTimeoutMillis);
-
- final String server = secureServer != null ? secureServer : defaultServer;
- return TextUtils.isEmpty(server) ? null : new NtpConnectionInfo(server, timeoutMillis);
+
+ final String hostname;
+ if (mHostnameForTests != null) {
+ hostname = mHostnameForTests;
+ } else {
+ String serverGlobalSetting =
+ Settings.Global.getString(resolver, Settings.Global.NTP_SERVER);
+ if (serverGlobalSetting != null) {
+ hostname = serverGlobalSetting;
+ } else {
+ hostname = res.getString(com.android.internal.R.string.config_ntpServer);
+ }
+ }
+
+ final Integer port;
+ if (mPortForTests != null) {
+ port = mPortForTests;
+ } else {
+ port = SntpClient.STANDARD_NTP_PORT;
+ }
+
+ final int timeoutMillis;
+ if (mTimeoutForTests != null) {
+ timeoutMillis = (int) mTimeoutForTests.toMillis();
+ } else {
+ int defaultTimeoutMillis =
+ res.getInteger(com.android.internal.R.integer.config_ntpTimeout);
+ timeoutMillis = Settings.Global.getInt(
+ resolver, Settings.Global.NTP_TIMEOUT, defaultTimeoutMillis);
+ }
+ return TextUtils.isEmpty(hostname) ? null :
+ new NtpConnectionInfo(hostname, port, timeoutMillis);
+ }
+
+ /** Prints debug information. */
+ public void dump(PrintWriter pw) {
+ synchronized (this) {
+ pw.println("getNtpConnectionInfo()=" + getNtpConnectionInfo());
+ pw.println("mTimeResult=" + mTimeResult);
+ if (mTimeResult != null) {
+ pw.println("mTimeResult.getAgeMillis()="
+ + Duration.ofMillis(mTimeResult.getAgeMillis()));
+ }
+ }
}
}
diff --git a/core/java/android/util/TimingsTraceLog.java b/core/java/android/util/TimingsTraceLog.java
index 066709fd8744..48a5ceae1aef 100644
--- a/core/java/android/util/TimingsTraceLog.java
+++ b/core/java/android/util/TimingsTraceLog.java
@@ -147,7 +147,7 @@ public class TimingsTraceLog {
* Logs a duration so it can be parsed by external tools for performance reporting.
*/
public void logDuration(String name, long timeMs) {
- Slog.d(mTag, name + " took to complete: " + timeMs + "ms");
+ Slog.v(mTag, name + " took to complete: " + timeMs + "ms");
}
/**
diff --git a/core/java/android/view/AccessibilityInteractionController.java b/core/java/android/view/AccessibilityInteractionController.java
index 43c07c8ab97e..7e0b79470cf2 100644
--- a/core/java/android/view/AccessibilityInteractionController.java
+++ b/core/java/android/view/AccessibilityInteractionController.java
@@ -992,6 +992,9 @@ public final class AccessibilityInteractionController {
// Unchecked cast - an app that puts other objects in this bundle with this
// key will crash.
RectF textLocation = ((RectF) textLocations[i]);
+ if (textLocation == null) {
+ continue;
+ }
textLocation.scale(applicationScale);
if (spec != null) {
textLocation.scale(spec.scale);
diff --git a/core/java/android/view/ContentRecordingSession.java b/core/java/android/view/ContentRecordingSession.java
index db4ec1155e64..c66c70af0656 100644
--- a/core/java/android/view/ContentRecordingSession.java
+++ b/core/java/android/view/ContentRecordingSession.java
@@ -66,10 +66,11 @@ public final class ContentRecordingSession implements Parcelable {
private int mContentToRecord = RECORD_CONTENT_DISPLAY;
/**
- * The window token of the layer of the hierarchy to record.
- * The display content if {@link #getContentToRecord()} is
- * {@link RecordContent#RECORD_CONTENT_DISPLAY}, or task if {@link #getContentToRecord()} is
- * {@link RecordContent#RECORD_CONTENT_TASK}.
+ * The token of the layer of the hierarchy to record.
+ * If {@link #getContentToRecord()} is @link RecordContent#RECORD_CONTENT_DISPLAY}, then
+ * represents the WindowToken corresponding to the DisplayContent to record.
+ * If {@link #getContentToRecord()} is {@link RecordContent#RECORD_CONTENT_TASK}, then
+ * represents the {@link android.window.WindowContainerToken} of the Task to record.
*/
@VisibleForTesting
@Nullable
@@ -192,10 +193,11 @@ public final class ContentRecordingSession implements Parcelable {
}
/**
- * The window token of the layer of the hierarchy to record.
- * The display content if {@link #getContentToRecord()} is
- * {@link RecordContent#RECORD_CONTENT_DISPLAY}, or task if {@link #getContentToRecord()} is
- * {@link RecordContent#RECORD_CONTENT_TASK}.
+ * {The token of the layer of the hierarchy to record.
+ * If {@link #getContentToRecord()} is @link RecordContent#RECORD_CONTENT_DISPLAY}, then
+ * represents the WindowToken corresponding to the DisplayContent to record.
+ * If {@link #getContentToRecord()} is {@link RecordContent#RECORD_CONTENT_TASK}, then
+ * represents the {@link android.window.WindowContainerToken} of the Task to record.
*/
@DataClass.Generated.Member
public @VisibleForTesting @Nullable IBinder getTokenToRecord() {
@@ -231,10 +233,11 @@ public final class ContentRecordingSession implements Parcelable {
}
/**
- * The window token of the layer of the hierarchy to record.
- * The display content if {@link #getContentToRecord()} is
- * {@link RecordContent#RECORD_CONTENT_DISPLAY}, or task if {@link #getContentToRecord()} is
- * {@link RecordContent#RECORD_CONTENT_TASK}.
+ * {The token of the layer of the hierarchy to record.
+ * If {@link #getContentToRecord()} is @link RecordContent#RECORD_CONTENT_DISPLAY}, then
+ * represents the WindowToken corresponding to the DisplayContent to record.
+ * If {@link #getContentToRecord()} is {@link RecordContent#RECORD_CONTENT_TASK}, then
+ * represents the {@link android.window.WindowContainerToken} of the Task to record.
*/
@DataClass.Generated.Member
public @NonNull ContentRecordingSession setTokenToRecord(@VisibleForTesting @NonNull IBinder value) {
@@ -390,10 +393,11 @@ public final class ContentRecordingSession implements Parcelable {
}
/**
- * The window token of the layer of the hierarchy to record.
- * The display content if {@link #getContentToRecord()} is
- * {@link RecordContent#RECORD_CONTENT_DISPLAY}, or task if {@link #getContentToRecord()} is
- * {@link RecordContent#RECORD_CONTENT_TASK}.
+ * {The token of the layer of the hierarchy to record.
+ * If {@link #getContentToRecord()} is @link RecordContent#RECORD_CONTENT_DISPLAY}, then
+ * represents the WindowToken corresponding to the DisplayContent to record.
+ * If {@link #getContentToRecord()} is {@link RecordContent#RECORD_CONTENT_TASK}, then
+ * represents the {@link android.window.WindowContainerToken} of the Task to record.
*/
@DataClass.Generated.Member
public @NonNull Builder setTokenToRecord(@VisibleForTesting @NonNull IBinder value) {
@@ -433,7 +437,7 @@ public final class ContentRecordingSession implements Parcelable {
}
@DataClass.Generated(
- time = 1644843382972L,
+ time = 1645803878639L,
codegenVersion = "1.0.23",
sourceFile = "frameworks/base/core/java/android/view/ContentRecordingSession.java",
inputSignatures = "public static final int RECORD_CONTENT_DISPLAY\npublic static final int RECORD_CONTENT_TASK\nprivate int mDisplayId\nprivate @android.view.ContentRecordingSession.RecordContent int mContentToRecord\nprivate @com.android.internal.annotations.VisibleForTesting @android.annotation.Nullable android.os.IBinder mTokenToRecord\npublic static android.view.ContentRecordingSession createDisplaySession(android.os.IBinder)\npublic static android.view.ContentRecordingSession createTaskSession(android.os.IBinder)\npublic static boolean isValid(android.view.ContentRecordingSession)\npublic static boolean isSameDisplay(android.view.ContentRecordingSession,android.view.ContentRecordingSession)\nclass ContentRecordingSession extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genConstructor=false, genToString=true, genSetters=true, genEqualsHashCode=true)")
diff --git a/core/java/android/view/HandwritingInitiator.java b/core/java/android/view/HandwritingInitiator.java
index c1413beb0143..61098d60566f 100644
--- a/core/java/android/view/HandwritingInitiator.java
+++ b/core/java/android/view/HandwritingInitiator.java
@@ -55,10 +55,10 @@ public class HandwritingInitiator {
*/
private final int mTouchSlop;
/**
- * The timeout used to distinguish tap from handwriting. If the stylus doesn't move before this
- * timeout, it's not considered as handwriting.
+ * The timeout used to distinguish tap or long click from handwriting. If the stylus doesn't
+ * move before this timeout, it's not considered as handwriting.
*/
- private final long mTapTimeoutInMillis;
+ private final long mHandwritingTimeoutInMillis;
private State mState = new State();
private final HandwritingAreaTracker mHandwritingAreasTracker = new HandwritingAreaTracker();
@@ -90,7 +90,7 @@ public class HandwritingInitiator {
public HandwritingInitiator(@NonNull ViewConfiguration viewConfiguration,
@NonNull InputMethodManager inputMethodManager) {
mTouchSlop = viewConfiguration.getScaledTouchSlop();
- mTapTimeoutInMillis = ViewConfiguration.getTapTimeout();
+ mHandwritingTimeoutInMillis = ViewConfiguration.getLongPressTimeout();
mImm = inputMethodManager;
}
@@ -145,7 +145,7 @@ public class HandwritingInitiator {
final long timeElapsed =
motionEvent.getEventTime() - mState.mStylusDownTimeInMillis;
- if (timeElapsed > mTapTimeoutInMillis) {
+ if (timeElapsed > mHandwritingTimeoutInMillis) {
reset();
return;
}
@@ -249,19 +249,19 @@ public class HandwritingInitiator {
return;
}
- Rect handwritingArea = getViewHandwritingArea(connectedView);
- if (handwritingArea != null) {
- if (contains(handwritingArea, mState.mStylusDownX, mState.mStylusDownY)) {
- startHandwriting(connectedView);
- }
+ final Rect handwritingArea = getViewHandwritingArea(connectedView);
+ if (contains(handwritingArea, mState.mStylusDownX, mState.mStylusDownY)) {
+ startHandwriting(connectedView);
+ } else {
+ reset();
}
- reset();
}
/** For test only. */
@VisibleForTesting
public void startHandwriting(@NonNull View view) {
mImm.startStylusHandwriting(view);
+ reset();
}
/**
@@ -287,7 +287,7 @@ public class HandwritingInitiator {
final View connectedView = getConnectedView();
if (connectedView != null && connectedView.isAutoHandwritingEnabled()) {
final Rect handwritingArea = getViewHandwritingArea(connectedView);
- if (handwritingArea != null && contains(handwritingArea, x, y)) {
+ if (contains(handwritingArea, x, y)) {
return connectedView;
}
}
@@ -298,8 +298,7 @@ public class HandwritingInitiator {
for (HandwritableViewInfo viewInfo : handwritableViewInfos) {
final View view = viewInfo.getView();
if (!view.isAutoHandwritingEnabled()) continue;
- final Rect rect = viewInfo.getHandwritingArea();
- if (rect != null && contains(rect, x, y)) {
+ if (contains(viewInfo.getHandwritingArea(), x, y)) {
return viewInfo.getView();
}
}
@@ -315,12 +314,15 @@ public class HandwritingInitiator {
private static Rect getViewHandwritingArea(@NonNull View view) {
final ViewParent viewParent = view.getParent();
if (viewParent != null && view.isAttachedToWindow() && view.isAggregatedVisible()) {
- Rect handwritingArea = view.getHandwritingArea();
- if (handwritingArea == null) {
- handwritingArea = new Rect(0, 0, view.getWidth(), view.getHeight());
+ final Rect localHandwritingArea = view.getHandwritingArea();
+ final Rect globalHandwritingArea = new Rect();
+ if (localHandwritingArea != null) {
+ globalHandwritingArea.set(localHandwritingArea);
+ } else {
+ globalHandwritingArea.set(0, 0, view.getWidth(), view.getHeight());
}
- if (viewParent.getChildVisibleRect(view, handwritingArea, null)) {
- return handwritingArea;
+ if (viewParent.getChildVisibleRect(view, globalHandwritingArea, null)) {
+ return globalHandwritingArea;
}
}
return null;
@@ -329,7 +331,8 @@ public class HandwritingInitiator {
/**
* Return true if the (x, y) is inside by the given {@link Rect}.
*/
- private boolean contains(@NonNull Rect rect, float x, float y) {
+ private boolean contains(@Nullable Rect rect, float x, float y) {
+ if (rect == null) return false;
return x >= rect.left && x < rect.right && y >= rect.top && y < rect.bottom;
}
@@ -481,17 +484,18 @@ public class HandwritingInitiator {
if (!mIsDirty) {
return true;
}
- final Rect localRect = view.getHandwritingArea();
- if (localRect == null) {
+ final Rect handwritingArea = view.getHandwritingArea();
+ if (handwritingArea == null) {
return false;
}
ViewParent parent = view.getParent();
if (parent != null) {
- final Rect newRect = new Rect(localRect);
- if (parent.getChildVisibleRect(view, newRect, null /* offset */)) {
- mHandwritingArea = newRect;
- } else {
+ if (mHandwritingArea == null) {
+ mHandwritingArea = new Rect();
+ }
+ mHandwritingArea.set(handwritingArea);
+ if (!parent.getChildVisibleRect(view, mHandwritingArea, null /* offset */)) {
mHandwritingArea = null;
}
}
diff --git a/core/java/android/view/IPinnedTaskListener.aidl b/core/java/android/view/IPinnedTaskListener.aidl
index 7d39ffe182c7..595a846e069a 100644
--- a/core/java/android/view/IPinnedTaskListener.aidl
+++ b/core/java/android/view/IPinnedTaskListener.aidl
@@ -47,7 +47,7 @@ oneway interface IPinnedTaskListener {
* Called when the set of actions for the current PiP activity changes, or when the listener
* is first registered to allow the listener to synchronize its state with the controller.
*/
- void onActionsChanged(in ParceledListSlice<RemoteAction> actions);
+ void onActionsChanged(in ParceledListSlice<RemoteAction> actions, in RemoteAction closeAction);
/**
* Called by the window manager to notify the listener that Activity (was or is in pinned mode)
diff --git a/core/java/android/view/IWindow.aidl b/core/java/android/view/IWindow.aidl
index 12421ed61b33..5dcf3931ecd6 100644
--- a/core/java/android/view/IWindow.aidl
+++ b/core/java/android/view/IWindow.aidl
@@ -55,7 +55,8 @@ oneway interface IWindow {
void resized(in ClientWindowFrames frames, boolean reportDraw,
in MergedConfiguration newMergedConfiguration,
- boolean forceLayout, boolean alwaysConsumeSystemBars, int displayId);
+ boolean forceLayout, boolean alwaysConsumeSystemBars, int displayId,
+ int syncSeqId, int resizeMode);
/**
* Called when the window insets configuration has changed.
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 3f29e3f3078e..a35a195c50b1 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -201,7 +201,12 @@ interface IWindowManager
boolean isKeyguardSecure(int userId);
void dismissKeyguard(IKeyguardDismissCallback callback, CharSequence message);
+ @JavaPassthrough(annotation = "@android.annotation.RequiresPermission(android.Manifest"
+ + ".permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE)")
void addKeyguardLockedStateListener(in IKeyguardLockedStateListener listener);
+
+ @JavaPassthrough(annotation = "@android.annotation.RequiresPermission(android.Manifest"
+ + ".permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE)")
void removeKeyguardLockedStateListener(in IKeyguardLockedStateListener listener);
// Requires INTERACT_ACROSS_USERS_FULL permission
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index 5c7c844ae773..fd8690009a6d 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -104,7 +104,8 @@ interface IWindowSession {
int requestedWidth, int requestedHeight, int viewVisibility,
int flags, out ClientWindowFrames outFrames,
out MergedConfiguration outMergedConfiguration, out SurfaceControl outSurfaceControl,
- out InsetsState insetsState, out InsetsSourceControl[] activeControls);
+ out InsetsState insetsState, out InsetsSourceControl[] activeControls,
+ out Bundle bundle);
/*
* Notify the window manager that an application is relaunching and
@@ -142,7 +143,8 @@ interface IWindowSession {
* is null if there is no sync required.
*/
@UnsupportedAppUsage
- oneway void finishDrawing(IWindow window, in SurfaceControl.Transaction postDrawTransaction);
+ oneway void finishDrawing(IWindow window, in SurfaceControl.Transaction postDrawTransaction,
+ int seqId);
@UnsupportedAppUsage
oneway void setInTouchMode(boolean showFocus);
diff --git a/core/java/android/view/InputWindowHandle.java b/core/java/android/view/InputWindowHandle.java
index 2b579d09d3a2..ef0c19c8dc02 100644
--- a/core/java/android/view/InputWindowHandle.java
+++ b/core/java/android/view/InputWindowHandle.java
@@ -16,20 +16,57 @@
package android.view;
+import android.annotation.IntDef;
import android.annotation.Nullable;
import android.graphics.Matrix;
import android.graphics.Region;
import android.gui.TouchOcclusionMode;
import android.os.IBinder;
+import android.os.InputConfig;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.lang.ref.WeakReference;
/**
- * Functions as a handle for a window that can receive input.
- * Enables the native input dispatcher to refer indirectly to the window manager's window state.
+ * Functions as a handle for a window that can receive input, and allows for the behavior of the
+ * input window to be configured.
* @hide
*/
public final class InputWindowHandle {
+
+ /**
+ * An internal annotation for all the {@link android.os.InputConfig} flags that can be
+ * specified to {@link #inputConfig} to control the behavior of an input window. Only the
+ * flags listed here are valid for use in Java.
+ *
+ * The default flag value is 0, which is what we expect for a normal application window. Adding
+ * a flag indicates that the window's behavior deviates from that of a normal application
+ * window.
+ *
+ * The flags are defined as an AIDL enum to keep it in sync with native code.
+ * {@link android.os.InputConfig} flags that are not listed here should not be used in Java, and
+ * are only meant to be used in native code.
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(flag = true, value = {
+ InputConfig.DEFAULT,
+ InputConfig.NO_INPUT_CHANNEL,
+ InputConfig.NOT_FOCUSABLE,
+ InputConfig.NOT_TOUCHABLE,
+ InputConfig.PREVENT_SPLITTING,
+ InputConfig.DUPLICATE_TOUCH_TO_WALLPAPER,
+ InputConfig.IS_WALLPAPER,
+ InputConfig.PAUSE_DISPATCHING,
+ InputConfig.TRUSTED_OVERLAY,
+ InputConfig.WATCH_OUTSIDE_TOUCH,
+ InputConfig.SLIPPERY,
+ InputConfig.DISABLE_USER_ACTIVITY,
+ InputConfig.SPY,
+ InputConfig.INTERCEPTS_STYLUS,
+ })
+ public @interface InputConfigFlags {}
+
// Pointer to the native input window handle.
// This field is lazily initialized via JNI.
@SuppressWarnings("unused")
@@ -56,7 +93,8 @@ public final class InputWindowHandle {
// The window name.
public String name;
- // Window layout params attributes. (WindowManager.LayoutParams)
+ // Window layout params attributes. (WindowManager.LayoutParams)
+ // These values do not affect any input configurations. Use {@link #inputConfig} instead.
public int layoutParamsFlags;
public int layoutParamsType;
@@ -78,20 +116,9 @@ public final class InputWindowHandle {
// Window touchable region.
public final Region touchableRegion = new Region();
- // Window is visible.
- public boolean visible;
-
- // Window can be focused.
- public boolean focusable;
-
- // Window has wallpaper. (window is the current wallpaper target)
- public boolean hasWallpaper;
-
- // Input event dispatching is paused.
- public boolean paused;
-
- // Window is trusted overlay.
- public boolean trustedOverlay;
+ // Flags that specify the behavior of this input window. See {@link #InputConfigFlags}.
+ @InputConfigFlags
+ public int inputConfig;
// What effect this window has on touch occlusion if it lets touches pass through
// By default windows will block touches if they are untrusted and from a different UID due to
@@ -105,25 +132,21 @@ public final class InputWindowHandle {
// Owner package of the window
public String packageName;
- // Window input features.
- public int inputFeatures;
-
- // Display this input is on.
+ // Display this input window is on.
public int displayId;
/**
- * Crops the touchable region to the bounds of the surface provided.
+ * Crops the {@link #touchableRegion} to the bounds of the surface provided.
*
- * This can be used in cases where the window is not
- * {@link android.view.WindowManager#FLAG_NOT_TOUCH_MODAL} but should be constrained to the
- * bounds of a parent window. That is the window should receive touch events outside its
- * window but be limited to its stack bounds, such as in the case of split screen.
+ * This can be used in cases where the window should be constrained to the bounds of a parent
+ * window. That is, the window should receive touch events outside its window frame, but be
+ * limited to its stack bounds, such as in the case of split screen.
*/
public WeakReference<SurfaceControl> touchableRegionSurfaceControl = new WeakReference<>(null);
/**
- * Replace {@link touchableRegion} with the bounds of {@link touchableRegionSurfaceControl}. If
- * the handle is {@code null}, the bounds of the surface associated with this window is used
+ * Replace {@link #touchableRegion} with the bounds of {@link #touchableRegionSurfaceControl}.
+ * If the handle is {@code null}, the bounds of the surface associated with this window is used
* as the touchable region.
*/
public boolean replaceTouchableRegionWithCrop;
@@ -147,7 +170,6 @@ public final class InputWindowHandle {
.append(", frame=[").append(frameLeft).append(",").append(frameTop).append(",")
.append(frameRight).append(",").append(frameBottom).append("]")
.append(", touchableRegion=").append(touchableRegion)
- .append(", visible=").append(visible)
.append(", scaleFactor=").append(scaleFactor)
.append(", transform=").append(transform)
.append(", windowToken=").append(windowToken)
@@ -165,11 +187,11 @@ public final class InputWindowHandle {
}
/**
- * Set the window touchable region to the bounds of {@link touchableRegionBounds} ignoring any
- * touchable region provided.
+ * Set the window's touchable region to the bounds of {@link #touchableRegionSurfaceControl}
+ * and ignore the value of {@link #touchableRegion}.
*
- * @param bounds surface to set the touchable region to. Set to {@code null} to set the bounds
- * to the current surface.
+ * @param bounds surface to set the touchable region to. Set to {@code null} to set the
+ * touchable region as the current surface bounds.
*/
public void replaceTouchableRegionWithCrop(@Nullable SurfaceControl bounds) {
setTouchableRegionCrop(bounds);
@@ -195,4 +217,17 @@ public final class InputWindowHandle {
window = IWindow.Stub.asInterface(windowToken);
return window;
}
+
+ /**
+ * Set the provided inputConfig flag values.
+ * @param inputConfig the flag values to change
+ * @param value the provided flag values are set when true, and cleared when false
+ */
+ public void setInputConfig(@InputConfigFlags int inputConfig, boolean value) {
+ if (value) {
+ this.inputConfig |= inputConfig;
+ return;
+ }
+ this.inputConfig &= ~inputConfig;
+ }
}
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index 71c1b7c47a9f..a4841f6f0d95 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -23,6 +23,7 @@ import static android.view.InsetsState.ITYPE_CAPTION_BAR;
import static android.view.InsetsState.ITYPE_IME;
import static android.view.InsetsState.toInternalType;
import static android.view.InsetsState.toPublicType;
+import static android.view.ViewRootImpl.CAPTION_ON_SHELL;
import static android.view.WindowInsets.Type.all;
import static android.view.WindowInsets.Type.ime;
@@ -682,9 +683,15 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
@VisibleForTesting
public boolean onStateChanged(InsetsState state) {
- boolean stateChanged = !mState.equals(state, true /* excludingCaptionInsets */,
- false /* excludeInvisibleIme */)
- || !captionInsetsUnchanged();
+ boolean stateChanged = false;
+ if (!CAPTION_ON_SHELL) {
+ stateChanged = !mState.equals(state, true /* excludingCaptionInsets */,
+ false /* excludeInvisibleIme */)
+ || captionInsetsUnchanged();
+ } else {
+ stateChanged = !mState.equals(state, false /* excludingCaptionInsets */,
+ false /* excludeInvisibleIme */);
+ }
if (!stateChanged && mLastDispatchedState.equals(state)) {
return false;
}
@@ -758,16 +765,20 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
}
private boolean captionInsetsUnchanged() {
+ if (CAPTION_ON_SHELL) {
+ return false;
+ }
if (mState.peekSource(ITYPE_CAPTION_BAR) == null
&& mCaptionInsetsHeight == 0) {
- return true;
+ return false;
}
if (mState.peekSource(ITYPE_CAPTION_BAR) != null
&& mCaptionInsetsHeight
== mState.peekSource(ITYPE_CAPTION_BAR).getFrame().height()) {
- return true;
+ return false;
}
- return false;
+
+ return true;
}
private void startResizingAnimationIfNeeded(InsetsState fromState) {
@@ -1582,11 +1593,15 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
@Override
public void setCaptionInsetsHeight(int height) {
+ // This method is to be removed once the caption is moved to the shell.
+ if (CAPTION_ON_SHELL) {
+ return;
+ }
if (mCaptionInsetsHeight != height) {
mCaptionInsetsHeight = height;
if (mCaptionInsetsHeight != 0) {
- mState.getSource(ITYPE_CAPTION_BAR).setFrame(new Rect(mFrame.left, mFrame.top,
- mFrame.right, mFrame.top + mCaptionInsetsHeight));
+ mState.getSource(ITYPE_CAPTION_BAR).setFrame(mFrame.left, mFrame.top,
+ mFrame.right, mFrame.top + mCaptionInsetsHeight);
} else {
mState.removeSource(ITYPE_CAPTION_BAR);
}
diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java
index 0ef585478346..cc93adc32541 100644
--- a/core/java/android/view/MotionEvent.java
+++ b/core/java/android/view/MotionEvent.java
@@ -1877,7 +1877,7 @@ public final class MotionEvent extends InputEvent implements Parcelable {
float x, float y, float pressure, float size, int metaState,
float xPrecision, float yPrecision, int deviceId, int edgeFlags) {
return obtain(downTime, eventTime, action, x, y, pressure, size, metaState,
- xPrecision, yPrecision, deviceId, edgeFlags, InputDevice.SOURCE_UNKNOWN,
+ xPrecision, yPrecision, deviceId, edgeFlags, InputDevice.SOURCE_CLASS_POINTER,
DEFAULT_DISPLAY);
}
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 64f5668d8c14..da582c5b4b2f 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -64,6 +64,7 @@ import android.util.proto.ProtoOutputStream;
import android.view.Surface.OutOfResourcesException;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.Preconditions;
import com.android.internal.util.VirtualRefBasePtr;
import dalvik.system.CloseGuard;
@@ -82,6 +83,7 @@ import java.util.Objects;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
+import java.util.function.Consumer;
/**
* Handle to an on-screen Surface managed by the system compositor. The SurfaceControl is
@@ -212,7 +214,7 @@ public final class SurfaceControl implements Parcelable {
private static native void nativeReparent(long transactionObj, long nativeObject,
long newParentNativeObject);
private static native void nativeSetBuffer(long transactionObj, long nativeObject,
- HardwareBuffer buffer, long fencePtr);
+ HardwareBuffer buffer, long fencePtr, Consumer<SyncFence> releaseCallback);
private static native void nativeSetBufferTransform(long transactionObj, long nativeObject,
int transform);
private static native void nativeSetDataSpace(long transactionObj, long nativeObject,
@@ -2961,6 +2963,8 @@ public final class SurfaceControl implements Parcelable {
@NonNull
public Transaction setScale(@NonNull SurfaceControl sc, float scaleX, float scaleY) {
checkPreconditions(sc);
+ Preconditions.checkArgument(scaleX >= 0, "Negative value passed in for scaleX");
+ Preconditions.checkArgument(scaleY >= 0, "Negative value passed in for scaleY");
nativeSetScale(mNativeObject, sc.mNativeObject, scaleX, scaleY);
return this;
}
@@ -3205,6 +3209,7 @@ public final class SurfaceControl implements Parcelable {
public @NonNull Transaction setCrop(@NonNull SurfaceControl sc, @Nullable Rect crop) {
checkPreconditions(sc);
if (crop != null) {
+ Preconditions.checkArgument(crop.isValid(), "Crop isn't valid.");
nativeSetWindowCrop(mNativeObject, sc.mNativeObject,
crop.left, crop.top, crop.right, crop.bottom);
} else {
@@ -3740,18 +3745,62 @@ public final class SurfaceControl implements Parcelable {
*/
public @NonNull Transaction setBuffer(@NonNull SurfaceControl sc,
@Nullable HardwareBuffer buffer, @Nullable SyncFence fence) {
+ return setBuffer(sc, buffer, fence, null);
+ }
+
+ /**
+ * Updates the HardwareBuffer displayed for the SurfaceControl.
+ *
+ * Note that the buffer must be allocated with {@link HardwareBuffer#USAGE_COMPOSER_OVERLAY}
+ * as well as {@link HardwareBuffer#USAGE_GPU_SAMPLED_IMAGE} as the surface control might
+ * be composited using either an overlay or using the GPU.
+ *
+ * A presentation fence may be passed to improve performance by allowing the buffer
+ * to complete rendering while it is waiting for the transaction to be applied.
+ * For example, if the buffer is being produced by rendering with OpenGL ES then
+ * a fence created with
+ * {@link android.opengl.EGLExt#eglDupNativeFenceFDANDROID(EGLDisplay, EGLSync)} can be
+ * used to allow the GPU rendering to be concurrent with the transaction. The compositor
+ * will wait for the fence to be signaled before the buffer is displayed. If multiple
+ * buffers are set as part of the same transaction, the presentation fences of all of them
+ * must signal before any buffer is displayed. That is, the entire transaction is delayed
+ * until all presentation fences have signaled, ensuring the transaction remains consistent.
+ *
+ * A releaseCallback may be passed to know when the buffer is safe to be reused. This
+ * is recommended when attempting to render continuously using SurfaceControl transactions
+ * instead of through {@link Surface}, as it provides a safe & reliable way to know when
+ * a buffer can be re-used. The callback will be invoked with a {@link SyncFence} which,
+ * if {@link SyncFence#isValid() valid}, must be waited on prior to using the buffer. This
+ * can either be done directly with {@link SyncFence#awaitForever()} or it may be done
+ * indirectly such as passing it as a release fence to
+ * {@link android.media.Image#setFence(SyncFence)} when using
+ * {@link android.media.ImageReader}.
+ *
+ * @param sc The SurfaceControl to update
+ * @param buffer The buffer to be displayed
+ * @param fence The presentation fence. If null or invalid, this is equivalent to
+ * {@link #setBuffer(SurfaceControl, HardwareBuffer)}
+ * @param releaseCallback The callback to invoke when the buffer being set has been released
+ * by a later transaction. That is, the point at which it is safe
+ * to re-use the buffer.
+ * @return this
+ */
+ public @NonNull Transaction setBuffer(@NonNull SurfaceControl sc,
+ @Nullable HardwareBuffer buffer, @Nullable SyncFence fence,
+ @Nullable Consumer<SyncFence> releaseCallback) {
checkPreconditions(sc);
if (fence != null) {
synchronized (fence.getLock()) {
nativeSetBuffer(mNativeObject, sc.mNativeObject, buffer,
- fence.getNativeFence());
+ fence.getNativeFence(), releaseCallback);
}
} else {
- nativeSetBuffer(mNativeObject, sc.mNativeObject, buffer, 0);
+ nativeSetBuffer(mNativeObject, sc.mNativeObject, buffer, 0, releaseCallback);
}
return this;
}
+
/**
* Sets the buffer transform that should be applied to the current buffer.
*
@@ -4090,4 +4139,10 @@ public final class SurfaceControl implements Parcelable {
return -1;
}
+
+ // Called by native
+ private static void invokeReleaseCallback(Consumer<SyncFence> callback, long nativeFencePtr) {
+ SyncFence fence = new SyncFence(nativeFencePtr);
+ callback.accept(fence);
+ }
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index c2229911bf12..1b8dc706371e 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -12016,7 +12016,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
/**
* Return the handwriting areas set on this view, in its local coordinates.
- * Notice: the caller of this method should not modify the Rect returned.
* @see #setHandwritingArea(Rect)
*
* @hide
@@ -12025,7 +12024,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
public Rect getHandwritingArea() {
final ListenerInfo info = mListenerInfo;
if (info != null) {
- return info.mHandwritingArea;
+ return new Rect(info.mHandwritingArea);
}
return null;
}
@@ -15617,7 +15616,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @param event the KeyEvent object that defines the button action
*/
public boolean onKeyDown(int keyCode, KeyEvent event) {
- if (event.hasNoModifiers() && KeyEvent.isConfirmKey(keyCode)) {
+ if (KeyEvent.isConfirmKey(keyCode) && event.hasNoModifiers()) {
if ((mViewFlags & ENABLED_MASK) == DISABLED) {
return true;
}
@@ -15674,7 +15673,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @param event The KeyEvent object that defines the button action.
*/
public boolean onKeyUp(int keyCode, KeyEvent event) {
- if (event.hasNoModifiers() && KeyEvent.isConfirmKey(keyCode)) {
+ if (KeyEvent.isConfirmKey(keyCode) && event.hasNoModifiers()) {
if ((mViewFlags & ENABLED_MASK) == DISABLED) {
return true;
}
diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java
index 5775944b4e97..ebc409e470e9 100644
--- a/core/java/android/view/ViewConfiguration.java
+++ b/core/java/android/view/ViewConfiguration.java
@@ -1104,6 +1104,7 @@ public class ViewConfiguration {
* clear, or -1 if Views should not set themselves as preferred to keep clear.
* @hide
*/
+ @TestApi
public int getPreferKeepClearForFocusDelay() {
return mPreferKeepClearForFocusDelay;
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index bde761e59620..76d360cc9b2c 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -53,8 +53,8 @@ import static android.view.ViewRootImplProto.WIDTH;
import static android.view.ViewRootImplProto.WINDOW_ATTRIBUTES;
import static android.view.ViewRootImplProto.WIN_FRAME;
import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION;
-import static android.view.WindowCallbacks.RESIZE_MODE_DOCKED_DIVIDER;
import static android.view.WindowCallbacks.RESIZE_MODE_FREEFORM;
+import static android.view.WindowCallbacks.RESIZE_MODE_INVALID;
import static android.view.WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS;
import static android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS;
import static android.view.WindowInsetsController.APPEARANCE_LOW_PROFILE_BARS;
@@ -85,8 +85,6 @@ import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_ADDITIONAL
import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
import static android.view.WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY;
-import static android.view.WindowManagerGlobal.RELAYOUT_RES_DRAG_RESIZING_DOCKED;
-import static android.view.WindowManagerGlobal.RELAYOUT_RES_DRAG_RESIZING_FREEFORM;
import static android.view.WindowManagerGlobal.RELAYOUT_RES_SURFACE_CHANGED;
import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.IME_FOCUS_CONTROLLER;
import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.INSETS_CONTROLLER;
@@ -277,6 +275,12 @@ public final class ViewRootImpl implements ViewParent,
private static final boolean ENABLE_INPUT_LATENCY_TRACKING = true;
/**
+ * Whether the caption is drawn by the shell.
+ * @hide
+ */
+ public static final boolean CAPTION_ON_SHELL = false;
+
+ /**
* Set this system property to true to force the view hierarchy to render
* at 60 Hz. This can be used to measure the potential framerate.
*/
@@ -497,9 +501,10 @@ public final class ViewRootImpl implements ViewParent,
public boolean mIsAnimating;
private boolean mUseMTRenderer;
+ private boolean mPendingDragResizing;
private boolean mDragResizing;
private boolean mInvalidateRootRequested;
- private int mResizeMode;
+ private int mResizeMode = RESIZE_MODE_INVALID;
private int mCanvasOffsetX;
private int mCanvasOffsetY;
private boolean mActivityRelaunched;
@@ -546,7 +551,6 @@ public final class ViewRootImpl implements ViewParent,
private final Rect mVisRect = new Rect(); // used to retrieve visible rect of focused view.
private final Rect mTempRect = new Rect();
- private final Rect mTempRect2 = new Rect();
private final WindowLayout mWindowLayout = new WindowLayout();
@@ -824,6 +828,25 @@ public final class ViewRootImpl implements ViewParent,
private int mLastTransformHint = Integer.MIN_VALUE;
+ /**
+ * A temporary object used so relayoutWindow can return the latest SyncSeqId
+ * system. The SyncSeqId system was designed to work without synchronous relayout
+ * window, and actually synchronous relayout window presents a problem. We could have
+ * a sequence like this:
+ * 1. We send MSG_RESIZED to the client with a new syncSeqId to begin a new sync
+ * 2. Due to scheduling the client executes performTraversals before calling MSG_RESIZED
+ * 3. Coincidentally for some random reason it also calls relayout
+ * 4. It observes the new state from relayout, and so the next frame will contain the state
+ * However it hasn't received the seqId yet, and so under the designed operation of
+ * seqId flowing through MSG_RESIZED, the next frame wouldn't be synced. Since it
+ * contains our target sync state, we need to sync it! This problem won't come up once
+ * we get rid of synchronous relayout, until then, we use this bundle to channel the
+ * integer back over relayout.
+ */
+ private Bundle mRelayoutBundle = new Bundle();
+ private int mSyncSeqId = 0;
+ private int mLastSyncSeqId = 0;
+
private String mTag = TAG;
public ViewRootImpl(Context context, Display display) {
@@ -867,6 +890,7 @@ public final class ViewRootImpl implements ViewParent,
mDensity = context.getResources().getDisplayMetrics().densityDpi;
mNoncompatDensity = context.getResources().getDisplayMetrics().noncompatDensityDpi;
mFallbackEventHandler = new PhoneFallbackEventHandler(context);
+ // TODO(b/222696368): remove getSfInstance usage and use vsyncId for transactions
mChoreographer = useSfChoreographer
? Choreographer.getSfInstance() : Choreographer.getInstance();
mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
@@ -1198,8 +1222,7 @@ public final class ViewRootImpl implements ViewParent,
displayCutoutSafe, winConfig.getBounds(), winConfig.getWindowingMode(),
UNSPECIFIED_LENGTH, UNSPECIFIED_LENGTH,
mInsetsController.getRequestedVisibilities(),
- getAttachedWindowFrame(), 1f /* compactScale */,
- mTmpFrames.displayFrame, mTempRect2, mTmpFrames.frame);
+ getAttachedWindowFrame(), 1f /* compactScale */, mTmpFrames);
setFrame(mTmpFrames.frame);
registerBackCallbackOnWindow();
if (!WindowOnBackInvokedDispatcher.isOnBackInvokedCallbackEnabled(mContext)) {
@@ -1679,17 +1702,22 @@ public final class ViewRootImpl implements ViewParent,
final MergedConfiguration mergedConfiguration = (MergedConfiguration) args.arg2;
final boolean forceNextWindowRelayout = args.argi1 != 0;
final int displayId = args.argi3;
+ final int resizeMode = args.argi5;
final Rect backdropFrame = frames.backdropFrame;
final boolean frameChanged = !mWinFrame.equals(frames.frame);
final boolean backdropFrameChanged = !mPendingBackDropFrame.equals(backdropFrame);
final boolean configChanged = !mLastReportedMergedConfiguration.equals(mergedConfiguration);
final boolean displayChanged = mDisplay.getDisplayId() != displayId;
+ final boolean resizeModeChanged = mResizeMode != resizeMode;
if (msg == MSG_RESIZED && !frameChanged && !backdropFrameChanged && !configChanged
- && !displayChanged && !forceNextWindowRelayout) {
+ && !displayChanged && !resizeModeChanged && !forceNextWindowRelayout) {
return;
}
+ mPendingDragResizing = resizeMode != RESIZE_MODE_INVALID;
+ mResizeMode = resizeMode;
+
if (configChanged) {
// If configuration changed - notify about that and, maybe, about move to display.
performConfigurationChange(mergedConfiguration, false /* force */,
@@ -1704,6 +1732,7 @@ public final class ViewRootImpl implements ViewParent,
mPendingBackDropFrame.set(backdropFrame);
mForceNextWindowRelayout = forceNextWindowRelayout;
mPendingAlwaysConsumeSystemBars = args.argi2 != 0;
+ mSyncSeqId = args.argi4;
if (msg == MSG_RESIZED_REPORT) {
reportNextDraw();
@@ -1771,6 +1800,7 @@ public final class ViewRootImpl implements ViewParent,
updateInternalDisplay(displayId, mView.getResources());
mImeFocusController.onMovedToDisplay();
mAttachInfo.mDisplayState = mDisplay.getState();
+ mDisplayInstallOrientation = mDisplay.getInstallOrientation();
// Internal state updated, now notify the view hierarchy.
mView.dispatchMovedToDisplay(mDisplay, config);
}
@@ -2561,6 +2591,9 @@ public final class ViewRootImpl implements ViewParent,
}
private boolean updateCaptionInsets() {
+ if (CAPTION_ON_SHELL) {
+ return false;
+ }
if (!(mView instanceof DecorView)) return false;
final int captionInsetsHeight = ((DecorView) mView).getCaptionInsetsHeight();
final Rect captionFrame = new Rect();
@@ -2885,12 +2918,9 @@ public final class ViewRootImpl implements ViewParent,
mViewFrameInfo.flags |= FrameInfo.FLAG_WINDOW_VISIBILITY_CHANGED;
}
relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
- final boolean freeformResizing = (relayoutResult
- & RELAYOUT_RES_DRAG_RESIZING_FREEFORM) != 0;
- final boolean dockedResizing = (relayoutResult
- & RELAYOUT_RES_DRAG_RESIZING_DOCKED) != 0;
- final boolean dragResizing = freeformResizing || dockedResizing;
- if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_BLAST_SYNC) != 0) {
+ final boolean dragResizing = mPendingDragResizing;
+ if (mSyncSeqId > mLastSyncSeqId) {
+ mLastSyncSeqId = mSyncSeqId;
if (DEBUG_BLAST) {
Log.d(mTag, "Relayout called with blastSync");
}
@@ -3032,9 +3062,6 @@ public final class ViewRootImpl implements ViewParent,
if (mDragResizing != dragResizing) {
if (dragResizing) {
- mResizeMode = freeformResizing
- ? RESIZE_MODE_FREEFORM
- : RESIZE_MODE_DOCKED_DIVIDER;
final boolean backdropSizeMatchesFrame =
mWinFrame.width() == mPendingBackDropFrame.width()
&& mWinFrame.height() == mPendingBackDropFrame.height();
@@ -3137,11 +3164,8 @@ public final class ViewRootImpl implements ViewParent,
// possible that checking the most recent value is actually more
// correct here.
if (!mStopped || wasReportNextDraw) {
- boolean focusChangedDueToTouchMode = ensureTouchModeLocally(
- (relayoutResult&WindowManagerGlobal.RELAYOUT_RES_IN_TOUCH_MODE) != 0);
- if (focusChangedDueToTouchMode || mWidth != host.getMeasuredWidth()
- || mHeight != host.getMeasuredHeight() || dispatchApplyInsets ||
- updatedConfiguration) {
+ if (mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight()
+ || dispatchApplyInsets || updatedConfiguration) {
int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width,
lp.privateFlags);
int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height,
@@ -3439,6 +3463,12 @@ public final class ViewRootImpl implements ViewParent,
mReportNextDraw = false;
pendingDrawFinished();
}
+
+ // Make sure the consumer is not waiting if the view root was just made invisible.
+ if (mBLASTDrawConsumer != null) {
+ mBLASTDrawConsumer.accept(null);
+ mBLASTDrawConsumer = null;
+ }
}
}
@@ -4111,7 +4141,7 @@ public final class ViewRootImpl implements ViewParent,
mDrawsNeededToReport = 0;
try {
- mWindowSession.finishDrawing(mWindow, mSurfaceChangedTransaction);
+ mWindowSession.finishDrawing(mWindow, mSurfaceChangedTransaction, Integer.MAX_VALUE);
} catch (RemoteException e) {
Log.e(mTag, "Unable to report draw finished", e);
mSurfaceChangedTransaction.apply();
@@ -8054,17 +8084,16 @@ public final class ViewRootImpl implements ViewParent,
requestedWidth, requestedHeight, viewVisibility,
insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0,
mTmpFrames, mPendingMergedConfiguration, mSurfaceControl, mTempInsets,
- mTempControls);
+ mTempControls, mRelayoutBundle);
+ mSyncSeqId = mRelayoutBundle.getInt("seqid");
final int transformHint = SurfaceControl.rotationToBufferTransform(
(mDisplayInstallOrientation + mDisplay.getRotation()) % 4);
final WindowConfiguration winConfig = getConfiguration().windowConfiguration;
- final boolean dragResizing = (relayoutResult
- & (RELAYOUT_RES_DRAG_RESIZING_DOCKED | RELAYOUT_RES_DRAG_RESIZING_FREEFORM)) != 0;
WindowLayout.computeSurfaceSize(mWindowAttributes, winConfig.getMaxBounds(), requestedWidth,
- requestedHeight, mTmpFrames.frame, dragResizing, mSurfaceSize);
-
+ requestedHeight, mTmpFrames.frame, mPendingDragResizing, mSurfaceSize);
+
final boolean transformHintChanged = transformHint != mLastTransformHint;
final boolean sizeChanged = !mLastSurfaceSize.equals(mSurfaceSize);
final boolean surfaceControlChanged =
@@ -8480,7 +8509,7 @@ public final class ViewRootImpl implements ViewParent,
if ((relayoutWindow(mWindowAttributes, viewVisibility, false)
& WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
mWindowSession.finishDrawing(
- mWindow, null /* postDrawTransaction */);
+ mWindow, null /* postDrawTransaction */, Integer.MAX_VALUE);
}
} catch (RemoteException e) {
}
@@ -8554,7 +8583,7 @@ public final class ViewRootImpl implements ViewParent,
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
private void dispatchResized(ClientWindowFrames frames, boolean reportDraw,
MergedConfiguration mergedConfiguration, boolean forceLayout,
- boolean alwaysConsumeSystemBars, int displayId) {
+ boolean alwaysConsumeSystemBars, int displayId, int seqId, int resizeMode) {
final Rect frame = frames.frame;
final Rect backDropFrame = frames.backdropFrame;
if (DEBUG_LAYOUT) Log.v(mTag, "Resizing " + this + ": frame=" + frame.toShortString()
@@ -8585,6 +8614,8 @@ public final class ViewRootImpl implements ViewParent,
args.argi1 = forceLayout ? 1 : 0;
args.argi2 = alwaysConsumeSystemBars ? 1 : 0;
args.argi3 = displayId;
+ args.argi4 = seqId;
+ args.argi5 = resizeMode;
msg.obj = args;
mHandler.sendMessage(msg);
}
@@ -9969,11 +10000,11 @@ public final class ViewRootImpl implements ViewParent,
@Override
public void resized(ClientWindowFrames frames, boolean reportDraw,
MergedConfiguration mergedConfiguration, boolean forceLayout,
- boolean alwaysConsumeSystemBars, int displayId) {
+ boolean alwaysConsumeSystemBars, int displayId, int seqId, int resizeMode) {
final ViewRootImpl viewAncestor = mViewAncestor.get();
if (viewAncestor != null) {
viewAncestor.dispatchResized(frames, reportDraw, mergedConfiguration, forceLayout,
- alwaysConsumeSystemBars, displayId);
+ alwaysConsumeSystemBars, displayId, seqId, resizeMode);
}
}
@@ -10891,7 +10922,7 @@ public final class ViewRootImpl implements ViewParent,
}
};
mOnBackInvokedDispatcher.registerOnBackInvokedCallback(
- mCompatOnBackInvokedCallback, OnBackInvokedDispatcher.PRIORITY_DEFAULT);
+ OnBackInvokedDispatcher.PRIORITY_DEFAULT, mCompatOnBackInvokedCallback);
}
private void unregisterCompatOnBackInvokedCallback() {
diff --git a/core/java/android/view/WindowCallbacks.java b/core/java/android/view/WindowCallbacks.java
index a99730205136..a7f0ef0a0324 100644
--- a/core/java/android/view/WindowCallbacks.java
+++ b/core/java/android/view/WindowCallbacks.java
@@ -28,9 +28,21 @@ import android.graphics.Rect;
*/
public interface WindowCallbacks {
- public static final int RESIZE_MODE_INVALID = -1;
- public static final int RESIZE_MODE_FREEFORM = 0;
- public static final int RESIZE_MODE_DOCKED_DIVIDER = 1;
+ int RESIZE_MODE_INVALID = -1;
+
+ /**
+ * The window is being resized by dragging one of the window corners,
+ * in this case the surface would be fullscreen-sized. The client should
+ * render to the actual frame location (instead of (0,curScrollY)).
+ */
+ int RESIZE_MODE_FREEFORM = 0;
+
+ /**
+ * The window is being resized by dragging on the docked divider. The client should render
+ * at (0, 0) and extend its background to the background frame passed into
+ * {@link IWindow#resized}.
+ */
+ int RESIZE_MODE_DOCKED_DIVIDER = 1;
/**
* Called by the system when the window got changed by the user, before the layouter got called.
diff --git a/core/java/android/view/WindowLayout.java b/core/java/android/view/WindowLayout.java
index ad9f21b4fa70..a3b1313202c2 100644
--- a/core/java/android/view/WindowLayout.java
+++ b/core/java/android/view/WindowLayout.java
@@ -42,6 +42,7 @@ import android.graphics.Insets;
import android.graphics.Point;
import android.graphics.Rect;
import android.util.Log;
+import android.window.ClientWindowFrames;
/**
* Computes window frames.
@@ -56,15 +57,17 @@ public class WindowLayout {
private final Rect mTempDisplayCutoutSafeExceptMaybeBarsRect = new Rect();
private final Rect mTempRect = new Rect();
- public boolean computeFrames(WindowManager.LayoutParams attrs, InsetsState state,
+ public void computeFrames(WindowManager.LayoutParams attrs, InsetsState state,
Rect displayCutoutSafe, Rect windowBounds, @WindowingMode int windowingMode,
int requestedWidth, int requestedHeight, InsetsVisibilities requestedVisibilities,
- Rect attachedWindowFrame, float compatScale, Rect outDisplayFrame, Rect outParentFrame,
- Rect outFrame) {
+ Rect attachedWindowFrame, float compatScale, ClientWindowFrames outFrames) {
final int type = attrs.type;
final int fl = attrs.flags;
final int pfl = attrs.privateFlags;
final boolean layoutInScreen = (fl & FLAG_LAYOUT_IN_SCREEN) == FLAG_LAYOUT_IN_SCREEN;
+ final Rect outDisplayFrame = outFrames.displayFrame;
+ final Rect outParentFrame = outFrames.parentFrame;
+ final Rect outFrame = outFrames.frame;
// Compute bounds restricted by insets
final Insets insets = state.calculateInsets(windowBounds, attrs.getFitInsetsTypes(),
@@ -95,7 +98,7 @@ public class WindowLayout {
final DisplayCutout cutout = state.getDisplayCutout();
final Rect displayCutoutSafeExceptMaybeBars = mTempDisplayCutoutSafeExceptMaybeBarsRect;
displayCutoutSafeExceptMaybeBars.set(displayCutoutSafe);
- boolean clippedByDisplayCutout = false;
+ outFrames.isParentFrameClippedByDisplayCutout = false;
if (cutoutMode != LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS && !cutout.isEmpty()) {
// Ensure that windows with a non-ALWAYS display cutout mode are laid out in
// the cutout safe zone.
@@ -158,7 +161,7 @@ public class WindowLayout {
if (!attachedInParent && !floatingInScreenWindow) {
mTempRect.set(outParentFrame);
outParentFrame.intersectUnchecked(displayCutoutSafeExceptMaybeBars);
- clippedByDisplayCutout = !mTempRect.equals(outParentFrame);
+ outFrames.isParentFrameClippedByDisplayCutout = !mTempRect.equals(outParentFrame);
}
outDisplayFrame.intersectUnchecked(displayCutoutSafeExceptMaybeBars);
}
@@ -287,9 +290,7 @@ public class WindowLayout {
}
if (DEBUG) Log.d(TAG, "computeWindowFrames " + attrs.getTitle()
- + " outFrame=" + outFrame.toShortString()
- + " outParentFrame=" + outParentFrame.toShortString()
- + " outDisplayFrame=" + outDisplayFrame.toShortString()
+ + " outFrames=" + outFrames
+ " windowBounds=" + windowBounds.toShortString()
+ " attachedWindowFrame=" + (attachedWindowFrame != null
? attachedWindowFrame.toShortString()
@@ -302,8 +303,6 @@ public class WindowLayout {
+ " attrs=" + attrs
+ " state=" + state
+ " requestedVisibilities=" + requestedVisibilities);
-
- return clippedByDisplayCutout;
}
public static void computeSurfaceSize(WindowManager.LayoutParams attrs, Rect maxBounds,
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index dbfae46a6e72..45169efd7d35 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -106,7 +106,6 @@ import android.graphics.Region;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
-import android.os.IInputConstants;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
@@ -3360,8 +3359,7 @@ public interface WindowManager extends ViewManager {
*
* @hide
*/
- public static final int INPUT_FEATURE_NO_INPUT_CHANNEL =
- IInputConstants.InputFeature.NO_INPUT_CHANNEL;
+ public static final int INPUT_FEATURE_NO_INPUT_CHANNEL = 1 << 0;
/**
* When this window has focus, does not call user activity for all input events so
@@ -3374,58 +3372,43 @@ public interface WindowManager extends ViewManager {
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public static final int INPUT_FEATURE_DISABLE_USER_ACTIVITY =
- IInputConstants.InputFeature.DISABLE_USER_ACTIVITY;
+ public static final int INPUT_FEATURE_DISABLE_USER_ACTIVITY = 1 << 1;
/**
* An input spy window. This window will receive all pointer events within its touchable
- * area, but will will not stop events from being sent to other windows below it in z-order.
+ * area, but will not stop events from being sent to other windows below it in z-order.
* An input event will be dispatched to all spy windows above the top non-spy window at the
* event's coordinates.
- * @hide
- */
- public static final int INPUT_FEATURE_SPY =
- IInputConstants.InputFeature.SPY;
-
- /**
- * When used with the window flag {@link #FLAG_NOT_TOUCHABLE}, this window will continue
- * to receive events from a stylus device within its touchable region. All other pointer
- * events, such as from a mouse or touchscreen, will be dispatched to the windows behind it.
- *
- * This input feature has no effect when the window flag {@link #FLAG_NOT_TOUCHABLE} is
- * not set.
- *
- * The window must be a trusted overlay to use this input feature.
- *
- * @see #FLAG_NOT_TOUCHABLE
*
* @hide
*/
- public static final int INPUT_FEATURE_INTERCEPTS_STYLUS =
- IInputConstants.InputFeature.INTERCEPTS_STYLUS;
+ @RequiresPermission(permission.MONITOR_INPUT)
+ public static final int INPUT_FEATURE_SPY = 1 << 2;
/**
* An internal annotation for flags that can be specified to {@link #inputFeatures}.
*
+ * NOTE: These are not the same as {@link android.os.InputConfig} flags.
+ *
* @hide
*/
@Retention(RetentionPolicy.SOURCE)
- @IntDef(flag = true, prefix = { "INPUT_FEATURE_" }, value = {
- INPUT_FEATURE_NO_INPUT_CHANNEL,
- INPUT_FEATURE_DISABLE_USER_ACTIVITY,
- INPUT_FEATURE_SPY,
- INPUT_FEATURE_INTERCEPTS_STYLUS,
+ @IntDef(flag = true, prefix = {"INPUT_FEATURE_"}, value = {
+ INPUT_FEATURE_NO_INPUT_CHANNEL,
+ INPUT_FEATURE_DISABLE_USER_ACTIVITY,
+ INPUT_FEATURE_SPY,
})
- public @interface InputFeatureFlags {}
+ public @interface InputFeatureFlags {
+ }
/**
- * Control special features of the input subsystem.
+ * Control a set of features of the input subsystem that are exposed to the app process.
+ *
+ * WARNING: Do NOT use {@link android.os.InputConfig} flags! This must be set to flag values
+ * included in {@link InputFeatureFlags}.
*
- * @see #INPUT_FEATURE_NO_INPUT_CHANNEL
- * @see #INPUT_FEATURE_DISABLE_USER_ACTIVITY
- * @see #INPUT_FEATURE_SPY
- * @see #INPUT_FEATURE_INTERCEPTS_STYLUS
* @hide
+ * @see InputFeatureFlags
*/
@InputFeatureFlags
@UnsupportedAppUsage
@@ -4845,10 +4828,6 @@ public interface WindowManager extends ViewManager {
inputFeatures &= ~INPUT_FEATURE_SPY;
features.add("INPUT_FEATURE_SPY");
}
- if ((inputFeatures & INPUT_FEATURE_INTERCEPTS_STYLUS) != 0) {
- inputFeatures &= ~INPUT_FEATURE_INTERCEPTS_STYLUS;
- features.add("INPUT_FEATURE_INTERCEPTS_STYLUS");
- }
if (inputFeatures != 0) {
features.add(Integer.toHexString(inputFeatures));
}
diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java
index 2dc5fbd5439f..29a9926aeb9f 100644
--- a/core/java/android/view/WindowManagerGlobal.java
+++ b/core/java/android/view/WindowManagerGlobal.java
@@ -60,55 +60,27 @@ public final class WindowManagerGlobal {
private static boolean sUseBLASTAdapter = false;
/**
- * The user is navigating with keys (not the touch screen), so
- * navigational focus should be shown.
- */
- public static final int RELAYOUT_RES_IN_TOUCH_MODE = 0x1;
-
- /**
* This is the first time the window is being drawn,
* so the client must call drawingFinished() when done
*/
- public static final int RELAYOUT_RES_FIRST_TIME = 0x2;
+ public static final int RELAYOUT_RES_FIRST_TIME = 1;
/**
* The window manager has changed the surface from the last call.
*/
- public static final int RELAYOUT_RES_SURFACE_CHANGED = 0x4;
-
- /**
- * The window is being resized by dragging on the docked divider. The client should render
- * at (0, 0) and extend its background to the background frame passed into
- * {@link IWindow#resized}.
- */
- public static final int RELAYOUT_RES_DRAG_RESIZING_DOCKED = 0x8;
-
- /**
- * The window is being resized by dragging one of the window corners,
- * in this case the surface would be fullscreen-sized. The client should
- * render to the actual frame location (instead of (0,curScrollY)).
- */
- public static final int RELAYOUT_RES_DRAG_RESIZING_FREEFORM = 0x10;
+ public static final int RELAYOUT_RES_SURFACE_CHANGED = 1 << 1;
/**
* The window manager has changed the size of the surface from the last call.
*/
- public static final int RELAYOUT_RES_SURFACE_RESIZED = 0x20;
+ public static final int RELAYOUT_RES_SURFACE_RESIZED = 1 << 2;
/**
* In multi-window we force show the system bars. Because we don't want that the surface size
* changes in this mode, we instead have a flag whether the system bar sizes should always be
* consumed, so the app is treated like there is no virtual system bars at all.
*/
- public static final int RELAYOUT_RES_CONSUME_ALWAYS_SYSTEM_BARS = 0x40;
-
- /**
- * This flag indicates the client should not directly submit it's next frame,
- * but instead should pass it in the postDrawTransaction of
- * {@link WindowManagerService#finishDrawing}. This is used by the WM
- * BLASTSyncEngine to synchronize rendering of multiple windows.
- */
- public static final int RELAYOUT_RES_BLAST_SYNC = 0x80;
+ public static final int RELAYOUT_RES_CONSUME_ALWAYS_SYSTEM_BARS = 1 << 3;
/**
* Flag for relayout: the client will be later giving
diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java
index a270c9283ddc..06588b2cbb6d 100644
--- a/core/java/android/view/WindowlessWindowManager.java
+++ b/core/java/android/view/WindowlessWindowManager.java
@@ -22,6 +22,7 @@ import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.Region;
import android.os.Binder;
+import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteCallback;
import android.os.RemoteException;
@@ -217,9 +218,13 @@ public class WindowlessWindowManager implements IWindowSession {
throw new IllegalArgumentException(
"Invalid window token (never added or removed already)");
}
+ removeSurface(state.mSurfaceControl);
+ }
+ /** Separate from {@link #remove} so that subclasses can put removal on a sync transaction. */
+ protected void removeSurface(SurfaceControl sc) {
try (SurfaceControl.Transaction t = new SurfaceControl.Transaction()) {
- t.remove(state.mSurfaceControl).apply();
+ t.remove(sc).apply();
}
}
@@ -277,7 +282,7 @@ public class WindowlessWindowManager implements IWindowSession {
int requestedWidth, int requestedHeight, int viewFlags, int flags,
ClientWindowFrames outFrames, MergedConfiguration mergedConfiguration,
SurfaceControl outSurfaceControl, InsetsState outInsetsState,
- InsetsSourceControl[] outActiveControls) {
+ InsetsSourceControl[] outActiveControls, Bundle outSyncSeqIdBundle) {
final State state;
synchronized (this) {
state = mStateForWindow.get(window.asBinder());
@@ -327,8 +332,7 @@ public class WindowlessWindowManager implements IWindowSession {
outInsetsState.set(mInsetsState);
}
- // Include whether the window is in touch mode.
- return isInTouchMode() ? WindowManagerGlobal.RELAYOUT_RES_IN_TOUCH_MODE : 0;
+ return 0;
}
@Override
@@ -354,7 +358,7 @@ public class WindowlessWindowManager implements IWindowSession {
@Override
public void finishDrawing(android.view.IWindow window,
- android.view.SurfaceControl.Transaction postDrawTransaction) {
+ android.view.SurfaceControl.Transaction postDrawTransaction, int seqId) {
synchronized (this) {
final ResizeCompleteCallback c =
mResizeCompletionForWindow.get(window.asBinder());
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index aeef76c3d048..0008aa64efa4 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -4487,8 +4487,8 @@ public class AccessibilityNodeInfo implements Parcelable {
case R.id.accessibilityActionDragDrop:
return "ACTION_DROP";
default: {
- if (action == R.id.accessibilityActionShowSuggestions) {
- return "ACTION_SHOW_SUGGESTIONS";
+ if (action == R.id.accessibilityActionShowTextSuggestions) {
+ return "ACTION_SHOW_TEXT_SUGGESTIONS";
}
return "ACTION_UNKNOWN";
}
@@ -5189,34 +5189,10 @@ public class AccessibilityNodeInfo implements Parcelable {
new AccessibilityAction(R.id.accessibilityActionDragCancel);
/**
- * Action to perform a left swipe.
- */
- @NonNull public static final AccessibilityAction ACTION_SWIPE_LEFT =
- new AccessibilityAction(R.id.accessibilityActionSwipeLeft);
-
- /**
- * Action to perform a right swipe.
- */
- @NonNull public static final AccessibilityAction ACTION_SWIPE_RIGHT =
- new AccessibilityAction(R.id.accessibilityActionSwipeRight);
-
- /**
- * Action to perform an up swipe.
- */
- @NonNull public static final AccessibilityAction ACTION_SWIPE_UP =
- new AccessibilityAction(R.id.accessibilityActionSwipeUp);
-
- /**
- * Action to perform a down swipe.
- */
- @NonNull public static final AccessibilityAction ACTION_SWIPE_DOWN =
- new AccessibilityAction(R.id.accessibilityActionSwipeDown);
-
- /**
* Action to show suggestions for editable text.
*/
- @NonNull public static final AccessibilityAction ACTION_SHOW_SUGGESTIONS =
- new AccessibilityAction(R.id.accessibilityActionShowSuggestions);
+ @NonNull public static final AccessibilityAction ACTION_SHOW_TEXT_SUGGESTIONS =
+ new AccessibilityAction(R.id.accessibilityActionShowTextSuggestions);
private final int mActionId;
private final CharSequence mLabel;
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index a8cc114c4d69..2c81eb1ae306 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -16,9 +16,9 @@
package android.view.autofill;
-import static android.service.autofill.FillRequest.FLAG_ACTIVITY_START;
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;
import static android.service.autofill.FillRequest.FLAG_VIEW_NOT_FOCUSED;
import static android.view.ContentInfo.SOURCE_AUTOFILL;
import static android.view.autofill.Helper.sDebug;
@@ -1118,7 +1118,7 @@ public final class AutofillManager {
return;
}
- int flags = FLAG_ACTIVITY_START;
+ int flags = FLAG_SUPPORTS_FILL_DIALOG;
flags |= FLAG_VIEW_NOT_FOCUSED;
notifyViewEntered(view, flags);
}
@@ -3121,17 +3121,19 @@ public final class AutofillManager {
}
/**
- * If autofill suggestions for a dialog-style UI are available for {@code view}, shows a dialog
- * allowing the user to select a suggestion and returns {@code true}.
+ * If autofill suggestions for a
+ * <a href="{@docRoot}reference/android/service/autofill/Dataset.html#FillDialogUI">
+ * 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.
* <p>
- * It is recommended 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 this method returns
- * {@code false}, you should then instead show the input method (assuming that is how the
- * view normally handles the focus event). If the user re-focuses on the view, you should not
- * call this method again so as to not disrupt usage of the input method.
+ * 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
+ * this method returns {@code false}, you should then instead show the input method (assuming
+ * that is how the view normally handles the focus event). If the user re-focuses on the view,
+ * you should not call this method again so as to not disrupt usage of the input method.
*
* @param view the view for which to show autofill suggestions. This is typically a view
* receiving a focus event. The autofill suggestions shown will include content for
diff --git a/core/java/android/view/inputmethod/InputMethod.java b/core/java/android/view/inputmethod/InputMethod.java
index 69ad739608b2..6209b46997e8 100644
--- a/core/java/android/view/inputmethod/InputMethod.java
+++ b/core/java/android/view/inputmethod/InputMethod.java
@@ -31,6 +31,7 @@ import android.view.MotionEvent;
import android.view.View;
import com.android.internal.inputmethod.IInputMethodPrivilegedOperations;
+import com.android.internal.inputmethod.InputMethodNavButtonFlags;
import com.android.internal.view.IInlineSuggestionsRequestCallback;
import com.android.internal.view.InlineSuggestionsRequestInfo;
@@ -105,14 +106,13 @@ public interface InputMethod {
* current IME.
* @param configChanges {@link InputMethodInfo#getConfigChanges()} declared by IME.
* @param stylusHwSupported {@link InputMethodInfo#supportsStylusHandwriting()} declared by IME.
- * @param shouldShowImeSwitcherWhenImeIsShown {@code true} If the IME switcher is expected to be
- * shown while the IME is shown.
+ * @param navButtonFlags The initial state of {@link InputMethodNavButtonFlags}.
* @hide
*/
@MainThread
default void initializeInternal(IBinder token,
IInputMethodPrivilegedOperations privilegedOperations, int configChanges,
- boolean stylusHwSupported, boolean shouldShowImeSwitcherWhenImeIsShown) {
+ boolean stylusHwSupported, @InputMethodNavButtonFlags int navButtonFlags) {
attachToken(token);
}
@@ -231,8 +231,7 @@ public interface InputMethod {
* the next {@link #startInput(InputConnection, EditorInfo, IBinder)} as
* long as your implementation of {@link InputMethod} relies on such
* IPCs
- * @param shouldShowImeSwitcherWhenImeIsShown {@code true} If the IME switcher is expected to be
- * shown while the IME is shown.
+ * @param navButtonFlags {@link InputMethodNavButtonFlags} in the initial state of this session.
* @see #startInput(InputConnection, EditorInfo)
* @see #restartInput(InputConnection, EditorInfo)
* @see EditorInfo
@@ -241,7 +240,7 @@ public interface InputMethod {
@MainThread
default void dispatchStartInputWithToken(@Nullable InputConnection inputConnection,
@NonNull EditorInfo editorInfo, boolean restarting,
- @NonNull IBinder startInputToken, boolean shouldShowImeSwitcherWhenImeIsShown) {
+ @NonNull IBinder startInputToken, @InputMethodNavButtonFlags int navButtonFlags) {
if (restarting) {
restartInput(inputConnection, editorInfo);
} else {
@@ -250,15 +249,13 @@ public interface InputMethod {
}
/**
- * Notifies that whether the IME should show the IME switcher or not is being changed.
+ * Notifies that {@link InputMethodNavButtonFlags} have been updated.
*
- * @param shouldShowImeSwitcherWhenImeIsShown {@code true} If the IME switcher is expected to be
- * shown while the IME is shown.
+ * @param navButtonFlags The new {@link InputMethodNavButtonFlags}.
* @hide
*/
@MainThread
- default void onShouldShowImeSwitcherWhenImeIsShownChanged(
- boolean shouldShowImeSwitcherWhenImeIsShown) {
+ default void onNavButtonFlagsChanged(@InputMethodNavButtonFlags int navButtonFlags) {
}
/**
@@ -417,4 +414,12 @@ public interface InputMethod {
// intentionally empty
}
+ /**
+ * Finish stylus handwriting session.
+ * @hide
+ */
+ default void finishStylusHandwriting() {
+ // intentionally empty
+ }
+
}
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 248025190b3e..da20e336627c 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -1919,10 +1919,17 @@ public final class InputMethodManager {
if (fallbackImm != null) {
fallbackImm.startStylusHandwriting(view);
}
+ Objects.requireNonNull(view);
+
+ if (Settings.Global.getInt(view.getContext().getContentResolver(),
+ Settings.Global.STYLUS_HANDWRITING_ENABLED, 0) == 0) {
+ Log.d(TAG, "Ignoring startStylusHandwriting(view) as stylus handwriting is disabled");
+ return;
+ }
checkFocus();
synchronized (mH) {
- if (view == null || !hasServedByInputMethodLocked(view)) {
+ if (!hasServedByInputMethodLocked(view)) {
Log.w(TAG,
"Ignoring startStylusHandwriting() as view=" + view + " is not served.");
return;
@@ -3251,10 +3258,11 @@ public final class InputMethodManager {
* @return Something that is not well-defined.
* @hide
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(trackingBug = 204906124, maxTargetSdk = Build.VERSION_CODES.TIRAMISU,
+ publicAlternatives = "Use {@link android.view.WindowInsets} instead")
public int getInputMethodWindowVisibleHeight() {
try {
- return mService.getInputMethodWindowVisibleHeight();
+ return mService.getInputMethodWindowVisibleHeight(mClient);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/view/selectiontoolbar/SelectionToolbarManager.java b/core/java/android/view/selectiontoolbar/SelectionToolbarManager.java
index ef04b2c52282..6de031628768 100644
--- a/core/java/android/view/selectiontoolbar/SelectionToolbarManager.java
+++ b/core/java/android/view/selectiontoolbar/SelectionToolbarManager.java
@@ -105,7 +105,7 @@ public final class SelectionToolbarManager {
private boolean isRemoteSelectionToolbarEnabled() {
return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SELECTION_TOOLBAR,
- REMOTE_SELECTION_TOOLBAR_ENABLED, true);
+ REMOTE_SELECTION_TOOLBAR_ENABLED, false);
}
/**
diff --git a/core/java/android/view/translation/UiTranslationManager.java b/core/java/android/view/translation/UiTranslationManager.java
index 3012e9344a1b..01acdfec6c27 100644
--- a/core/java/android/view/translation/UiTranslationManager.java
+++ b/core/java/android/view/translation/UiTranslationManager.java
@@ -101,33 +101,32 @@ public final class UiTranslationManager {
public static final String LOG_TAG = "UiTranslation";
/**
- * The state caller request to disable utranslation,, it is no longer need to ui translation.
+ * The state the caller requests to enable UI translation.
*
* @hide
*/
public static final int STATE_UI_TRANSLATION_STARTED = 0;
/**
- * The state caller request to pause ui translation, it will switch back to the original text.
+ * The state caller requests to pause UI translation. It will switch back to the original text.
*
* @hide
*/
public static final int STATE_UI_TRANSLATION_PAUSED = 1;
/**
- * The state caller request to resume the paused ui translation, it will show the translated
+ * The state caller requests to resume the paused UI translation. It will show the translated
* text again if the text had been translated.
*
* @hide
*/
public static final int STATE_UI_TRANSLATION_RESUMED = 2;
/**
- * The state the caller request to enable ui translation.
+ * The state caller requests to disable UI translation when it no longer needs translation.
*
* @hide
*/
public static final int STATE_UI_TRANSLATION_FINISHED = 3;
- /**
- * @hide
- */
+
+ /** @hide */
@IntDef(prefix = {"STATE__TRANSLATION"}, value = {
STATE_UI_TRANSLATION_STARTED,
STATE_UI_TRANSLATION_PAUSED,
@@ -145,6 +144,8 @@ public final class UiTranslationManager {
public static final String EXTRA_SOURCE_LOCALE = "source_locale";
/** @hide */
public static final String EXTRA_TARGET_LOCALE = "target_locale";
+ /** @hide */
+ public static final String EXTRA_PACKAGE_NAME = "package_name";
@NonNull
private final Context mContext;
@@ -215,7 +216,7 @@ public final class UiTranslationManager {
/**
* Request to disable the ui translation. It will destroy all the {@link Translator}s and no
- * longer to show to show the translated text.
+ * longer to show the translated text.
*
* @param activityId the identifier for the Activity which needs ui translation
* @throws NullPointerException the activityId or
@@ -362,8 +363,8 @@ public final class UiTranslationManager {
public void onTranslationFinished(boolean activityDestroyed, ActivityId activityId,
ComponentName componentName) {
try {
- mService.onTranslationFinished(activityDestroyed,
- activityId.getToken(), componentName, mContext.getUserId());
+ mService.onTranslationFinished(activityDestroyed, activityId.getToken(), componentName,
+ mContext.getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -392,20 +393,21 @@ public final class UiTranslationManager {
private void onStateChange(Bundle bundle) {
int state = bundle.getInt(EXTRA_STATE);
+ String packageName = bundle.getString(EXTRA_PACKAGE_NAME);
switch (state) {
case STATE_UI_TRANSLATION_STARTED:
- mSourceLocale = (ULocale) bundle.getSerializable(EXTRA_SOURCE_LOCALE);
- mTargetLocale = (ULocale) bundle.getSerializable(EXTRA_TARGET_LOCALE);
- mCallback.onStarted(mSourceLocale, mTargetLocale);
+ mSourceLocale = bundle.getSerializable(EXTRA_SOURCE_LOCALE, ULocale.class);
+ mTargetLocale = bundle.getSerializable(EXTRA_TARGET_LOCALE, ULocale.class);
+ mCallback.onStarted(mSourceLocale, mTargetLocale, packageName);
break;
case STATE_UI_TRANSLATION_RESUMED:
- mCallback.onResumed(mSourceLocale, mTargetLocale);
+ mCallback.onResumed(mSourceLocale, mTargetLocale, packageName);
break;
case STATE_UI_TRANSLATION_PAUSED:
- mCallback.onPaused();
+ mCallback.onPaused(packageName);
break;
case STATE_UI_TRANSLATION_FINISHED:
- mCallback.onFinished();
+ mCallback.onFinished(packageName);
break;
default:
Log.wtf(TAG, "Unexpected translation state:" + state);
diff --git a/core/java/android/view/translation/UiTranslationStateCallback.java b/core/java/android/view/translation/UiTranslationStateCallback.java
index d7dc284a2a09..3ccca5f5290f 100644
--- a/core/java/android/view/translation/UiTranslationStateCallback.java
+++ b/core/java/android/view/translation/UiTranslationStateCallback.java
@@ -24,11 +24,21 @@ import java.util.concurrent.Executor;
/**
* Callback for listening to UI Translation state changes. See {@link
* UiTranslationManager#registerUiTranslationStateCallback(Executor, UiTranslationStateCallback)}.
+ * <p>
+ * Prior to Android version {@link android.os.Build.VERSION_CODES#TIRAMISU}, callback methods
+ * <em>without</em> {@code packageName} are invoked. Apps with minSdkVersion lower than {@link
+ * android.os.Build.VERSION_CODES#TIRAMISU} <em>must</em> implement those methods if they want to
+ * handle the events.
+ * <p>
+ * In Android version {@link android.os.Build.VERSION_CODES#TIRAMISU} and later, if both methods
+ * with and without {@code packageName} are implemented (e.g., {@link #onFinished()} and {@link
+ * #onFinished(String)}, only the one <em>with</em> {@code packageName} will be called.
*/
public interface UiTranslationStateCallback {
/**
- * @removed use {@link #onStarted(ULocale, ULocale)} instead.
+ * @removed use {@link #onStarted(ULocale, ULocale)} or {@link #onStarted(ULocale, ULocale,
+ * String)} instead.
*/
@Deprecated
default void onStarted(@NonNull String sourceLocale, @NonNull String targetLocale) {
@@ -41,27 +51,122 @@ public interface UiTranslationStateCallback {
* <p>
* This is also called if either the requested {@code sourceLocale} or {@code targetLocale} has
* changed.
+ * <p>
+ * Apps should implement {@link #onStarted(ULocale, ULocale, String)} instead if they need the
+ * name of the package that owns the activity being translated.
+ * <p>
+ * Apps with minSdkVersion lower than {@link android.os.Build.VERSION_CODES#TIRAMISU}
+ * <em>must</em> implement this method if they want to handle the "started" event.
+ *
+ * @param sourceLocale {@link ULocale} the UI is being translated from.
+ * @param targetLocale {@link ULocale} the UI is being translated to.
*/
default void onStarted(@NonNull ULocale sourceLocale, @NonNull ULocale targetLocale) {
onStarted(sourceLocale.getLanguage(), targetLocale.getLanguage());
}
/**
+ * The system is requesting translation of the UI from {@code sourceLocale} to {@code
+ * targetLocale}.
+ * <p>
+ * This is also called if either the requested {@code sourceLocale} or {@code targetLocale} has
+ * changed.
+ * <p>
+ * Apps <em>may</em> implement {@link #onStarted(ULocale, ULocale)} instead if they don't need
+ * the name of the package that owns the activity being translated.
+ * <p>
+ * Apps with minSdkVersion lower than {@link android.os.Build.VERSION_CODES#TIRAMISU}
+ * <em>must</em> implement {@link #onStarted(ULocale, ULocale)} if they want to handle the
+ * "started" event.
+ *
+ * @param sourceLocale {@link ULocale} the UI is being translated from.
+ * @param targetLocale {@link ULocale} the UI is being translated to.
+ * @param packageName The name of the package that owns the activity being translated.
+ */
+ default void onStarted(@NonNull ULocale sourceLocale, @NonNull ULocale targetLocale,
+ @NonNull String packageName) {
+ onStarted(sourceLocale, targetLocale);
+ }
+
+ /**
* The system is requesting that the application temporarily show the UI contents in their
* original language.
+ * <p>
+ * Apps should implement {@link #onPaused(String)} as well if they need the name of the
+ * package that owns the activity being translated.
*/
void onPaused();
/**
+ * The system is requesting that the application temporarily show the UI contents in their
+ * original language.
+ * <p>
+ * Apps <em>may</em> implement {@link #onPaused()} instead if they don't need the name of the
+ * package that owns the activity being translated.
+ * <p>
+ * Apps with minSdkVersion lower than {@link android.os.Build.VERSION_CODES#TIRAMISU}
+ * <em>must</em> implement {@link #onPaused()} if they want to handle the "paused" event.
+ */
+ default void onPaused(@NonNull String packageName) {
+ onPaused();
+ }
+
+ /**
* The system is requesting that the application restore from the temporarily paused state and
- * show the content in translated language.
+ * show the content in the translated language.
+ * <p>
+ * Apps should implement {@link #onResumed(ULocale, ULocale, String)} instead if they need the
+ * name of the package that owns the activity being translated.
+ * <p>
+ * Apps with minSdkVersion lower than {@link android.os.Build.VERSION_CODES#TIRAMISU}
+ * <em>must</em> implement this method if they want to handle the "resumed" event.
+ *
+ * @param sourceLocale {@link ULocale} the UI is being translated from.
+ * @param targetLocale {@link ULocale} the UI is being translated to.
*/
- // TODO: Remove the default implementation when clients have implemented this.
default void onResumed(@NonNull ULocale sourceLocale, @NonNull ULocale targetLocale) {
}
/**
+ * The system is requesting that the application restore from the temporarily paused state and
+ * show the content in the translated language.
+ * <p>
+ * Apps <em>may</em> implement {@link #onResumed(ULocale, ULocale)} instead if they don't need
+ * the name of the package that owns the activity being translated.
+ * <p>
+ * Apps with minSdkVersion lower than {@link android.os.Build.VERSION_CODES#TIRAMISU}
+ * <em>must</em> implement {@link #onResumed(ULocale, ULocale)} if they want to handle the
+ * "resumed" event.
+ *
+ * @param sourceLocale {@link ULocale} the UI is being translated from.
+ * @param targetLocale {@link ULocale} the UI is being translated to.
+ * @param packageName The name of the package that owns the activity being translated.
+ */
+ default void onResumed(@NonNull ULocale sourceLocale, @NonNull ULocale targetLocale,
+ @NonNull String packageName) {
+ onResumed(sourceLocale, targetLocale);
+ }
+
+ /**
* The UI Translation session has ended.
+ * <p>
+ * Apps should implement {@link #onFinished(String)} as well if they need the name of the
+ * package that owns the activity being translated.
*/
void onFinished();
+
+ /**
+ * The UI Translation session has ended.
+ * <p>
+ * Apps <em>may</em> implement {@link #onFinished()} instead if they don't need the name of the
+ * package that owns the activity being translated.
+ * <p>
+ * Apps with minSdkVersion lower than {@link android.os.Build.VERSION_CODES#TIRAMISU}
+ * <em>must</em> implement {@link #onFinished()} if they want to handle the "finished" event.
+ *
+ * @param packageName The name of the package that owns the activity being translated.
+ */
+ default void onFinished(@NonNull String packageName) {
+ onFinished();
+ }
}
diff --git a/core/java/android/view/translation/ViewTranslationCallback.java b/core/java/android/view/translation/ViewTranslationCallback.java
index 66c028b48dc6..3936b639592d 100644
--- a/core/java/android/view/translation/ViewTranslationCallback.java
+++ b/core/java/android/view/translation/ViewTranslationCallback.java
@@ -60,7 +60,7 @@ public interface ViewTranslationCallback {
/**
* Called when user wants to view the original content instead of the translated content. This
* method will not be called before {@link View#onViewTranslationResponse} or
- * {@link View#onViewTranslationResponse}.
+ * {@link View#onVirtualViewTranslationResponses}.
*
* @return {@code true} if the View handles hiding the translation.
*/
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 3a7a544a334b..67f284b437b0 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -4595,7 +4595,7 @@ public class Editor {
if (includeEditorBounds) {
final RectF bounds = new RectF();
- mTextView.getBoundsOnScreen(bounds, false /* clipToParent */);
+ bounds.set(0 /* left */, 0 /* top */, mTextView.getWidth(), mTextView.getHeight());
EditorBoundsInfo.Builder boundsBuilder = new EditorBoundsInfo.Builder();
//TODO(b/210039666): add Handwriting bounds once they're available.
builder.setEditorBoundsInfo(
@@ -6309,7 +6309,8 @@ public class Editor {
}
switch (event.getActionMasked()) {
case MotionEvent.ACTION_MOVE:
- if (event.isFromSource(InputDevice.SOURCE_MOUSE)) {
+ if (event.isFromSource(InputDevice.SOURCE_MOUSE)
+ || (mTextView.isAutoHandwritingEnabled() && isFromStylus(event))) {
break;
}
if (mIsDraggingCursor) {
@@ -6332,6 +6333,11 @@ public class Editor {
}
}
+ private boolean isFromStylus(MotionEvent motionEvent) {
+ final int pointerIndex = motionEvent.getActionIndex();
+ return motionEvent.getToolType(pointerIndex) == MotionEvent.TOOL_TYPE_STYLUS;
+ }
+
private void positionCursorDuringDrag(MotionEvent event) {
mPrevLineDuringDrag = getLineDuringDrag(event);
int offset = mTextView.getOffsetAtCoordinate(mPrevLineDuringDrag, event.getX());
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index b00a3829f468..fbad38f27a23 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -6681,7 +6681,13 @@ public class RemoteViews implements Parcelable, Filter {
opts = ActivityOptions.makeBasic();
opts.setPendingIntentLaunchFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}
- opts.setLaunchDisplayId(view.getDisplay().getDisplayId());
+ if (view.getDisplay() != null) {
+ opts.setLaunchDisplayId(view.getDisplay().getDisplayId());
+ } else {
+ // TODO(b/218409359): Remove once bug is fixed.
+ Log.w(LOG_TAG, "getLaunchOptions: view.getDisplay() is null!",
+ new Exception());
+ }
return Pair.create(intent, opts);
}
}
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index c207af53fab7..3c8fcb978fbd 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -788,7 +788,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
private Layout mLayout;
private boolean mLocalesChanged = false;
private int mTextSizeUnit = -1;
- private LineBreakConfig mLineBreakConfig = new LineBreakConfig();
+ private int mLineBreakStyle = DEFAULT_LINE_BREAK_STYLE;
+ private int mLineBreakWordStyle = DEFAULT_LINE_BREAK_WORD_STYLE;
// This is used to reflect the current user preference for changing font weight and making text
// more bold.
@@ -1457,13 +1458,12 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
break;
case com.android.internal.R.styleable.TextView_lineBreakStyle:
- mLineBreakConfig.setLineBreakStyle(
- a.getInt(attr, LineBreakConfig.LINE_BREAK_STYLE_NONE));
+ mLineBreakStyle = a.getInt(attr, LineBreakConfig.LINE_BREAK_STYLE_NONE);
break;
case com.android.internal.R.styleable.TextView_lineBreakWordStyle:
- mLineBreakConfig.setLineBreakWordStyle(
- a.getInt(attr, LineBreakConfig.LINE_BREAK_WORD_STYLE_NONE));
+ mLineBreakWordStyle = a.getInt(attr,
+ LineBreakConfig.LINE_BREAK_WORD_STYLE_NONE);
break;
case com.android.internal.R.styleable.TextView_autoSizeTextType:
@@ -4301,13 +4301,12 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
@LineBreakConfig.LineBreakStyle int lineBreakStyle,
@LineBreakConfig.LineBreakWordStyle int lineBreakWordStyle) {
boolean updated = false;
- if (isLineBreakStyleSpecified && mLineBreakConfig.getLineBreakStyle() != lineBreakStyle) {
- mLineBreakConfig.setLineBreakStyle(lineBreakStyle);
+ if (isLineBreakStyleSpecified && mLineBreakStyle != lineBreakStyle) {
+ mLineBreakStyle = lineBreakStyle;
updated = true;
}
- if (isLineBreakWordStyleSpecified
- && mLineBreakConfig.getLineBreakWordStyle() != lineBreakWordStyle) {
- mLineBreakConfig.setLineBreakWordStyle(lineBreakWordStyle);
+ if (isLineBreakWordStyleSpecified && mLineBreakWordStyle != lineBreakWordStyle) {
+ mLineBreakWordStyle = lineBreakWordStyle;
updated = true;
}
if (updated && mLayout != null) {
@@ -4871,50 +4870,72 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
/**
- * Sets line break configuration indicates which strategy needs to be used when calculating the
- * text wrapping.
- * <P>
- * There are two types of line break rules that can be configured at the same time. One is
- * line break style(lb) and the other is line break word style(lw). The line break style
- * affects rule-based breaking. The line break word style affects dictionary-based breaking
- * and provide phrase-based breaking opportunities. There are several types for the
- * line break style:
+ * Set the line break style for text wrapping.
+ *
+ * The line break style to indicates the line break strategies can be used when
+ * calculating the text wrapping. The line break style affects rule-based breaking. It
+ * specifies the strictness of line-breaking rules.
+ * There are several types for the line break style:
* {@link LineBreakConfig#LINE_BREAK_STYLE_LOOSE},
* {@link LineBreakConfig#LINE_BREAK_STYLE_NORMAL} and
- * {@link LineBreakConfig#LINE_BREAK_STYLE_STRICT}.
- * The type for the line break word style is
- * {@link LineBreakConfig#LINE_BREAK_WORD_STYLE_PHRASE}.
- * The default values of the line break style and the line break word style are
- * {@link LineBreakConfig#LINE_BREAK_STYLE_NONE} and
- * {@link LineBreakConfig#LINE_BREAK_WORD_STYLE_NONE} respectively, indicating that no line
- * breaking rules are specified.
- * See <a href="https://drafts.csswg.org/css-text/#line-break-property">
+ * {@link LineBreakConfig#LINE_BREAK_STYLE_STRICT}. The default values of the line break style
+ * is {@link LineBreakConfig#LINE_BREAK_STYLE_NONE}, indicating no breaking rule is specified.
+ * See <a href="https://www.w3.org/TR/css-text-3/#line-break-property">
* the line-break property</a>
*
- * @param lineBreakConfig the line break config for text wrapping.
+ * @param lineBreakStyle the line break style for the text.
*/
- public void setLineBreakConfig(@NonNull LineBreakConfig lineBreakConfig) {
- Objects.requireNonNull(lineBreakConfig);
- if (mLineBreakConfig.equals(lineBreakConfig)) {
- return;
+ public void setLineBreakStyle(@LineBreakConfig.LineBreakStyle int lineBreakStyle) {
+ if (mLineBreakStyle != lineBreakStyle) {
+ mLineBreakStyle = lineBreakStyle;
+ if (mLayout != null) {
+ nullLayouts();
+ requestLayout();
+ invalidate();
+ }
}
- mLineBreakConfig.set(lineBreakConfig);
- if (mLayout != null) {
- nullLayouts();
- requestLayout();
- invalidate();
+ }
+
+ /**
+ * Set the line break word style for text wrapping.
+ *
+ * The line break word style affects dictionary-based breaking and provide phrase-based
+ * breaking opportunities. The type for the line break word style is
+ * {@link LineBreakConfig#LINE_BREAK_WORD_STYLE_PHRASE}. The default values of the line break
+ * word style is {@link LineBreakConfig#LINE_BREAK_WORD_STYLE_NONE}, indicating no breaking rule
+ * is specified.
+ * See <a href="https://www.w3.org/TR/css-text-3/#word-break-property">
+ * the word-break property</a>
+ *
+ * @param lineBreakWordStyle the line break word style for the tet
+ */
+ public void setLineBreakWordStyle(@LineBreakConfig.LineBreakWordStyle int lineBreakWordStyle) {
+ if (mLineBreakWordStyle != lineBreakWordStyle) {
+ mLineBreakWordStyle = lineBreakWordStyle;
+ if (mLayout != null) {
+ nullLayouts();
+ requestLayout();
+ invalidate();
+ }
}
}
/**
- * Get the current line break configuration for text wrapping.
+ * Get the current line break style for text wrapping.
*
- * @return the current line break configuration to be used for text wrapping.
+ * @return the current line break style to be used for text wrapping.
*/
- public @NonNull LineBreakConfig getLineBreakConfig() {
- LineBreakConfig lbConfig = new LineBreakConfig();
- lbConfig.set(mLineBreakConfig);
- return lbConfig;
+ public @LineBreakConfig.LineBreakStyle int getLineBreakStyle() {
+ return mLineBreakStyle;
+ }
+
+ /**
+ * Get the current line word break style for text wrapping.
+ *
+ * @return the current line break word style to be used for text wrapping.
+ */
+ public @LineBreakConfig.LineBreakWordStyle int getLineBreakWordStyle() {
+ return mLineBreakWordStyle;
}
/**
@@ -4924,7 +4945,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
* @see PrecomputedText
*/
public @NonNull PrecomputedText.Params getTextMetricsParams() {
- return new PrecomputedText.Params(new TextPaint(mTextPaint), mLineBreakConfig,
+ return new PrecomputedText.Params(new TextPaint(mTextPaint),
+ LineBreakConfig.getLineBreakConfig(mLineBreakStyle, mLineBreakWordStyle),
getTextDirectionHeuristic(),
mBreakStrategy, mHyphenationFrequency);
}
@@ -4941,13 +4963,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
mTextDir = params.getTextDirection();
mBreakStrategy = params.getBreakStrategy();
mHyphenationFrequency = params.getHyphenationFrequency();
- if (params.getLineBreakConfig() != null) {
- mLineBreakConfig.set(params.getLineBreakConfig());
- } else {
- // Set default value if the line break config in the PrecomputedText.Params is null.
- mLineBreakConfig.setLineBreakStyle(DEFAULT_LINE_BREAK_STYLE);
- mLineBreakConfig.setLineBreakWordStyle(DEFAULT_LINE_BREAK_WORD_STYLE);
- }
+ LineBreakConfig lineBreakConfig = params.getLineBreakConfig();
+ mLineBreakStyle = lineBreakConfig.getLineBreakStyle();
+ mLineBreakWordStyle = lineBreakConfig.getLineBreakWordStyle();
if (mLayout != null) {
nullLayouts();
requestLayout();
@@ -6486,7 +6504,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
final @PrecomputedText.Params.CheckResultUsableResult int checkResult =
precomputed.getParams().checkResultUsable(getPaint(), mTextDir, mBreakStrategy,
- mHyphenationFrequency, mLineBreakConfig);
+ mHyphenationFrequency, LineBreakConfig.getLineBreakConfig(
+ mLineBreakStyle, mLineBreakWordStyle));
switch (checkResult) {
case PrecomputedText.Params.UNUSABLE:
throw new IllegalArgumentException(
@@ -9383,7 +9402,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
.setHyphenationFrequency(mHyphenationFrequency)
.setJustificationMode(mJustificationMode)
.setMaxLines(mMaxMode == LINES ? mMaximum : Integer.MAX_VALUE)
- .setLineBreakConfig(mLineBreakConfig);
+ .setLineBreakConfig(LineBreakConfig.getLineBreakConfig(
+ mLineBreakStyle, mLineBreakWordStyle));
if (shouldEllipsize) {
builder.setEllipsize(mEllipsize)
.setEllipsizedWidth(ellipsisWidth);
@@ -9498,7 +9518,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
.setHyphenationFrequency(mHyphenationFrequency)
.setJustificationMode(mJustificationMode)
.setMaxLines(mMaxMode == LINES ? mMaximum : Integer.MAX_VALUE)
- .setLineBreakConfig(mLineBreakConfig);
+ .setLineBreakConfig(LineBreakConfig.getLineBreakConfig(
+ mLineBreakStyle, mLineBreakWordStyle));
if (shouldEllipsize) {
builder.setEllipsize(effectiveEllipsize)
.setEllipsizedWidth(ellipsisWidth);
@@ -9866,7 +9887,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
.setJustificationMode(getJustificationMode())
.setMaxLines(mMaxMode == LINES ? mMaximum : Integer.MAX_VALUE)
.setTextDirection(getTextDirectionHeuristic())
- .setLineBreakConfig(mLineBreakConfig);
+ .setLineBreakConfig(LineBreakConfig.getLineBreakConfig(
+ mLineBreakStyle, mLineBreakWordStyle));
final StaticLayout layout = layoutBuilder.build();
@@ -12313,7 +12335,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
info.addAction(AccessibilityNodeInfo.ACTION_CUT);
}
if (canReplace()) {
- info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_SHOW_SUGGESTIONS);
+ info.addAction(
+ AccessibilityNodeInfo.AccessibilityAction.ACTION_SHOW_TEXT_SUGGESTIONS);
}
if (canShare()) {
info.addAction(new AccessibilityNodeInfo.AccessibilityAction(
@@ -12634,7 +12657,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
default: {
// New ids have static blocks to assign values, so they can't be used in a case
// block.
- if (action == R.id.accessibilityActionShowSuggestions) {
+ if (action == R.id.accessibilityActionShowTextSuggestions) {
return isFocused() && canReplace() && onTextContextMenuItem(ID_REPLACE);
}
return super.performAccessibilityActionInternal(action, arguments);
diff --git a/core/java/android/window/ClientWindowFrames.java b/core/java/android/window/ClientWindowFrames.java
index acf9882e6658..5b915cc22ec5 100644
--- a/core/java/android/window/ClientWindowFrames.java
+++ b/core/java/android/window/ClientWindowFrames.java
@@ -27,47 +27,55 @@ import android.os.Parcelable;
*/
public class ClientWindowFrames implements Parcelable {
/** The actual window bounds. */
- public final @NonNull Rect frame;
+ public final @NonNull Rect frame = new Rect();
/**
* The container frame that is usually the same as display size. It may exclude the area of
* insets if the window layout parameter has specified fit-insets-sides.
*/
- public final @NonNull Rect displayFrame;
+ public final @NonNull Rect displayFrame = new Rect();
+
+ /**
+ * The frame to be referenced while applying gravity and MATCH_PARENT.
+ */
+ public final @NonNull Rect parentFrame = new Rect();
/** The background area while the window is resizing. */
- public final @NonNull Rect backdropFrame;
+ public final @NonNull Rect backdropFrame = new Rect();
+
+ public boolean isParentFrameClippedByDisplayCutout;
public ClientWindowFrames() {
- frame = new Rect();
- displayFrame = new Rect();
- backdropFrame = new Rect();
}
public ClientWindowFrames(ClientWindowFrames other) {
- frame = new Rect(other.frame);
- displayFrame = new Rect(other.displayFrame);
- backdropFrame = new Rect(other.backdropFrame);
+ frame.set(other.frame);
+ displayFrame.set(other.displayFrame);
+ parentFrame.set(other.parentFrame);
+ backdropFrame.set(other.backdropFrame);
+ isParentFrameClippedByDisplayCutout = other.isParentFrameClippedByDisplayCutout;
}
private ClientWindowFrames(Parcel in) {
- frame = Rect.CREATOR.createFromParcel(in);
- displayFrame = Rect.CREATOR.createFromParcel(in);
- backdropFrame = Rect.CREATOR.createFromParcel(in);
+ readFromParcel(in);
}
/** Needed for AIDL out parameters. */
public void readFromParcel(Parcel in) {
frame.readFromParcel(in);
displayFrame.readFromParcel(in);
+ parentFrame.readFromParcel(in);
backdropFrame.readFromParcel(in);
+ isParentFrameClippedByDisplayCutout = in.readBoolean();
}
@Override
public void writeToParcel(Parcel dest, int flags) {
frame.writeToParcel(dest, flags);
displayFrame.writeToParcel(dest, flags);
+ parentFrame.writeToParcel(dest, flags);
backdropFrame.writeToParcel(dest, flags);
+ dest.writeBoolean(isParentFrameClippedByDisplayCutout);
}
@Override
@@ -75,7 +83,9 @@ public class ClientWindowFrames implements Parcelable {
final StringBuilder sb = new StringBuilder(32);
return "ClientWindowFrames{frame=" + frame.toShortString(sb)
+ " display=" + displayFrame.toShortString(sb)
- + " backdrop=" + backdropFrame.toShortString(sb) + "}";
+ + " parentFrame=" + parentFrame.toShortString(sb)
+ + " backdrop=" + backdropFrame.toShortString(sb)
+ + " parentClippedByDisplayCutout=" + isParentFrameClippedByDisplayCutout + "}";
}
@Override
diff --git a/core/java/android/window/DisplayWindowPolicyController.java b/core/java/android/window/DisplayWindowPolicyController.java
index 3359a41369d7..1270d87e3a04 100644
--- a/core/java/android/window/DisplayWindowPolicyController.java
+++ b/core/java/android/window/DisplayWindowPolicyController.java
@@ -17,12 +17,14 @@
package android.window;
import android.annotation.NonNull;
+import android.app.WindowConfiguration;
import android.content.ComponentName;
import android.content.pm.ActivityInfo;
import android.util.ArraySet;
import java.io.PrintWriter;
import java.util.List;
+import java.util.Set;
/**
* Abstract class to control the policies of the windows that can be displayed on the virtual
@@ -46,6 +48,22 @@ public abstract class DisplayWindowPolicyController {
private int mSystemWindowFlags;
/**
+ * The set of windowing mode that are supported in this display.
+ * @see android.app.WindowConfiguration.WindowingMode
+ */
+ private final Set<Integer> mSupportedWindowingModes = new ArraySet<>();
+
+ /**
+ * A controller to control the policies of the windows that can be displayed on the virtual
+ * display.
+ */
+ public DisplayWindowPolicyController() {
+ synchronized (mSupportedWindowingModes) {
+ mSupportedWindowingModes.add(WindowConfiguration.WINDOWING_MODE_FULLSCREEN);
+ }
+ }
+
+ /**
* Returns {@code true} if the given window flags contain the flags that we're interested in.
*/
public final boolean isInterestedWindowFlags(int windowFlags, int systemWindowFlags) {
@@ -62,9 +80,34 @@ public abstract class DisplayWindowPolicyController {
}
/**
- * Returns {@code true} if the given activities can be displayed on this virtual display.
+ * Returns {@code true} if the given windowing mode is supported in this display.
+ */
+ public final boolean isWindowingModeSupported(
+ @WindowConfiguration.WindowingMode int windowingMode) {
+ synchronized (mSupportedWindowingModes) {
+ return mSupportedWindowingModes.contains(windowingMode);
+ }
+ }
+
+ /**
+ * Sets the windowing modes are supported in this display.
+ *
+ * @param supportedWindowingModes The set of
+ * {@link android.app.WindowConfiguration.WindowingMode}.
+ */
+ public final void setSupportedWindowingModes(Set<Integer> supportedWindowingModes) {
+ synchronized (mSupportedWindowingModes) {
+ mSupportedWindowingModes.clear();
+ mSupportedWindowingModes.addAll(supportedWindowingModes);
+ }
+ }
+
+ /**
+ * Returns {@code true} if the given activities can be displayed on this virtual display and
+ * the windowing mode is supported.
*/
- public abstract boolean canContainActivities(@NonNull List<ActivityInfo> activities);
+ public abstract boolean canContainActivities(@NonNull List<ActivityInfo> activities,
+ @WindowConfiguration.WindowingMode int windowingMode);
/**
* Called when an Activity window is layouted with the new changes where contains the
diff --git a/core/java/android/window/ITaskOrganizerController.aidl b/core/java/android/window/ITaskOrganizerController.aidl
index 022d05da8825..172456e4d0fa 100644
--- a/core/java/android/window/ITaskOrganizerController.aidl
+++ b/core/java/android/window/ITaskOrganizerController.aidl
@@ -52,7 +52,7 @@ interface ITaskOrganizerController {
/** Gets all root tasks on a display (ordered from top-to-bottom) */
List<ActivityManager.RunningTaskInfo> getRootTasks(int displayId, in int[] activityTypes);
- /** Get the root task which contains the current ime target */
+ /** Get the {@link WindowContainerToken} of the task which contains the current ime target */
WindowContainerToken getImeTarget(int display);
/**
diff --git a/core/java/android/window/OnBackInvokedCallback.java b/core/java/android/window/OnBackInvokedCallback.java
index dcd80fd76e09..400a56f2c485 100644
--- a/core/java/android/window/OnBackInvokedCallback.java
+++ b/core/java/android/window/OnBackInvokedCallback.java
@@ -33,7 +33,7 @@ import android.view.View;
* within the same priority. Between different pirorities, callbacks with higher priority
* are invoked first.
*
- * See {@link OnBackInvokedDispatcher#registerOnBackInvokedCallback(OnBackInvokedCallback, int)}
+ * See {@link OnBackInvokedDispatcher#registerOnBackInvokedCallback(int, OnBackInvokedCallback)}
* for specifying callback priority.
*/
public interface OnBackInvokedCallback {
diff --git a/core/java/android/window/OnBackInvokedDispatcher.java b/core/java/android/window/OnBackInvokedDispatcher.java
index 63e6d30c8c0b..5eed8cde8c7c 100644
--- a/core/java/android/window/OnBackInvokedDispatcher.java
+++ b/core/java/android/window/OnBackInvokedDispatcher.java
@@ -94,15 +94,15 @@ public interface OnBackInvokedDispatcher {
* Within the same priority level, callbacks are invoked in the reverse order in which
* they are registered. Higher priority callbacks are invoked before lower priority ones.
*
+ * @param priority The priority of the callback.
* @param callback The callback to be registered. If the callback instance has been already
* registered, the existing instance (no matter its priority) will be
* unregistered and registered again.
- * @param priority The priority of the callback.
* @throws {@link IllegalArgumentException} if the priority is negative.
*/
- @SuppressLint({"SamShouldBeLast", "ExecutorRegistration"})
+ @SuppressLint({"ExecutorRegistration"})
void registerOnBackInvokedCallback(
- @NonNull OnBackInvokedCallback callback, @Priority @IntRange(from = 0) int priority);
+ @Priority @IntRange(from = 0) int priority, @NonNull OnBackInvokedCallback callback);
/**
* Unregisters a {@link OnBackInvokedCallback}.
diff --git a/core/java/android/window/ProxyOnBackInvokedDispatcher.java b/core/java/android/window/ProxyOnBackInvokedDispatcher.java
index cf17a2116aac..2b2f5e945710 100644
--- a/core/java/android/window/ProxyOnBackInvokedDispatcher.java
+++ b/core/java/android/window/ProxyOnBackInvokedDispatcher.java
@@ -44,7 +44,7 @@ public class ProxyOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
/**
* List of pair representing an {@link OnBackInvokedCallback} and its associated priority.
*
- * @see OnBackInvokedDispatcher#registerOnBackInvokedCallback(OnBackInvokedCallback, int)
+ * @see OnBackInvokedDispatcher#registerOnBackInvokedCallback(int, OnBackInvokedCallback)
*/
private final List<Pair<OnBackInvokedCallback, Integer>> mCallbacks = new ArrayList<>();
private final Object mLock = new Object();
@@ -52,7 +52,7 @@ public class ProxyOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
@Override
public void registerOnBackInvokedCallback(
- @NonNull OnBackInvokedCallback callback, int priority) {
+ int priority, @NonNull OnBackInvokedCallback callback) {
if (DEBUG) {
Log.v(TAG, String.format("Pending register %s. Actual=%s", callback,
mActualDispatcherOwner));
@@ -91,7 +91,7 @@ public class ProxyOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
mCallbacks.add(Pair.create(callback, priority));
if (mActualDispatcherOwner != null) {
mActualDispatcherOwner.getOnBackInvokedDispatcher().registerOnBackInvokedCallback(
- callback, priority);
+ priority, callback);
}
}
}
@@ -115,7 +115,7 @@ public class ProxyOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
for (Pair<OnBackInvokedCallback, Integer> callbackPair : mCallbacks) {
int priority = callbackPair.second;
if (priority >= 0) {
- dispatcher.registerOnBackInvokedCallback(callbackPair.first, priority);
+ dispatcher.registerOnBackInvokedCallback(priority, callbackPair.first);
} else {
dispatcher.registerSystemOnBackInvokedCallback(callbackPair.first);
}
diff --git a/core/java/android/window/SplashScreen.java b/core/java/android/window/SplashScreen.java
index fab180dae0bf..f1c0d8dee525 100644
--- a/core/java/android/window/SplashScreen.java
+++ b/core/java/android/window/SplashScreen.java
@@ -100,8 +100,12 @@ public interface SplashScreen {
* <p>
* To reset to the default theme, set this the themeId to {@link Resources#ID_NULL}.
* <p>
- * <b>Note:</b> The theme name must be stable across versions, otherwise it won't be found
- * after your application is updated.
+ * <b>Note:</b> Internally, the theme name is resolved and persisted. This means that the theme
+ * name must be stable across versions, otherwise it won't be found after your application is
+ * updated.
+ *
+ * @param themeId The ID of the splashscreen theme to be used in place of the one defined in
+ * the manifest.
*/
void setSplashScreenTheme(@StyleRes int themeId);
diff --git a/core/java/android/window/TaskOrganizer.java b/core/java/android/window/TaskOrganizer.java
index 3ec18dbe0ebc..8d88f80ff483 100644
--- a/core/java/android/window/TaskOrganizer.java
+++ b/core/java/android/window/TaskOrganizer.java
@@ -199,7 +199,7 @@ public class TaskOrganizer extends WindowOrganizer {
}
}
- /** Get the root task which contains the current ime target */
+ /** Get the {@link WindowContainerToken} of the task which contains the current ime target */
@RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS)
@Nullable
public WindowContainerToken getImeTarget(int display) {
diff --git a/core/java/android/window/WindowInfosListener.java b/core/java/android/window/WindowInfosListener.java
index 9d4545c6e25d..8db5a5eb0e47 100644
--- a/core/java/android/window/WindowInfosListener.java
+++ b/core/java/android/window/WindowInfosListener.java
@@ -17,6 +17,7 @@
package android.window;
import android.graphics.Matrix;
+import android.util.Pair;
import android.util.Size;
import android.view.InputWindowHandle;
@@ -47,9 +48,13 @@ public abstract class WindowInfosListener {
/**
* Register the WindowInfosListener.
+ *
+ * @return The cached values for InputWindowHandles and DisplayInfos. This is the last updated
+ * value that was sent from SurfaceFlinger to this particular process. If there was nothing
+ * registered previously, then the data can be empty.
*/
- public void register() {
- nativeRegister(mNativeListener);
+ public Pair<InputWindowHandle[], DisplayInfo[]> register() {
+ return nativeRegister(mNativeListener);
}
/**
@@ -60,7 +65,7 @@ public abstract class WindowInfosListener {
}
private static native long nativeCreate(WindowInfosListener thiz);
- private static native void nativeRegister(long ptr);
+ private static native Pair<InputWindowHandle[], DisplayInfo[]> nativeRegister(long ptr);
private static native void nativeUnregister(long ptr);
private static native long nativeGetFinalizer();
diff --git a/core/java/android/window/WindowOnBackInvokedDispatcher.java b/core/java/android/window/WindowOnBackInvokedDispatcher.java
index 5f82fb00ed75..97573c291340 100644
--- a/core/java/android/window/WindowOnBackInvokedDispatcher.java
+++ b/core/java/android/window/WindowOnBackInvokedDispatcher.java
@@ -28,6 +28,7 @@ import android.util.Log;
import android.view.IWindow;
import android.view.IWindowSession;
+import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.TreeMap;
@@ -52,7 +53,7 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
private static final String TAG = "WindowOnBackDispatcher";
private static final String BACK_PREDICTABILITY_PROP = "persist.debug.back_predictability";
private static final boolean IS_BACK_PREDICTABILITY_ENABLED = SystemProperties
- .getInt(BACK_PREDICTABILITY_PROP, 0) > 0;
+ .getInt(BACK_PREDICTABILITY_PROP, 1) > 0;
/** Convenience hashmap to quickly decide if a callback has been added. */
private final HashMap<OnBackInvokedCallback, Integer> mAllCallbacks = new HashMap<>();
@@ -82,7 +83,7 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
// TODO: Take an Executor for the callback to run on.
@Override
public void registerOnBackInvokedCallback(
- @NonNull OnBackInvokedCallback callback, @Priority int priority) {
+ @Priority int priority, @NonNull OnBackInvokedCallback callback) {
if (priority < 0) {
throw new IllegalArgumentException("Application registered OnBackInvokedCallback "
+ "cannot have negative priority. Priority: " + priority);
@@ -185,35 +186,58 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
}
private static class OnBackInvokedCallbackWrapper extends IOnBackInvokedCallback.Stub {
- private final OnBackInvokedCallback mCallback;
+ private final WeakReference<OnBackInvokedCallback> mCallback;
OnBackInvokedCallbackWrapper(@NonNull OnBackInvokedCallback callback) {
- mCallback = callback;
- }
-
- @NonNull
- public OnBackInvokedCallback getCallback() {
- return mCallback;
+ mCallback = new WeakReference<>(callback);
}
@Override
public void onBackStarted() {
- Handler.getMain().post(() -> mCallback.onBackStarted());
+ Handler.getMain().post(() -> {
+ final OnBackInvokedCallback callback = mCallback.get();
+ if (callback == null) {
+ return;
+ }
+
+ callback.onBackStarted();
+ });
}
@Override
public void onBackProgressed(BackEvent backEvent) {
- Handler.getMain().post(() -> mCallback.onBackProgressed(backEvent));
+ Handler.getMain().post(() -> {
+ final OnBackInvokedCallback callback = mCallback.get();
+ if (callback == null) {
+ return;
+ }
+
+ callback.onBackProgressed(backEvent);
+ });
}
@Override
public void onBackCancelled() {
- Handler.getMain().post(() -> mCallback.onBackCancelled());
+ Handler.getMain().post(() -> {
+ final OnBackInvokedCallback callback = mCallback.get();
+ if (callback == null) {
+ return;
+ }
+
+ callback.onBackCancelled();
+ });
}
@Override
public void onBackInvoked() throws RemoteException {
- Handler.getMain().post(() -> mCallback.onBackInvoked());
+ Handler.getMain().post(() -> {
+ final OnBackInvokedCallback callback = mCallback.get();
+ if (callback == null) {
+ return;
+ }
+
+ callback.onBackInvoked();
+ });
}
}
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 70506ccaebb8..c2e145eccb97 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -107,7 +107,6 @@ import android.widget.Button;
import android.widget.ImageView;
import android.widget.Space;
import android.widget.TextView;
-import android.widget.Toast;
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
@@ -1054,7 +1053,6 @@ public class ChooserActivity extends ResolverActivity implements
ClipboardManager clipboardManager = (ClipboardManager) getSystemService(
Context.CLIPBOARD_SERVICE);
clipboardManager.setPrimaryClipAsPackage(clipData, getReferrerPackageName());
- Toast.makeText(getApplicationContext(), R.string.copied, Toast.LENGTH_SHORT).show();
// Log share completion via copy
LogMaker targetLogMaker = new LogMaker(
diff --git a/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java b/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java
index 393bff483a20..916408984674 100644
--- a/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java
+++ b/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java
@@ -247,54 +247,54 @@ public class ChooserMultiProfilePagerAdapter extends AbstractMultiProfilePagerAd
}
private String getWorkAppPausedTitle() {
- return getContext().getSystemService(DevicePolicyManager.class).getString(
+ return getContext().getSystemService(DevicePolicyManager.class).getResources().getString(
RESOLVER_WORK_PAUSED_TITLE,
() -> getContext().getString(R.string.resolver_turn_on_work_apps));
}
private String getCrossProfileBlockedTitle() {
- return getContext().getSystemService(DevicePolicyManager.class).getString(
+ return getContext().getSystemService(DevicePolicyManager.class).getResources().getString(
RESOLVER_CROSS_PROFILE_BLOCKED_TITLE,
() -> getContext().getString(R.string.resolver_cross_profile_blocked));
}
private String getCantShareWithWorkMessage() {
- return getContext().getSystemService(DevicePolicyManager.class).getString(
+ return getContext().getSystemService(DevicePolicyManager.class).getResources().getString(
RESOLVER_CANT_SHARE_WITH_WORK,
() -> getContext().getString(
R.string.resolver_cant_share_with_work_apps_explanation));
}
private String getCantShareWithPersonalMessage() {
- return getContext().getSystemService(DevicePolicyManager.class).getString(
+ return getContext().getSystemService(DevicePolicyManager.class).getResources().getString(
RESOLVER_CANT_SHARE_WITH_PERSONAL,
() -> getContext().getString(
R.string.resolver_cant_share_with_personal_apps_explanation));
}
private String getCantAccessWorkMessage() {
- return getContext().getSystemService(DevicePolicyManager.class).getString(
+ return getContext().getSystemService(DevicePolicyManager.class).getResources().getString(
RESOLVER_CANT_ACCESS_WORK,
() -> getContext().getString(
R.string.resolver_cant_access_work_apps_explanation));
}
private String getCantAccessPersonalMessage() {
- return getContext().getSystemService(DevicePolicyManager.class).getString(
+ return getContext().getSystemService(DevicePolicyManager.class).getResources().getString(
RESOLVER_CANT_ACCESS_PERSONAL,
() -> getContext().getString(
R.string.resolver_cant_access_personal_apps_explanation));
}
private String getNoWorkAppsAvailableMessage() {
- return getContext().getSystemService(DevicePolicyManager.class).getString(
+ return getContext().getSystemService(DevicePolicyManager.class).getResources().getString(
RESOLVER_NO_WORK_APPS,
() -> getContext().getString(
R.string.resolver_no_work_apps_available));
}
private String getNoPersonalAppsAvailableMessage() {
- return getContext().getSystemService(DevicePolicyManager.class).getString(
+ return getContext().getSystemService(DevicePolicyManager.class).getResources().getString(
RESOLVER_NO_PERSONAL_APPS,
() -> getContext().getString(
R.string.resolver_no_personal_apps_available));
diff --git a/core/java/com/android/internal/app/IntentForwarderActivity.java b/core/java/com/android/internal/app/IntentForwarderActivity.java
index 25b8dba2870b..6e7690678d21 100644
--- a/core/java/com/android/internal/app/IntentForwarderActivity.java
+++ b/core/java/com/android/internal/app/IntentForwarderActivity.java
@@ -163,13 +163,13 @@ public class IntentForwarderActivity extends Activity {
}
private String getForwardToPersonalMessage() {
- return getSystemService(DevicePolicyManager.class).getString(
+ return getSystemService(DevicePolicyManager.class).getResources().getString(
FORWARD_INTENT_TO_PERSONAL,
() -> getString(com.android.internal.R.string.forward_intent_to_owner));
}
private String getForwardToWorkMessage() {
- return getSystemService(DevicePolicyManager.class).getString(
+ return getSystemService(DevicePolicyManager.class).getResources().getString(
FORWARD_INTENT_TO_WORK,
() -> getString(com.android.internal.R.string.forward_intent_to_work));
}
diff --git a/core/java/com/android/internal/app/OWNERS b/core/java/com/android/internal/app/OWNERS
index e6c911e5b41d..3833976fcdb1 100644
--- a/core/java/com/android/internal/app/OWNERS
+++ b/core/java/com/android/internal/app/OWNERS
@@ -9,3 +9,6 @@ per-file *BatteryStats* = file:/BATTERY_STATS_OWNERS
per-file *Assist* = file:/core/java/android/service/voice/OWNERS
per-file *Hotword* = file:/core/java/android/service/voice/OWNERS
per-file *Voice* = file:/core/java/android/service/voice/OWNERS
+
+# System language settings
+per-file *Locale* = file:platform/packages/apps/Settings:/src/com/android/settings/localepicker/OWNERS \ No newline at end of file
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index e336e96d577e..5ebb148760c6 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -850,13 +850,13 @@ public class ResolverActivity extends Activity implements
}
private String getForwardToPersonalMsg() {
- return getSystemService(DevicePolicyManager.class).getString(
+ return getSystemService(DevicePolicyManager.class).getResources().getString(
FORWARD_INTENT_TO_PERSONAL,
() -> getString(com.android.internal.R.string.forward_intent_to_owner));
}
private String getForwardToWorkMsg() {
- return getSystemService(DevicePolicyManager.class).getString(
+ return getSystemService(DevicePolicyManager.class).getResources().getString(
FORWARD_INTENT_TO_WORK,
() -> getString(com.android.internal.R.string.forward_intent_to_work));
}
@@ -1150,7 +1150,7 @@ public class ResolverActivity extends Activity implements
}
private String getWorkProfileNotSupportedMsg(String launcherName) {
- return getSystemService(DevicePolicyManager.class).getString(
+ return getSystemService(DevicePolicyManager.class).getResources().getString(
RESOLVER_WORK_PROFILE_NOT_SUPPORTED,
() -> getString(
com.android.internal.R.string.activity_resolver_work_profiles_support,
@@ -1603,6 +1603,11 @@ public class ResolverActivity extends Activity implements
List<DisplayResolveInfo> otherProfileList =
mMultiProfilePagerAdapter.getInactiveListAdapter().mDisplayList;
+ if (sameProfileList.isEmpty()) {
+ Log.d(TAG, "No targets in the current profile");
+ return false;
+ }
+
if (otherProfileList.size() != 1) {
Log.d(TAG, "Found " + otherProfileList.size() + " resolvers in the other profile");
return false;
@@ -1874,12 +1879,12 @@ public class ResolverActivity extends Activity implements
}
private String getPersonalTabLabel() {
- return getSystemService(DevicePolicyManager.class).getString(
+ return getSystemService(DevicePolicyManager.class).getResources().getString(
RESOLVER_PERSONAL_TAB, () -> getString(R.string.resolver_personal_tab));
}
private String getWorkTabLabel() {
- return getSystemService(DevicePolicyManager.class).getString(
+ return getSystemService(DevicePolicyManager.class).getResources().getString(
RESOLVER_WORK_TAB, () -> getString(R.string.resolver_work_tab));
}
@@ -1930,13 +1935,13 @@ public class ResolverActivity extends Activity implements
}
private String getPersonalTabAccessibilityLabel() {
- return getSystemService(DevicePolicyManager.class).getString(
+ return getSystemService(DevicePolicyManager.class).getResources().getString(
RESOLVER_PERSONAL_TAB_ACCESSIBILITY,
() -> getString(R.string.resolver_personal_tab_accessibility));
}
private String getWorkTabAccessibilityLabel() {
- return getSystemService(DevicePolicyManager.class).getString(
+ return getSystemService(DevicePolicyManager.class).getResources().getString(
RESOLVER_WORK_TAB_ACCESSIBILITY,
() -> getString(R.string.resolver_work_tab_accessibility));
}
diff --git a/core/java/com/android/internal/app/ResolverMultiProfilePagerAdapter.java b/core/java/com/android/internal/app/ResolverMultiProfilePagerAdapter.java
index 4da59a3e77d9..f4e568b6676a 100644
--- a/core/java/com/android/internal/app/ResolverMultiProfilePagerAdapter.java
+++ b/core/java/com/android/internal/app/ResolverMultiProfilePagerAdapter.java
@@ -242,40 +242,40 @@ public class ResolverMultiProfilePagerAdapter extends AbstractMultiProfilePagerA
}
private String getWorkAppPausedTitle() {
- return getContext().getSystemService(DevicePolicyManager.class).getString(
+ return getContext().getSystemService(DevicePolicyManager.class).getResources().getString(
RESOLVER_WORK_PAUSED_TITLE,
() -> getContext().getString(R.string.resolver_turn_on_work_apps));
}
private String getCrossProfileBlockedTitle() {
- return getContext().getSystemService(DevicePolicyManager.class).getString(
+ return getContext().getSystemService(DevicePolicyManager.class).getResources().getString(
RESOLVER_CROSS_PROFILE_BLOCKED_TITLE,
() -> getContext().getString(R.string.resolver_cross_profile_blocked));
}
private String getCantAccessWorkMessage() {
- return getContext().getSystemService(DevicePolicyManager.class).getString(
+ return getContext().getSystemService(DevicePolicyManager.class).getResources().getString(
RESOLVER_CANT_ACCESS_WORK,
() -> getContext().getString(
R.string.resolver_cant_access_work_apps_explanation));
}
private String getCantAccessPersonalMessage() {
- return getContext().getSystemService(DevicePolicyManager.class).getString(
+ return getContext().getSystemService(DevicePolicyManager.class).getResources().getString(
RESOLVER_CANT_ACCESS_PERSONAL,
() -> getContext().getString(
R.string.resolver_cant_access_personal_apps_explanation));
}
private String getNoWorkAppsAvailableMessage() {
- return getContext().getSystemService(DevicePolicyManager.class).getString(
+ return getContext().getSystemService(DevicePolicyManager.class).getResources().getString(
RESOLVER_NO_WORK_APPS,
() -> getContext().getString(
R.string.resolver_no_work_apps_available));
}
private String getNoPersonalAppsAvailableMessage() {
- return getContext().getSystemService(DevicePolicyManager.class).getString(
+ return getContext().getSystemService(DevicePolicyManager.class).getResources().getString(
RESOLVER_NO_PERSONAL_APPS,
() -> getContext().getString(
R.string.resolver_no_personal_apps_available));
diff --git a/core/java/com/android/internal/app/UnlaunchableAppActivity.java b/core/java/com/android/internal/app/UnlaunchableAppActivity.java
index 3531fad353db..957a6365739d 100644
--- a/core/java/com/android/internal/app/UnlaunchableAppActivity.java
+++ b/core/java/com/android/internal/app/UnlaunchableAppActivity.java
@@ -95,12 +95,12 @@ public class UnlaunchableAppActivity extends Activity
}
private String getDialogTitle() {
- return getSystemService(DevicePolicyManager.class).getString(
+ return getSystemService(DevicePolicyManager.class).getResources().getString(
UNLAUNCHABLE_APP_WORK_PAUSED_TITLE, () -> getString(R.string.work_mode_off_title));
}
private String getDialogMessage() {
- return getSystemService(DevicePolicyManager.class).getString(
+ return getSystemService(DevicePolicyManager.class).getResources().getString(
UNLAUNCHABLE_APP_WORK_PAUSED_MESSAGE,
() -> getString(R.string.work_mode_off_message));
}
diff --git a/core/java/com/android/internal/graphics/SfVsyncFrameCallbackProvider.java b/core/java/com/android/internal/graphics/SfVsyncFrameCallbackProvider.java
index 45555bf98071..dbbe4b9675d7 100644
--- a/core/java/com/android/internal/graphics/SfVsyncFrameCallbackProvider.java
+++ b/core/java/com/android/internal/graphics/SfVsyncFrameCallbackProvider.java
@@ -24,6 +24,7 @@ import android.view.Choreographer;
*
* @hide
*/
+// TODO(b/222698397): remove getSfInstance/this class usage and use vsyncId for transactions
public final class SfVsyncFrameCallbackProvider implements AnimationFrameCallbackProvider {
private final Choreographer mChoreographer;
diff --git a/core/java/com/android/internal/infra/ServiceConnector.java b/core/java/com/android/internal/infra/ServiceConnector.java
index 9e07f973b3c4..cb162674eb16 100644
--- a/core/java/com/android/internal/infra/ServiceConnector.java
+++ b/core/java/com/android/internal/infra/ServiceConnector.java
@@ -31,6 +31,7 @@ import android.os.Looper;
import android.os.RemoteException;
import android.os.UserHandle;
import android.util.Log;
+import android.util.Slog;
import java.io.PrintWriter;
import java.util.ArrayDeque;
@@ -562,10 +563,21 @@ public interface ServiceConnector<I extends IInterface> {
void unbindJobThread() {
cancelTimeout();
I service = mService;
+ // TODO(b/224695239): This is actually checking wasConnected. Rename and/or fix
+ // implementation based on what this should actually be checking. At least the first
+ // check for calling unbind is the correct behavior, though.
boolean wasBound = service != null;
+ if (wasBound || mBinding) {
+ try {
+ mContext.unbindService(mServiceConnection);
+ } catch (IllegalArgumentException e) { // TODO(b/224697137): Fix the race condition
+ // that requires catching this (crashes if
+ // service isn't currently bound).
+ Slog.e(LOG_TAG, "Failed to unbind: " + e);
+ }
+ }
if (wasBound) {
dispatchOnServiceConnectionStatusChanged(service, false);
- mContext.unbindService(mServiceConnection);
service.asBinder().unlinkToDeath(this, 0);
mService = null;
}
diff --git a/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl b/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl
index b18c98b58516..2ee47b64b1a5 100644
--- a/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl
+++ b/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl
@@ -43,5 +43,5 @@ oneway interface IInputMethodPrivilegedOperations {
void notifyUserActionAsync();
void applyImeVisibilityAsync(IBinder showOrHideInputToken, boolean setVisible);
void onStylusHandwritingReady(int requestId, int pid);
- void finishStylusHandwriting(int requestId);
+ void resetStylusHandwriting(int requestId);
}
diff --git a/core/java/com/android/internal/inputmethod/InputMethodNavButtonFlags.java b/core/java/com/android/internal/inputmethod/InputMethodNavButtonFlags.java
new file mode 100644
index 000000000000..728a42907cc4
--- /dev/null
+++ b/core/java/com/android/internal/inputmethod/InputMethodNavButtonFlags.java
@@ -0,0 +1,49 @@
+/*
+ * 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.internal.inputmethod;
+
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import android.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+
+/**
+ * A set of flags notified from {@link com.android.server.inputmethod.InputMethodManagerService} to
+ * {@link android.inputmethodservice.InputMethodService} regarding how
+ * {@link android.inputmethodservice.NavigationBarController} should behave.
+ *
+ * <p>These flags will take effect when and only when
+ * {@link android.inputmethodservice.InputMethodService#canImeRenderGesturalNavButtons} returns
+ * {@code true}.</p>
+ */
+@Retention(SOURCE)
+@IntDef(flag = true, value = {
+ InputMethodNavButtonFlags.IME_DRAWS_IME_NAV_BAR,
+ InputMethodNavButtonFlags.SHOW_IME_SWITCHER_WHEN_IME_IS_SHOWN,
+})
+public @interface InputMethodNavButtonFlags {
+ /**
+ * When set, the IME process needs to render and handle the navigation bar buttons such as the
+ * back button and the IME switcher button.
+ */
+ int IME_DRAWS_IME_NAV_BAR = 1;
+ /**
+ * When set, the IME switcher icon needs to be shown on the navigation bar.
+ */
+ int SHOW_IME_SWITCHER_WHEN_IME_IS_SHOWN = 2;
+}
diff --git a/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java b/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java
index e8a2d810d563..15d7acfb6e0a 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java
@@ -416,13 +416,13 @@ public final class InputMethodPrivilegedOperations {
* @param requestId
*/
@AnyThread
- public void finishStylusHandwriting(int requestId) {
+ public void resetStylusHandwriting(int requestId) {
final IInputMethodPrivilegedOperations ops = mOps.getAndWarnIfNull();
if (ops == null) {
return;
}
try {
- ops.finishStylusHandwriting(requestId);
+ ops.resetStylusHandwriting(requestId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/com/android/internal/jank/FrameTracker.java b/core/java/com/android/internal/jank/FrameTracker.java
index 34c47ede99f0..06bc4b56901a 100644
--- a/core/java/com/android/internal/jank/FrameTracker.java
+++ b/core/java/com/android/internal/jank/FrameTracker.java
@@ -33,6 +33,7 @@ import android.annotation.Nullable;
import android.graphics.HardwareRendererObserver;
import android.os.Handler;
import android.os.Trace;
+import android.text.TextUtils;
import android.util.Log;
import android.util.SparseArray;
import android.view.Choreographer;
@@ -188,6 +189,7 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
if (mBeginVsyncId != INVALID_ID) {
mSurfaceControlWrapper.addJankStatsListener(
FrameTracker.this, mSurfaceControl);
+ markEvent("FT#deferMonitoring");
postTraceStartMarker();
}
}
@@ -241,8 +243,9 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
}
if (mSurfaceControl != null) {
if (mDeferMonitoring) {
+ markEvent("FT#deferMonitoring");
// Normal case, we begin the instrument from the very beginning,
- // except the first frame.
+ // will exclude the first frame.
postTraceStartMarker();
} else {
// If we don't begin the instrument from the very beginning,
@@ -272,6 +275,7 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
return;
}
mTracingStarted = true;
+ markEvent("FT#begin");
Trace.beginAsyncSection(mSession.getName(), (int) mBeginVsyncId);
}
}
@@ -295,6 +299,7 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
Log.d(TAG, "end: " + mSession.getName()
+ ", end=" + mEndVsyncId + ", reason=" + reason);
}
+ markEvent("FT#end#" + reason);
Trace.endAsyncSection(mSession.getName(), (int) mBeginVsyncId);
mSession.setReason(reason);
@@ -322,6 +327,7 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
reason == REASON_CANCEL_NOT_BEGUN || reason == REASON_CANCEL_SAME_VSYNC;
if (mCancelled || (mEndVsyncId != INVALID_ID && !cancelFromEnd)) return false;
mCancelled = true;
+ markEvent("FT#cancel#" + reason);
// We don't need to end the trace section if it never begun.
if (mTracingStarted) {
Trace.endAsyncSection(mSession.getName(), (int) mBeginVsyncId);
@@ -343,6 +349,11 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
}
}
+ private void markEvent(String desc) {
+ Trace.beginSection(TextUtils.formatSimple("%s#%s", mSession.getName(), desc));
+ Trace.endSection();
+ }
+
private void notifyCujEvent(String action) {
if (mListener == null) return;
mListener.onCujEvents(mSession, action);
diff --git a/core/java/com/android/internal/jank/InteractionJankMonitor.java b/core/java/com/android/internal/jank/InteractionJankMonitor.java
index 3746bfdae781..5947e66b2d30 100644
--- a/core/java/com/android/internal/jank/InteractionJankMonitor.java
+++ b/core/java/com/android/internal/jank/InteractionJankMonitor.java
@@ -62,6 +62,10 @@ import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_IN
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SPLASHSCREEN_AVD;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SPLASHSCREEN_EXIT_ANIM;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__STATUS_BAR_APP_LAUNCH_FROM_CALL_CHIP;
+import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SUW_LOADING_SCREEN_FOR_STATUS;
+import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SUW_LOADING_TO_NEXT_FLOW;
+import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SUW_LOADING_TO_SHOW_INFO_WITH_ACTIONS;
+import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SUW_SHOW_FUNCTION_SCREEN_WITH_ACTIONS;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__UNFOLD_ANIM;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__USER_SWITCH;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__WALLPAPER_TRANSITION;
@@ -176,6 +180,10 @@ public class InteractionJankMonitor {
public static final int CUJ_ONE_HANDED_ENTER_TRANSITION = 42;
public static final int CUJ_ONE_HANDED_EXIT_TRANSITION = 43;
public static final int CUJ_UNFOLD_ANIM = 44;
+ public static final int CUJ_SUW_LOADING_TO_SHOW_INFO_WITH_ACTIONS = 45;
+ public static final int CUJ_SUW_SHOW_FUNCTION_SCREEN_WITH_ACTIONS = 46;
+ public static final int CUJ_SUW_LOADING_TO_NEXT_FLOW = 47;
+ public static final int CUJ_SUW_LOADING_SCREEN_FOR_STATUS = 48;
private static final int NO_STATSD_LOGGING = -1;
@@ -229,6 +237,10 @@ public class InteractionJankMonitor {
UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__ONE_HANDED_ENTER_TRANSITION,
UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__ONE_HANDED_EXIT_TRANSITION,
UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__UNFOLD_ANIM,
+ UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SUW_LOADING_TO_SHOW_INFO_WITH_ACTIONS,
+ UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SUW_SHOW_FUNCTION_SCREEN_WITH_ACTIONS,
+ UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SUW_LOADING_TO_NEXT_FLOW,
+ UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SUW_LOADING_SCREEN_FOR_STATUS,
};
private static volatile InteractionJankMonitor sInstance;
@@ -294,6 +306,10 @@ public class InteractionJankMonitor {
CUJ_ONE_HANDED_ENTER_TRANSITION,
CUJ_ONE_HANDED_EXIT_TRANSITION,
CUJ_UNFOLD_ANIM,
+ CUJ_SUW_LOADING_TO_SHOW_INFO_WITH_ACTIONS,
+ CUJ_SUW_SHOW_FUNCTION_SCREEN_WITH_ACTIONS,
+ CUJ_SUW_LOADING_TO_NEXT_FLOW,
+ CUJ_SUW_LOADING_SCREEN_FOR_STATUS
})
@Retention(RetentionPolicy.SOURCE)
public @interface CujType {
@@ -701,6 +717,14 @@ public class InteractionJankMonitor {
return "ONE_HANDED_EXIT_TRANSITION";
case CUJ_UNFOLD_ANIM:
return "UNFOLD_ANIM";
+ case CUJ_SUW_LOADING_TO_SHOW_INFO_WITH_ACTIONS:
+ return "SUW_LOADING_TO_SHOW_INFO_WITH_ACTIONS";
+ case CUJ_SUW_SHOW_FUNCTION_SCREEN_WITH_ACTIONS:
+ return "SUW_SHOW_FUNCTION_SCREEN_WITH_ACTIONS";
+ case CUJ_SUW_LOADING_TO_NEXT_FLOW:
+ return "SUW_LOADING_TO_NEXT_FLOW";
+ case CUJ_SUW_LOADING_SCREEN_FOR_STATUS:
+ return "SUW_LOADING_SCREEN_FOR_STATUS";
}
return "UNKNOWN";
}
diff --git a/core/java/com/android/internal/logging/InstanceId.java b/core/java/com/android/internal/logging/InstanceId.java
deleted file mode 100644
index c90d851201a2..000000000000
--- a/core/java/com/android/internal/logging/InstanceId.java
+++ /dev/null
@@ -1,98 +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.internal.logging;
-
-import static java.lang.Math.max;
-import static java.lang.Math.min;
-
-import android.annotation.Nullable;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-/**
- * An opaque identifier used to disambiguate which logs refer to a particular instance of some
- * UI element. Useful when there might be multiple instances simultaneously active.
- * Obtain from InstanceIdSequence. Clipped to range [0, INSTANCE_ID_MAX].
- */
-public final class InstanceId implements Parcelable {
- // At most 20 bits: ~1m possibilities, ~0.5% probability of collision in 100 values
- static final int INSTANCE_ID_MAX = 1 << 20;
-
- private final int mId;
- InstanceId(int id) {
- mId = min(max(0, id), INSTANCE_ID_MAX);
- }
-
- private InstanceId(Parcel in) {
- this(in.readInt());
- }
-
- @VisibleForTesting
- public int getId() {
- return mId;
- }
-
- /**
- * Create a fake instance ID for testing purposes. Not for production use. See also
- * InstanceIdSequenceFake, which is a testing replacement for InstanceIdSequence.
- * @param id The ID you want to assign.
- * @return new InstanceId.
- */
- @VisibleForTesting
- public static InstanceId fakeInstanceId(int id) {
- return new InstanceId(id);
- }
-
- @Override
- public int hashCode() {
- return mId;
- }
-
- @Override
- public boolean equals(@Nullable Object obj) {
- if (!(obj instanceof InstanceId)) {
- return false;
- }
- return mId == ((InstanceId) obj).mId;
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel out, int flags) {
- out.writeInt(mId);
- }
-
- public static final Parcelable.Creator<InstanceId> CREATOR =
- new Parcelable.Creator<InstanceId>() {
- @Override
- public InstanceId createFromParcel(Parcel in) {
- return new InstanceId(in);
- }
-
- @Override
- public InstanceId[] newArray(int size) {
- return new InstanceId[size];
- }
- };
-
-}
diff --git a/core/java/com/android/internal/logging/InstanceIdSequence.java b/core/java/com/android/internal/logging/InstanceIdSequence.java
deleted file mode 100644
index 34643105b965..000000000000
--- a/core/java/com/android/internal/logging/InstanceIdSequence.java
+++ /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.internal.logging;
-
-import static java.lang.Math.max;
-import static java.lang.Math.min;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-import java.security.SecureRandom;
-import java.util.Random;
-
-/**
- * Generates random InstanceIds in range [1, instanceIdMax] for passing to
- * UiEventLogger.logWithInstanceId(). Holds a SecureRandom, which self-seeds on
- * first use; try to give it a long lifetime. Safe for concurrent use.
- */
-public class InstanceIdSequence {
- protected final int mInstanceIdMax;
- private final Random mRandom = new SecureRandom();
-
- /**
- * Constructs a sequence with identifiers [1, instanceIdMax]. Capped at INSTANCE_ID_MAX.
- * @param instanceIdMax Limiting value of identifiers. Normally positive: otherwise you get
- * an all-1 sequence.
- */
- public InstanceIdSequence(int instanceIdMax) {
- mInstanceIdMax = min(max(1, instanceIdMax), InstanceId.INSTANCE_ID_MAX);
- }
-
- /**
- * Gets the next instance from the sequence. Safe for concurrent use.
- * @return new InstanceId
- */
- public InstanceId newInstanceId() {
- return newInstanceIdInternal(1 + mRandom.nextInt(mInstanceIdMax));
- }
-
- /**
- * Factory function for instance IDs, used for testing.
- * @param id
- * @return new InstanceId(id)
- */
- @VisibleForTesting
- protected InstanceId newInstanceIdInternal(int id) {
- return new InstanceId(id);
- }
-}
diff --git a/core/java/com/android/internal/logging/UiEventLogger.java b/core/java/com/android/internal/logging/UiEventLogger.java
deleted file mode 100644
index 5378b03fe1c5..000000000000
--- a/core/java/com/android/internal/logging/UiEventLogger.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.logging;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-
-/**
- * Logging interface for UI events. Normal implementation is UiEventLoggerImpl.
- * For testing, use fake implementation UiEventLoggerFake.
- *
- * See go/sysui-event-logs and UiEventReported atom in atoms.proto.
- */
-public interface UiEventLogger {
- /** 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).
- */
- interface UiEventEnum {
-
- /**
- * Tag used to request new UI Event IDs via presubmit analysis.
- *
- * <p>Use RESERVE_NEW_UI_EVENT_ID as the constructor parameter for a new {@link EventEnum}
- * to signal the presubmit analyzer to reserve a new ID for the event. The new ID will be
- * returned as a Gerrit presubmit finding. Do not submit {@code RESERVE_NEW_UI_EVENT_ID} as
- * the constructor parameter for any event.
- *
- * <pre>
- * &#064;UiEvent(doc = "Briefly describe the interaction when this event will be logged")
- * UNIQUE_EVENT_NAME(RESERVE_NEW_UI_EVENT_ID);
- * </pre>
- */
- int RESERVE_NEW_UI_EVENT_ID = Integer.MIN_VALUE; // Negative IDs are ignored by the logger.
-
- int getId();
- }
-
- /**
- * Log a simple event, with no package information. Does nothing if event.getId() <= 0.
- * @param event an enum implementing UiEventEnum interface.
- */
- void log(@NonNull UiEventEnum event);
-
- /**
- * Log a simple event with an instance id, without package information.
- * Does nothing if event.getId() <= 0.
- * @param event an enum implementing UiEventEnum interface.
- * @param instance An identifier obtained from an InstanceIdSequence. If null, reduces to log().
- */
- void log(@NonNull UiEventEnum event, @Nullable InstanceId instance);
-
- /**
- * Log an event with package information. Does nothing if event.getId() <= 0.
- * Give both uid and packageName if both are known, but one may be omitted if unknown.
- * @param event an enum implementing UiEventEnum interface.
- * @param uid the uid of the relevant app, if known (0 otherwise).
- * @param packageName the package name of the relevant app, if known (null otherwise).
- */
- void log(@NonNull UiEventEnum event, int uid, @Nullable String packageName);
-
- /**
- * Log an event with package information and an instance ID.
- * Does nothing if event.getId() <= 0.
- * @param event an enum implementing UiEventEnum interface.
- * @param uid the uid of the relevant app, if known (0 otherwise).
- * @param packageName the package name of the relevant app, if known (null otherwise).
- * @param instance An identifier obtained from an InstanceIdSequence. If null, reduces to log().
- */
- void logWithInstanceId(@NonNull UiEventEnum event, int uid, @Nullable String packageName,
- @Nullable InstanceId instance);
-
- /**
- * Log an event with ranked-choice information along with package.
- * Does nothing if event.getId() <= 0.
- * @param event an enum implementing UiEventEnum interface.
- * @param uid the uid of the relevant app, if known (0 otherwise).
- * @param packageName the package name of the relevant app, if known (null otherwise).
- * @param position the position picked.
- */
- void logWithPosition(@NonNull UiEventEnum event, int uid, @Nullable String packageName,
- int position);
-
- /**
- * Log an event with ranked-choice information along with package and instance ID.
- * Does nothing if event.getId() <= 0.
- * @param event an enum implementing UiEventEnum interface.
- * @param uid the uid of the relevant app, if known (0 otherwise).
- * @param packageName the package name of the relevant app, if known (null otherwise).
- * @param instance An identifier obtained from an InstanceIdSequence. If null, reduces to
- * logWithPosition().
- * @param position the position picked.
- */
- void logWithInstanceIdAndPosition(@NonNull UiEventEnum event, int uid,
- @Nullable String packageName, @Nullable InstanceId instance, int position);
-}
diff --git a/core/java/com/android/internal/net/VpnConfig.java b/core/java/com/android/internal/net/VpnConfig.java
index ec95baae8c19..2784da00a02e 100644
--- a/core/java/com/android/internal/net/VpnConfig.java
+++ b/core/java/com/android/internal/net/VpnConfig.java
@@ -106,6 +106,7 @@ public class VpnConfig implements Parcelable {
public boolean allowIPv6;
public boolean isMetered = true;
public boolean requiresInternetValidation = false;
+ public boolean excludeLocalRoutes = false;
public Network[] underlyingNetworks;
public ProxyInfo proxyInfo;
@@ -133,6 +134,7 @@ public class VpnConfig implements Parcelable {
allowIPv6 = other.allowIPv6;
isMetered = other.isMetered;
requiresInternetValidation = other.requiresInternetValidation;
+ excludeLocalRoutes = other.excludeLocalRoutes;
underlyingNetworks = other.underlyingNetworks != null ? Arrays.copyOf(
other.underlyingNetworks, other.underlyingNetworks.length) : null;
proxyInfo = other.proxyInfo;
@@ -192,6 +194,7 @@ public class VpnConfig implements Parcelable {
out.writeInt(allowIPv6 ? 1 : 0);
out.writeInt(isMetered ? 1 : 0);
out.writeInt(requiresInternetValidation ? 1 : 0);
+ out.writeInt(excludeLocalRoutes ? 1 : 0);
out.writeTypedArray(underlyingNetworks, flags);
out.writeParcelable(proxyInfo, flags);
}
@@ -220,6 +223,7 @@ public class VpnConfig implements Parcelable {
config.allowIPv6 = in.readInt() != 0;
config.isMetered = in.readInt() != 0;
config.requiresInternetValidation = in.readInt() != 0;
+ config.excludeLocalRoutes = in.readInt() != 0;
config.underlyingNetworks = in.createTypedArray(Network.CREATOR);
config.proxyInfo = in.readParcelable(null, android.net.ProxyInfo.class);
return config;
@@ -253,7 +257,8 @@ public class VpnConfig implements Parcelable {
.append(", allowIPv4=").append(allowIPv4)
.append(", allowIPv6=").append(allowIPv6)
.append(", isMetered=").append(isMetered)
- .append(", requiresInternetValidation").append(requiresInternetValidation)
+ .append(", requiresInternetValidation=").append(requiresInternetValidation)
+ .append(", excludeLocalRoutes=").append(excludeLocalRoutes)
.append(", underlyingNetworks=").append(Arrays.toString(underlyingNetworks))
.append(", proxyInfo=").append(proxyInfo)
.append("}")
diff --git a/core/java/com/android/internal/notification/SystemNotificationChannels.java b/core/java/com/android/internal/notification/SystemNotificationChannels.java
index b79c0bed4564..a93c487db7d7 100644
--- a/core/java/com/android/internal/notification/SystemNotificationChannels.java
+++ b/core/java/com/android/internal/notification/SystemNotificationChannels.java
@@ -221,7 +221,7 @@ public class SystemNotificationChannels {
private static String getDeviceAdminNotificationChannelName(Context context) {
DevicePolicyManager dpm = context.getSystemService(DevicePolicyManager.class);
- return dpm.getString(NOTIFICATION_CHANNEL_DEVICE_ADMIN,
+ return dpm.getResources().getString(NOTIFICATION_CHANNEL_DEVICE_ADMIN,
() -> context.getString(R.string.notification_channel_device_admin));
}
diff --git a/core/java/com/android/internal/os/AudioPowerCalculator.java b/core/java/com/android/internal/os/AudioPowerCalculator.java
index f9310b0c28d9..ebf0ca263a62 100644
--- a/core/java/com/android/internal/os/AudioPowerCalculator.java
+++ b/core/java/com/android/internal/os/AudioPowerCalculator.java
@@ -78,7 +78,9 @@ public class AudioPowerCalculator extends PowerCalculator {
final double powerMah = mPowerEstimator.calculatePower(durationMs);
app.setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_AUDIO, durationMs)
.setConsumedPower(BatteryConsumer.POWER_COMPONENT_AUDIO, powerMah);
- total.durationMs += durationMs;
- total.powerMah += powerMah;
+ if (!app.isVirtualUid()) {
+ total.durationMs += durationMs;
+ total.powerMah += powerMah;
+ }
}
}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 70b96392b0e5..8901c0774783 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -166,7 +166,7 @@ public class BatteryStatsImpl extends BatteryStats {
private static final int MAGIC = 0xBA757475; // 'BATSTATS'
// Current on-disk Parcel version
- static final int VERSION = 206;
+ static final int VERSION = 207;
// The maximum number of names wakelocks we will keep track of
// per uid; once the limit is reached, we batch the remaining wakelocks
@@ -546,9 +546,9 @@ public class BatteryStatsImpl extends BatteryStats {
final LongArrayMultiStateCounter onBatteryScreenOffCounter =
u.getProcStateScreenOffTimeCounter().getCounter();
- if (uid == parentUid) {
- mKernelSingleUidTimeReader.addDelta(uid, onBatteryCounter, timestampMs);
- mKernelSingleUidTimeReader.addDelta(uid, onBatteryScreenOffCounter,
+ if (uid == parentUid || Process.isSdkSandboxUid(uid)) {
+ mKernelSingleUidTimeReader.addDelta(parentUid, onBatteryCounter, timestampMs);
+ mKernelSingleUidTimeReader.addDelta(parentUid, onBatteryScreenOffCounter,
timestampMs);
} else {
Uid.ChildUid childUid = u.getChildUid(uid);
@@ -964,6 +964,16 @@ public class BatteryStatsImpl extends BatteryStats {
* Timers for each combination of frequency range and signal strength.
*/
public final StopwatchTimer[][] perStateTimers;
+ /**
+ * Counters tracking the time (in milliseconds) spent transmitting data in a given state.
+ */
+ @Nullable
+ private LongSamplingCounter[][] mPerStateTxDurationMs = null;
+ /**
+ * Counters tracking the time (in milliseconds) spent receiving data in at given frequency.
+ */
+ @Nullable
+ private LongSamplingCounter[] mPerFrequencyRxDurationMs = null;
RadioAccessTechnologyBatteryStats(int freqCount, Clock clock, TimeBase timeBase) {
perStateTimers =
@@ -1024,16 +1034,199 @@ public class BatteryStatsImpl extends BatteryStats {
}
/**
- * Reset display timers.
+ * Returns the duration in milliseconds spent in a given state since the last mark.
+ */
+ public long getTimeSinceMark(@ServiceState.FrequencyRange int frequencyRange,
+ int signalStrength, long elapsedRealtimeMs) {
+ return perStateTimers[frequencyRange][signalStrength].getTimeSinceMarkLocked(
+ elapsedRealtimeMs * 1000) / 1000;
+ }
+
+ /**
+ * Set mark for all timers.
+ */
+ public void setMark(long elapsedRealtimeMs) {
+ final int size = perStateTimers.length;
+ for (int i = 0; i < size; i++) {
+ for (int j = 0; j < CellSignalStrength.NUM_SIGNAL_STRENGTH_BINS; j++) {
+ perStateTimers[i][j].setMark(elapsedRealtimeMs);
+ }
+ }
+ }
+
+ /**
+ * Returns numbers of frequencies tracked for this RAT.
+ */
+ public int getFrequencyRangeCount() {
+ return perStateTimers.length;
+ }
+
+ /**
+ * Add TX time for a given state.
+ */
+ public void incrementTxDuration(@ServiceState.FrequencyRange int frequencyRange,
+ int signalStrength, long durationMs) {
+ getTxDurationCounter(frequencyRange, signalStrength, true).addCountLocked(durationMs);
+ }
+
+ /**
+ * Add TX time for a given frequency.
+ */
+ public void incrementRxDuration(@ServiceState.FrequencyRange int frequencyRange,
+ long durationMs) {
+ getRxDurationCounter(frequencyRange, true).addCountLocked(durationMs);
+ }
+
+ /**
+ * Reset radio access technology timers and counts.
*/
public void reset(long elapsedRealtimeUs) {
final int size = perStateTimers.length;
for (int i = 0; i < size; i++) {
for (int j = 0; j < CellSignalStrength.NUM_SIGNAL_STRENGTH_BINS; j++) {
perStateTimers[i][j].reset(false, elapsedRealtimeUs);
+ if (mPerStateTxDurationMs == null) continue;
+ mPerStateTxDurationMs[i][j].reset(false, elapsedRealtimeUs);
+ }
+ if (mPerFrequencyRxDurationMs == null) continue;
+ mPerFrequencyRxDurationMs[i].reset(false, elapsedRealtimeUs);
+ }
+ }
+
+ /**
+ * Write data to summary parcel
+ */
+ public void writeSummaryToParcel(Parcel out, long elapsedRealtimeUs) {
+ final int freqCount = perStateTimers.length;
+ out.writeInt(freqCount);
+ out.writeInt(CellSignalStrength.NUM_SIGNAL_STRENGTH_BINS);
+ for (int i = 0; i < freqCount; i++) {
+ for (int j = 0; j < CellSignalStrength.NUM_SIGNAL_STRENGTH_BINS; j++) {
+ perStateTimers[i][j].writeSummaryFromParcelLocked(out, elapsedRealtimeUs);
+ }
+ }
+
+ if (mPerStateTxDurationMs == null) {
+ out.writeInt(0);
+ } else {
+ out.writeInt(1);
+ for (int i = 0; i < freqCount; i++) {
+ for (int j = 0; j < CellSignalStrength.NUM_SIGNAL_STRENGTH_BINS; j++) {
+ mPerStateTxDurationMs[i][j].writeSummaryFromParcelLocked(out);
+ }
+ }
+ }
+
+ if (mPerFrequencyRxDurationMs == null) {
+ out.writeInt(0);
+ } else {
+ out.writeInt(1);
+ for (int i = 0; i < freqCount; i++) {
+ mPerFrequencyRxDurationMs[i].writeSummaryFromParcelLocked(out);
+ }
+ }
+ }
+
+ /**
+ * Read data from summary parcel
+ */
+ public void readSummaryFromParcel(Parcel in) {
+ final int oldFreqCount = in.readInt();
+ final int oldSignalStrengthCount = in.readInt();
+ final int currFreqCount = perStateTimers.length;
+ final int currSignalStrengthCount = CellSignalStrength.NUM_SIGNAL_STRENGTH_BINS;
+
+ for (int freq = 0; freq < oldFreqCount; freq++) {
+ for (int strength = 0; strength < oldSignalStrengthCount; strength++) {
+ if (freq >= currFreqCount || strength >= currSignalStrengthCount) {
+ // Mismatch with the summary parcel. Consume the data but don't use it.
+ final StopwatchTimer temp = new StopwatchTimer(null, null, -1, null,
+ new TimeBase());
+ // Consume perStateTimers data.
+ temp.readSummaryFromParcelLocked(in);
+ } else {
+ perStateTimers[freq][strength].readSummaryFromParcelLocked(in);
+ }
+ }
+ }
+
+ if (in.readInt() == 1) {
+ for (int freq = 0; freq < oldFreqCount; freq++) {
+ for (int strength = 0; strength < oldSignalStrengthCount; strength++) {
+ if (freq >= currFreqCount || strength >= currSignalStrengthCount) {
+ // Mismatch with the summary parcel. Consume the data but don't use it.
+ final StopwatchTimer temp = new StopwatchTimer(null, null, -1, null,
+ new TimeBase());
+ // Consume mPerStateTxDurationMs data.
+ temp.readSummaryFromParcelLocked(in);
+ }
+ getTxDurationCounter(freq, strength, true).readSummaryFromParcelLocked(in);
+ }
+ }
+ }
+
+ if (in.readInt() == 1) {
+ for (int freq = 0; freq < oldFreqCount; freq++) {
+ if (freq >= currFreqCount) {
+ // Mismatch with the summary parcel. Consume the data but don't use it.
+ final StopwatchTimer
+ temp = new StopwatchTimer(null, null, -1, null, new TimeBase());
+ // Consume mPerFrequencyRxDurationMs data.
+ temp.readSummaryFromParcelLocked(in);
+ continue;
+ }
+ getRxDurationCounter(freq, true).readSummaryFromParcelLocked(in);
}
}
}
+
+ private LongSamplingCounter getTxDurationCounter(
+ @ServiceState.FrequencyRange int frequencyRange, int signalStrength, boolean make) {
+ if (mPerStateTxDurationMs == null) {
+ if (!make) return null;
+
+ final int freqCount = getFrequencyRangeCount();
+ final int signalStrengthCount = perStateTimers[0].length;
+ final TimeBase timeBase = perStateTimers[0][0].mTimeBase;
+ mPerStateTxDurationMs = new LongSamplingCounter[freqCount][signalStrengthCount];
+ for (int freq = 0; freq < freqCount; freq++) {
+ for (int strength = 0; strength < signalStrengthCount; strength++) {
+ mPerStateTxDurationMs[freq][strength] = new LongSamplingCounter(timeBase);
+ }
+ }
+ }
+ if (frequencyRange < 0 || frequencyRange >= getFrequencyRangeCount()) {
+ Slog.w(TAG, "Unexpected frequency range (" + frequencyRange
+ + ") requested in getTxDurationCounter");
+ return null;
+ }
+ if (signalStrength < 0 || signalStrength >= perStateTimers[0].length) {
+ Slog.w(TAG, "Unexpected signal strength (" + signalStrength
+ + ") requested in getTxDurationCounter");
+ return null;
+ }
+ return mPerStateTxDurationMs[frequencyRange][signalStrength];
+ }
+
+ private LongSamplingCounter getRxDurationCounter(
+ @ServiceState.FrequencyRange int frequencyRange, boolean make) {
+ if (mPerFrequencyRxDurationMs == null) {
+ if (!make) return null;
+
+ final int freqCount = getFrequencyRangeCount();
+ final TimeBase timeBase = perStateTimers[0][0].mTimeBase;
+ mPerFrequencyRxDurationMs = new LongSamplingCounter[freqCount];
+ for (int freq = 0; freq < freqCount; freq++) {
+ mPerFrequencyRxDurationMs[freq] = new LongSamplingCounter(timeBase);
+ }
+ }
+ if (frequencyRange < 0 || frequencyRange >= getFrequencyRangeCount()) {
+ Slog.w(TAG, "Unexpected frequency range (" + frequencyRange
+ + ") requested in getRxDurationCounter");
+ return null;
+ }
+ return mPerFrequencyRxDurationMs[frequencyRange];
+ }
}
/**
@@ -1929,20 +2122,28 @@ public class BatteryStatsImpl extends BatteryStats {
private final TimeBase mTimeBase;
private final LongMultiStateCounter mCounter;
- private TimeMultiStateCounter(TimeBase timeBase, Parcel in, long timestampMs) {
- mTimeBase = timeBase;
- mCounter = LongMultiStateCounter.CREATOR.createFromParcel(in);
- mCounter.setEnabled(mTimeBase.isRunning(), timestampMs);
- timeBase.add(this);
+ private TimeMultiStateCounter(TimeBase timeBase, int stateCount, long timestampMs) {
+ this(timeBase, new LongMultiStateCounter(stateCount), timestampMs);
}
- private TimeMultiStateCounter(TimeBase timeBase, int stateCount, long timestampMs) {
+ private TimeMultiStateCounter(TimeBase timeBase, LongMultiStateCounter counter,
+ long timestampMs) {
mTimeBase = timeBase;
- mCounter = new LongMultiStateCounter(stateCount);
+ mCounter = counter;
mCounter.setEnabled(mTimeBase.isRunning(), timestampMs);
timeBase.add(this);
}
+ @Nullable
+ private static TimeMultiStateCounter readFromParcel(Parcel in, TimeBase timeBase,
+ int stateCount, long timestampMs) {
+ LongMultiStateCounter counter = LongMultiStateCounter.CREATOR.createFromParcel(in);
+ if (counter.getStateCount() != stateCount) {
+ return null;
+ }
+ return new TimeMultiStateCounter(timeBase, counter, timestampMs);
+ }
+
private void writeToParcel(Parcel out) {
mCounter.writeToParcel(out, 0);
}
@@ -3510,11 +3711,8 @@ public class BatteryStatsImpl extends BatteryStats {
private TimeMultiStateCounter readTimeMultiStateCounter(Parcel in, TimeBase timeBase) {
if (in.readBoolean()) {
- final TimeMultiStateCounter counter =
- new TimeMultiStateCounter(timeBase, in, mClock.elapsedRealtime());
- if (counter.getStateCount() == BatteryConsumer.PROCESS_STATE_COUNT) {
- return counter;
- }
+ return TimeMultiStateCounter.readFromParcel(in, timeBase,
+ BatteryConsumer.PROCESS_STATE_COUNT, mClock.elapsedRealtime());
}
return null;
}
@@ -3537,9 +3735,10 @@ public class BatteryStatsImpl extends BatteryStats {
// invalid.
TimeMultiStateCounter[] counters = new TimeMultiStateCounter[numCounters];
for (int i = 0; i < numCounters; i++) {
- final TimeMultiStateCounter counter =
- new TimeMultiStateCounter(timeBase, in, mClock.elapsedRealtime());
- if (counter.getStateCount() == BatteryConsumer.PROCESS_STATE_COUNT) {
+ final TimeMultiStateCounter counter = TimeMultiStateCounter.readFromParcel(in,
+ timeBase, BatteryConsumer.PROCESS_STATE_COUNT,
+ mClock.elapsedRealtime());
+ if (counter != null) {
counters[i] = counter;
} else {
valid = false;
@@ -4560,9 +4759,15 @@ public class BatteryStatsImpl extends BatteryStats {
mIsolatedUidRefCounts.put(uid, refCount + 1);
}
- public int mapUid(int uid) {
- int isolated = mIsolatedUids.get(uid, -1);
- return isolated > 0 ? isolated : uid;
+ private int mapUid(int uid) {
+ if (Process.isSdkSandboxUid(uid)) {
+ return Process.getAppUidForSdkSandboxUid(uid);
+ }
+ return mapIsolatedUid(uid);
+ }
+
+ private int mapIsolatedUid(int uid) {
+ return mIsolatedUids.get(/*key=*/uid, /*valueIfKeyNotFound=*/uid);
}
@GuardedBy("this")
@@ -4656,16 +4861,18 @@ public class BatteryStatsImpl extends BatteryStats {
long elapsedRealtimeMs, long uptimeMs) {
int parentUid = mapUid(uid);
if (uid != parentUid) {
- // Isolated UIDs process state is already rolled up into parent, so no need to track
- // Otherwise the parent's process state will get downgraded incorrectly
- return;
+ if (Process.isIsolated(uid)) {
+ // Isolated UIDs process state is already rolled up into parent, so no need to track
+ // Otherwise the parent's process state will get downgraded incorrectly
+ return;
+ }
}
// TODO(b/155216561): It is possible for isolated uids to be in a higher
// state than its parent uid. We should track the highest state within the union of host
// and isolated uids rather than only the parent uid.
FrameworkStatsLog.write(FrameworkStatsLog.UID_PROCESS_STATE_CHANGED, uid,
ActivityManager.processStateAmToProto(state));
- getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs)
+ getUidStatsLocked(parentUid, elapsedRealtimeMs, uptimeMs)
.updateUidProcessStateLocked(state, elapsedRealtimeMs, uptimeMs);
}
@@ -5011,7 +5218,7 @@ public class BatteryStatsImpl extends BatteryStats {
FrameworkStatsLog.WAKELOCK_STATE_CHANGED__STATE__ACQUIRE);
} else {
FrameworkStatsLog.write_non_chained(FrameworkStatsLog.WAKELOCK_STATE_CHANGED,
- mappedUid, null, getPowerManagerWakeLockLevel(type), name,
+ mapIsolatedUid(uid), null, getPowerManagerWakeLockLevel(type), name,
FrameworkStatsLog.WAKELOCK_STATE_CHANGED__STATE__ACQUIRE);
}
}
@@ -5065,7 +5272,7 @@ public class BatteryStatsImpl extends BatteryStats {
FrameworkStatsLog.WAKELOCK_STATE_CHANGED__STATE__RELEASE);
} else {
FrameworkStatsLog.write_non_chained(FrameworkStatsLog.WAKELOCK_STATE_CHANGED,
- mappedUid, null, getPowerManagerWakeLockLevel(type), name,
+ mapIsolatedUid(uid), null, getPowerManagerWakeLockLevel(type), name,
FrameworkStatsLog.WAKELOCK_STATE_CHANGED__STATE__RELEASE);
}
@@ -5489,7 +5696,10 @@ public class BatteryStatsImpl extends BatteryStats {
@GuardedBy("this")
private void noteStartGpsLocked(int uid, WorkChain workChain,
long elapsedRealtimeMs, long uptimeMs) {
- uid = getAttributionUid(uid, workChain);
+ if (workChain != null) {
+ uid = workChain.getAttributionUid();
+ }
+ final int mappedUid = mapUid(uid);
if (mGpsNesting == 0) {
mHistoryCur.states |= HistoryItem.STATE_GPS_ON_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Start GPS to: "
@@ -5499,21 +5709,24 @@ public class BatteryStatsImpl extends BatteryStats {
mGpsNesting++;
if (workChain == null) {
- FrameworkStatsLog.write_non_chained(FrameworkStatsLog.GPS_SCAN_STATE_CHANGED, uid, null,
- FrameworkStatsLog.GPS_SCAN_STATE_CHANGED__STATE__ON);
+ FrameworkStatsLog.write_non_chained(FrameworkStatsLog.GPS_SCAN_STATE_CHANGED,
+ mapIsolatedUid(uid), null, FrameworkStatsLog.GPS_SCAN_STATE_CHANGED__STATE__ON);
} else {
FrameworkStatsLog.write(FrameworkStatsLog.GPS_SCAN_STATE_CHANGED,
workChain.getUids(), workChain.getTags(),
FrameworkStatsLog.GPS_SCAN_STATE_CHANGED__STATE__ON);
}
- getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs).noteStartGps(elapsedRealtimeMs);
+ getUidStatsLocked(mappedUid, elapsedRealtimeMs, uptimeMs).noteStartGps(elapsedRealtimeMs);
}
@GuardedBy("this")
private void noteStopGpsLocked(int uid, WorkChain workChain,
long elapsedRealtimeMs, long uptimeMs) {
- uid = getAttributionUid(uid, workChain);
+ if (workChain != null) {
+ uid = workChain.getAttributionUid();
+ }
+ final int mappedUid = mapUid(uid);
mGpsNesting--;
if (mGpsNesting == 0) {
mHistoryCur.states &= ~HistoryItem.STATE_GPS_ON_FLAG;
@@ -5525,14 +5738,15 @@ public class BatteryStatsImpl extends BatteryStats {
}
if (workChain == null) {
- FrameworkStatsLog.write_non_chained(FrameworkStatsLog.GPS_SCAN_STATE_CHANGED, uid, null,
+ FrameworkStatsLog.write_non_chained(FrameworkStatsLog.GPS_SCAN_STATE_CHANGED,
+ mapIsolatedUid(uid), null,
FrameworkStatsLog.GPS_SCAN_STATE_CHANGED__STATE__OFF);
} else {
FrameworkStatsLog.write(FrameworkStatsLog.GPS_SCAN_STATE_CHANGED, workChain.getUids(),
workChain.getTags(), FrameworkStatsLog.GPS_SCAN_STATE_CHANGED__STATE__OFF);
}
- getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs).noteStopGps(elapsedRealtimeMs);
+ getUidStatsLocked(mappedUid, elapsedRealtimeMs, uptimeMs).noteStopGps(elapsedRealtimeMs);
}
@GuardedBy("this")
@@ -6950,7 +7164,10 @@ public class BatteryStatsImpl extends BatteryStats {
@GuardedBy("this")
private void noteBluetoothScanStartedLocked(WorkChain workChain, int uid,
boolean isUnoptimized, long elapsedRealtimeMs, long uptimeMs) {
- uid = getAttributionUid(uid, workChain);
+ if (workChain != null) {
+ uid = workChain.getAttributionUid();
+ }
+ uid = mapUid(uid);
if (mBluetoothScanNesting == 0) {
mHistoryCur.states2 |= HistoryItem.STATE2_BLUETOOTH_SCAN_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "BLE scan started for: "
@@ -6990,7 +7207,10 @@ public class BatteryStatsImpl extends BatteryStats {
@GuardedBy("this")
private void noteBluetoothScanStoppedLocked(WorkChain workChain, int uid,
boolean isUnoptimized, long elapsedRealtimeMs, long uptimeMs) {
- uid = getAttributionUid(uid, workChain);
+ if (workChain != null) {
+ uid = workChain.getAttributionUid();
+ }
+ uid = mapUid(uid);
mBluetoothScanNesting--;
if (mBluetoothScanNesting == 0) {
mHistoryCur.states2 &= ~HistoryItem.STATE2_BLUETOOTH_SCAN_FLAG;
@@ -7003,14 +7223,6 @@ public class BatteryStatsImpl extends BatteryStats {
.noteBluetoothScanStoppedLocked(elapsedRealtimeMs, isUnoptimized);
}
- private int getAttributionUid(int uid, WorkChain workChain) {
- if (workChain != null) {
- return mapUid(workChain.getAttributionUid());
- }
-
- return mapUid(uid);
- }
-
@GuardedBy("this")
public void noteBluetoothScanStoppedFromSourceLocked(WorkSource ws, boolean isUnoptimized) {
noteBluetoothScanStoppedFromSourceLocked(ws, isUnoptimized,
@@ -7995,6 +8207,32 @@ public class BatteryStatsImpl extends BatteryStats {
elapsedRealtimeMs * 1000, STATS_SINCE_CHARGED) / 1000;
}
+ @Override
+ public long getActiveTxRadioDurationMs(@RadioAccessTechnology int rat,
+ @ServiceState.FrequencyRange int frequencyRange, int signalStrength,
+ long elapsedRealtimeMs) {
+ final RadioAccessTechnologyBatteryStats stats = mPerRatBatteryStats[rat];
+ if (stats == null) return DURATION_UNAVAILABLE;
+
+ final LongSamplingCounter counter = stats.getTxDurationCounter(frequencyRange,
+ signalStrength, false);
+ if (counter == null) return DURATION_UNAVAILABLE;
+
+ return counter.getCountLocked(STATS_SINCE_CHARGED);
+ }
+
+ @Override
+ public long getActiveRxRadioDurationMs(@RadioAccessTechnology int rat,
+ @ServiceState.FrequencyRange int frequencyRange, long elapsedRealtimeMs) {
+ final RadioAccessTechnologyBatteryStats stats = mPerRatBatteryStats[rat];
+ if (stats == null) return DURATION_UNAVAILABLE;
+
+ final LongSamplingCounter counter = stats.getRxDurationCounter(frequencyRange, false);
+ if (counter == null) return DURATION_UNAVAILABLE;
+
+ return counter.getCountLocked(STATS_SINCE_CHARGED);
+ }
+
@UnsupportedAppUsage
@Override public long getMobileRadioActiveTime(long elapsedRealtimeUs, int which) {
return mMobileRadioActiveTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
@@ -10739,11 +10977,9 @@ public class BatteryStatsImpl extends BatteryStats {
= new LongSamplingCounter(mBsi.mOnBatteryTimeBase, in);
}
if (in.readBoolean()) {
- final TimeMultiStateCounter counter =
- new TimeMultiStateCounter(mBsi.mOnBatteryTimeBase, in, timestampMs);
- if (counter.getStateCount() == BatteryConsumer.PROCESS_STATE_COUNT) {
- mMobileRadioActiveTime = counter;
- }
+ mMobileRadioActiveTime = TimeMultiStateCounter.readFromParcel(in,
+ mBsi.mOnBatteryTimeBase, BatteryConsumer.PROCESS_STATE_COUNT,
+ timestampMs);
}
mMobileRadioActiveCount = new LongSamplingCounter(mBsi.mOnBatteryTimeBase, in);
@@ -10789,11 +11025,9 @@ public class BatteryStatsImpl extends BatteryStats {
int stateCount = in.readInt();
if (stateCount != 0) {
- final TimeMultiStateCounter counter = new TimeMultiStateCounter(
- mBsi.mOnBatteryTimeBase, in, timestampMs);
- if (stateCount == BatteryConsumer.PROCESS_STATE_COUNT) {
- mCpuActiveTimeMs = counter;
- }
+ mCpuActiveTimeMs = TimeMultiStateCounter.readFromParcel(in,
+ mBsi.mOnBatteryTimeBase, BatteryConsumer.PROCESS_STATE_COUNT,
+ timestampMs);
}
mCpuClusterTimesMs = new LongSamplingCounterArray(mBsi.mOnBatteryTimeBase, in);
@@ -13477,6 +13711,67 @@ public class BatteryStatsImpl extends BatteryStats {
addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
mTmpRailStats.resetCellularTotalEnergyUsed();
}
+
+ // Proportionally smear Rx and Tx times across each RAt
+ final int levelCount = CellSignalStrength.getNumSignalStrengthLevels();
+ long[] perSignalStrengthActiveTimeMs = new long[levelCount];
+ long totalActiveTimeMs = 0;
+
+ for (int rat = 0; rat < RADIO_ACCESS_TECHNOLOGY_COUNT; rat++) {
+ final RadioAccessTechnologyBatteryStats ratStats = mPerRatBatteryStats[rat];
+ if (ratStats == null) continue;
+
+ final int freqCount = ratStats.getFrequencyRangeCount();
+ for (int freq = 0; freq < freqCount; freq++) {
+ for (int level = 0; level < levelCount; level++) {
+ final long durationMs = ratStats.getTimeSinceMark(freq, level,
+ elapsedRealtimeMs);
+ perSignalStrengthActiveTimeMs[level] += durationMs;
+ totalActiveTimeMs += durationMs;
+ }
+ }
+ }
+
+ if (totalActiveTimeMs != 0) {
+ // Smear the provided Tx/Rx durations across each RAT, frequency, and signal
+ // strength.
+ for (int rat = 0; rat < RADIO_ACCESS_TECHNOLOGY_COUNT; rat++) {
+ final RadioAccessTechnologyBatteryStats ratStats = mPerRatBatteryStats[rat];
+ if (ratStats == null) continue;
+
+ final int freqCount = ratStats.getFrequencyRangeCount();
+ for (int freq = 0; freq < freqCount; freq++) {
+ long frequencyDurationMs = 0;
+ for (int level = 0; level < levelCount; level++) {
+ final long durationMs = ratStats.getTimeSinceMark(freq, level,
+ elapsedRealtimeMs);
+ final long totalLvlDurationMs =
+ perSignalStrengthActiveTimeMs[level];
+ if (totalLvlDurationMs == 0) continue;
+ final long totalTxLvlDurations =
+ deltaInfo.getTransmitDurationMillisAtPowerLevel(level);
+ // Smear HAL provided Tx power level duration based on active modem
+ // duration in a given state. (Add totalLvlDurationMs / 2 before
+ // the integer division with totalLvlDurationMs for rounding.)
+ final long proportionalTxDurationMs =
+ (durationMs * totalTxLvlDurations
+ + (totalLvlDurationMs / 2)) / totalLvlDurationMs;
+ ratStats.incrementTxDuration(freq, level, proportionalTxDurationMs);
+ frequencyDurationMs += durationMs;
+ }
+ final long totalRxDuration = deltaInfo.getReceiveTimeMillis();
+ // Smear HAL provided Rx power duration based on active modem
+ // duration in a given state. (Add totalActiveTimeMs / 2 before the
+ // integer division with totalActiveTimeMs for rounding.)
+ final long proportionalRxDurationMs =
+ (frequencyDurationMs * totalRxDuration + (totalActiveTimeMs
+ / 2)) / totalActiveTimeMs;
+ ratStats.incrementRxDuration(freq, proportionalRxDurationMs);
+ }
+
+ ratStats.setMark(elapsedRealtimeMs);
+ }
+ }
}
long totalAppRadioTimeUs = mMobileRadioActivePerAppTimer.getTimeSinceMarkLocked(
elapsedRealtimeMs * 1000);
@@ -15970,6 +16265,9 @@ public class BatteryStatsImpl extends BatteryStats {
public Uid getUidStatsLocked(int uid, long elapsedRealtimeMs, long uptimeMs) {
Uid u = mUidStats.get(uid);
if (u == null) {
+ if (Process.isSdkSandboxUid(uid)) {
+ Log.wtf(TAG, "Tracking an SDK Sandbox UID");
+ }
u = new Uid(this, uid, elapsedRealtimeMs, uptimeMs);
mUidStats.put(uid, u);
}
@@ -16879,14 +17177,18 @@ public class BatteryStatsImpl extends BatteryStats {
mNextMaxDailyDeadlineMs = in.readLong();
mBatteryTimeToFullSeconds = in.readLong();
- mMeasuredEnergyStatsConfig = MeasuredEnergyStats.Config.createFromParcel(in);
-
- /**
- * WARNING: Supported buckets may have changed across boots. Bucket mismatch is handled
- * later when {@link #initMeasuredEnergyStatsLocked} is called.
- */
- mGlobalMeasuredEnergyStats = MeasuredEnergyStats.createAndReadSummaryFromParcel(
- mMeasuredEnergyStatsConfig, in);
+ final MeasuredEnergyStats.Config config = MeasuredEnergyStats.Config.createFromParcel(in);
+ final MeasuredEnergyStats measuredEnergyStats =
+ MeasuredEnergyStats.createAndReadSummaryFromParcel(mMeasuredEnergyStatsConfig, in);
+ if (config != null && Arrays.equals(config.getStateNames(),
+ getBatteryConsumerProcessStateNames())) {
+ /**
+ * WARNING: Supported buckets may have changed across boots. Bucket mismatch is handled
+ * later when {@link #initMeasuredEnergyStatsLocked} is called.
+ */
+ mMeasuredEnergyStatsConfig = config;
+ mGlobalMeasuredEnergyStats = measuredEnergyStats;
+ }
mStartCount++;
@@ -16918,6 +17220,13 @@ public class BatteryStatsImpl extends BatteryStats {
mNetworkByteActivityCounters[i].readSummaryFromParcelLocked(in);
mNetworkPacketActivityCounters[i].readSummaryFromParcelLocked(in);
}
+
+ final int numRat = in.readInt();
+ for (int i = 0; i < numRat; i++) {
+ if (in.readInt() == 0) continue;
+ getRatBatteryStatsLocked(i).readSummaryFromParcel(in);
+ }
+
mMobileRadioPowerState = DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
mMobileRadioActiveTimer.readSummaryFromParcelLocked(in);
mMobileRadioActivePerAppTimer.readSummaryFromParcelLocked(in);
@@ -16978,7 +17287,6 @@ public class BatteryStatsImpl extends BatteryStats {
getScreenOffRpmTimerLocked(rpmName).readSummaryFromParcelLocked(in);
}
}
-
int NKW = in.readInt();
if (NKW > 10000) {
throw new ParcelFormatException("File corrupt: too many kernel wake locks " + NKW);
@@ -17106,11 +17414,9 @@ public class BatteryStatsImpl extends BatteryStats {
u.mNetworkPacketActivityCounters[i].readSummaryFromParcelLocked(in);
}
if (in.readBoolean()) {
- TimeMultiStateCounter counter = new TimeMultiStateCounter(
- mOnBatteryTimeBase, in, elapsedRealtimeMs);
- if (counter.getStateCount() == BatteryConsumer.PROCESS_STATE_COUNT) {
- u.mMobileRadioActiveTime = counter;
- }
+ u.mMobileRadioActiveTime = TimeMultiStateCounter.readFromParcel(in,
+ mOnBatteryTimeBase, BatteryConsumer.PROCESS_STATE_COUNT,
+ elapsedRealtimeMs);
}
u.mMobileRadioActiveCount.readSummaryFromParcelLocked(in);
}
@@ -17160,11 +17466,9 @@ public class BatteryStatsImpl extends BatteryStats {
int stateCount = in.readInt();
if (stateCount != 0) {
- final TimeMultiStateCounter counter = new TimeMultiStateCounter(
- mOnBatteryTimeBase, in, mClock.elapsedRealtime());
- if (stateCount == BatteryConsumer.PROCESS_STATE_COUNT) {
- u.mCpuActiveTimeMs = counter;
- }
+ u.mCpuActiveTimeMs = TimeMultiStateCounter.readFromParcel(in,
+ mOnBatteryTimeBase, BatteryConsumer.PROCESS_STATE_COUNT,
+ mClock.elapsedRealtime());
}
u.mCpuClusterTimesMs.readSummaryFromParcelLocked(in);
@@ -17423,6 +17727,17 @@ public class BatteryStatsImpl extends BatteryStats {
mNetworkByteActivityCounters[i].writeSummaryFromParcelLocked(out);
mNetworkPacketActivityCounters[i].writeSummaryFromParcelLocked(out);
}
+ final int numRat = mPerRatBatteryStats.length;
+ out.writeInt(numRat);
+ for (int i = 0; i < numRat; i++) {
+ final RadioAccessTechnologyBatteryStats ratStat = mPerRatBatteryStats[i];
+ if (ratStat == null) {
+ out.writeInt(0);
+ continue;
+ }
+ out.writeInt(1);
+ ratStat.writeSummaryToParcel(out, nowRealtime);
+ }
mMobileRadioActiveTimer.writeSummaryFromParcelLocked(out, nowRealtime);
mMobileRadioActivePerAppTimer.writeSummaryFromParcelLocked(out, nowRealtime);
mMobileRadioActiveAdjustedTime.writeSummaryFromParcelLocked(out);
@@ -17999,9 +18314,15 @@ public class BatteryStatsImpl extends BatteryStats {
mLastWriteTimeMs = in.readLong();
mBatteryTimeToFullSeconds = in.readLong();
- mMeasuredEnergyStatsConfig = MeasuredEnergyStats.Config.createFromParcel(in);
- mGlobalMeasuredEnergyStats =
+
+ final MeasuredEnergyStats.Config config = MeasuredEnergyStats.Config.createFromParcel(in);
+ final MeasuredEnergyStats measuredEnergyStats =
MeasuredEnergyStats.createFromParcel(mMeasuredEnergyStatsConfig, in);
+ if (config != null && Arrays.equals(config.getStateNames(),
+ getBatteryConsumerProcessStateNames())) {
+ mMeasuredEnergyStatsConfig = config;
+ mGlobalMeasuredEnergyStats = measuredEnergyStats;
+ }
mRpmStats.clear();
int NRPMS = in.readInt();
diff --git a/core/java/com/android/internal/os/BatteryUsageStatsProvider.java b/core/java/com/android/internal/os/BatteryUsageStatsProvider.java
index a1c1917fd83e..81c6ee71e060 100644
--- a/core/java/com/android/internal/os/BatteryUsageStatsProvider.java
+++ b/core/java/com/android/internal/os/BatteryUsageStatsProvider.java
@@ -22,6 +22,7 @@ import android.os.BatteryStats;
import android.os.BatteryUsageStats;
import android.os.BatteryUsageStatsQuery;
import android.os.Parcel;
+import android.os.Process;
import android.os.SystemClock;
import android.os.UidBatteryConsumer;
import android.util.Log;
@@ -162,6 +163,8 @@ public class BatteryUsageStatsProvider {
final boolean includeProcessStateData = ((query.getFlags()
& BatteryUsageStatsQuery.FLAG_BATTERY_USAGE_STATS_INCLUDE_PROCESS_STATE_DATA) != 0)
&& mStats.isProcessStateDataAvailable();
+ final boolean includeVirtualUids = ((query.getFlags()
+ & BatteryUsageStatsQuery.FLAG_BATTERY_USAGE_STATS_INCLUDE_VIRTUAL_UIDS) != 0);
final BatteryUsageStats.Builder batteryUsageStatsBuilder = new BatteryUsageStats.Builder(
mStats.getCustomEnergyConsumerNames(), includePowerModels,
@@ -174,6 +177,10 @@ public class BatteryUsageStatsProvider {
SparseArray<? extends BatteryStats.Uid> uidStats = mStats.getUidStats();
for (int i = uidStats.size() - 1; i >= 0; i--) {
final BatteryStats.Uid uid = uidStats.valueAt(i);
+ if (!includeVirtualUids && uid.getUid() == Process.SDK_SANDBOX_VIRTUAL_UID) {
+ continue;
+ }
+
batteryUsageStatsBuilder.getOrCreateUidBatteryConsumerBuilder(uid)
.setTimeInStateMs(UidBatteryConsumer.STATE_BACKGROUND,
getProcessBackgroundTimeMs(uid, realtimeUs))
diff --git a/core/java/com/android/internal/os/BluetoothPowerCalculator.java b/core/java/com/android/internal/os/BluetoothPowerCalculator.java
index 2ebf689e2c7f..e52c8a3a3efb 100644
--- a/core/java/com/android/internal/os/BluetoothPowerCalculator.java
+++ b/core/java/com/android/internal/os/BluetoothPowerCalculator.java
@@ -139,8 +139,10 @@ public class BluetoothPowerCalculator extends PowerCalculator {
BatteryConsumer.POWER_COMPONENT_BLUETOOTH, powerAndDuration.powerMah,
powerModel);
- powerAndDuration.totalDurationMs += powerAndDuration.durationMs;
- powerAndDuration.totalPowerMah += powerAndDuration.powerMah;
+ if (!app.isVirtualUid()) {
+ powerAndDuration.totalDurationMs += powerAndDuration.durationMs;
+ powerAndDuration.totalPowerMah += powerAndDuration.powerMah;
+ }
if (query.isProcessStateDataNeeded() && powerAndDuration.keys != null) {
for (int j = 0; j < powerAndDuration.keys.length; j++) {
diff --git a/core/java/com/android/internal/os/CpuPowerCalculator.java b/core/java/com/android/internal/os/CpuPowerCalculator.java
index 1fc2baf040b6..8704e936c747 100644
--- a/core/java/com/android/internal/os/CpuPowerCalculator.java
+++ b/core/java/com/android/internal/os/CpuPowerCalculator.java
@@ -117,7 +117,9 @@ public class CpuPowerCalculator extends PowerCalculator {
}
}
calculateApp(app, app.getBatteryStatsUid(), query, result, keys);
- totalPowerMah += result.powerMah;
+ if (!app.isVirtualUid()) {
+ totalPowerMah += result.powerMah;
+ }
}
final long consumptionUC = batteryStats.getCpuMeasuredBatteryConsumptionUC();
diff --git a/core/java/com/android/internal/os/CustomMeasuredPowerCalculator.java b/core/java/com/android/internal/os/CustomMeasuredPowerCalculator.java
index cbbb52621111..0853bd801137 100644
--- a/core/java/com/android/internal/os/CustomMeasuredPowerCalculator.java
+++ b/core/java/com/android/internal/os/CustomMeasuredPowerCalculator.java
@@ -96,7 +96,9 @@ public class CustomMeasuredPowerCalculator extends PowerCalculator {
app.setConsumedPowerForCustomComponent(
BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID + i,
customMeasuredPowerMah[i]);
- newTotalPowerMah[i] += customMeasuredPowerMah[i];
+ if (!app.isVirtualUid()) {
+ newTotalPowerMah[i] += customMeasuredPowerMah[i];
+ }
}
}
return newTotalPowerMah;
diff --git a/core/java/com/android/internal/os/GnssPowerCalculator.java b/core/java/com/android/internal/os/GnssPowerCalculator.java
index 0f783062f3e7..070783a04105 100644
--- a/core/java/com/android/internal/os/GnssPowerCalculator.java
+++ b/core/java/com/android/internal/os/GnssPowerCalculator.java
@@ -58,8 +58,11 @@ public class GnssPowerCalculator extends PowerCalculator {
final long consumptionUC =
app.getBatteryStatsUid().getGnssMeasuredBatteryConsumptionUC();
final int powerModel = getPowerModel(consumptionUC, query);
- appsPowerMah += calculateApp(app, app.getBatteryStatsUid(), powerModel,
+ final double powerMah = calculateApp(app, app.getBatteryStatsUid(), powerModel,
rawRealtimeUs, averageGnssPowerMa, consumptionUC);
+ if (!app.isVirtualUid()) {
+ appsPowerMah += powerMah;
+ }
}
final long consumptionUC = batteryStats.getGnssMeasuredBatteryConsumptionUC();
diff --git a/core/java/com/android/internal/os/KernelAllocationStats.java b/core/java/com/android/internal/os/KernelAllocationStats.java
index 1c3f8b0bf095..58d51e327ade 100644
--- a/core/java/com/android/internal/os/KernelAllocationStats.java
+++ b/core/java/com/android/internal/os/KernelAllocationStats.java
@@ -24,21 +24,29 @@ public final class KernelAllocationStats {
/** Process dma-buf stats. */
public static final class ProcessDmabuf {
+ public final int uid;
+ public final String processName;
+ public final int oomScore;
+
/** Size of buffers retained by the process. */
public final int retainedSizeKb;
/** Number of buffers retained by the process. */
public final int retainedBuffersCount;
- /** Size of buffers mapped to the address space. */
- public final int mappedSizeKb;
- /** Count of buffers mapped to the address space. */
- public final int mappedBuffersCount;
+ /** Size of buffers shared with Surface Flinger. */
+ public final int surfaceFlingerSizeKb;
+ /** Count of buffers shared with Surface Flinger. */
+ public final int surfaceFlingerCount;
- ProcessDmabuf(int retainedSizeKb, int retainedBuffersCount,
- int mappedSizeKb, int mappedBuffersCount) {
+ ProcessDmabuf(int uid, String processName, int oomScore, int retainedSizeKb,
+ int retainedBuffersCount, int surfaceFlingerSizeKb,
+ int surfaceFlingerCount) {
+ this.uid = uid;
+ this.processName = processName;
+ this.oomScore = oomScore;
this.retainedSizeKb = retainedSizeKb;
this.retainedBuffersCount = retainedBuffersCount;
- this.mappedSizeKb = mappedSizeKb;
- this.mappedBuffersCount = mappedBuffersCount;
+ this.surfaceFlingerSizeKb = surfaceFlingerSizeKb;
+ this.surfaceFlingerCount = surfaceFlingerCount;
}
}
@@ -47,7 +55,7 @@ public final class KernelAllocationStats {
* stats could not be read.
*/
@Nullable
- public static native ProcessDmabuf getDmabufAllocations(int pid);
+ public static native ProcessDmabuf[] getDmabufAllocations();
/** Pid to gpu memory size. */
public static final class ProcessGpuMem {
diff --git a/core/java/com/android/internal/os/MobileRadioPowerCalculator.java b/core/java/com/android/internal/os/MobileRadioPowerCalculator.java
index f4624de289be..d0df45c9af65 100644
--- a/core/java/com/android/internal/os/MobileRadioPowerCalculator.java
+++ b/core/java/com/android/internal/os/MobileRadioPowerCalculator.java
@@ -136,12 +136,14 @@ public class MobileRadioPowerCalculator extends PowerCalculator {
PowerAndDuration total,
BatteryUsageStatsQuery query, BatteryConsumer.Key[] keys) {
final long radioActiveDurationMs = calculateDuration(u, BatteryStats.STATS_SINCE_CHARGED);
- total.totalAppDurationMs += radioActiveDurationMs;
-
final long consumptionUC = u.getMobileRadioMeasuredBatteryConsumptionUC();
final int powerModel = getPowerModel(consumptionUC, query);
final double powerMah = calculatePower(u, powerModel, radioActiveDurationMs, consumptionUC);
- total.totalAppPowerMah += powerMah;
+
+ if (!app.isVirtualUid()) {
+ total.totalAppDurationMs += radioActiveDurationMs;
+ total.totalAppPowerMah += powerMah;
+ }
app.setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO,
radioActiveDurationMs)
diff --git a/core/java/com/android/internal/os/ScreenPowerCalculator.java b/core/java/com/android/internal/os/ScreenPowerCalculator.java
index 67d3d6e7bede..5ca1a857fbcd 100644
--- a/core/java/com/android/internal/os/ScreenPowerCalculator.java
+++ b/core/java/com/android/internal/os/ScreenPowerCalculator.java
@@ -96,8 +96,10 @@ public class ScreenPowerCalculator extends PowerCalculator {
appPowerAndDuration.durationMs)
.setConsumedPower(BatteryConsumer.POWER_COMPONENT_SCREEN,
appPowerAndDuration.powerMah, powerModel);
- totalAppPower += appPowerAndDuration.powerMah;
- totalAppDuration += appPowerAndDuration.durationMs;
+ if (!app.isVirtualUid()) {
+ totalAppPower += appPowerAndDuration.powerMah;
+ totalAppDuration += appPowerAndDuration.durationMs;
+ }
}
break;
case BatteryConsumer.POWER_MODEL_POWER_PROFILE:
@@ -192,10 +194,13 @@ public class ScreenPowerCalculator extends PowerCalculator {
long totalActivityTimeMs = 0;
final SparseLongArray activityTimeArray = new SparseLongArray();
for (int i = uidBatteryConsumerBuilders.size() - 1; i >= 0; i--) {
- final BatteryStats.Uid uid = uidBatteryConsumerBuilders.valueAt(i).getBatteryStatsUid();
+ final UidBatteryConsumer.Builder app = uidBatteryConsumerBuilders.valueAt(i);
+ final BatteryStats.Uid uid = app.getBatteryStatsUid();
final long timeMs = getProcessForegroundTimeMs(uid, rawRealtimeUs);
activityTimeArray.put(uid.getUid(), timeMs);
- totalActivityTimeMs += timeMs;
+ if (!app.isVirtualUid()) {
+ totalActivityTimeMs += timeMs;
+ }
}
if (totalActivityTimeMs >= MIN_ACTIVE_TIME_FOR_SMEARING) {
diff --git a/core/java/com/android/internal/os/SensorPowerCalculator.java b/core/java/com/android/internal/os/SensorPowerCalculator.java
index 4a9c91d14c4c..573692ea63f3 100644
--- a/core/java/com/android/internal/os/SensorPowerCalculator.java
+++ b/core/java/com/android/internal/os/SensorPowerCalculator.java
@@ -51,7 +51,9 @@ public class SensorPowerCalculator extends PowerCalculator {
builder.getUidBatteryConsumerBuilders();
for (int i = uidBatteryConsumerBuilders.size() - 1; i >= 0; i--) {
final UidBatteryConsumer.Builder app = uidBatteryConsumerBuilders.valueAt(i);
- appsPowerMah += calculateApp(app, app.getBatteryStatsUid(), rawRealtimeUs);
+ if (!app.isVirtualUid()) {
+ appsPowerMah += calculateApp(app, app.getBatteryStatsUid(), rawRealtimeUs);
+ }
}
builder.getAggregateBatteryConsumerBuilder(
diff --git a/core/java/com/android/internal/os/UserPowerCalculator.java b/core/java/com/android/internal/os/UserPowerCalculator.java
index 22cff6e2435a..79e3a195dc82 100644
--- a/core/java/com/android/internal/os/UserPowerCalculator.java
+++ b/core/java/com/android/internal/os/UserPowerCalculator.java
@@ -49,7 +49,11 @@ public class UserPowerCalculator extends PowerCalculator {
builder.getUidBatteryConsumerBuilders();
for (int i = uidBatteryConsumerBuilders.size() - 1; i >= 0; i--) {
- UidBatteryConsumer.Builder uidBuilder = uidBatteryConsumerBuilders.valueAt(i);
+ final UidBatteryConsumer.Builder uidBuilder = uidBatteryConsumerBuilders.valueAt(i);
+ if (uidBuilder.isVirtualUid()) {
+ continue;
+ }
+
final int uid = uidBuilder.getUid();
if (UserHandle.getAppId(uid) < Process.FIRST_APPLICATION_UID) {
continue;
diff --git a/core/java/com/android/internal/os/VideoPowerCalculator.java b/core/java/com/android/internal/os/VideoPowerCalculator.java
index a222bcb4dfbf..2daf15eb14a6 100644
--- a/core/java/com/android/internal/os/VideoPowerCalculator.java
+++ b/core/java/com/android/internal/os/VideoPowerCalculator.java
@@ -75,7 +75,9 @@ public class VideoPowerCalculator extends PowerCalculator {
final double powerMah = mPowerEstimator.calculatePower(durationMs);
app.setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_VIDEO, durationMs)
.setConsumedPower(BatteryConsumer.POWER_COMPONENT_VIDEO, powerMah);
- total.durationMs += durationMs;
- total.powerMah += powerMah;
+ if (!app.isVirtualUid()) {
+ total.durationMs += durationMs;
+ total.powerMah += powerMah;
+ }
}
}
diff --git a/core/java/com/android/internal/os/WakelockPowerCalculator.java b/core/java/com/android/internal/os/WakelockPowerCalculator.java
index 0251e1ccc885..3ae7113faf71 100644
--- a/core/java/com/android/internal/os/WakelockPowerCalculator.java
+++ b/core/java/com/android/internal/os/WakelockPowerCalculator.java
@@ -62,8 +62,10 @@ public class WakelockPowerCalculator extends PowerCalculator {
BatteryStats.STATS_SINCE_CHARGED);
app.setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_WAKELOCK, result.durationMs)
.setConsumedPower(BatteryConsumer.POWER_COMPONENT_WAKELOCK, result.powerMah);
- totalAppDurationMs += result.durationMs;
- appPowerMah += result.powerMah;
+ if (!app.isVirtualUid()) {
+ totalAppDurationMs += result.durationMs;
+ appPowerMah += result.powerMah;
+ }
if (app.getUid() == Process.ROOT_UID) {
osBatteryConsumer = app;
diff --git a/core/java/com/android/internal/os/WifiPowerCalculator.java b/core/java/com/android/internal/os/WifiPowerCalculator.java
index 8c3fb86331b2..2181821dd55a 100644
--- a/core/java/com/android/internal/os/WifiPowerCalculator.java
+++ b/core/java/com/android/internal/os/WifiPowerCalculator.java
@@ -111,9 +111,10 @@ public class WifiPowerCalculator extends PowerCalculator {
calculateApp(powerDurationAndTraffic, app.getBatteryStatsUid(), powerModel,
rawRealtimeUs, BatteryStats.STATS_SINCE_CHARGED,
batteryStats.hasWifiActivityReporting(), consumptionUC);
-
- totalAppDurationMs += powerDurationAndTraffic.durationMs;
- totalAppPowerMah += powerDurationAndTraffic.powerMah;
+ if (!app.isVirtualUid()) {
+ totalAppDurationMs += powerDurationAndTraffic.durationMs;
+ totalAppPowerMah += powerDurationAndTraffic.powerMah;
+ }
app.setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_WIFI,
powerDurationAndTraffic.durationMs);
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index 40e40856b000..89ac72255306 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -30,6 +30,7 @@ import static android.view.View.MeasureSpec.EXACTLY;
import static android.view.View.MeasureSpec.getMode;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
+import static android.view.ViewRootImpl.CAPTION_ON_SHELL;
import static android.view.Window.DECOR_CAPTION_SHADE_DARK;
import static android.view.Window.DECOR_CAPTION_SHADE_LIGHT;
import static android.view.WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS;
@@ -2120,7 +2121,9 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
* corresponding insets change to the InsetsController.
*/
public void notifyCaptionHeightChanged() {
- getWindowInsetsController().setCaptionInsetsHeight(getCaptionInsetsHeight());
+ if (!CAPTION_ON_SHELL) {
+ getWindowInsetsController().setCaptionInsetsHeight(getCaptionInsetsHeight());
+ }
}
void setWindow(PhoneWindow phoneWindow) {
diff --git a/core/java/com/android/internal/policy/TransitionAnimation.java b/core/java/com/android/internal/policy/TransitionAnimation.java
index 37c96e71a0a8..74749cc9bf0b 100644
--- a/core/java/com/android/internal/policy/TransitionAnimation.java
+++ b/core/java/com/android/internal/policy/TransitionAnimation.java
@@ -100,7 +100,7 @@ public class TransitionAnimation {
// TODO (b/215515255): remove once we full migrate to shell transitions
private static final boolean SHELL_TRANSITIONS_ENABLED =
- SystemProperties.getBoolean("persist.debug.shell_transit", false);
+ SystemProperties.getBoolean("persist.wm.debug.shell_transit", false);
private final Context mContext;
private final String mTag;
@@ -312,9 +312,9 @@ public class TransitionAnimation {
/** Load animation by attribute Id from android package. */
@Nullable
- public Animation loadDefaultAnimationAttr(int animAttr) {
+ public Animation loadDefaultAnimationAttr(int animAttr, boolean translucent) {
return loadAnimationAttr(DEFAULT_PACKAGE, mDefaultWindowAnimationStyleResId, animAttr,
- false /* translucent */);
+ translucent);
}
@Nullable
diff --git a/core/java/com/android/internal/power/MeasuredEnergyStats.java b/core/java/com/android/internal/power/MeasuredEnergyStats.java
index 7262e846d9b0..7fb8696a217d 100644
--- a/core/java/com/android/internal/power/MeasuredEnergyStats.java
+++ b/core/java/com/android/internal/power/MeasuredEnergyStats.java
@@ -194,6 +194,7 @@ public class MeasuredEnergyStats {
return mSupportedMultiStateBuckets[index];
}
+ @NonNull
public String[] getStateNames() {
return mStateNames;
}
@@ -321,6 +322,10 @@ public class MeasuredEnergyStats {
LongMultiStateCounter multiStateCounter = null;
if (in.readBoolean()) {
multiStateCounter = LongMultiStateCounter.CREATOR.createFromParcel(in);
+ if (mConfig == null
+ || multiStateCounter.getStateCount() != mConfig.getStateNames().length) {
+ multiStateCounter = null;
+ }
}
if (index < mAccumulatedChargeMicroCoulomb.length) {
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index d629d66d1c31..089179dbba27 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -297,6 +297,11 @@ oneway interface IStatusBar
*/
void runGcForTest();
+ /**
+ * Send a request to SystemUI to put a given active tile in listening state
+ */
+ void requestTileServiceListeningState(in ComponentName componentName);
+
void requestAddTile(in ComponentName componentName, in CharSequence appName, in CharSequence label, in Icon icon, in IAddTileResultCallback callback);
void cancelRequestAddTile(in String packageName);
diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
index 9163b6d6215e..2ee5e797b4ab 100644
--- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
@@ -70,7 +70,7 @@ interface IStatusBarService
void onPanelRevealed(boolean clearNotificationEffects, int numItems);
void onPanelHidden();
// Mark current notifications as "seen" and stop ringing, vibrating, blinking.
- void clearNotificationEffects();
+ oneway void clearNotificationEffects();
void onNotificationClick(String key, in NotificationVisibility nv);
void onNotificationActionClick(String key, int actionIndex, in Notification.Action action, in NotificationVisibility nv, boolean generatedByAssistant);
void onNotificationError(String pkg, String tag, int id,
@@ -91,7 +91,7 @@ interface IStatusBarService
void onBubbleNotificationSuppressionChanged(String key, boolean isNotifSuppressed, boolean isBubbleSuppressed);
void hideCurrentInputMethodForBubbles();
void grantInlineReplyUriPermission(String key, in Uri uri, in UserHandle user, String packageName);
- void clearInlineReplyUriPermissions(String key);
+ oneway void clearInlineReplyUriPermissions(String key);
void onNotificationFeedbackReceived(String key, in Bundle feedback);
void onGlobalActionsShown();
@@ -171,6 +171,11 @@ interface IStatusBarService
*/
void suppressAmbientDisplay(boolean suppress);
+ /**
+ * Send a request to SystemUI to put a given active tile in listening state
+ */
+ void requestTileServiceListeningState(in ComponentName componentName, int userId);
+
void requestAddTile(in ComponentName componentName, in CharSequence label, in Icon icon, int userId, in IAddTileResultCallback callback);
void cancelRequestAddTile(in String packageName);
diff --git a/core/java/com/android/internal/telephony/ICarrierPrivilegesListener.aidl b/core/java/com/android/internal/telephony/ICarrierPrivilegesCallback.aidl
index 6ca8cecba3c8..0c8e73fb2b67 100644
--- a/core/java/com/android/internal/telephony/ICarrierPrivilegesListener.aidl
+++ b/core/java/com/android/internal/telephony/ICarrierPrivilegesCallback.aidl
@@ -16,7 +16,8 @@
package com.android.internal.telephony;
-oneway interface ICarrierPrivilegesListener {
+oneway interface ICarrierPrivilegesCallback {
void onCarrierPrivilegesChanged(
in List<String> privilegedPackageNames, in int[] privilegedUids);
+ void onCarrierServiceChanged(in String carrierServicePackageName, in int carrierServiceUid);
}
diff --git a/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl
index 9712d7e38a4b..c7fa757ac0b7 100644
--- a/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl
+++ b/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl
@@ -32,7 +32,7 @@ import android.telephony.PreciseDataConnectionState;
import android.telephony.ServiceState;
import android.telephony.SignalStrength;
import android.telephony.emergency.EmergencyNumber;
-import com.android.internal.telephony.ICarrierPrivilegesListener;
+import com.android.internal.telephony.ICarrierPrivilegesCallback;
import com.android.internal.telephony.IPhoneStateListener;
import com.android.internal.telephony.IOnSubscriptionsChangedListener;
@@ -102,9 +102,11 @@ interface ITelephonyRegistry {
void notifyLinkCapacityEstimateChanged(in int phoneId, in int subId,
in List<LinkCapacityEstimate> linkCapacityEstimateList);
- void addCarrierPrivilegesListener(
- int phoneId, ICarrierPrivilegesListener callback, String pkg, String featureId);
- void removeCarrierPrivilegesListener(ICarrierPrivilegesListener callback, String pkg);
+ void addCarrierPrivilegesCallback(
+ int phoneId, ICarrierPrivilegesCallback callback, String pkg, String featureId);
+ void removeCarrierPrivilegesCallback(ICarrierPrivilegesCallback callback, String pkg);
void notifyCarrierPrivilegesChanged(
int phoneId, in List<String> privilegedPackageNames, in int[] privilegedUids);
+ void notifyCarrierServiceChanged(int phoneId, in String packageName, int uid);
+
}
diff --git a/core/java/com/android/internal/util/LatencyTracker.java b/core/java/com/android/internal/util/LatencyTracker.java
index 1cd758c0f43b..3f7c4d53d333 100644
--- a/core/java/com/android/internal/util/LatencyTracker.java
+++ b/core/java/com/android/internal/util/LatencyTracker.java
@@ -132,6 +132,11 @@ public class LatencyTracker {
*/
public static final int ACTION_UDFPS_ILLUMINATE = 14;
+ /**
+ * Time it takes for the gesture back affordance arrow to show up.
+ */
+ public static final int ACTION_SHOW_BACK_ARROW = 15;
+
private static final int[] ACTIONS_ALL = {
ACTION_EXPAND_PANEL,
ACTION_TOGGLE_RECENTS,
@@ -147,7 +152,8 @@ public class LatencyTracker {
ACTION_LOCKSCREEN_UNLOCK,
ACTION_USER_SWITCH,
ACTION_SWITCH_DISPLAY_UNFOLD,
- ACTION_UDFPS_ILLUMINATE
+ ACTION_UDFPS_ILLUMINATE,
+ ACTION_SHOW_BACK_ARROW,
};
/** @hide */
@@ -166,7 +172,8 @@ public class LatencyTracker {
ACTION_LOCKSCREEN_UNLOCK,
ACTION_USER_SWITCH,
ACTION_SWITCH_DISPLAY_UNFOLD,
- ACTION_UDFPS_ILLUMINATE
+ ACTION_UDFPS_ILLUMINATE,
+ ACTION_SHOW_BACK_ARROW
})
@Retention(RetentionPolicy.SOURCE)
public @interface Action {
@@ -187,7 +194,8 @@ public class LatencyTracker {
FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_LOCKSCREEN_UNLOCK,
FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_USER_SWITCH,
FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_SWITCH_DISPLAY_UNFOLD,
- FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_UDFPS_ILLUMINATE
+ FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_UDFPS_ILLUMINATE,
+ FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_SHOW_BACK_ARROW,
};
private static LatencyTracker sLatencyTracker;
@@ -277,6 +285,8 @@ public class LatencyTracker {
return "ACTION_SWITCH_DISPLAY_UNFOLD";
case 15:
return "ACTION_UDFPS_ILLUMINATE";
+ case 16:
+ return "ACTION_SHOW_BACK_ARROW";
default:
throw new IllegalArgumentException("Invalid action");
}
diff --git a/core/java/com/android/internal/util/ScreenshotHelper.java b/core/java/com/android/internal/util/ScreenshotHelper.java
index d3c3917cd791..f4f438b1f601 100644
--- a/core/java/com/android/internal/util/ScreenshotHelper.java
+++ b/core/java/com/android/internal/util/ScreenshotHelper.java
@@ -11,8 +11,12 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
+import android.graphics.Bitmap;
+import android.graphics.ColorSpace;
import android.graphics.Insets;
+import android.graphics.ParcelableColorSpace;
import android.graphics.Rect;
+import android.hardware.HardwareBuffer;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
@@ -26,6 +30,7 @@ import android.os.UserHandle;
import android.util.Log;
import android.view.WindowManager;
+import java.util.Objects;
import java.util.function.Consumer;
public class ScreenshotHelper {
@@ -154,6 +159,72 @@ public class ScreenshotHelper {
};
}
+ /**
+ * Bundler used to convert between a hardware bitmap and a bundle without copying the internal
+ * content. This is expected to be used together with {@link #provideScreenshot} to handle a
+ * hardware bitmap as a screenshot.
+ */
+ public static final class HardwareBitmapBundler {
+ private static final String KEY_BUFFER = "bitmap_util_buffer";
+ private static final String KEY_COLOR_SPACE = "bitmap_util_color_space";
+
+ private HardwareBitmapBundler() {
+ }
+
+ /**
+ * Creates a Bundle that represents the given Bitmap.
+ * <p>The Bundle will contain a wrapped version of the Bitmaps HardwareBuffer, so will avoid
+ * copies when passing across processes, only pass to processes you trust.
+ *
+ * <p>Returns a new Bundle rather than modifying an exiting one to avoid key collisions, the
+ * returned Bundle should be treated as a standalone object.
+ *
+ * @param bitmap to convert to bundle
+ * @return a Bundle representing the bitmap, should only be parsed by
+ * {@link #bundleToHardwareBitmap(Bundle)}
+ */
+ public static Bundle hardwareBitmapToBundle(Bitmap bitmap) {
+ if (bitmap.getConfig() != Bitmap.Config.HARDWARE) {
+ throw new IllegalArgumentException(
+ "Passed bitmap must have hardware config, found: " + bitmap.getConfig());
+ }
+
+ // Bitmap assumes SRGB for null color space
+ ParcelableColorSpace colorSpace =
+ bitmap.getColorSpace() == null
+ ? new ParcelableColorSpace(ColorSpace.get(ColorSpace.Named.SRGB))
+ : new ParcelableColorSpace(bitmap.getColorSpace());
+
+ Bundle bundle = new Bundle();
+ bundle.putParcelable(KEY_BUFFER, bitmap.getHardwareBuffer());
+ bundle.putParcelable(KEY_COLOR_SPACE, colorSpace);
+
+ return bundle;
+ }
+
+ /**
+ * Extracts the Bitmap added to a Bundle with {@link #hardwareBitmapToBundle(Bitmap)} .}
+ *
+ * <p>This Bitmap contains the HardwareBuffer from the original caller, be careful passing
+ * this
+ * Bitmap on to any other source.
+ *
+ * @param bundle containing the bitmap
+ * @return a hardware Bitmap
+ */
+ public static Bitmap bundleToHardwareBitmap(Bundle bundle) {
+ if (!bundle.containsKey(KEY_BUFFER) || !bundle.containsKey(KEY_COLOR_SPACE)) {
+ throw new IllegalArgumentException("Bundle does not contain a hardware bitmap");
+ }
+
+ HardwareBuffer buffer = bundle.getParcelable(KEY_BUFFER);
+ ParcelableColorSpace colorSpace = bundle.getParcelable(KEY_COLOR_SPACE);
+
+ return Bitmap.wrapHardwareBuffer(Objects.requireNonNull(buffer),
+ colorSpace.getColorSpace());
+ }
+ }
+
private static final String TAG = "ScreenshotHelper";
// Time until we give up on the screenshot & show an error instead.
diff --git a/core/java/com/android/internal/view/BaseIWindow.java b/core/java/com/android/internal/view/BaseIWindow.java
index 6673f6781ef8..52f0fb578e3d 100644
--- a/core/java/com/android/internal/view/BaseIWindow.java
+++ b/core/java/com/android/internal/view/BaseIWindow.java
@@ -51,10 +51,10 @@ public class BaseIWindow extends IWindow.Stub {
@Override
public void resized(ClientWindowFrames frames, boolean reportDraw,
MergedConfiguration mergedConfiguration, boolean forceLayout,
- boolean alwaysConsumeSystemBars, int displayId) {
+ boolean alwaysConsumeSystemBars, int displayId, int seqId, int resizeMode) {
if (reportDraw) {
try {
- mSession.finishDrawing(this, null /* postDrawTransaction */);
+ mSession.finishDrawing(this, null /* postDrawTransaction */, seqId);
} catch (RemoteException e) {
}
}
diff --git a/core/java/com/android/internal/view/IInputMethod.aidl b/core/java/com/android/internal/view/IInputMethod.aidl
index d2bc3442ed36..40d89db6165c 100644
--- a/core/java/com/android/internal/view/IInputMethod.aidl
+++ b/core/java/com/android/internal/view/IInputMethod.aidl
@@ -37,8 +37,7 @@ import com.android.internal.view.InlineSuggestionsRequestInfo;
*/
oneway interface IInputMethod {
void initializeInternal(IBinder token, IInputMethodPrivilegedOperations privOps,
- int configChanges, boolean stylusHwSupported,
- boolean shouldShowImeSwitcherWhenImeIsShown);
+ int configChanges, boolean stylusHwSupported, int navigationBarFlags);
void onCreateInlineSuggestionsRequest(in InlineSuggestionsRequestInfo requestInfo,
in IInlineSuggestionsRequestCallback cb);
@@ -48,10 +47,9 @@ oneway interface IInputMethod {
void unbindInput();
void startInput(in IBinder startInputToken, in IInputContext inputContext,
- in EditorInfo attribute, boolean restarting,
- boolean shouldShowImeSwitcherWhenImeIsShown);
+ in EditorInfo attribute, boolean restarting, int navigationBarFlags);
- void onShouldShowImeSwitcherWhenImeIsShownChanged(boolean shouldShowImeSwitcherWhenImeIsShown);
+ void onNavButtonFlagsChanged(int navButtonFlags);
void createSession(in InputChannel channel, IInputSessionCallback callback);
@@ -69,4 +67,6 @@ oneway interface IInputMethod {
in List<MotionEvent> events);
void initInkWindow();
+
+ void finishStylusHandwriting();
}
diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl
index 0df3e870b80c..c5346b95440b 100644
--- a/core/java/com/android/internal/view/IInputMethodManager.aidl
+++ b/core/java/com/android/internal/view/IInputMethodManager.aidl
@@ -67,7 +67,7 @@ interface IInputMethodManager {
void setAdditionalInputMethodSubtypes(String id, in InputMethodSubtype[] subtypes);
// This is kept due to @UnsupportedAppUsage.
// TODO(Bug 113914148): Consider removing this.
- int getInputMethodWindowVisibleHeight();
+ int getInputMethodWindowVisibleHeight(in IInputMethodClient client);
oneway void reportPerceptibleAsync(in IBinder windowToken, boolean perceptible);
/** Remove the IME surface. Requires INTERNAL_SYSTEM_WINDOW permission. */
diff --git a/core/java/com/android/internal/widget/ConversationLayout.java b/core/java/com/android/internal/widget/ConversationLayout.java
index 5fa4a652e176..4706affa3541 100644
--- a/core/java/com/android/internal/widget/ConversationLayout.java
+++ b/core/java/com/android/internal/widget/ConversationLayout.java
@@ -66,7 +66,6 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
-import java.util.function.Consumer;
/**
* A custom-built layout for the Notification.MessagingStyle allows dynamic addition and removal
@@ -76,8 +75,6 @@ import java.util.function.Consumer;
public class ConversationLayout extends FrameLayout
implements ImageMessageConsumer, IMessagingLayout {
- private static final Consumer<MessagingMessage> REMOVE_MESSAGE
- = MessagingMessage::removeMessage;
public static final Interpolator LINEAR_OUT_SLOW_IN = new PathInterpolator(0f, 0f, 0.2f, 1f);
public static final Interpolator FAST_OUT_LINEAR_IN = new PathInterpolator(0.4f, 0f, 1f, 1f);
public static final Interpolator FAST_OUT_SLOW_IN = new PathInterpolator(0.4f, 0f, 0.2f, 1f);
@@ -150,7 +147,7 @@ public class ConversationLayout extends FrameLayout
private Icon mShortcutIcon;
private View mAppNameDivider;
private TouchDelegateComposite mTouchDelegate = new TouchDelegateComposite(this);
- private ArrayList<MessagingGroup> mToRecycle = new ArrayList<>();
+ private ArrayList<MessagingLinearLayout.MessagingChild> mToRecycle = new ArrayList<>();
public ConversationLayout(@NonNull Context context) {
super(context);
@@ -463,8 +460,12 @@ public class ConversationLayout extends FrameLayout
removeGroups(oldGroups);
// Let's remove the remaining messages
- mMessages.forEach(REMOVE_MESSAGE);
- mHistoricMessages.forEach(REMOVE_MESSAGE);
+ for (MessagingMessage message : mMessages) {
+ message.removeMessage(mToRecycle);
+ }
+ for (MessagingMessage historicMessage : mHistoricMessages) {
+ historicMessage.removeMessage(mToRecycle);
+ }
mMessages = messages;
mHistoricMessages = historicMessages;
@@ -475,8 +476,8 @@ public class ConversationLayout extends FrameLayout
updateConversationLayout();
// Recycle everything at the end of the update, now that we know it's no longer needed.
- for (MessagingGroup group : mToRecycle) {
- group.recycle();
+ for (MessagingLinearLayout.MessagingChild child : mToRecycle) {
+ child.recycle();
}
mToRecycle.clear();
}
diff --git a/core/java/com/android/internal/widget/ILockSettings.aidl b/core/java/com/android/internal/widget/ILockSettings.aidl
index db4bc2c7e24a..3494c9e05b4a 100644
--- a/core/java/com/android/internal/widget/ILockSettings.aidl
+++ b/core/java/com/android/internal/widget/ILockSettings.aidl
@@ -53,7 +53,6 @@ interface ILockSettings {
VerifyCredentialResponse verifyTiedProfileChallenge(in LockscreenCredential credential, int userId, int flags);
VerifyCredentialResponse verifyGatekeeperPasswordHandle(long gatekeeperPasswordHandle, long challenge, int userId);
void removeGatekeeperPasswordHandle(long gatekeeperPasswordHandle);
- boolean checkVoldPassword(int userId);
int getCredentialType(int userId);
byte[] getHashFactor(in LockscreenCredential currentCredential, int userId);
void setSeparateProfileChallengeEnabled(int userId, boolean enabled, in LockscreenCredential managedUserPassword);
@@ -97,7 +96,6 @@ interface ILockSettings {
boolean hasSecureLockScreen();
boolean tryUnlockWithCachedUnifiedChallenge(int userId);
void removeCachedUnifiedChallenge(int userId);
- void updateEncryptionPassword(int type, in byte[] password);
boolean registerWeakEscrowTokenRemovedListener(in IWeakEscrowTokenRemovedListener listener);
boolean unregisterWeakEscrowTokenRemovedListener(in IWeakEscrowTokenRemovedListener listener);
long addWeakEscrowToken(in byte[] token, int userId, in IWeakEscrowTokenActivatedListener callback);
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 1e11c6d1fddb..a94b30707604 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -526,20 +526,6 @@ public class LockPatternUtils {
}
/**
- * Check to see if vold already has the password.
- * Note that this also clears vold's copy of the password.
- * @return Whether the vold password matches or not.
- */
- public boolean checkVoldPassword(int userId) {
- try {
- return getLockSettings().checkVoldPassword(userId);
- } catch (RemoteException re) {
- Log.e(TAG, "failed to check vold password", re);
- return false;
- }
- }
-
- /**
* Returns the password history hash factor, needed to check new password against password
* history with {@link #checkPasswordHistory(byte[], byte[], int)}
*/
@@ -722,38 +708,14 @@ public class LockPatternUtils {
return true;
}
- private void updateCryptoUserInfo(int userId) {
- if (userId != UserHandle.USER_SYSTEM) {
- return;
- }
-
- final String ownerInfo = isOwnerInfoEnabled(userId) ? getOwnerInfo(userId) : "";
-
- IBinder service = ServiceManager.getService("mount");
- if (service == null) {
- Log.e(TAG, "Could not find the mount service to update the user info");
- return;
- }
-
- IStorageManager storageManager = IStorageManager.Stub.asInterface(service);
- try {
- Log.d(TAG, "Setting owner info");
- storageManager.setField(StorageManager.OWNER_INFO_KEY, ownerInfo);
- } catch (RemoteException e) {
- Log.e(TAG, "Error changing user info", e);
- }
- }
-
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public void setOwnerInfo(String info, int userId) {
setString(LOCK_SCREEN_OWNER_INFO, info, userId);
- updateCryptoUserInfo(userId);
}
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public void setOwnerInfoEnabled(boolean enabled, int userId) {
setBoolean(LOCK_SCREEN_OWNER_INFO_ENABLED, enabled, userId);
- updateCryptoUserInfo(userId);
}
@UnsupportedAppUsage
@@ -808,17 +770,6 @@ public class LockPatternUtils {
}
/**
- * Clears the encryption password.
- */
- public void clearEncryptionPassword() {
- try {
- getLockSettings().updateEncryptionPassword(StorageManager.CRYPT_TYPE_DEFAULT, null);
- } catch (RemoteException e) {
- Log.e(TAG, "Couldn't clear encryption password");
- }
- }
-
- /**
* Retrieves the quality mode for {@code userHandle}.
* @see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)
*
@@ -843,7 +794,7 @@ public class LockPatternUtils {
*/
public void setSeparateProfileChallengeEnabled(int userHandle, boolean enabled,
LockscreenCredential profilePassword) {
- if (!isCredentialSharedWithParent(userHandle)) {
+ if (!isCredentialSharableWithParent(userHandle)) {
return;
}
try {
@@ -859,7 +810,7 @@ public class LockPatternUtils {
* Returns true if {@code userHandle} is a managed profile with separate challenge.
*/
public boolean isSeparateProfileChallengeEnabled(int userHandle) {
- return isCredentialSharedWithParent(userHandle) && hasSeparateChallenge(userHandle);
+ return isCredentialSharableWithParent(userHandle) && hasSeparateChallenge(userHandle);
}
/**
@@ -884,8 +835,8 @@ public class LockPatternUtils {
return info != null && info.isManagedProfile();
}
- private boolean isCredentialSharedWithParent(int userHandle) {
- return getUserManager(userHandle).isCredentialSharedWithParent();
+ private boolean isCredentialSharableWithParent(int userHandle) {
+ return getUserManager(userHandle).isCredentialSharableWithParent();
}
/**
@@ -1042,24 +993,6 @@ public class LockPatternUtils {
*/
public void setVisiblePatternEnabled(boolean enabled, int userId) {
setBoolean(Settings.Secure.LOCK_PATTERN_VISIBLE, enabled, userId);
-
- // Update for crypto if owner
- if (userId != UserHandle.USER_SYSTEM) {
- return;
- }
-
- IBinder service = ServiceManager.getService("mount");
- if (service == null) {
- Log.e(TAG, "Could not find the mount service to update the user info");
- return;
- }
-
- IStorageManager storageManager = IStorageManager.Stub.asInterface(service);
- try {
- storageManager.setField(StorageManager.PATTERN_VISIBLE_KEY, enabled ? "1" : "0");
- } catch (RemoteException e) {
- Log.e(TAG, "Error changing pattern visible state", e);
- }
}
public boolean isVisiblePatternEverChosen(int userId) {
@@ -1070,23 +1003,7 @@ public class LockPatternUtils {
* Set whether the visible password is enabled for cryptkeeper screen.
*/
public void setVisiblePasswordEnabled(boolean enabled, int userId) {
- // Update for crypto if owner
- if (userId != UserHandle.USER_SYSTEM) {
- return;
- }
-
- IBinder service = ServiceManager.getService("mount");
- if (service == null) {
- Log.e(TAG, "Could not find the mount service to update the user info");
- return;
- }
-
- IStorageManager storageManager = IStorageManager.Stub.asInterface(service);
- try {
- storageManager.setField(StorageManager.PASSWORD_VISIBLE_KEY, enabled ? "1" : "0");
- } catch (RemoteException e) {
- Log.e(TAG, "Error changing password visible state", e);
- }
+ // No longer does anything.
}
/**
@@ -1204,7 +1121,7 @@ public class LockPatternUtils {
public List<ComponentName> getEnabledTrustAgents(int userId) {
String serialized = getString(ENABLED_TRUST_AGENTS, userId);
if (TextUtils.isEmpty(serialized)) {
- return null;
+ return new ArrayList<ComponentName>();
}
String[] split = serialized.split(",");
ArrayList<ComponentName> activeTrustAgents = new ArrayList<ComponentName>(split.length);
diff --git a/core/java/com/android/internal/widget/LockPatternView.java b/core/java/com/android/internal/widget/LockPatternView.java
index 2b6b933c6886..01cec7727c4e 100644
--- a/core/java/com/android/internal/widget/LockPatternView.java
+++ b/core/java/com/android/internal/widget/LockPatternView.java
@@ -45,6 +45,7 @@ import android.util.AttributeSet;
import android.util.IntArray;
import android.util.Log;
import android.util.SparseArray;
+import android.util.TypedValue;
import android.view.HapticFeedbackConstants;
import android.view.MotionEvent;
import android.view.RenderNodeAnimator;
@@ -82,10 +83,12 @@ public class LockPatternView extends View {
private static final int DOT_ACTIVATION_DURATION_MILLIS = 50;
private static final int DOT_RADIUS_INCREASE_DURATION_MILLIS = 96;
private static final int DOT_RADIUS_DECREASE_DURATION_MILLIS = 192;
+ private static final float MIN_DOT_HIT_FACTOR = 0.2f;
private final CellState[][] mCellStates;
private final int mDotSize;
private final int mDotSizeActivated;
+ private final float mDotHitFactor;
private final int mPathWidth;
private boolean mDrawingProfilingStarted = false;
@@ -143,12 +146,11 @@ public class LockPatternView extends View {
private boolean mPatternInProgress = false;
private boolean mFadePattern = true;
- private float mHitFactor = 0.6f;
-
@UnsupportedAppUsage
private float mSquareWidth;
@UnsupportedAppUsage
private float mSquareHeight;
+ private float mDotHitRadius;
private final LinearGradient mFadeOutGradientShader;
private final Path mCurrentPath = new Path();
@@ -164,8 +166,7 @@ public class LockPatternView extends View {
private final Interpolator mFastOutSlowInInterpolator;
private final Interpolator mLinearOutSlowInInterpolator;
- private PatternExploreByTouchHelper mExploreByTouchHelper;
- private AudioManager mAudioManager;
+ private final PatternExploreByTouchHelper mExploreByTouchHelper;
private Drawable mSelectedDrawable;
private Drawable mNotSelectedDrawable;
@@ -349,6 +350,9 @@ public class LockPatternView extends View {
mDotSize = getResources().getDimensionPixelSize(R.dimen.lock_pattern_dot_size);
mDotSizeActivated = getResources().getDimensionPixelSize(
R.dimen.lock_pattern_dot_size_activated);
+ TypedValue outValue = new TypedValue();
+ getResources().getValue(R.dimen.lock_pattern_dot_hit_factor, outValue, true);
+ mDotHitFactor = Math.max(Math.min(outValue.getFloat(), 1f), MIN_DOT_HIT_FACTOR);
mUseLockPatternDrawable = getResources().getBoolean(R.bool.use_lock_pattern_drawable);
if (mUseLockPatternDrawable) {
@@ -375,7 +379,6 @@ public class LockPatternView extends View {
AnimationUtils.loadInterpolator(context, android.R.interpolator.linear_out_slow_in);
mExploreByTouchHelper = new PatternExploreByTouchHelper(this);
setAccessibilityDelegate(mExploreByTouchHelper);
- mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
int fadeAwayGradientWidth = getResources().getDimensionPixelSize(
R.dimen.lock_pattern_fade_away_gradient_width);
@@ -679,6 +682,7 @@ public class LockPatternView extends View {
final int height = h - mPaddingTop - mPaddingBottom;
mSquareHeight = height / 3.0f;
mExploreByTouchHelper.invalidateRoot();
+ mDotHitRadius = Math.min(mSquareHeight / 2, mSquareWidth / 2) * mDotHitFactor;
if (mUseLockPatternDrawable) {
mNotSelectedDrawable.setBounds(mPaddingLeft, mPaddingTop, width, height);
@@ -890,63 +894,30 @@ public class LockPatternView extends View {
return set;
}
- // helper method to find which cell a point maps to
+ @Nullable
private Cell checkForNewHit(float x, float y) {
-
- final int rowHit = getRowHit(y);
- if (rowHit < 0) {
- return null;
- }
- final int columnHit = getColumnHit(x);
- if (columnHit < 0) {
- return null;
- }
-
- if (mPatternDrawLookup[rowHit][columnHit]) {
- return null;
- }
- return Cell.of(rowHit, columnHit);
- }
-
- /**
- * Helper method to find the row that y falls into.
- * @param y The y coordinate
- * @return The row that y falls in, or -1 if it falls in no row.
- */
- private int getRowHit(float y) {
-
- final float squareHeight = mSquareHeight;
- float hitSize = squareHeight * mHitFactor;
-
- float offset = mPaddingTop + (squareHeight - hitSize) / 2f;
- for (int i = 0; i < 3; i++) {
-
- final float hitTop = offset + squareHeight * i;
- if (y >= hitTop && y <= hitTop + hitSize) {
- return i;
- }
+ Cell cellHit = detectCellHit(x, y);
+ if (cellHit != null && !mPatternDrawLookup[cellHit.row][cellHit.column]) {
+ return cellHit;
}
- return -1;
+ return null;
}
- /**
- * Helper method to find the column x fallis into.
- * @param x The x coordinate.
- * @return The column that x falls in, or -1 if it falls in no column.
- */
- private int getColumnHit(float x) {
- final float squareWidth = mSquareWidth;
- float hitSize = squareWidth * mHitFactor;
-
- float offset = mPaddingLeft + (squareWidth - hitSize) / 2f;
- for (int i = 0; i < 3; i++) {
-
- final float hitLeft = offset + squareWidth * i;
- if (x >= hitLeft && x <= hitLeft + hitSize) {
- return i;
+ /** Helper method to find which cell a point maps to. */
+ @Nullable
+ private Cell detectCellHit(float x, float y) {
+ final float hitRadiusSquared = mDotHitRadius * mDotHitRadius;
+ for (int row = 0; row < 3; row++) {
+ for (int column = 0; column < 3; column++) {
+ float centerY = getCenterYForRow(row);
+ float centerX = getCenterXForColumn(column);
+ if ((x - centerX) * (x - centerX) + (y - centerY) * (y - centerY)
+ < hitRadiusSquared) {
+ return Cell.of(row, column);
+ }
}
}
- return -1;
+ return null;
}
@Override
@@ -1553,8 +1524,7 @@ public class LockPatternView extends View {
protected int getVirtualViewAt(float x, float y) {
// This must use the same hit logic for the screen to ensure consistency whether
// accessibility is on or off.
- int id = getVirtualViewIdForHit(x, y);
- return id;
+ return getVirtualViewIdForHit(x, y);
}
@Override
@@ -1670,12 +1640,11 @@ public class LockPatternView extends View {
final int col = ordinal % 3;
float centerX = getCenterXForColumn(col);
float centerY = getCenterYForRow(row);
- float cellheight = mSquareHeight * mHitFactor * 0.5f;
- float cellwidth = mSquareWidth * mHitFactor * 0.5f;
- bounds.left = (int) (centerX - cellwidth);
- bounds.right = (int) (centerX + cellwidth);
- bounds.top = (int) (centerY - cellheight);
- bounds.bottom = (int) (centerY + cellheight);
+ float cellHitRadius = mDotHitRadius;
+ bounds.left = (int) (centerX - cellHitRadius);
+ bounds.right = (int) (centerX + cellHitRadius);
+ bounds.top = (int) (centerY - cellHitRadius);
+ bounds.bottom = (int) (centerY + cellHitRadius);
return bounds;
}
@@ -1694,16 +1663,12 @@ public class LockPatternView extends View {
* @return VIRTUAL_BASE_VIEW_ID+id or 0 if no view was hit
*/
private int getVirtualViewIdForHit(float x, float y) {
- final int rowHit = getRowHit(y);
- if (rowHit < 0) {
- return ExploreByTouchHelper.INVALID_ID;
- }
- final int columnHit = getColumnHit(x);
- if (columnHit < 0) {
+ Cell cellHit = detectCellHit(x, y);
+ if (cellHit == null) {
return ExploreByTouchHelper.INVALID_ID;
}
- boolean dotAvailable = mPatternDrawLookup[rowHit][columnHit];
- int dotId = (rowHit * 3 + columnHit) + VIRTUAL_BASE_VIEW_ID;
+ boolean dotAvailable = mPatternDrawLookup[cellHit.row][cellHit.column];
+ int dotId = (cellHit.row * 3 + cellHit.column) + VIRTUAL_BASE_VIEW_ID;
int view = dotAvailable ? dotId : ExploreByTouchHelper.INVALID_ID;
if (DEBUG_A11Y) Log.v(TAG, "getVirtualViewIdForHit(" + x + "," + y + ") => "
+ view + "avail =" + dotAvailable);
diff --git a/core/java/com/android/internal/widget/MessagingGroup.java b/core/java/com/android/internal/widget/MessagingGroup.java
index 9e06e33b79b5..146cb3fadaac 100644
--- a/core/java/com/android/internal/widget/MessagingGroup.java
+++ b/core/java/com/android/internal/widget/MessagingGroup.java
@@ -262,7 +262,8 @@ public class MessagingGroup extends LinearLayout implements MessagingLinearLayou
return createdGroup;
}
- public void removeMessage(MessagingMessage messagingMessage) {
+ public void removeMessage(MessagingMessage messagingMessage,
+ ArrayList<MessagingLinearLayout.MessagingChild> toRecycle) {
View view = messagingMessage.getView();
boolean wasShown = view.isShown();
ViewGroup messageParent = (ViewGroup) view.getParent();
@@ -270,15 +271,14 @@ public class MessagingGroup extends LinearLayout implements MessagingLinearLayou
return;
}
messageParent.removeView(view);
- Runnable recycleRunnable = () -> {
- messageParent.removeTransientView(view);
- messagingMessage.recycle();
- };
if (wasShown && !MessagingLinearLayout.isGone(view)) {
messageParent.addTransientView(view, 0);
- performRemoveAnimation(view, recycleRunnable);
+ performRemoveAnimation(view, () -> {
+ messageParent.removeTransientView(view);
+ messagingMessage.recycle();
+ });
} else {
- recycleRunnable.run();
+ toRecycle.add(messagingMessage);
}
}
diff --git a/core/java/com/android/internal/widget/MessagingLayout.java b/core/java/com/android/internal/widget/MessagingLayout.java
index 21ca196886ab..9ac6ef77bc07 100644
--- a/core/java/com/android/internal/widget/MessagingLayout.java
+++ b/core/java/com/android/internal/widget/MessagingLayout.java
@@ -51,7 +51,6 @@ import com.android.internal.util.ContrastColorUtil;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
-import java.util.function.Consumer;
/**
* A custom-built layout for the Notification.MessagingStyle allows dynamic addition and removal
@@ -62,8 +61,6 @@ public class MessagingLayout extends FrameLayout
implements ImageMessageConsumer, IMessagingLayout {
private static final float COLOR_SHIFT_AMOUNT = 60;
- private static final Consumer<MessagingMessage> REMOVE_MESSAGE
- = MessagingMessage::removeMessage;
public static final Interpolator LINEAR_OUT_SLOW_IN = new PathInterpolator(0f, 0f, 0.2f, 1f);
public static final Interpolator FAST_OUT_LINEAR_IN = new PathInterpolator(0.4f, 0f, 1f, 1f);
public static final Interpolator FAST_OUT_SLOW_IN = new PathInterpolator(0.4f, 0f, 0.2f, 1f);
@@ -89,6 +86,7 @@ public class MessagingLayout extends FrameLayout
private boolean mIsCollapsed;
private ImageResolver mImageResolver;
private CharSequence mConversationTitle;
+ private ArrayList<MessagingLinearLayout.MessagingChild> mToRecycle = new ArrayList<>();
public MessagingLayout(@NonNull Context context) {
super(context);
@@ -212,8 +210,12 @@ public class MessagingLayout extends FrameLayout
removeGroups(oldGroups);
// Let's remove the remaining messages
- mMessages.forEach(REMOVE_MESSAGE);
- mHistoricMessages.forEach(REMOVE_MESSAGE);
+ for (MessagingMessage message : mMessages) {
+ message.removeMessage(mToRecycle);
+ }
+ for (MessagingMessage historicMessage : mHistoricMessages) {
+ historicMessage.removeMessage(mToRecycle);
+ }
mMessages = messages;
mHistoricMessages = historicMessages;
@@ -223,6 +225,12 @@ public class MessagingLayout extends FrameLayout
// after groups are finalized, hide the first sender name if it's showing as the title
mPeopleHelper.maybeHideFirstSenderName(mGroups, mIsOneToOne, mConversationTitle);
updateImageMessages();
+
+ // Recycle everything at the end of the update, now that we know it's no longer needed.
+ for (MessagingLinearLayout.MessagingChild child : mToRecycle) {
+ child.recycle();
+ }
+ mToRecycle.clear();
}
private void updateImageMessages() {
@@ -263,18 +271,17 @@ public class MessagingLayout extends FrameLayout
MessagingGroup group = oldGroups.get(i);
if (!mGroups.contains(group)) {
List<MessagingMessage> messages = group.getMessages();
- Runnable endRunnable = () -> {
- mMessagingLinearLayout.removeTransientView(group);
- group.recycle();
- };
boolean wasShown = group.isShown();
mMessagingLinearLayout.removeView(group);
if (wasShown && !MessagingLinearLayout.isGone(group)) {
mMessagingLinearLayout.addTransientView(group, 0);
- group.removeGroupAnimated(endRunnable);
+ group.removeGroupAnimated(() -> {
+ mMessagingLinearLayout.removeTransientView(group);
+ group.recycle();
+ });
} else {
- endRunnable.run();
+ mToRecycle.add(group);
}
mMessages.removeAll(messages);
mHistoricMessages.removeAll(messages);
diff --git a/core/java/com/android/internal/widget/MessagingLinearLayout.java b/core/java/com/android/internal/widget/MessagingLinearLayout.java
index cb1d387dbd07..c06f5f75514f 100644
--- a/core/java/com/android/internal/widget/MessagingLinearLayout.java
+++ b/core/java/com/android/internal/widget/MessagingLinearLayout.java
@@ -365,6 +365,7 @@ public class MessagingLinearLayout extends ViewGroup {
default int getExtraSpacing() {
return 0;
}
+ void recycle();
}
public static class LayoutParams extends MarginLayoutParams {
diff --git a/core/java/com/android/internal/widget/MessagingMessage.java b/core/java/com/android/internal/widget/MessagingMessage.java
index 8c8437951402..2cc0d2305a78 100644
--- a/core/java/com/android/internal/widget/MessagingMessage.java
+++ b/core/java/com/android/internal/widget/MessagingMessage.java
@@ -20,6 +20,7 @@ import android.app.ActivityManager;
import android.app.Notification;
import android.view.View;
+import java.util.ArrayList;
import java.util.Objects;
/**
@@ -96,8 +97,8 @@ public interface MessagingMessage extends MessagingLinearLayout.MessagingChild {
return sameAs(message.getMessage());
}
- default void removeMessage() {
- getGroup().removeMessage(this);
+ default void removeMessage(ArrayList<MessagingLinearLayout.MessagingChild> toRecycle) {
+ getGroup().removeMessage(this, toRecycle);
}
default void setMessagingGroup(MessagingGroup group) {
diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java
index b1846d2402dd..db41d333e1d4 100644
--- a/core/java/com/android/server/SystemConfig.java
+++ b/core/java/com/android/server/SystemConfig.java
@@ -31,9 +31,11 @@ import android.os.FileUtils;
import android.os.Process;
import android.os.SystemProperties;
import android.os.Trace;
+import android.os.VintfRuntimeInfo;
import android.os.incremental.IncrementalManager;
import android.os.storage.StorageManager;
import android.permission.PermissionManager.SplitPermissionInfo;
+import android.sysprop.ApexProperties;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -56,7 +58,10 @@ import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
import java.nio.file.Path;
+import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -435,15 +440,15 @@ public class SystemConfig {
}
/** Get privapp permission allowlist for an apk-in-apex. */
- public ArraySet<String> getApexPrivAppPermissions(String module, String packageName) {
- return mApexPrivAppPermissions.getOrDefault(module, EMPTY_PERMISSIONS)
- .get(packageName);
+ public ArraySet<String> getApexPrivAppPermissions(String apexName, String apkPackageName) {
+ return mApexPrivAppPermissions.getOrDefault(apexName, EMPTY_PERMISSIONS)
+ .get(apkPackageName);
}
/** Get privapp permissions denylist for an apk-in-apex. */
- public ArraySet<String> getApexPrivAppDenyPermissions(String module, String packageName) {
- return mApexPrivAppDenyPermissions.getOrDefault(module, EMPTY_PERMISSIONS)
- .get(packageName);
+ public ArraySet<String> getApexPrivAppDenyPermissions(String apexName, String apkPackageName) {
+ return mApexPrivAppDenyPermissions.getOrDefault(apexName, EMPTY_PERMISSIONS)
+ .get(apkPackageName);
}
public ArraySet<String> getVendorPrivAppPermissions(String packageName) {
@@ -1187,7 +1192,8 @@ public class SystemConfig {
boolean systemExt = permFile.toPath().startsWith(
Environment.getSystemExtDirectory().toPath() + "/");
boolean apex = permFile.toPath().startsWith(
- Environment.getApexDirectory().toPath() + "/");
+ Environment.getApexDirectory().toPath() + "/")
+ && ApexProperties.updatable().orElse(false);
if (vendor) {
readPrivAppPermissions(parser, mVendorPrivAppPermissions,
mVendorPrivAppDenyPermissions);
@@ -1445,6 +1451,14 @@ public class SystemConfig {
addFeature(PackageManager.FEATURE_IPSEC_TUNNELS, 0);
}
+ if (isFilesystemSupported("erofs")) {
+ if (isKernelVersionAtLeast(5, 10)) {
+ addFeature(PackageManager.FEATURE_EROFS, 0);
+ } else if (isKernelVersionAtLeast(4, 19)) {
+ addFeature(PackageManager.FEATURE_EROFS_LEGACY, 0);
+ }
+ }
+
for (String featureName : mUnavailableFeatures) {
removeFeature(featureName);
}
@@ -1814,4 +1828,29 @@ public class SystemConfig {
private static boolean isSystemProcess() {
return Process.myUid() == Process.SYSTEM_UID;
}
+
+ private static boolean isFilesystemSupported(String fs) {
+ try {
+ final byte[] fsTableData = Files.readAllBytes(Paths.get("/proc/filesystems"));
+ final String fsTable = new String(fsTableData, StandardCharsets.UTF_8);
+ return fsTable.contains("\t" + fs + "\n");
+ } catch (Exception e) {
+ return false;
+ }
+ }
+
+ private static boolean isKernelVersionAtLeast(int major, int minor) {
+ final String kernelVersion = VintfRuntimeInfo.getKernelVersion();
+ final String[] parts = kernelVersion.split("\\.");
+ if (parts.length < 2) {
+ return false;
+ }
+ try {
+ final int majorVersion = Integer.parseInt(parts[0]);
+ final int minorVersion = Integer.parseInt(parts[1]);
+ return majorVersion > major || (majorVersion == major && minorVersion >= minor);
+ } catch (NumberFormatException e) {
+ return false;
+ }
+ }
}
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 4aa00f6117b9..a1be88440c97 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -272,6 +272,7 @@ cc_library_shared {
"libinput",
"libcamera_client",
"libcamera_metadata",
+ "libprocinfo",
"libsqlite",
"libEGL",
"libGLESv1_CM",
@@ -361,7 +362,7 @@ cc_library_shared {
"libwuffs_mirror_release_c",
],
},
- linux_glibc: {
+ host_linux: {
srcs: [
"android_content_res_ApkAssets.cpp",
"android_database_CursorWindow.cpp",
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index eedf7fa34a04..eba6cca76389 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -1567,6 +1567,7 @@ static const RegJNIRec gRegJNI[] = {
REG_JNI(register_android_graphics_classes),
REG_JNI(register_android_graphics_BLASTBufferQueue),
REG_JNI(register_android_graphics_GraphicBuffer),
+ REG_JNI(register_android_graphics_GraphicsStatsService),
REG_JNI(register_android_graphics_SurfaceTexture),
REG_JNI(register_android_database_CursorWindow),
REG_JNI(register_android_database_SQLiteConnection),
diff --git a/core/jni/android_hardware_input_InputWindowHandle.cpp b/core/jni/android_hardware_input_InputWindowHandle.cpp
index f453d1f06e22..db92310f2a26 100644
--- a/core/jni/android_hardware_input_InputWindowHandle.cpp
+++ b/core/jni/android_hardware_input_InputWindowHandle.cpp
@@ -23,6 +23,7 @@
#include <android_runtime/AndroidRuntime.h>
#include <android_runtime/Log.h>
#include <binder/IPCThreadState.h>
+#include <ftl/cast.h>
#include <gui/SurfaceControl.h>
#include <gui/WindowInfo.h>
#include <nativehelper/JNIHelp.h>
@@ -63,16 +64,11 @@ static struct {
jfieldID surfaceInset;
jfieldID scaleFactor;
jfieldID touchableRegion;
- jfieldID visible;
- jfieldID focusable;
- jfieldID hasWallpaper;
- jfieldID paused;
- jfieldID trustedOverlay;
jfieldID touchOcclusionMode;
jfieldID ownerPid;
jfieldID ownerUid;
jfieldID packageName;
- jfieldID inputFeatures;
+ jfieldID inputConfig;
jfieldID displayId;
jfieldID replaceTouchableRegionWithCrop;
WeakRefHandleField touchableRegionSurfaceControl;
@@ -162,64 +158,8 @@ bool NativeInputWindowHandle::updateInfo() {
mInfo.layoutParamsFlags = flags;
mInfo.layoutParamsType = type;
- using InputConfig = gui::WindowInfo::InputConfig;
- // Determine the value for each of the InputConfig flags. We rely on a switch statement and
- // -Wswitch-enum to give us a build error if we forget to explicitly handle an InputConfig flag.
- mInfo.inputConfig = InputConfig::NONE;
- InputConfig enumerationStart = InputConfig::NONE;
- switch (enumerationStart) {
- case InputConfig::NONE:
- FALLTHROUGH_INTENDED;
- case InputConfig::NOT_VISIBLE:
- if (env->GetBooleanField(obj, gInputWindowHandleClassInfo.visible) == JNI_FALSE) {
- mInfo.inputConfig |= InputConfig::NOT_VISIBLE;
- }
- FALLTHROUGH_INTENDED;
- case InputConfig::NOT_FOCUSABLE:
- if (env->GetBooleanField(obj, gInputWindowHandleClassInfo.focusable) == JNI_FALSE) {
- mInfo.inputConfig |= InputConfig::NOT_FOCUSABLE;
- }
- FALLTHROUGH_INTENDED;
- case InputConfig::NOT_TOUCHABLE:
- if (flags.test(WindowInfo::Flag::NOT_TOUCHABLE)) {
- mInfo.inputConfig |= InputConfig::NOT_TOUCHABLE;
- }
- FALLTHROUGH_INTENDED;
- case InputConfig::PREVENT_SPLITTING:
- if (!flags.test(WindowInfo::Flag::SPLIT_TOUCH)) {
- mInfo.inputConfig |= InputConfig::PREVENT_SPLITTING;
- }
- FALLTHROUGH_INTENDED;
- case InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER:
- if (env->GetBooleanField(obj, gInputWindowHandleClassInfo.hasWallpaper) == JNI_TRUE) {
- mInfo.inputConfig |= InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER;
- }
- FALLTHROUGH_INTENDED;
- case InputConfig::IS_WALLPAPER:
- if (type == WindowInfo::Type::WALLPAPER) {
- mInfo.inputConfig |= InputConfig::IS_WALLPAPER;
- }
- FALLTHROUGH_INTENDED;
- case InputConfig::PAUSE_DISPATCHING:
- if (env->GetBooleanField(obj, gInputWindowHandleClassInfo.paused) == JNI_TRUE) {
- mInfo.inputConfig |= InputConfig::PAUSE_DISPATCHING;
- }
- FALLTHROUGH_INTENDED;
- case InputConfig::TRUSTED_OVERLAY:
- if (env->GetBooleanField(obj, gInputWindowHandleClassInfo.trustedOverlay) == JNI_TRUE) {
- mInfo.inputConfig |= InputConfig::TRUSTED_OVERLAY;
- }
- FALLTHROUGH_INTENDED;
- case InputConfig::WATCH_OUTSIDE_TOUCH:
- if (flags.test(WindowInfo::Flag::WATCH_OUTSIDE_TOUCH)) {
- mInfo.inputConfig |= InputConfig::WATCH_OUTSIDE_TOUCH;
- }
- FALLTHROUGH_INTENDED;
- case InputConfig::SLIPPERY:
- if (flags.test(WindowInfo::Flag::SLIPPERY)) {
- mInfo.inputConfig |= InputConfig::SLIPPERY;
- }
- }
+ mInfo.inputConfig = static_cast<gui::WindowInfo::InputConfig>(
+ env->GetIntField(obj, gInputWindowHandleClassInfo.inputConfig));
mInfo.touchOcclusionMode = static_cast<TouchOcclusionMode>(
env->GetIntField(obj, gInputWindowHandleClassInfo.touchOcclusionMode));
@@ -228,8 +168,6 @@ bool NativeInputWindowHandle::updateInfo() {
mInfo.ownerUid = env->GetIntField(obj,
gInputWindowHandleClassInfo.ownerUid);
mInfo.packageName = getStringField(env, obj, gInputWindowHandleClassInfo.packageName, "<null>");
- mInfo.inputFeatures = static_cast<WindowInfo::Feature>(
- env->GetIntField(obj, gInputWindowHandleClassInfo.inputFeatures));
mInfo.displayId = env->GetIntField(obj,
gInputWindowHandleClassInfo.displayId);
@@ -359,17 +297,6 @@ jobject android_view_InputWindowHandle_fromWindowInfo(JNIEnv* env, gui::WindowIn
env->SetObjectField(inputWindowHandle, gInputWindowHandleClassInfo.touchableRegion,
regionObj.get());
- using InputConfig = gui::WindowInfo::InputConfig;
- env->SetBooleanField(inputWindowHandle, gInputWindowHandleClassInfo.visible,
- !windowInfo.inputConfig.test(InputConfig::NOT_VISIBLE));
- env->SetBooleanField(inputWindowHandle, gInputWindowHandleClassInfo.focusable,
- !windowInfo.inputConfig.test(gui::WindowInfo::InputConfig::NOT_FOCUSABLE));
- env->SetBooleanField(inputWindowHandle, gInputWindowHandleClassInfo.hasWallpaper,
- windowInfo.inputConfig.test(InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER));
- env->SetBooleanField(inputWindowHandle, gInputWindowHandleClassInfo.paused,
- windowInfo.inputConfig.test(InputConfig::PAUSE_DISPATCHING));
- env->SetBooleanField(inputWindowHandle, gInputWindowHandleClassInfo.trustedOverlay,
- windowInfo.inputConfig.test(InputConfig::TRUSTED_OVERLAY));
env->SetIntField(inputWindowHandle, gInputWindowHandleClassInfo.touchOcclusionMode,
static_cast<int32_t>(windowInfo.touchOcclusionMode));
env->SetIntField(inputWindowHandle, gInputWindowHandleClassInfo.ownerPid, windowInfo.ownerPid);
@@ -377,8 +304,11 @@ jobject android_view_InputWindowHandle_fromWindowInfo(JNIEnv* env, gui::WindowIn
ScopedLocalRef<jstring> packageName(env, env->NewStringUTF(windowInfo.packageName.data()));
env->SetObjectField(inputWindowHandle, gInputWindowHandleClassInfo.packageName,
packageName.get());
- env->SetIntField(inputWindowHandle, gInputWindowHandleClassInfo.inputFeatures,
- static_cast<int32_t>(windowInfo.inputFeatures.get()));
+
+ const auto inputConfig = windowInfo.inputConfig.get();
+ static_assert(sizeof(inputConfig) == sizeof(int32_t));
+ env->SetIntField(inputWindowHandle, gInputWindowHandleClassInfo.inputConfig,
+ static_cast<int32_t>(inputConfig));
float transformVals[9];
for (int i = 0; i < 9; i++) {
@@ -481,19 +411,6 @@ int register_android_view_InputWindowHandle(JNIEnv* env) {
GET_FIELD_ID(gInputWindowHandleClassInfo.touchableRegion, clazz,
"touchableRegion", "Landroid/graphics/Region;");
- GET_FIELD_ID(gInputWindowHandleClassInfo.visible, clazz,
- "visible", "Z");
-
- GET_FIELD_ID(gInputWindowHandleClassInfo.focusable, clazz, "focusable", "Z");
-
- GET_FIELD_ID(gInputWindowHandleClassInfo.hasWallpaper, clazz,
- "hasWallpaper", "Z");
-
- GET_FIELD_ID(gInputWindowHandleClassInfo.paused, clazz,
- "paused", "Z");
-
- GET_FIELD_ID(gInputWindowHandleClassInfo.trustedOverlay, clazz, "trustedOverlay", "Z");
-
GET_FIELD_ID(gInputWindowHandleClassInfo.touchOcclusionMode, clazz, "touchOcclusionMode", "I");
GET_FIELD_ID(gInputWindowHandleClassInfo.ownerPid, clazz,
@@ -505,8 +422,7 @@ int register_android_view_InputWindowHandle(JNIEnv* env) {
GET_FIELD_ID(gInputWindowHandleClassInfo.packageName, clazz, "packageName",
"Ljava/lang/String;");
- GET_FIELD_ID(gInputWindowHandleClassInfo.inputFeatures, clazz,
- "inputFeatures", "I");
+ GET_FIELD_ID(gInputWindowHandleClassInfo.inputConfig, clazz, "inputConfig", "I");
GET_FIELD_ID(gInputWindowHandleClassInfo.displayId, clazz,
"displayId", "I");
diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp
index 7c67cbcbd23c..a6fbf094a030 100644
--- a/core/jni/android_util_Process.cpp
+++ b/core/jni/android_util_Process.cpp
@@ -235,9 +235,7 @@ void android_os_Process_setThreadGroupAndCpuset(JNIEnv* env, jobject clazz, int
void android_os_Process_setProcessGroup(JNIEnv* env, jobject clazz, int pid, jint grp)
{
ALOGV("%s pid=%d grp=%" PRId32, __func__, pid, grp);
- DIR *d;
char proc_path[255];
- struct dirent *de;
if (!verifyGroup(env, grp)) {
return;
@@ -277,84 +275,8 @@ void android_os_Process_setProcessGroup(JNIEnv* env, jobject clazz, int pid, jin
}
}
- sprintf(proc_path, "/proc/%d/task", pid);
- if (!(d = opendir(proc_path))) {
- // If the process exited on us, don't generate an exception
- if (errno != ENOENT)
- signalExceptionForGroupError(env, errno, pid);
- return;
- }
-
- while ((de = readdir(d))) {
- int t_pid;
- int t_pri;
- std::string taskprofile;
-
- if (de->d_name[0] == '.')
- continue;
- t_pid = atoi(de->d_name);
-
- if (!t_pid) {
- ALOGE("Error getting pid for '%s'\n", de->d_name);
- continue;
- }
-
- t_pri = getpriority(PRIO_PROCESS, t_pid);
-
- if (t_pri <= ANDROID_PRIORITY_AUDIO) {
- int scheduler = sched_getscheduler(t_pid) & ~SCHED_RESET_ON_FORK;
- if ((scheduler == SCHED_FIFO) || (scheduler == SCHED_RR)) {
- // This task wants to stay in its current audio group so it can keep its budget
- // don't update its cpuset or cgroup
- continue;
- }
- }
-
- errno = 0;
- // grp == SP_BACKGROUND. Set background cpuset policy profile for all threads.
- if (grp == SP_BACKGROUND) {
- if (!SetTaskProfiles(t_pid, {"CPUSET_SP_BACKGROUND"}, true)) {
- signalExceptionForGroupError(env, errno ? errno : EPERM, t_pid);
- break;
- }
- continue;
- }
-
- // grp != SP_BACKGROUND. Only change the cpuset cgroup for low priority thread, so it could
- // preserve it sched policy profile setting.
- if (t_pri >= ANDROID_PRIORITY_BACKGROUND) {
- switch (grp) {
- case SP_SYSTEM:
- taskprofile = "ServiceCapacityLow";
- break;
- case SP_RESTRICTED:
- taskprofile = "ServiceCapacityRestricted";
- break;
- case SP_FOREGROUND:
- case SP_AUDIO_APP:
- case SP_AUDIO_SYS:
- taskprofile = "ProcessCapacityHigh";
- break;
- case SP_TOP_APP:
- taskprofile = "ProcessCapacityMax";
- break;
- default:
- taskprofile = "ProcessCapacityNormal";
- break;
- }
- if (!SetTaskProfiles(t_pid, {taskprofile}, true)) {
- signalExceptionForGroupError(env, errno ? errno : EPERM, t_pid);
- break;
- }
- // Change the cpuset policy profile for non-low priority thread according to the grp
- } else {
- if (!SetTaskProfiles(t_pid, {get_cpuset_policy_profile_name((SchedPolicy)grp)}, true)) {
- signalExceptionForGroupError(env, errno ? errno : EPERM, t_pid);
- break;
- }
- }
- }
- closedir(d);
+ if (!SetProcessProfilesCached(0, pid, {get_cpuset_policy_profile_name((SchedPolicy)grp)}))
+ signalExceptionForGroupError(env, errno ? errno : EPERM, pid);
}
void android_os_Process_setProcessFrozen(
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 68025a8ba0e4..39f192b662ee 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -253,6 +253,11 @@ static struct {
jfieldID alphaInterpretation;
} gDisplayDecorationSupportInfo;
+static struct {
+ jclass clazz;
+ jmethodID invokeReleaseCallback;
+} gInvokeReleaseCallback;
+
class JNamedColorSpace {
public:
// ColorSpace.Named.SRGB.ordinal() = 0;
@@ -625,8 +630,59 @@ static void nativeSetGeometry(JNIEnv* env, jclass clazz, jlong transactionObj, j
transaction->setGeometry(ctrl, source, dst, orientation);
}
+class JGlobalRefHolder {
+public:
+ JGlobalRefHolder(JavaVM* vm, jobject object) : mVm(vm), mObject(object) {}
+
+ virtual ~JGlobalRefHolder() {
+ env()->DeleteGlobalRef(mObject);
+ mObject = nullptr;
+ }
+
+ jobject object() { return mObject; }
+ JavaVM* vm() { return mVm; }
+
+ JNIEnv* env() {
+ JNIEnv* env = nullptr;
+ if (mVm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
+ if (mVm->AttachCurrentThreadAsDaemon(&env, nullptr) != JNI_OK) {
+ LOG_ALWAYS_FATAL("Failed to AttachCurrentThread!");
+ }
+ }
+ return env;
+ }
+
+private:
+ JGlobalRefHolder(const JGlobalRefHolder&) = delete;
+ void operator=(const JGlobalRefHolder&) = delete;
+
+ JavaVM* mVm;
+ jobject mObject;
+};
+
+static ReleaseBufferCallback genReleaseCallback(JNIEnv* env, jobject releaseCallback) {
+ if (releaseCallback == nullptr) return nullptr;
+
+ JavaVM* vm = nullptr;
+ LOG_ALWAYS_FATAL_IF(env->GetJavaVM(&vm) != JNI_OK, "Unable to get Java VM");
+ auto globalCallbackRef =
+ std::make_shared<JGlobalRefHolder>(vm, env->NewGlobalRef(releaseCallback));
+ return [globalCallbackRef](const ReleaseCallbackId&, const sp<Fence>& releaseFence,
+ std::optional<uint32_t> currentMaxAcquiredBufferCount) {
+ Fence* fenceCopy = releaseFence.get();
+ // We need to grab an extra ref as Java's SyncFence takes ownership
+ if (fenceCopy) {
+ fenceCopy->incStrong(0);
+ }
+ globalCallbackRef->env()->CallStaticVoidMethod(gInvokeReleaseCallback.clazz,
+ gInvokeReleaseCallback.invokeReleaseCallback,
+ globalCallbackRef->object(),
+ reinterpret_cast<jlong>(fenceCopy));
+ };
+}
+
static void nativeSetBuffer(JNIEnv* env, jclass clazz, jlong transactionObj, jlong nativeObject,
- jobject bufferObject, jlong fencePtr) {
+ jobject bufferObject, jlong fencePtr, jobject releaseCallback) {
auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl*>(nativeObject);
sp<GraphicBuffer> graphicBuffer(GraphicBuffer::fromAHardwareBuffer(
@@ -635,7 +691,8 @@ static void nativeSetBuffer(JNIEnv* env, jclass clazz, jlong transactionObj, jlo
if (fencePtr != 0) {
optFence = sp<Fence>{reinterpret_cast<Fence*>(fencePtr)};
}
- transaction->setBuffer(ctrl, graphicBuffer, optFence);
+ transaction->setBuffer(ctrl, graphicBuffer, optFence, std::nullopt,
+ genReleaseCallback(env, releaseCallback));
}
static void nativeSetBufferTransform(JNIEnv* env, jclass clazz, jlong transactionObj,
@@ -2155,7 +2212,7 @@ static const JNINativeMethod sSurfaceControlMethods[] = {
(void*)nativeGetDisplayedContentSample },
{"nativeSetGeometry", "(JJLandroid/graphics/Rect;Landroid/graphics/Rect;J)V",
(void*)nativeSetGeometry },
- {"nativeSetBuffer", "(JJLandroid/hardware/HardwareBuffer;J)V",
+ {"nativeSetBuffer", "(JJLandroid/hardware/HardwareBuffer;JLjava/util/function/Consumer;)V",
(void*)nativeSetBuffer },
{"nativeSetBufferTransform", "(JJI)V", (void*) nativeSetBufferTransform},
{"nativeSetDataSpace", "(JJI)V",
@@ -2451,6 +2508,12 @@ int register_android_view_SurfaceControl(JNIEnv* env)
gDisplayDecorationSupportInfo.alphaInterpretation =
GetFieldIDOrDie(env, displayDecorationSupportClazz, "alphaInterpretation", "I");
+ jclass surfaceControlClazz = FindClassOrDie(env, "android/view/SurfaceControl");
+ gInvokeReleaseCallback.clazz = MakeGlobalRefOrDie(env, surfaceControlClazz);
+ gInvokeReleaseCallback.invokeReleaseCallback =
+ GetStaticMethodIDOrDie(env, surfaceControlClazz, "invokeReleaseCallback",
+ "(Ljava/util/function/Consumer;J)V");
+
return err;
}
diff --git a/core/jni/android_window_WindowInfosListener.cpp b/core/jni/android_window_WindowInfosListener.cpp
index 08c9f20b0815..aae2549df429 100644
--- a/core/jni/android_window_WindowInfosListener.cpp
+++ b/core/jni/android_window_WindowInfosListener.cpp
@@ -44,6 +44,11 @@ static struct {
jmethodID ctor;
} gDisplayInfoClassInfo;
+static struct {
+ jclass clazz;
+ jmethodID ctor;
+} gPairClassInfo;
+
static jclass gInputWindowHandleClass;
jobject fromDisplayInfo(JNIEnv* env, gui::DisplayInfo displayInfo) {
@@ -57,6 +62,30 @@ jobject fromDisplayInfo(JNIEnv* env, gui::DisplayInfo displayInfo) {
displayInfo.logicalHeight, matrixObj.get());
}
+static jobjectArray fromWindowInfos(JNIEnv* env, const std::vector<WindowInfo>& windowInfos) {
+ jobjectArray jWindowHandlesArray =
+ env->NewObjectArray(windowInfos.size(), gInputWindowHandleClass, nullptr);
+ for (int i = 0; i < windowInfos.size(); i++) {
+ ScopedLocalRef<jobject>
+ jWindowHandle(env,
+ android_view_InputWindowHandle_fromWindowInfo(env, windowInfos[i]));
+ env->SetObjectArrayElement(jWindowHandlesArray, i, jWindowHandle.get());
+ }
+
+ return jWindowHandlesArray;
+}
+
+static jobjectArray fromDisplayInfos(JNIEnv* env, const std::vector<DisplayInfo>& displayInfos) {
+ jobjectArray jDisplayInfoArray =
+ env->NewObjectArray(displayInfos.size(), gDisplayInfoClassInfo.clazz, nullptr);
+ for (int i = 0; i < displayInfos.size(); i++) {
+ ScopedLocalRef<jobject> jDisplayInfo(env, fromDisplayInfo(env, displayInfos[i]));
+ env->SetObjectArrayElement(jDisplayInfoArray, i, jDisplayInfo.get());
+ }
+
+ return jDisplayInfoArray;
+}
+
struct WindowInfosListener : public gui::WindowInfosListener {
WindowInfosListener(JNIEnv* env, jobject listener)
: mListener(env->NewWeakGlobalRef(listener)) {}
@@ -72,26 +101,8 @@ struct WindowInfosListener : public gui::WindowInfosListener {
return;
}
- ScopedLocalRef<jobjectArray>
- jWindowHandlesArray(env,
- env->NewObjectArray(windowInfos.size(), gInputWindowHandleClass,
- nullptr));
- for (int i = 0; i < windowInfos.size(); i++) {
- ScopedLocalRef<jobject>
- jWindowHandle(env,
- android_view_InputWindowHandle_fromWindowInfo(env,
- windowInfos[i]));
- env->SetObjectArrayElement(jWindowHandlesArray.get(), i, jWindowHandle.get());
- }
-
- ScopedLocalRef<jobjectArray>
- jDisplayInfoArray(env,
- env->NewObjectArray(displayInfos.size(),
- gDisplayInfoClassInfo.clazz, nullptr));
- for (int i = 0; i < displayInfos.size(); i++) {
- ScopedLocalRef<jobject> jDisplayInfo(env, fromDisplayInfo(env, displayInfos[i]));
- env->SetObjectArrayElement(jDisplayInfoArray.get(), i, jDisplayInfo.get());
- }
+ ScopedLocalRef<jobjectArray> jWindowHandlesArray(env, fromWindowInfos(env, windowInfos));
+ ScopedLocalRef<jobjectArray> jDisplayInfoArray(env, fromDisplayInfos(env, displayInfos));
env->CallVoidMethod(listener, gListenerClassInfo.onWindowInfosChanged,
jWindowHandlesArray.get(), jDisplayInfoArray.get());
@@ -124,9 +135,16 @@ void destroyNativeService(void* ptr) {
listener->decStrong((void*)nativeCreate);
}
-void nativeRegister(JNIEnv* env, jclass clazz, jlong ptr) {
+jobject nativeRegister(JNIEnv* env, jclass clazz, jlong ptr) {
sp<WindowInfosListener> listener = reinterpret_cast<WindowInfosListener*>(ptr);
- SurfaceComposerClient::getDefault()->addWindowInfosListener(listener);
+ std::pair<std::vector<gui::WindowInfo>, std::vector<gui::DisplayInfo>> initialInfo;
+ SurfaceComposerClient::getDefault()->addWindowInfosListener(listener, &initialInfo);
+
+ ScopedLocalRef<jobjectArray> jWindowHandlesArray(env, fromWindowInfos(env, initialInfo.first));
+ ScopedLocalRef<jobjectArray> jDisplayInfoArray(env, fromDisplayInfos(env, initialInfo.second));
+
+ return env->NewObject(gPairClassInfo.clazz, gPairClassInfo.ctor, jWindowHandlesArray.get(),
+ jDisplayInfoArray.get());
}
void nativeUnregister(JNIEnv* env, jclass clazz, jlong ptr) {
@@ -141,7 +159,7 @@ static jlong nativeGetFinalizer(JNIEnv* /* env */, jclass /* clazz */) {
const JNINativeMethod gMethods[] = {
/* name, signature, funcPtr */
{"nativeCreate", "(Landroid/window/WindowInfosListener;)J", (void*)nativeCreate},
- {"nativeRegister", "(J)V", (void*)nativeRegister},
+ {"nativeRegister", "(J)Landroid/util/Pair;", (void*)nativeRegister},
{"nativeUnregister", "(J)V", (void*)nativeUnregister},
{"nativeGetFinalizer", "()J", (void*)nativeGetFinalizer}};
@@ -166,6 +184,12 @@ int register_android_window_WindowInfosListener(JNIEnv* env) {
gDisplayInfoClassInfo.clazz = MakeGlobalRefOrDie(env, clazz);
gDisplayInfoClassInfo.ctor = env->GetMethodID(gDisplayInfoClassInfo.clazz, "<init>",
"(IIILandroid/graphics/Matrix;)V");
+
+ clazz = env->FindClass("android/util/Pair");
+ gPairClassInfo.clazz = MakeGlobalRefOrDie(env, clazz);
+ gPairClassInfo.ctor = env->GetMethodID(gPairClassInfo.clazz, "<init>",
+ "(Ljava/lang/Object;Ljava/lang/Object;)V");
+
return 0;
}
diff --git a/core/jni/com_android_internal_os_KernelAllocationStats.cpp b/core/jni/com_android_internal_os_KernelAllocationStats.cpp
index e0a24430e739..5b104977f1d8 100644
--- a/core/jni/com_android_internal_os_KernelAllocationStats.cpp
+++ b/core/jni/com_android_internal_os_KernelAllocationStats.cpp
@@ -13,12 +13,19 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
#include <dmabufinfo/dmabufinfo.h>
#include <jni.h>
#include <meminfo/sysmeminfo.h>
+#include <procinfo/process.h>
#include "core_jni_helpers.h"
+using DmaBuffer = ::android::dmabufinfo::DmaBuffer;
+using android::base::ReadFileToString;
+using android::base::StringPrintf;
+
namespace {
static jclass gProcessDmabufClazz;
static jmethodID gProcessDmabufCtor;
@@ -28,30 +35,127 @@ static jmethodID gProcessGpuMemCtor;
namespace android {
-static jobject KernelAllocationStats_getDmabufAllocations(JNIEnv *env, jobject, jint pid) {
- std::vector<dmabufinfo::DmaBuffer> buffers;
- if (!dmabufinfo::ReadDmaBufMapRefs(pid, &buffers)) {
+struct PidDmaInfo {
+ uid_t uid;
+ std::string cmdline;
+ int oomScoreAdj;
+};
+
+static jobjectArray KernelAllocationStats_getDmabufAllocations(JNIEnv *env, jobject) {
+ std::vector<DmaBuffer> buffers;
+
+ if (!dmabufinfo::ReadDmaBufs(&buffers)) {
return nullptr;
}
- jint mappedSize = 0;
- jint mappedCount = buffers.size();
- for (const auto &buffer : buffers) {
- mappedSize += buffer.size();
+
+ // Create a reverse map from pid to dmabufs
+ // Store dmabuf inodes & sizes for later processing.
+ std::unordered_map<pid_t, std::set<ino_t>> pidToInodes;
+ std::unordered_map<ino_t, long> inodeToSize;
+ for (auto &buf : buffers) {
+ for (auto pid : buf.pids()) {
+ pidToInodes[pid].insert(buf.inode());
+ }
+ inodeToSize[buf.inode()] = buf.size();
+ }
+
+ pid_t surfaceFlingerPid = -1;
+ // The set of all inodes that are being retained by SurfaceFlinger. Buffers
+ // shared between another process and SF will appear in this set.
+ std::set<ino_t> surfaceFlingerBufferInodes;
+ // The set of all inodes that are being retained by any process other
+ // than SurfaceFlinger. Buffers shared between another process and SF will
+ // appear in this set.
+ std::set<ino_t> otherProcessBufferInodes;
+
+ // Find SurfaceFlinger pid & get cmdlines, oomScoreAdj, etc for each pid
+ // holding any DMA buffers.
+ std::unordered_map<pid_t, PidDmaInfo> pidDmaInfos;
+ for (const auto &pidToInodeEntry : pidToInodes) {
+ pid_t pid = pidToInodeEntry.first;
+
+ android::procinfo::ProcessInfo processInfo;
+ if (!android::procinfo::GetProcessInfo(pid, &processInfo)) {
+ continue;
+ }
+
+ std::string cmdline;
+ if (!ReadFileToString(StringPrintf("/proc/%d/cmdline", pid), &cmdline)) {
+ continue;
+ }
+
+ // cmdline strings are null-delimited, so we split on \0 here
+ if (cmdline.substr(0, cmdline.find('\0')) == "/system/bin/surfaceflinger") {
+ if (surfaceFlingerPid == -1) {
+ surfaceFlingerPid = pid;
+ surfaceFlingerBufferInodes = pidToInodes[pid];
+ } else {
+ LOG(ERROR) << "getDmabufAllocations found multiple SF processes; pid1: " << pid
+ << ", pid2:" << surfaceFlingerPid;
+ surfaceFlingerPid = -2; // Used as a sentinel value below
+ }
+ } else {
+ otherProcessBufferInodes.insert(pidToInodes[pid].begin(), pidToInodes[pid].end());
+ }
+
+ std::string oomScoreAdjStr;
+ if (!ReadFileToString(StringPrintf("/proc/%d/oom_score_adj", pid), &oomScoreAdjStr)) {
+ continue;
+ }
+
+ pidDmaInfos[pid] = PidDmaInfo{.uid = processInfo.uid,
+ .cmdline = cmdline,
+ .oomScoreAdj = atoi(oomScoreAdjStr.c_str())};
+ }
+
+ if (surfaceFlingerPid < 0) {
+ LOG(ERROR) << "getDmabufAllocations could not identify SurfaceFlinger "
+ << "process via /proc/pid/cmdline";
}
- mappedSize /= 1024;
-
- jint retainedSize = -1;
- jint retainedCount = -1;
- if (dmabufinfo::ReadDmaBufFdRefs(pid, &buffers)) {
- retainedCount = buffers.size();
- retainedSize = 0;
- for (const auto &buffer : buffers) {
- retainedSize += buffer.size();
+
+ jobjectArray ret = env->NewObjectArray(pidDmaInfos.size(), gProcessDmabufClazz, NULL);
+ int retArrayIndex = 0;
+ for (const auto &pidDmaInfosEntry : pidDmaInfos) {
+ pid_t pid = pidDmaInfosEntry.first;
+
+ // For all processes apart from SurfaceFlinger, this set will store the
+ // dmabuf inodes that are shared with SF. For SF, it will store the inodes
+ // that are shared with any other process.
+ std::set<ino_t> sharedBuffers;
+ if (pid == surfaceFlingerPid) {
+ set_intersection(surfaceFlingerBufferInodes.begin(), surfaceFlingerBufferInodes.end(),
+ otherProcessBufferInodes.begin(), otherProcessBufferInodes.end(),
+ std::inserter(sharedBuffers, sharedBuffers.end()));
+ } else if (surfaceFlingerPid > 0) {
+ set_intersection(pidToInodes[pid].begin(), pidToInodes[pid].end(),
+ surfaceFlingerBufferInodes.begin(), surfaceFlingerBufferInodes.end(),
+ std::inserter(sharedBuffers, sharedBuffers.begin()));
+ } // If surfaceFlingerPid < 0; it means we failed to identify it, and
+ // the SF-related fields below should be left empty.
+
+ long totalSize = 0;
+ long sharedBuffersSize = 0;
+ for (const auto &inode : pidToInodes[pid]) {
+ totalSize += inodeToSize[inode];
+ if (sharedBuffers.count(inode)) {
+ sharedBuffersSize += inodeToSize[inode];
+ }
}
- retainedSize /= 1024;
+
+ jobject obj = env->NewObject(gProcessDmabufClazz, gProcessDmabufCtor,
+ /* uid */ pidDmaInfos[pid].uid,
+ /* process name */
+ env->NewStringUTF(pidDmaInfos[pid].cmdline.c_str()),
+ /* oomscore */ pidDmaInfos[pid].oomScoreAdj,
+ /* retainedSize */ totalSize / 1024,
+ /* retainedCount */ pidToInodes[pid].size(),
+ /* sharedWithSurfaceFlinger size */ sharedBuffersSize / 1024,
+ /* sharedWithSurfaceFlinger count */ sharedBuffers.size());
+
+ env->SetObjectArrayElement(ret, retArrayIndex++, obj);
}
- return env->NewObject(gProcessDmabufClazz, gProcessDmabufCtor, retainedSize, retainedCount,
- mappedSize, mappedCount);
+
+ return ret;
}
static jobject KernelAllocationStats_getGpuAllocations(JNIEnv *env) {
@@ -74,7 +178,7 @@ static jobject KernelAllocationStats_getGpuAllocations(JNIEnv *env) {
}
static const JNINativeMethod methods[] = {
- {"getDmabufAllocations", "(I)Lcom/android/internal/os/KernelAllocationStats$ProcessDmabuf;",
+ {"getDmabufAllocations", "()[Lcom/android/internal/os/KernelAllocationStats$ProcessDmabuf;",
(void *)KernelAllocationStats_getDmabufAllocations},
{"getGpuAllocations", "()[Lcom/android/internal/os/KernelAllocationStats$ProcessGpuMem;",
(void *)KernelAllocationStats_getGpuAllocations},
@@ -86,7 +190,8 @@ int register_com_android_internal_os_KernelAllocationStats(JNIEnv *env) {
jclass clazz =
FindClassOrDie(env, "com/android/internal/os/KernelAllocationStats$ProcessDmabuf");
gProcessDmabufClazz = MakeGlobalRefOrDie(env, clazz);
- gProcessDmabufCtor = GetMethodIDOrDie(env, gProcessDmabufClazz, "<init>", "(IIII)V");
+ gProcessDmabufCtor =
+ GetMethodIDOrDie(env, gProcessDmabufClazz, "<init>", "(ILjava/lang/String;IIIII)V");
clazz = FindClassOrDie(env, "com/android/internal/os/KernelAllocationStats$ProcessGpuMem");
gProcessGpuMemClazz = MakeGlobalRefOrDie(env, clazz);
@@ -94,4 +199,4 @@ int register_com_android_internal_os_KernelAllocationStats(JNIEnv *env) {
return res;
}
-} // namespace android
+} // namespace android \ No newline at end of file
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 5b7092cabfcb..7bc69055292d 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -895,7 +895,7 @@ void SetThreadName(const std::string& thread_name) {
// pthread_setname_np fails rather than truncating long strings.
char buf[16]; // MAX_TASK_COMM_LEN=16 is hard-coded into bionic
- strlcpy(buf, name_start_ptr, sizeof(buf) - 1);
+ strlcpy(buf, name_start_ptr, sizeof(buf));
errno = pthread_setname_np(pthread_self(), buf);
if (errno != 0) {
ALOGW("Unable to set the name of current thread to '%s': %s", buf, strerror(errno));
diff --git a/core/jni/com_android_internal_os_ZygoteCommandBuffer.cpp b/core/jni/com_android_internal_os_ZygoteCommandBuffer.cpp
index 248db76da71d..679a4f070290 100644
--- a/core/jni/com_android_internal_os_ZygoteCommandBuffer.cpp
+++ b/core/jni/com_android_internal_os_ZygoteCommandBuffer.cpp
@@ -34,6 +34,7 @@
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/socket.h>
+#include <sys/system_properties.h>
#include <vector>
namespace android {
@@ -43,10 +44,10 @@ using android::base::StringPrintf;
using android::zygote::ZygoteFailure;
// WARNING: Knows a little about the wire protocol used to communicate with Zygote.
-// TODO: Fix error handling.
-constexpr size_t MAX_COMMAND_BYTES = 12200;
-constexpr size_t NICE_NAME_BYTES = 50;
+// Commands and nice names have large arbitrary size limits to avoid dynamic memory allocation.
+constexpr size_t MAX_COMMAND_BYTES = 32768;
+constexpr size_t NICE_NAME_BYTES = 128;
// A buffer optionally bundled with a file descriptor from which we can fill it.
// Does not own the file descriptor; destroying a NativeCommandBuffer does not
@@ -190,6 +191,9 @@ class NativeCommandBuffer {
size_t copy_len = std::min(name_len, NICE_NAME_BYTES - 1);
memcpy(mNiceName, arg_start + NN_LENGTH, copy_len);
mNiceName[copy_len] = '\0';
+ if (haveWrapProperty()) {
+ return false;
+ }
continue;
}
if (arg_end - arg_start == IW_LENGTH
@@ -222,6 +226,8 @@ class NativeCommandBuffer {
}
saw_setgid = true;
}
+ // ro.debuggable can be handled entirely in the child unless --invoke-with is also specified.
+ // Thus we do not need to check it here.
}
return saw_runtime_args && saw_setuid && saw_setgid;
}
@@ -249,6 +255,14 @@ class NativeCommandBuffer {
}
private:
+ bool haveWrapProperty() {
+ static const char* WRAP = "wrap.";
+ static const size_t WRAP_LENGTH = strlen(WRAP);
+ char propNameBuf[WRAP_LENGTH + NICE_NAME_BYTES];
+ strcpy(propNameBuf, WRAP);
+ strlcpy(propNameBuf + WRAP_LENGTH, mNiceName, NICE_NAME_BYTES);
+ return __system_property_find(propNameBuf) != nullptr;
+ }
// Picky version of atoi(). No sign or unexpected characters allowed. Return -1 on failure.
static int digitsVal(char* start, char* end) {
int result = 0;
@@ -269,12 +283,10 @@ class NativeCommandBuffer {
uint32_t mNext; // Index of first character past last line returned by readLine.
int32_t mLinesLeft; // Lines in current command that haven't yet been read.
int mFd; // Open file descriptor from which we can read more. -1 if none.
- char mNiceName[NICE_NAME_BYTES];
+ char mNiceName[NICE_NAME_BYTES]; // Always null terminated.
char mBuffer[MAX_COMMAND_BYTES];
};
-static_assert(sizeof(NativeCommandBuffer) < 3 * 4096);
-
static int buffersAllocd(0);
// Get a new NativeCommandBuffer. Can only be called once between freeNativeBuffer calls,
@@ -374,6 +386,7 @@ jboolean com_android_internal_os_ZygoteCommandBuffer_nativeForkRepeatedly(
jint minUid,
jstring managed_nice_name) {
+ ALOGI("Entering forkRepeatedly native zygote loop");
NativeCommandBuffer* n_buffer = reinterpret_cast<NativeCommandBuffer*>(j_buffer);
int session_socket = n_buffer->getFd();
std::vector<int> session_socket_fds {session_socket};
@@ -402,7 +415,8 @@ jboolean com_android_internal_os_ZygoteCommandBuffer_nativeForkRepeatedly(
socklen_t cred_size = sizeof credentials;
if (getsockopt(n_buffer->getFd(), SOL_SOCKET, SO_PEERCRED, &credentials, &cred_size) == -1
|| cred_size != sizeof credentials) {
- fail_fn_1(CREATE_ERROR("ForkMany failed to get initial credentials, %s", strerror(errno)));
+ fail_fn_1(CREATE_ERROR("ForkRepeatedly failed to get initial credentials, %s",
+ strerror(errno)));
}
bool first_time = true;
diff --git a/core/proto/android/os/appbatterystats.proto b/core/proto/android/os/appbatterystats.proto
new file mode 100644
index 000000000000..8769ebb74979
--- /dev/null
+++ b/core/proto/android/os/appbatterystats.proto
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ */
+
+syntax = "proto2";
+package android.os;
+
+option java_multiple_files = true;
+
+message AppBatteryStatsProto {
+ message UidStats {
+ optional int32 uid = 1;
+
+ message ProcessStateStats {
+ enum ProcessState {
+ UNSPECIFIED = 0;
+ FOREGROUND = 1;
+ BACKGROUND = 2;
+ FOREGROUND_SERVICE = 3;
+ CACHED = 4;
+ }
+
+ optional ProcessState process_state = 1;
+
+ // Time spent in this state in the past 24 hours
+ optional int64 duration_ms = 2;
+ // Estimated power consumed in this state in the past 24 hours
+ optional double power_mah = 3;
+ }
+
+ repeated ProcessStateStats process_state_stats = 2;
+ }
+
+ repeated UidStats uid_stats = 1;
+}
diff --git a/core/proto/android/os/batteryusagestats.proto b/core/proto/android/os/batteryusagestats.proto
index cc90e05de744..856bc839aee5 100644
--- a/core/proto/android/os/batteryusagestats.proto
+++ b/core/proto/android/os/batteryusagestats.proto
@@ -76,6 +76,7 @@ message BatteryUsageStatsAtomsProto {
FOREGROUND = 1;
BACKGROUND = 2;
FOREGROUND_SERVICE = 3;
+ CACHED = 4;
}
optional ProcessState process_state = 2;
diff --git a/core/proto/android/os/incident.proto b/core/proto/android/os/incident.proto
index 51e150e28437..57026d95ceb8 100644
--- a/core/proto/android/os/incident.proto
+++ b/core/proto/android/os/incident.proto
@@ -48,7 +48,6 @@ import "frameworks/base/core/proto/android/service/batterystats.proto";
import "frameworks/base/core/proto/android/service/diskstats.proto";
import "frameworks/base/core/proto/android/service/dropbox.proto";
import "frameworks/base/core/proto/android/service/graphicsstats.proto";
-import "frameworks/base/core/proto/android/service/netstats.proto";
import "frameworks/base/core/proto/android/service/notification.proto";
import "frameworks/base/core/proto/android/service/package.proto";
import "frameworks/base/core/proto/android/service/print.proto";
@@ -62,7 +61,8 @@ import "frameworks/base/core/proto/android/util/textdump.proto";
import "frameworks/base/core/proto/android/privacy.proto";
import "frameworks/base/core/proto/android/section.proto";
import "frameworks/base/proto/src/ipconnectivity.proto";
-import "packages/modules/Permission/service/proto/com/android/role/roleservice.proto";
+import "packages/modules/Connectivity/framework/proto/netstats.proto";
+import "packages/modules/Permission/service/proto/role_service.proto";
package android.os;
diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto
index 3929027a4e94..0ade0934f2a6 100644
--- a/core/proto/android/server/windowmanagerservice.proto
+++ b/core/proto/android/server/windowmanagerservice.proto
@@ -53,6 +53,7 @@ message WindowManagerServiceDumpProto {
optional int32 last_orientation = 8 [(.android.typedef) = "android.content.pm.ActivityInfo.ScreenOrientation", deprecated=true];
optional int32 focused_display_id = 9;
optional bool hard_keyboard_available = 10;
+ optional bool window_frames_valid = 11;
}
/* represents RootWindowContainer object */
diff --git a/core/proto/android/service/netstats.proto b/core/proto/android/service/netstats.proto
deleted file mode 100644
index ba2b6d6bd7e0..000000000000
--- a/core/proto/android/service/netstats.proto
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-syntax = "proto2";
-package android.service;
-
-option java_multiple_files = true;
-option java_outer_classname = "NetworkStatsServiceProto";
-
-// Represents dumpsys from NetworkStatsService (netstats).
-message NetworkStatsServiceDumpProto {
- repeated NetworkInterfaceProto active_interfaces = 1;
-
- repeated NetworkInterfaceProto active_uid_interfaces = 2;
-
- // Device level network stats, which may include non-IP layer traffic.
- optional NetworkStatsRecorderProto dev_stats = 3;
-
- // IP-layer traffic stats.
- optional NetworkStatsRecorderProto xt_stats = 4;
-
- // Per-UID network stats.
- optional NetworkStatsRecorderProto uid_stats = 5;
-
- // Per-UID, per-tag network stats, excluding the default tag (i.e. tag=0).
- optional NetworkStatsRecorderProto uid_tag_stats = 6;
-}
-
-// Corresponds to NetworkStatsService.mActiveIfaces/mActiveUidIfaces.
-message NetworkInterfaceProto {
- // Name of the network interface (eg: wlan).
- optional string interface = 1;
-
- optional NetworkIdentitySetProto identities = 2;
-}
-
-// Corresponds to NetworkIdentitySet.
-message NetworkIdentitySetProto {
- repeated NetworkIdentityProto identities = 1;
-}
-
-// Corresponds to NetworkIdentity.
-message NetworkIdentityProto {
- // Constants from ConnectivityManager.TYPE_*.
- optional int32 type = 1;
-
- optional bool roaming = 4;
-
- optional bool metered = 5;
-
- optional bool default_network = 6;
-
- optional int32 oem_managed_network = 7;
-}
-
-// Corresponds to NetworkStatsRecorder.
-message NetworkStatsRecorderProto {
- optional int64 pending_total_bytes = 1;
-
- optional NetworkStatsCollectionProto complete_history = 2;
-}
-
-// Corresponds to NetworkStatsCollection.
-message NetworkStatsCollectionProto {
- repeated NetworkStatsCollectionStatsProto stats = 1;
-}
-
-// Corresponds to NetworkStatsCollection.mStats.
-message NetworkStatsCollectionStatsProto {
- optional NetworkStatsCollectionKeyProto key = 1;
-
- optional NetworkStatsHistoryProto history = 2;
-}
-
-// Corresponds to NetworkStatsCollection.Key.
-message NetworkStatsCollectionKeyProto {
- optional NetworkIdentitySetProto identity = 1;
-
- optional int32 uid = 2;
-
- optional int32 set = 3;
-
- optional int32 tag = 4;
-}
-
-// Corresponds to NetworkStatsHistory.
-message NetworkStatsHistoryProto {
- // Duration for this bucket in milliseconds.
- optional int64 bucket_duration_ms = 1;
-
- repeated NetworkStatsHistoryBucketProto buckets = 2;
-}
-
-// Corresponds to each bucket in NetworkStatsHistory.
-message NetworkStatsHistoryBucketProto {
- // Bucket start time in milliseconds since epoch.
- optional int64 bucket_start_ms = 1;
-
- optional int64 rx_bytes = 2;
-
- optional int64 rx_packets = 3;
-
- optional int64 tx_bytes = 4;
-
- optional int64 tx_packets = 5;
-
- optional int64 operations = 6;
-}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 434222ae8016..45b6c786670d 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -528,6 +528,7 @@
<protected-broadcast android:name="android.intent.action.MANAGED_PROFILE_ADDED" />
<protected-broadcast android:name="android.intent.action.MANAGED_PROFILE_UNLOCKED" />
<protected-broadcast android:name="android.intent.action.MANAGED_PROFILE_REMOVED" />
+ <protected-broadcast android:name="android.app.action.MANAGED_PROFILE_PROVISIONED" />
<protected-broadcast android:name="android.bluetooth.adapter.action.BLE_STATE_CHANGED" />
<protected-broadcast android:name="com.android.bluetooth.map.USER_CONFIRM_TIMEOUT" />
@@ -720,10 +721,12 @@
<!-- Added in T -->
<protected-broadcast android:name="android.safetycenter.action.REFRESH_SAFETY_SOURCES" />
+ <protected-broadcast android:name="android.safetycenter.action.SAFETY_CENTER_ENABLED_CHANGED" />
<protected-broadcast android:name="android.app.action.DEVICE_POLICY_RESOURCE_UPDATED" />
<protected-broadcast android:name="android.intent.action.SHOW_FOREGROUND_SERVICE_MANAGER" />
<protected-broadcast android:name="android.service.autofill.action.DELAYED_FILL" />
<protected-broadcast android:name="android.app.action.PROVISIONING_COMPLETED" />
+ <protected-broadcast android:name="android.app.action.LOST_MODE_LOCATION_UPDATE" />
<!-- ====================================================================== -->
<!-- RUNTIME PERMISSIONS -->
@@ -991,10 +994,12 @@
<!-- Allows an application to read audio files from external storage.
<p>This permission is enforced starting in API level
- {@link android.os.Build.VERSION_CODES#TIRAMISU}.
+ {@link android.os.Build.VERSION_CODES#TIRAMISU}. An app which targets
+ {@link android.os.Build.VERSION_CODES#TIRAMISU} or higher and needs to read audio files from
+ external storage must hold this permission; {@link #READ_EXTERNAL_STORAGE} is not required.
For apps with a <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code
- targetSdkVersion}</a> of {@link android.os.Build.VERSION_CODES#S} or lower, this permission
- must not be used and the READ_EXTERNAL_STORAGE permission must be used instead.
+ targetSdkVersion}</a> of {@link android.os.Build.VERSION_CODES#S_V2} or lower, the
+ {@link #READ_EXTERNAL_STORAGE} permission is required, instead, to read audio files.
<p>Protection level: dangerous -->
<permission android:name="android.permission.READ_MEDIA_AUDIO"
android:permissionGroup="android.permission-group.UNDEFINED"
@@ -1010,12 +1015,14 @@
android:description="@string/permgroupdesc_readMediaVisual"
android:priority="1000" />
- <!-- Allows an application to read audio files from external storage.
- <p>This permission is enforced starting in API level
- {@link android.os.Build.VERSION_CODES#TIRAMISU}.
- For apps with a <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code
- targetSdkVersion}</a> of {@link android.os.Build.VERSION_CODES#S} or lower, this permission
- must not be used and the READ_EXTERNAL_STORAGE permission must be used instead.
+ <!-- Allows an application to read video files from external storage.
+ <p>This permission is enforced starting in API level
+ {@link android.os.Build.VERSION_CODES#TIRAMISU}. An app which targets
+ {@link android.os.Build.VERSION_CODES#TIRAMISU} or higher and needs to read video files from
+ external storage must hold this permission; {@link #READ_EXTERNAL_STORAGE} is not required.
+ For apps with a <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code
+ targetSdkVersion}</a> of {@link android.os.Build.VERSION_CODES#S_V2} or lower, the
+ {@link #READ_EXTERNAL_STORAGE} permission is required, instead, to read video files.
<p>Protection level: dangerous -->
<permission android:name="android.permission.READ_MEDIA_VIDEO"
android:permissionGroup="android.permission-group.UNDEFINED"
@@ -1025,15 +1032,17 @@
<!-- Allows an application to read image files from external storage.
<p>This permission is enforced starting in API level
- {@link android.os.Build.VERSION_CODES#TIRAMISU}.
+ {@link android.os.Build.VERSION_CODES#TIRAMISU}. An app which targets
+ {@link android.os.Build.VERSION_CODES#TIRAMISU} or higher and needs to read image files from
+ external storage must hold this permission; {@link #READ_EXTERNAL_STORAGE} is not required.
For apps with a <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code
- targetSdkVersion}</a> of {@link android.os.Build.VERSION_CODES#S} or lower, this permission
- must not be used and the READ_EXTERNAL_STORAGE permission must be used instead.
- <p>Protection level: dangerous -->
- <permission android:name="android.permission.READ_MEDIA_IMAGE"
+ targetSdkVersion}</a> of {@link android.os.Build.VERSION_CODES#S_V2} or lower, the
+ {@link #READ_EXTERNAL_STORAGE} permission is required, instead, to read image files.
+ <p>Protection level: dangerous -->
+ <permission android:name="android.permission.READ_MEDIA_IMAGES"
android:permissionGroup="android.permission-group.UNDEFINED"
- android:label="@string/permlab_readMediaImage"
- android:description="@string/permdesc_readMediaImage"
+ android:label="@string/permlab_readMediaImages"
+ android:description="@string/permdesc_readMediaImages"
android:protectionLevel="dangerous" />
<!-- Allows an application to write to external storage.
@@ -1901,11 +1910,21 @@
<!-- 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. -->
+ <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,
+ modify connectivity scan intervals, and approve Wi-Fi Direct connections.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.MANAGE_WIFI_NETWORK_SELECTION"
+ android:protectionLevel="signature|privileged|knownSigner"
+ android:knownCerts="@array/wifi_known_signers" />
+
<!-- Allows applications to get notified when a Wi-Fi interface request cannot
be satisfied without tearing down one or more other interfaces, and provide a decision
whether to approve the request or reject it.
@@ -2937,7 +2956,7 @@
<!-- @SystemApi @hide Allows an application to set the profile owners and the device owner.
This permission is not available to third party applications.-->
<permission android:name="android.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS"
- android:protectionLevel="signature|role|setup"
+ android:protectionLevel="signature|role"
android:label="@string/permlab_manageProfileAndDeviceOwners"
android:description="@string/permdesc_manageProfileAndDeviceOwners" />
@@ -2946,6 +2965,10 @@
<permission android:name="android.permission.QUERY_ADMIN_POLICY"
android:protectionLevel="signature|role" />
+ <!-- @SystemApi @hide Allows an application to set a device owner on retail demo devices.-->
+ <permission android:name="android.permission.PROVISION_DEMO_DEVICE"
+ android:protectionLevel="signature|setup" />
+
<!-- @TestApi @hide Allows an application to reset the record of previous system update freeze
periods. -->
<permission android:name="android.permission.CLEAR_FREEZE_PERIOD"
@@ -3085,7 +3108,7 @@
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.SYSTEM_APPLICATION_OVERLAY"
- android:protectionLevel="signature|recents|role"/>
+ android:protectionLevel="signature|recents|role|installer"/>
<!-- @deprecated Use {@link android.Manifest.permission#REQUEST_COMPANION_RUN_IN_BACKGROUND}
@hide
@@ -3714,15 +3737,26 @@
android:protectionLevel="signature|privileged" />
<!-- ========================================= -->
- <!-- Permissions for SupplementalApi -->
+ <!-- Permissions for AdServices -->
<!-- ========================================= -->
<eat-comment />
- <!-- TODO(b/213488783): Update with correct names. -->
- <!-- Allows an application to access SupplementalApis. -->
- <permission android:name="android.permission.ACCESS_SUPPLEMENTAL_APIS"
- android:label="@string/permlab_accessSupplementalApi"
- android:description="@string/permdesc_accessSupplementalApi"
+ <!-- Allows an application to access AdServices Topics API. -->
+ <permission android:name="android.permission.ACCESS_ADSERVICES_TOPICS"
+ android:label="@string/permlab_accessAdServicesTopics"
+ android:description="@string/permdesc_accessAdServicesTopics"
+ android:protectionLevel="normal" />
+
+ <!-- Allows an application to access AdServices Attribution APIs. -->
+ <permission android:name="android.permission.ACCESS_ADSERVICES_ATTRIBUTION"
+ android:label="@string/permlab_accessAdServicesAttribution"
+ android:description="@string/permdesc_accessAdServicesAttribution"
+ android:protectionLevel="normal" />
+
+ <!-- Allows an application to access AdServices Custom Audiences APIs. -->
+ <permission android:name="android.permission.ACCESS_ADSERVICES_CUSTOM_AUDIENCES"
+ android:label="@string/permlab_accessAdServicesCustomAudiences"
+ android:description="@string/permdesc_accessAdServicesCustomAudiences"
android:protectionLevel="normal" />
<!-- ==================================== -->
@@ -5118,6 +5152,14 @@
android:protectionLevel="signature|privileged|development|appop|retailDemo" />
<uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" />
+ <!-- Allows an application to query broadcast response stats (see
+ {@link android.app.usage.BroadcastResponseStats}).
+ @SystemApi
+ @hide
+ -->
+ <permission android:name="android.permission.ACCESS_BROADCAST_RESPONSE_STATS"
+ android:protectionLevel="signature|privileged|development" />
+
<!-- Allows a data loader to read a package's access logs. The access logs contain the
set of pages referenced over time.
<p>Declaring the permission implies intention to use the API and the user of the
@@ -6026,10 +6068,10 @@
<permission android:name="android.permission.MANAGE_APPOPS"
android:protectionLevel="signature" />
- <!-- @hide Permission that allows background clipboard access.
- <p>Not for use by third-party applications. -->
+ <!-- @SystemApi Permission that allows background clipboard access.
+ @hide Not for use by third-party applications. -->
<permission android:name="android.permission.READ_CLIPBOARD_IN_BACKGROUND"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature|role" />
<!-- @hide Permission that suppresses the notification when the clipboard is accessed.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.SUPPRESS_CLIPBOARD_ACCESS_NOTIFICATION"
@@ -6135,10 +6177,10 @@
<!-- Allows input events to be monitored. Very dangerous! @hide -->
<permission android:name="android.permission.MONITOR_INPUT"
android:protectionLevel="signature|recents" />
- <!-- Allows the use of FLAG_SLIPPERY, which permits touch events to slip from the current
- window to the window where the touch currently is on top of. @hide -->
+ <!-- @SystemApi Allows the use of FLAG_SLIPPERY, which permits touch events to slip from the
+ current window to the window where the touch currently is on top of. @hide -->
<permission android:name="android.permission.ALLOW_SLIPPERY_TOUCHES"
- android:protectionLevel="signature|recents" />
+ android:protectionLevel="signature|privileged|recents|role" />
<!-- Allows the caller to change the associations between input devices and displays.
Very dangerous! @hide -->
<permission android:name="android.permission.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY"
@@ -6395,6 +6437,12 @@
<permission android:name="android.permission.WRITE_SECURITY_LOG"
android:protectionLevel="signature|privileged" />
+ <!-- Allows an UID to be visible to the application based on an interaction between the
+ two apps. This permission is not intended to be held by apps.
+ @hide @TestApi @SystemApi(client=android.annotation.SystemApi.Client.MODULE_LIBRARIES) -->
+ <permission android:name="android.permission.MAKE_UID_VISIBLE"
+ android:protectionLevel="signature" />
+
<!-- Attribution for Geofencing service. -->
<attribution android:tag="GeofencingService" android:label="@string/geofencing_service"/>
<!-- Attribution for Country Detector. -->
@@ -6653,10 +6701,9 @@
android:exported="false">
</activity>
- <activity android:name="com.android.server.logcat.LogAccessConfirmationActivity"
- android:theme="@style/Theme.Dialog.Confirmation"
+ <activity android:name="com.android.server.logcat.LogAccessDialogActivity"
+ android:theme="@style/Theme.DeviceDefault.Dialog.Alert.DayNight"
android:excludeFromRecents="true"
- android:process=":ui"
android:label="@string/log_access_confirmation_title"
android:exported="false">
</activity>
@@ -6815,6 +6862,13 @@
</intent-filter>
</receiver>
+ <receiver android:name="com.android.server.sdksandbox.SdkSandboxVerifierReceiver"
+ android:exported="false">
+ <intent-filter>
+ <action android:name="android.intent.action.PACKAGE_NEEDS_VERIFICATION"/>
+ </intent-filter>
+ </receiver>
+
<service android:name="android.hardware.location.GeofenceHardwareService"
android:permission="android.permission.LOCATION_HARDWARE"
android:exported="false" />
diff --git a/core/res/OWNERS b/core/res/OWNERS
index 4bea4d55e5ef..ca8b3f8aa070 100644
--- a/core/res/OWNERS
+++ b/core/res/OWNERS
@@ -26,6 +26,10 @@ toddke@google.com
tsuji@google.com
yamasani@google.com
+# Resources finalization
+per-file res/xml/public-staging.xml = file:/tools/aapt2/OWNERS
+per-file res/xml/public-final.xml = file:/tools/aapt2/OWNERS
+
# Multiuser
per-file res/xml/config_user_types.xml = file:/MULTIUSER_OWNERS
diff --git a/core/res/res/anim-ldrtl/activity_close_enter.xml b/core/res/res/anim-ldrtl/activity_close_enter.xml
new file mode 100644
index 000000000000..6a699e7fcdfa
--- /dev/null
+++ b/core/res/res/anim-ldrtl/activity_close_enter.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 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.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shareInterpolator="false">
+
+ <alpha
+ android:fromAlpha="1.0"
+ android:toAlpha="1.0"
+ android:fillEnabled="true"
+ android:fillBefore="true"
+ android:fillAfter="true"
+ android:interpolator="@interpolator/linear"
+ android:startOffset="0"
+ android:duration="450" />
+
+ <translate
+ android:fromXDelta="10%"
+ android:toXDelta="0"
+ android:fillEnabled="true"
+ android:fillBefore="true"
+ android:fillAfter="true"
+ android:interpolator="@interpolator/fast_out_extra_slow_in"
+ android:startOffset="0"
+ android:duration="450" />
+
+ <extend
+ android:fromExtendLeft="10%"
+ android:fromExtendTop="0"
+ android:fromExtendRight="0"
+ android:fromExtendBottom="0"
+ android:toExtendLeft="10%"
+ android:toExtendTop="0"
+ android:toExtendRight="0"
+ android:toExtendBottom="0"
+ android:interpolator="@interpolator/fast_out_extra_slow_in"
+ android:startOffset="0"
+ android:duration="450" />
+</set> \ No newline at end of file
diff --git a/core/res/res/anim-ldrtl/activity_close_exit.xml b/core/res/res/anim-ldrtl/activity_close_exit.xml
new file mode 100644
index 000000000000..06a0d6916f61
--- /dev/null
+++ b/core/res/res/anim-ldrtl/activity_close_exit.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 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.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shareInterpolator="false">
+
+ <alpha
+ android:fromAlpha="1.0"
+ android:toAlpha="0.0"
+ android:fillEnabled="true"
+ android:fillBefore="true"
+ android:fillAfter="true"
+ android:interpolator="@interpolator/linear"
+ android:startOffset="35"
+ android:duration="83" />
+
+ <translate
+ android:fromXDelta="0"
+ android:toXDelta="-10%"
+ android:fillEnabled="true"
+ android:fillBefore="true"
+ android:fillAfter="true"
+ android:interpolator="@interpolator/fast_out_extra_slow_in"
+ android:startOffset="0"
+ android:duration="450" />
+
+ <extend
+ android:fromExtendLeft="0"
+ android:fromExtendTop="0"
+ android:fromExtendRight="10%"
+ android:fromExtendBottom="0"
+ android:toExtendLeft="0"
+ android:toExtendTop="0"
+ android:toExtendRight="10%"
+ android:toExtendBottom="0"
+ android:interpolator="@interpolator/fast_out_extra_slow_in"
+ android:startOffset="0"
+ android:duration="450" />
+</set>
diff --git a/core/res/res/anim-ldrtl/activity_open_enter.xml b/core/res/res/anim-ldrtl/activity_open_enter.xml
new file mode 100644
index 000000000000..7b1829466884
--- /dev/null
+++ b/core/res/res/anim-ldrtl/activity_open_enter.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+/*
+** Copyright 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.
+*/
+-->
+
+<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="83" />
+
+ <translate
+ android:fromXDelta="-10%"
+ android:toXDelta="0"
+ android:fillEnabled="true"
+ android:fillBefore="true"
+ android:fillAfter="true"
+ android:interpolator="@interpolator/fast_out_extra_slow_in"
+ android:duration="450" />
+
+ <extend
+ android:fromExtendLeft="0"
+ android:fromExtendTop="0"
+ android:fromExtendRight="10%"
+ android:fromExtendBottom="0"
+ android:toExtendLeft="0"
+ android:toExtendTop="0"
+ android:toExtendRight="10%"
+ android:toExtendBottom="0"
+ android:interpolator="@interpolator/fast_out_extra_slow_in"
+ android:startOffset="0"
+ android:duration="450" />
+</set>
diff --git a/core/res/res/anim-ldrtl/activity_open_exit.xml b/core/res/res/anim-ldrtl/activity_open_exit.xml
new file mode 100644
index 000000000000..c29509ef1b2a
--- /dev/null
+++ b/core/res/res/anim-ldrtl/activity_open_exit.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+/*
+** Copyright 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.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shareInterpolator="false">
+
+ <alpha
+ android:fromAlpha="1.0"
+ android:toAlpha="1.0"
+ android:fillEnabled="true"
+ android:fillBefore="true"
+ android:fillAfter="true"
+ android:interpolator="@interpolator/standard_accelerate"
+ android:startOffset="0"
+ android:duration="450" />
+
+ <translate
+ android:fromXDelta="0"
+ android:toXDelta="10%"
+ android:fillEnabled="true"
+ android:fillBefore="true"
+ android:fillAfter="true"
+ android:interpolator="@interpolator/fast_out_extra_slow_in"
+ android:startOffset="0"
+ android:duration="450" />
+
+ <extend
+ android:fromExtendLeft="10%"
+ android:fromExtendTop="0"
+ android:fromExtendRight="0"
+ android:fromExtendBottom="0"
+ android:toExtendLeft="10%"
+ android:toExtendTop="0"
+ android:toExtendRight="0"
+ android:toExtendBottom="0"
+ android:interpolator="@interpolator/fast_out_extra_slow_in"
+ android:startOffset="0"
+ android:duration="450" />
+</set> \ No newline at end of file
diff --git a/core/res/res/drawable-nodpi/stat_sys_adb.xml b/core/res/res/drawable-nodpi/stat_sys_adb.xml
index f8c04517800a..cb4462c9a169 100644
--- a/core/res/res/drawable-nodpi/stat_sys_adb.xml
+++ b/core/res/res/drawable-nodpi/stat_sys_adb.xml
@@ -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.
@@ -13,11 +13,78 @@ Copyright (C) 2021 The Android Open Source Project
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">
- <path android:pathData="M18 9c0-.69268-.1174-1.35795-.3333-1.97699C16.8495 4.68061 14.621 3 12 3 8.68629 3 6 5.68629 6 9v3h6M6 15c0 .6927.11738 1.3579.33333 1.977C7.15047 19.3194 9.37897 21 12 21c3.3137 0 6-2.6863 6-6v-3h-6" android:strokeColor="#000000" android:strokeWidth="2" android:fillColor="#00000000"/>
- <path android:fillColor="#000000" android:pathData="M10 7a1 1 0 1 0 0 2 1 1 0 1 0 0-2zM14 7a1 1 0 1 0 0 2 1 1 0 1 0 0-2z"/>
- <path android:pathData="M6 3l1.5 1.5M18 3l-1.5 1.5" android:strokeColor="#000000" android:strokeWidth="2" android:fillColor="#000000"/>
+<vector android:width="24dp" android:height="24dp"
+ android:viewportWidth="24" android:viewportHeight="24"
+ xmlns:android="http://schemas.android.com/apk/res/android">
+ <path android:pathData="
+ M22.45 11.94
+ l-.58-.21
+ a1.19 1.19 0 0 1-.26-2.12
+ l.51-.34
+ a1.2 1.2 0 0 0-.83-2.19
+ l-.61.08
+ a1.2 1.2 0 0 1-1.21-1.76
+ l.29-.54
+ A1.2 1.2 0 0 0 18 3.31
+ l-.5.36
+ a1.21 1.21 0 0 1-1.9-1
+ v-.61
+ a1.2 1.2 0 0 0-2.27-.56
+ l-.26.5
+ a1.2 1.2 0 0 1-2.14 0
+ l-.28-.54
+ a1.2 1.2 0 0 0-2.27.56
+ v.61
+ a1.21 1.21 0 0 1-1.9 1
+ L6 3.31
+ a1.2 1.2 0 0 0-1.76 1.55
+ l.29.54
+ a1.2 1.2 0 0 1-1.21 1.76
+ l-.61-.08
+ a1.2 1.2 0 0 0-.83 2.19
+ l.51.34
+ a1.19 1.19 0 0 1-.26 2.12
+ l-.58.21
+ a1.21 1.21 0 0 0 .29 2.33
+ l.61.06
+ a1.2 1.2 0 0 1 .76 2
+ l-.42.46
+ a1.2 1.2 0 0 0 1.33 1.92
+ l.57-.22
+ a1.21 1.21 0 0 1 1.61 1.42
+ l-.16.59
+ a1.2 1.2 0 0 0 2.07 1.09
+ l.4-.47
+ a1.2 1.2 0 0 1 2.08.51
+ l.14.6
+ a1.2 1.2 0 0 0 2.34 0
+ l.14-.6
+ a1.2 1.2 0 0 1 2.08-.51
+ l.4.47
+ a1.2 1.2 0 0 0 2.07-1.09
+ l-.16-.59
+ a1.21 1.21 0 0 1 1.61-1.42
+ l.57.22
+ a1.2 1.2 0 0 0 1.33-1.92
+ l-.42-.46
+ a1.2 1.2 0 0 1 .76-2
+ l.61-.06
+ a1.21 1.21 0 0 0 .29-2.33
+ z
+ M12 19
+ a7 7 0 1 1 7-7 7 7 0 0 1-7 7
+ z
+ "
+ android:fillColor="#000000" />
+ <path android:pathData="
+ M9 7.75
+ a.75.75 0 1 0 0 1.5.75.75 0 1 0 0-1.5
+ z
+ M15 7.75
+ a.75.75 0 1 0 0 1.5.75.75 0 1 0 0-1.5
+ z
+ "
+ android:fillColor="#000000" />
+ <path android:strokeColor="#000000" android:strokeMiterLimit="10" android:strokeWidth="2"
+ android:pathData="M4 12h16M12 12v8" />
</vector>
diff --git a/core/res/res/drawable/grant_permissions_buttons_bottom.xml b/core/res/res/drawable/grant_permissions_buttons_bottom.xml
new file mode 100644
index 000000000000..a800f15b297e
--- /dev/null
+++ b/core/res/res/drawable/grant_permissions_buttons_bottom.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.
+ -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <solid android:color="@android:color/system_accent1_100"/>
+ <corners android:topLeftRadius="4dp" android:topRightRadius="4dp"
+ android:bottomLeftRadius="12dp" android:bottomRightRadius="12dp"/>
+</shape> \ No newline at end of file
diff --git a/core/res/res/drawable/grant_permissions_buttons_top.xml b/core/res/res/drawable/grant_permissions_buttons_top.xml
new file mode 100644
index 000000000000..2bf803e340ec
--- /dev/null
+++ b/core/res/res/drawable/grant_permissions_buttons_top.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.
+ -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <solid android:color="@android:color/system_accent1_100"/>
+ <corners android:topLeftRadius="12dp" android:topRightRadius="12dp"
+ android:bottomLeftRadius="4dp" android:bottomRightRadius="4dp"/>
+</shape> \ No newline at end of file
diff --git a/core/res/res/layout/log_access_user_consent_dialog_permission.xml b/core/res/res/layout/log_access_user_consent_dialog_permission.xml
new file mode 100644
index 000000000000..bd7efbd59c33
--- /dev/null
+++ b/core/res/res/layout/log_access_user_consent_dialog_permission.xml
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 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:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="380dp"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ android:gravity="center"
+ android:paddingLeft="24dp"
+ android:paddingRight="24dp"
+ android:paddingTop="24dp"
+ android:paddingBottom="24dp"
+ android:background="?attr/colorSurface">
+
+ <ImageView
+ android:id="@+id/log_access_image_view"
+ android:layout_width="32dp"
+ android:layout_height="32dp"
+ android:layout_marginBottom="16dp"
+ android:src="@drawable/ic_doc_document"
+ tools:layout_editor_absoluteX="148dp"
+ tools:layout_editor_absoluteY="35dp"
+ android:gravity="center" />
+
+
+ <TextView
+ android:id="@+id/log_access_dialog_title"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:layout_marginBottom="32dp"
+ android:text="@string/log_access_confirmation_title"
+ android:textAppearance="?attr/textAppearanceLarge"
+ android:textColor="@android:color/system_neutral1_900"
+ android:gravity="center" />
+
+ <TextView
+ android:id="@+id/log_access_dialog_body"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:text="@string/log_access_confirmation_body"
+ android:textAppearance="@style/PrimaryAllowLogAccess"
+ android:gravity="center" />
+
+ <Button
+ android:id="@+id/log_access_dialog_allow_button"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:text="@string/log_access_confirmation_allow"
+ style="@style/PermissionGrantButtonTop"
+ android:layout_marginBottom="5dp"
+ android:layout_centerHorizontal="true"
+ android:layout_alignParentTop="true"
+ android:layout_alignParentBottom="true"
+ android:clipToOutline="true"
+ android:gravity="center" />
+
+ <Button
+ android:id="@+id/log_access_dialog_deny_button"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:text="@string/log_access_confirmation_deny"
+ style="@style/PermissionGrantButtonBottom"
+ android:layout_centerHorizontal="true"
+ android:layout_alignParentTop="true"
+ android:layout_alignParentBottom="true"
+ android:clipToOutline="true"
+ android:gravity="center" />
+
+</LinearLayout> \ No newline at end of file
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index da5f8998d156..2107f651eade 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -5479,9 +5479,9 @@
<enum name="none" value="0" />
<!-- Use the least restrictive rule for line-breaking. -->
<enum name="loose" value="1" />
- <!-- Indicate breaking text with the most comment set of line-breaking rules. -->
+ <!-- Indicates breaking text with the most comment set of line-breaking rules. -->
<enum name="normal" value="2" />
- <!-- ndicates breaking text with the most strictest line-breaking rules. -->
+ <!-- Indicates breaking text with the most strictest line-breaking rules. -->
<enum name="strict" value="3" />
</attr>
<!-- Specify the phrase-based line break can be used when calculating the text wrapping.-->
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 579ef512e671..7562b9aa0ead 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -401,15 +401,6 @@
and before. -->
<attr name="sharedUserMaxSdkVersion" format="integer" />
- <!-- Whether the application should inherit all AndroidKeyStore keys of its shared user
- group in the case of leaving its shared user ID in an upgrade. If set to false, all
- AndroidKeyStore keys will remain in the shared user group, and the application will no
- longer have access to those keys after the upgrade. If set to true, all AndroidKeyStore
- keys owned by the shared user group will be transferred to the upgraded application;
- other applications in the shared user group will no longer have access to those keys
- after the migration. The default value is false if not explicitly set. -->
- <attr name="inheritKeyStoreKeys" format="boolean" />
-
<!-- Internal version code. This is the number used to determine whether
one version is more recent than another: it has no other meaning than
that higher numbers are more recent. You could use this number to
@@ -1704,7 +1695,6 @@
<attr name="sharedUserId" />
<attr name="sharedUserLabel" />
<attr name="sharedUserMaxSdkVersion" />
- <attr name="inheritKeyStoreKeys" />
<attr name="installLocation" />
<attr name="isolatedSplits" />
<attr name="isFeatureSplit" />
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 7f16cdcfc595..3707cb756b05 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2335,7 +2335,7 @@
<!-- Remote server that can provide NTP responses. -->
<string translatable="false" name="config_ntpServer">time.android.com</string>
<!-- Normal polling frequency in milliseconds -->
- <integer name="config_ntpPollingInterval">86400000</integer>
+ <integer name="config_ntpPollingInterval">64800000</integer>
<!-- Try-again polling interval in milliseconds, in case the network request failed -->
<integer name="config_ntpPollingIntervalShorter">60000</integer>
<!-- Number of times to try again with the shorter interval, before backing
@@ -2723,7 +2723,7 @@
<string name="config_bandwidthEstimateSource">bandwidth_estimator</string>
<!-- Whether force to enable telephony new data stack or not -->
- <bool name="config_force_enable_telephony_new_data_stack">false</bool>
+ <bool name="config_force_enable_telephony_new_data_stack">true</bool>
<!-- Whether WiFi display is supported by this device.
There are many prerequisites for this feature to work correctly.
@@ -2931,6 +2931,11 @@
<!-- Apps that are authorized to access shared accounts, overridden by product overlays -->
<string name="config_appsAuthorizedForSharedAccounts" translatable="false">;com.android.settings;</string>
+ <!-- Settings intelligence package name -->
+ <string name="config_settingsIntelligencePackageName" translatable="false">
+ com.android.settings.intelligence
+ </string>
+
<!-- Flag indicating that the media framework should not allow changes or mute on any
stream or global volumes. -->
<bool name="config_useFixedVolume">false</bool>
@@ -2958,6 +2963,11 @@
the currently focused view is a text editor. -->
<bool name="config_preventImeStartupUnlessTextEditor">false</bool>
+ <!-- These IMEs are known not to behave well when evicted from memory and thus are exempt
+ from the IME startup prevention behavior that is enabled by
+ config_preventImeStartupUnlessTextEditor. -->
+ <string-array name="config_nonPreemptibleInputMethods" translatable="false" />
+
<!-- The list of classes that should be added to the notification ranking pipeline.
See {@link com.android.server.notification.NotificationSignalExtractor}
If you add a new extractor to this list make sure to update
@@ -2983,6 +2993,12 @@
</string-array>
+ <!-- When migrating notification settings into the permission framework, whether all existing
+ apps should be marked as 'user-set' (true) or whether only the apps that have explicitly
+ modified notification settings should be marked as 'user-set' (false). Users will not see
+ system generated permission prompts for 'user-set' apps. -->
+ <bool name="config_notificationForceUserSetOnUpgrade">true</bool>
+
<!-- Default Gravity setting for the system Toast view. Equivalent to: Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM -->
<integer name="config_toastDefaultGravity">0x00000051</integer>
@@ -4130,9 +4146,9 @@
This service must be trusted, as it can be activated without explicit consent of the user.
If no service with the specified name exists on the device, cloudsearch will be disabled.
Example: "com.android.intelligence/.CloudSearchService"
- config_defaultCloudSearchService is for the single provider case.
+ config_defaultCloudSearchServices is for the multiple provider case.
-->
- <string name="config_defaultCloudSearchService" translatable="false"></string>
+ <string-array name="config_defaultCloudSearchServices"></string-array>
<!-- The package name for the system's translation service.
This service must be trusted, as it can be activated without explicit consent of the user.
@@ -4846,6 +4862,7 @@
<item>0.25</item>
<item>0.5</item>
<item>0.75</item>
+ <item>0.875</item>
</string-array>
<!-- Messages that should not be shown to the user during face auth enrollment. This should be
@@ -5262,9 +5279,9 @@
<bool name="config_cecPowerStateChangeOnActiveSourceLost_userConfigurable">true</bool>
<bool name="config_cecPowerStateChangeOnActiveSourceLostNone_allowed">true</bool>
- <bool name="config_cecPowerStateChangeOnActiveSourceLostNone_default">true</bool>
+ <bool name="config_cecPowerStateChangeOnActiveSourceLostNone_default">false</bool>
<bool name="config_cecPowerStateChangeOnActiveSourceLostStandbyNow_allowed">true</bool>
- <bool name="config_cecPowerStateChangeOnActiveSourceLostStandbyNow_default">false</bool>
+ <bool name="config_cecPowerStateChangeOnActiveSourceLostStandbyNow_default">true</bool>
<bool name="config_cecSystemAudioControl_userConfigurable">true</bool>
<bool name="config_cecSystemAudioControlEnabled_allowed">true</bool>
@@ -5730,13 +5747,13 @@
exceeds the threshold, it'll be moved to restricted standby bucket. The value must be
one of or combination of the definitions in AppBatteryPolicy.
-->
- <integer name="config_bg_current_drain_types_to_restricted_bucket">4</integer>
+ <integer name="config_bg_current_drain_types_to_restricted_bucket">20</integer>
<!-- The types of battery drain we're checking on each app; if the sum of the battery drain
exceeds the threshold, it'll be moved to background restricted level. The value must be
one of or combination of the definitions in AppBatteryPolicy.
-->
- <integer name="config_bg_current_drain_types_to_bg_restricted">12</integer>
+ <integer name="config_bg_current_drain_types_to_bg_restricted">28</integer>
<!-- The power usage components we're monitoring. Must one of the definition in BatteryConsumer.
-->
@@ -5784,11 +5801,21 @@
<!-- The types of state where we'll exempt its battery usage during that state.
The state here must be one or a combination of STATE_TYPE_* in BaseAppStateTracker.
-->
- <integer name="config_bg_current_drain_exempted_types">9</integer>
+ <integer name="config_bg_current_drain_exempted_types">25</integer>
<!-- The behavior when an app has the permission ACCESS_BACKGROUND_LOCATION granted,
whether or not the system will use a higher threshold towards its background battery usage
because of it.
-->
<bool name="config_bg_current_drain_high_threshold_by_bg_location">false</bool>
+
+ <!-- Start safety protection resources to be overlaid -->
+
+ <!-- Safety protection icon to be overlaid -->
+ <item name="ic_safety_protection" type="drawable">@null</item>
+
+ <!-- Display text for safety protection to be overlaid. This is translatable -->
+ <string name="safety_protection_display_text"></string>
+
+ <!-- End safety protection resources to be overlaid -->
</resources>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 1b9f7feec0ef..44c551259375 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -668,6 +668,9 @@
<dimen name="lock_pattern_dot_line_width">22dp</dimen>
<dimen name="lock_pattern_dot_size">14dp</dimen>
<dimen name="lock_pattern_dot_size_activated">30dp</dimen>
+ <!-- How much of the cell space is classified as hit areas [0..1] where 1 means that hit area is
+ a circle with diameter equals to cell minimum side min(width, height). -->
+ <item type="dimen" format="float" name="lock_pattern_dot_hit_factor">0.6</item>
<!-- Width of a gradient applied to a lock pattern line while its disappearing animation. -->
<dimen name="lock_pattern_fade_away_gradient_width">8dp</dimen>
diff --git a/core/res/res/values/ids.xml b/core/res/res/values/ids.xml
index 29eb0c0365b3..082acbe3443a 100644
--- a/core/res/res/values/ids.xml
+++ b/core/res/res/values/ids.xml
@@ -270,20 +270,8 @@
<!-- Accessibility action identifier for {@link android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction#ACTION_DRAG_CANCEL}. -->
<item type="id" name="accessibilityActionDragCancel" />
- <!-- Accessibility action identifier for {@link android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction#ACTION_SWIPE_LEFT}. -->
- <item type="id" name="accessibilityActionSwipeLeft" />
-
- <!-- Accessibility action identifier for {@link android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction#ACTION_SWIPE_RIGHT}. -->
- <item type="id" name="accessibilityActionSwipeRight" />
-
- <!-- Accessibility action identifier for {@link android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction#ACTION_SWIPE_UP}. -->
- <item type="id" name="accessibilityActionSwipeUp" />
-
- <!-- Accessibility action identifier for {@link android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction#ACTION_SWIPE_DOWN}. -->
- <item type="id" name="accessibilityActionSwipeDown" />
-
- <!-- Accessibility action identifier for {@link android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction#ACTION_SHOW_SUGGESTIONS}. -->
- <item type="id" name="accessibilityActionShowSuggestions" />
+ <!-- Accessibility action identifier for {@link android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction#ACTION_SHOW_TEXT_SUGGESTIONS}. -->
+ <item type="id" name="accessibilityActionShowTextSuggestions" />
<!-- View tag for remote views to store the index of the next child when adding nested remote views dynamically. -->
<item type="id" name="remote_views_next_child" />
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public-final.xml
index 3467e1b40470..19a484293b0a 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public-final.xml
@@ -3211,8 +3211,6 @@
</staging-public-group-final>
<public type="attr" name="shouldUseDefaultUnfoldTransition" id="0x0101064c" />
- <public type="attr" name="lineBreakStyle" id="0x0101064d" />
- <public type="attr" name="lineBreakWordStyle" id="0x0101064e" />
<staging-public-group-final type="id" first-id="0x01fe0000">
<public name="accessibilityActionDragStart" />
@@ -3224,147 +3222,4 @@
<public type="id" name="accessibilityActionDragDrop" id="0x01020056" />
<public type="id" name="accessibilityActionDragCancel" id="0x01020057" />
- <!-- ===============================================================
- Resources added in version T of the platform
-
- NOTE: add <public> elements within a <staging-public-group> like so:
-
- <staging-public-group type="attr" first-id="0x01ff0000">
- <public name="exampleAttr1" />
- <public name="exampleAttr2" />
- </staging-public-group>
-
- To add a new <staging-public-group> block, find the id value for the
- last <staging-public-group> block defined for thie API level, and
- subtract 0x00010000 from it to get to the id of the new block.
-
- For example, if the block closest to the end of this file has an id
- of 0x01ee0000, the id of the new block should be 0x01ed0000
- (0x01ee0000 - 0x00010000 = 0x01ed0000).
- =============================================================== -->
- <eat-comment />
-
- <staging-public-group type="attr" first-id="0x01df0000">
- <public name="sharedUserMaxSdkVersion" />
- <public name="requiredSplitTypes" />
- <public name="splitTypes" />
- <public name="canDisplayOnRemoteDevices" />
- <public name="supportedTypes" />
- <public name="resetEnabledSettingsOnAppDataCleared" />
- <public name="supportsStylusHandwriting" />
- <public name="showClockAndComplications" />
- <!-- @hide @SystemApi -->
- <public name="gameSessionService" />
- <public name="supportsBatteryGameMode" />
- <public name="supportsPerformanceGameMode" />
- <public name="allowGameAngleDriver" />
- <public name="allowGameDownscaling" />
- <public name="allowGameFpsOverride" />
- <public name="localeConfig" />
- <public name="showBackground" />
- <public name="useTargetActivityForQuickAccess"/>
- <public name="inheritKeyStoreKeys" />
- <public name="preferKeepClear" />
- <public name="autoHandwritingEnabled" />
- <public name="fromExtendLeft" />
- <public name="fromExtendTop" />
- <public name="fromExtendRight" />
- <public name="fromExtendBottom" />
- <public name="toExtendLeft" />
- <public name="toExtendTop" />
- <public name="toExtendRight" />
- <public name="toExtendBottom" />
- <public name="tileService" />
- <public name="windowSplashScreenBehavior" />
- <public name="allowUntrustedActivityEmbedding" />
- <public name="knownActivityEmbeddingCerts" />
- <public name="intro" />
- <public name="enableOnBackInvokedCallback" />
- <public name="supportsInlineSuggestionsWithTouchExploration" />
- </staging-public-group>
-
- <staging-public-group type="id" first-id="0x01de0000">
- <public name="accessibilityActionSwipeLeft" />
- <public name="accessibilityActionSwipeRight" />
- <public name="accessibilityActionSwipeUp" />
- <public name="accessibilityActionSwipeDown" />
- <public name="accessibilityActionShowSuggestions" />
- <public name="inputExtractAction" />
- <public name="inputExtractAccessories" />
- </staging-public-group>
-
- <staging-public-group type="style" first-id="0x01dd0000">
- <public name="TextAppearance.DeviceDefault.Headline" />
- </staging-public-group>
-
- <staging-public-group type="string" first-id="0x01dc0000">
- <!-- @hide @SystemApi -->
- <public name="config_systemSupervision" />
- <!-- @hide @SystemApi -->
- <public name="config_devicePolicyManagement" />
- <!-- @hide @SystemApi -->
- <public name="config_systemAppProtectionService" />
- <!-- @hide @SystemApi @TestApi -->
- <public name="config_systemAutomotiveCalendarSyncManager" />
- <!-- @hide @SystemApi -->
- <public name="config_defaultAutomotiveNavigation" />
- </staging-public-group>
-
- <staging-public-group type="dimen" first-id="0x01db0000">
- </staging-public-group>
-
- <staging-public-group type="color" first-id="0x01da0000">
- </staging-public-group>
-
- <staging-public-group type="array" first-id="0x01d90000">
- <!-- @hide @SystemApi -->
- <public name="config_optionalIpSecAlgorithms" />
- </staging-public-group>
-
- <staging-public-group type="drawable" first-id="0x01d80000">
- </staging-public-group>
-
- <staging-public-group type="layout" first-id="0x01d70000">
- </staging-public-group>
-
- <staging-public-group type="anim" first-id="0x01d60000">
- </staging-public-group>
-
- <staging-public-group type="animator" first-id="0x01d50000">
- </staging-public-group>
-
- <staging-public-group type="interpolator" first-id="0x01d40000">
- </staging-public-group>
-
- <staging-public-group type="mipmap" first-id="0x01d30000">
- </staging-public-group>
-
- <staging-public-group type="integer" first-id="0x01d20000">
- </staging-public-group>
-
- <staging-public-group type="transition" first-id="0x01d10000">
- </staging-public-group>
-
- <staging-public-group type="raw" first-id="0x01d00000">
- </staging-public-group>
-
- <staging-public-group type="bool" first-id="0x01cf0000">
- <!-- @hide @TestApi -->
- <public name="config_preventImeStartupUnlessTextEditor" />
- <!-- @hide @SystemApi -->
- <public name="config_enableQrCodeScannerOnLockScreen" />
- </staging-public-group>
-
- <staging-public-group type="fraction" first-id="0x01ce0000">
- </staging-public-group>
-
- <!-- ===============================================================
- DO NOT ADD UN-GROUPED ITEMS HERE
-
- Any new items (attrs, styles, ids, etc.) *must* be added in a
- staging-public-group block, as the preceding comment explains.
- Items added outside of a group may have their value recalculated
- every time something new is added to this file.
- =============================================================== -->
-
</resources>
diff --git a/core/res/res/values/public-staging.xml b/core/res/res/values/public-staging.xml
new file mode 100644
index 000000000000..b985528aec1b
--- /dev/null
+++ b/core/res/res/values/public-staging.xml
@@ -0,0 +1,231 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Exposing a new resource:
+ To add a new entry, find the corresponding "staging-public-group" with the correct type for
+ your resource, and add a new entry to the BOTTOM of the list. This ensures that indexes
+ don't shift for previously added resources, and the new one will be appended to the end.
+
+ To add R.attr.exampleAttrName:
+ <staging-public-group type="attr" first-id="0x1ff0000">
+ <public name="previouslyAdded1"/>
+ <public name="previouslyAdded2"/>
+ <public name="exampleAttrName"/>
+ </staging-public-group>
+
+ Deleting a resource:
+ If a resource is no longer supported/used, it can be marked removed by renaming the
+ resource with a `removed_` prefix. This preserves the indexes of other resources so as not
+ to break apps that have compiled with their integers previously.
+
+ To remove R.attr.previouslyAdded2:
+ <staging-public-group type="attr" first-id="0x1ff0000">
+ <public name="previouslyAdded1"/>
+ <public name="removed_previouslyAdded2"/>
+ <public name="exampleAttrName"/>
+ </staging-public-group>
+
+ IMPORTANT: Deleting an entry is never allowed, even across branches or reverts. Please take
+ this into account before merging a change which edits this file. Small, isolated changes
+ which only add/remove resources is recommended to avoid reverts due to build/test failures.
+
+ Renaming a resource:
+ This is generally fine and can be done to the entry directly, with no other changes. But
+ note that any apps/tooling that resolve against resource names rather than IDs may break
+ as a result. This is uncommon, but not rare.
+
+ Finalizing a release's resources:
+ 1. $ANDROID_BUILD_TOP/frameworks/base/tools/aapt2/tools/finalize_res.py \
+ $ANDROID_BUILD_TOP/frameworks/base/core/res/res/values/public-staging.xml \
+ $ANDROID_BUILD_TOP/frameworks/base/core/res/res/values/public-final.xml
+ 2. Rename "NEXT" in the new public-staging.xml resources header to the next platform short
+ version code
+
+ Finalizing a release's resources (manually; only for reference):
+ 1. Delete all "staging-public-group" blocks for the release with no entries inside them
+ 2. Rename the remaining "staging-public-group" blocks for that release to
+ "staging-public-group-final"
+ 3. Cut them out this file and place at the bottom of public-final.xml; also move the
+ "Resources added in version ? of the platform" header
+ 4. Copy-paste all of the non-"removed_" resources outside of the staging blocks into being
+ siblings alongside them
+ 5. Assign them final public IDs in the form of
+ <public type="attr" name="exampleAttrName" id="0x0101088a" />
+ by finding the last ID for that type and incrementing the last 4 characters by 1 in
+ hexadecimal
+ 6. Back in this file, seed the next release's resources by adding "staging-public-group"
+ tags with their "first-id" value shifted by -0x00010000 from the lowest "first-id"
+ in the last used "staging-public-group-final"
+
+ Example:
+ Starting public-staging.xml:
+ <!\- ===============================================================
+ Resources added in version ? of the platform
+ =============================================================== -\>
+ <eat-comment />
+
+ <staging-public-group type="attr" first-id="0x01ff0000">
+ <public name="exampleAttr1"/>
+ <public name="removed_exampleAttr2"/>
+ <public name="exampleAttr3"/>
+ </staging-public-group>
+
+ <staging-public-group type="id" first-id="0x01fe0000">
+ </staging-public-group>
+
+ Resulting public-final.xml:
+ <!\- ===============================================================
+ Resources added in version ? of the platform
+ =============================================================== -\>
+ <eat-comment />
+
+ <staging-public-group-final type="attr" first-id="0x01ff0000">
+ <public name="exampleAttr1"/>
+ <public name="removed_exampleAttr2"/>
+ <public name="exampleAttr3"/>
+ </staging-public-group-final>
+
+ <public type="id" name="exampleAttr1" id="0x0101088a"/>
+ <public type="id" name="exampleAttr3" id="0x0101088b"/>
+
+ Resulting public-staging.xml:
+ <!\- ===============================================================
+ Resources added in version (? + 1) of the platform
+ =============================================================== -\>
+ <eat-comment />
+
+ <staging-public-group type="attr" first-id="0x01fd0000">
+ </staging-public-group>
+
+ <staging-public-group type="id" first-id="0x01fc0000">
+ </staging-public-group>
+-->
+<resources>
+
+ <!-- ===============================================================
+ Resources added in version T of the platform
+
+ NOTE: After this version of the platform is forked, changes cannot be made to the root
+ branch's groups for that release. Only merge changes to the forked platform branch.
+ =============================================================== -->
+ <eat-comment/>
+
+ <staging-public-group type="attr" first-id="0x01df0000">
+ <public name="sharedUserMaxSdkVersion" />
+ <public name="requiredSplitTypes" />
+ <public name="splitTypes" />
+ <public name="canDisplayOnRemoteDevices" />
+ <public name="supportedTypes" />
+ <public name="resetEnabledSettingsOnAppDataCleared" />
+ <public name="supportsStylusHandwriting" />
+ <public name="showClockAndComplications" />
+ <!-- @hide @SystemApi -->
+ <public name="gameSessionService" />
+ <public name="supportsBatteryGameMode" />
+ <public name="supportsPerformanceGameMode" />
+ <public name="allowGameAngleDriver" />
+ <public name="allowGameDownscaling" />
+ <public name="allowGameFpsOverride" />
+ <public name="localeConfig" />
+ <public name="showBackground" />
+ <public name="useTargetActivityForQuickAccess"/>
+ <public name="preferKeepClear" />
+ <public name="autoHandwritingEnabled" />
+ <public name="fromExtendLeft" />
+ <public name="fromExtendTop" />
+ <public name="fromExtendRight" />
+ <public name="fromExtendBottom" />
+ <public name="toExtendLeft" />
+ <public name="toExtendTop" />
+ <public name="toExtendRight" />
+ <public name="toExtendBottom" />
+ <public name="tileService" />
+ <public name="windowSplashScreenBehavior" />
+ <public name="allowUntrustedActivityEmbedding" />
+ <public name="knownActivityEmbeddingCerts" />
+ <public name="intro" />
+ <public name="enableOnBackInvokedCallback" />
+ <public name="supportsInlineSuggestionsWithTouchExploration" />
+ <public name="lineBreakStyle" />
+ <public name="lineBreakWordStyle" />
+ </staging-public-group>
+
+ <staging-public-group type="id" first-id="0x01de0000">
+ <public name="removed_accessibilityActionSwipeLeft" />
+ <public name="removed_accessibilityActionSwipeRight" />
+ <public name="removed_accessibilityActionSwipeUp" />
+ <public name="removed_accessibilityActionSwipeDown" />
+ <public name="accessibilityActionShowTextSuggestions" />
+ <public name="inputExtractAction" />
+ <public name="inputExtractAccessories" />
+ </staging-public-group>
+
+ <staging-public-group type="style" first-id="0x01dd0000">
+ <public name="TextAppearance.DeviceDefault.Headline" />
+ </staging-public-group>
+
+ <staging-public-group type="string" first-id="0x01dc0000">
+ <!-- @hide @SystemApi -->
+ <public name="config_systemSupervision" />
+ <!-- @hide @SystemApi -->
+ <public name="config_devicePolicyManagement" />
+ <!-- @hide @SystemApi -->
+ <public name="config_systemAppProtectionService" />
+ <!-- @hide @SystemApi @TestApi -->
+ <public name="config_systemAutomotiveCalendarSyncManager" />
+ <!-- @hide @SystemApi -->
+ <public name="config_defaultAutomotiveNavigation" />
+ <!-- @hide @SystemApi -->
+ <public name="safety_protection_display_text" />
+ </staging-public-group>
+
+ <staging-public-group type="dimen" first-id="0x01db0000">
+ </staging-public-group>
+
+ <staging-public-group type="color" first-id="0x01da0000">
+ </staging-public-group>
+
+ <staging-public-group type="array" first-id="0x01d90000">
+ <!-- @hide @SystemApi -->
+ <public name="config_optionalIpSecAlgorithms" />
+ </staging-public-group>
+
+ <staging-public-group type="drawable" first-id="0x01d80000">
+ <!-- @hide @SystemApi -->
+ <public name="ic_safety_protection" />
+ </staging-public-group>
+
+ <staging-public-group type="layout" first-id="0x01d70000">
+ </staging-public-group>
+
+ <staging-public-group type="anim" first-id="0x01d60000">
+ </staging-public-group>
+
+ <staging-public-group type="animator" first-id="0x01d50000">
+ </staging-public-group>
+
+ <staging-public-group type="interpolator" first-id="0x01d40000">
+ </staging-public-group>
+
+ <staging-public-group type="mipmap" first-id="0x01d30000">
+ </staging-public-group>
+
+ <staging-public-group type="integer" first-id="0x01d20000">
+ </staging-public-group>
+
+ <staging-public-group type="transition" first-id="0x01d10000">
+ </staging-public-group>
+
+ <staging-public-group type="raw" first-id="0x01d00000">
+ </staging-public-group>
+
+ <staging-public-group type="bool" first-id="0x01cf0000">
+ <!-- @hide @TestApi -->
+ <public name="config_preventImeStartupUnlessTextEditor" />
+ <!-- @hide @SystemApi -->
+ <public name="config_enableQrCodeScannerOnLockScreen" />
+ </staging-public-group>
+
+ <staging-public-group type="fraction" first-id="0x01ce0000">
+ </staging-public-group>
+
+</resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 34bd2fbad576..648073454f22 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -234,9 +234,9 @@
<!-- Displayed to tell the user that they should switch their network preference. -->
<string name="NetworkPreferenceSwitchSummary">Try changing preferred network. Tap to change.</string>
<!-- Displayed to tell the user that emergency calls might not be available. -->
- <string name="EmergencyCallWarningTitle">Emergency calling unavailable</string>
+ <string name="EmergencyCallWarningTitle">Emergency calls may be unavailable</string>
<!-- Displayed to tell the user that emergency calls might not be available. -->
- <string name="EmergencyCallWarningSummary">Can\u2019t make emergency calls over Wi\u2011Fi</string>
+ <string name="EmergencyCallWarningSummary"><xliff:g id="spn" example="Operator">%s</xliff:g> doesn\'t support emergency calls over Wi-Fi. Tap for details.</string>
<!-- Telephony notification channel name for a channel containing network alert notifications. -->
<string name="notification_channel_network_alert">Alerts</string>
@@ -1248,14 +1248,13 @@
Malicious apps may use this to erase or modify your call log.</string>
<!-- Title of the body sensors permission, listed so the user can decide whether to allow the application to access body sensor data. [CHAR LIMIT=80] -->
- <string name="permlab_bodySensors">access body sensors (like heart rate monitors)
- </string>
+ <string name="permlab_bodySensors">Access body sensor data, like heart rate, while in use</string>
<!-- Description of the body sensors permission, listed so the user can decide whether to allow the application to access data from body sensors. [CHAR LIMIT=NONE] -->
- <string name="permdesc_bodySensors" product="default">Access to data from body sensors such as heart rate, temperature, blood oxygen percentage, etc.</string>
+ <string name="permdesc_bodySensors" product="default">Allows the app to access body sensor data, such as heart rate, temperature, and blood oxygen percentage, while the app is in use.</string>
<!-- Title of the background body sensors permission, listed so the user can decide whether to allow the application to access body sensor data in the background. [CHAR LIMIT=80] -->
- <string name="permlab_bodySensors_background">access body sensors (like heart rate monitors) while in the background</string>
+ <string name="permlab_bodySensors_background">Access body sensor data, like heart rate, while in the background</string>
<!-- Description of the background body sensors permission, listed so the user can decide whether to allow the application to access data from body sensors in the background. [CHAR LIMIT=NONE] -->
- <string name="permdesc_bodySensors_background" product="default">Access to data from body sensors such as heart rate, temperature, blood oxygen percentage, etc. while in the background.</string>
+ <string name="permdesc_bodySensors_background" product="default">Allows the app to access body sensor data, such as heart rate, temperature, and blood oxygen percentage, while the app is in the background.</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_readCalendar">Read calendar events and details</string>
@@ -1919,9 +1918,9 @@
<string name="permdesc_readMediaVideo">Allows the app to read video files from your shared storage.</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. "shared storage" refers to a storage space on the device that all apps with this permission can read from. [CHAR LIMIT=none] -->
- <string name="permlab_readMediaImage">read image files from shared storage</string>
+ <string name="permlab_readMediaImages">read image files from shared storage</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. "shared storage" refers to a storage space on the device that all apps with this permission can read from. [CHAR LIMIT=none] -->
- <string name="permdesc_readMediaImage">Allows the app to read image files from your shared storage.</string>
+ <string name="permdesc_readMediaImages">Allows the app to read image files from your shared storage.</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. "shared storage" refers to a storage space on the device that all apps with this permission can write to. [CHAR LIMIT=none] -->
<string name="permlab_sdcardWrite">modify or delete the contents of your shared storage</string>
@@ -2415,7 +2414,7 @@
<!-- On the unlock pattern screen, shown at the top of the unlock screen to tell the user what to do. Below this text is the place for theu ser to draw the pattern. -->
<string name="lockscreen_pattern_instructions">Draw pattern to unlock</string>
<!-- Button at the bottom of the unlock screen to make an emergency call or access other emergency assistance functions. -->
- <string name="lockscreen_emergency_call">Emergency call</string>
+ <string name="lockscreen_emergency_call">Emergency</string>
<!-- Button at the bottom of the unlock screen that lets the user return to a call -->
<string name="lockscreen_return_to_call">Return to call</string>
<!-- Shown to confirm that the user entered their lock pattern correctly. -->
@@ -2989,9 +2988,6 @@
<!-- Displayed to the user to confirm that they have copied text from a web page to the clipboard. -->
<string name="text_copied">Text copied to clipboard.</string>
- <!-- Displayed to the user to confirm that they have copied text/images to the clipboard [CHAR LIMIT=NONE] -->
- <string name="copied">Copied</string>
-
<!-- Displayed to the user to inform them that an app has accessed clipboard data (pasted as in "copy and paste") that was copied from another app [CHAR LIMIT=50] -->
<string name="pasted_from_app"><xliff:g id="pasting_app_name" example="Gmail">%1$s</xliff:g> pasted from <xliff:g id="source_app_name" example="Chrome">%2$s</xliff:g></string>
@@ -4095,10 +4091,20 @@
<!-- Description of an application permission that lets it query all other packages. [CHAR LIMIT=NONE] -->
<string name="permdesc_queryAllPackages">Allows an app to see all installed packages.</string>
- <!-- Title of an application permission that lets it access SupplementalApis. [CHAR LIMIT=NONE] -->
- <string name="permlab_accessSupplementalApi">access SupplementalApis</string>
- <!-- Description of an application permission that lets it access SupplementalApis. [CHAR LIMIT=NONE]-->
- <string name="permdesc_accessSupplementalApi">Allows an application to access SupplementalApis.</string>
+ <!-- Title of an application permission that lets it access AdServices Topics API. [CHAR LIMIT=NONE] -->
+ <string name="permlab_accessAdServicesTopics">access AdServices Topics API</string>
+ <!-- Description of an application permission that lets it access AdServices Topics API. [CHAR LIMIT=NONE]-->
+ <string name="permdesc_accessAdServicesTopics">Allows an application to access AdServices Topics API.</string>
+
+ <!-- Title of an application permission that lets it access AdServices Attribution APIs. [CHAR LIMIT=NONE] -->
+ <string name="permlab_accessAdServicesAttribution">access AdServices Attribution APIs</string>
+ <!-- Description of an application permission that lets it access AdServices Attribution APIs. [CHAR LIMIT=NONE]-->
+ <string name="permdesc_accessAdServicesAttribution">Allows an application to access AdServices Attribution APIs.</string>
+
+ <!-- Title of an application permission that lets it access AdServices Custom Audiences API. [CHAR LIMIT=NONE] -->
+ <string name="permlab_accessAdServicesCustomAudiences">access AdServices Custom Audiences API</string>
+ <!-- Description of an application permission that lets it access AdServices Custom Audiences API. [CHAR LIMIT=NONE]-->
+ <string name="permdesc_accessAdServicesCustomAudiences">Allows an application to access AdServices Custom Audiences API.</string>
<!-- Shown in the tutorial for tap twice for zoom control. -->
<string name="tutorial_double_tap_to_zoom_message_short">Tap twice for zoom control</string>
@@ -5721,16 +5727,17 @@
<!-- Title for the harmful app warning dialog. [CHAR LIMIT=40] -->
<string name="harmful_app_warning_title">Harmful app detected</string>
- <!-- Title for the log access confirmation dialog. [CHAR LIMIT=40] -->
- <string name="log_access_confirmation_title">System log access request</string>
+ <!-- Title for the log access confirmation dialog. [CHAR LIMIT=NONE] -->
+ <string name="log_access_confirmation_title">Allow <xliff:g id="log_access_app_name" example="Example App">%s</xliff:g> to access all device logs?</string>
<!-- Label for the allow button on the log access confirmation dialog. [CHAR LIMIT=20] -->
<string name="log_access_confirmation_allow">Only this time</string>
<!-- Label for the deny button on the log access confirmation dialog. [CHAR LIMIT=20] -->
<string name="log_access_confirmation_deny">Don\u2019t allow</string>
<!-- Content for the log access confirmation dialog. [CHAR LIMIT=NONE]-->
- <string name="log_access_confirmation_body"><xliff:g id="log_access_app_name" example="Example App">%s</xliff:g> requests system logs for functional debugging.
- These logs might contain information that apps and services on your device have written.</string>
+ <string name="log_access_confirmation_body">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 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>
<!-- Privacy notice do not show [CHAR LIMIT=20] -->
<string name="log_access_do_not_show_again">Don\u2019t show again</string>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 9553f95fe5c9..7a9f520b4d3c 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -1499,5 +1499,43 @@ please see styles_device_defaults.xml.
<item name="textColor">#555555</item>
</style>
+ <!-- The style for log access consent text -->
+ <style name="AllowLogAccess">
+ <item name="android:layout_width">332dp</item>
+ <item name="android:textSize">24sp</item>
+ <item name="android:textColor">@android:color/system_neutral1_900</item>
+ <item name="android:fontFamily">google-sans</item>
+ </style>
+
+ <style name="PrimaryAllowLogAccess">
+ <item name="android:layout_width">332dp</item>
+ <item name="android:textSize">14sp</item>
+ <item name="android:textColor">@android:color/system_neutral1_900</item>
+ <item name="android:fontFamily">google-sans</item>
+ </style>
+
+ <style name="PermissionGrantButtonTop"
+ parent="@android:style/Widget.DeviceDefault.Button.Borderless.Colored">
+ <item name="android:layout_width">332dp</item>
+ <item name="android:layout_height">56dp</item>
+ <item name="android:layout_marginTop">2dp</item>
+ <item name="android:layout_marginBottom">2dp</item>
+ <item name="android:fontFamily">google-sans-medium</item>
+ <item name="android:textSize">14sp</item>
+ <item name="android:textColor">@android:color/system_neutral1_900</item>
+ <item name="android:background">@drawable/grant_permissions_buttons_top</item>
+ </style>
+
+ <style name="PermissionGrantButtonBottom"
+ parent="@android:style/Widget.DeviceDefault.Button.Borderless.Colored">
+ <item name="android:layout_width">332dp</item>
+ <item name="android:layout_height">56dp</item>
+ <item name="android:layout_marginTop">2dp</item>
+ <item name="android:layout_marginBottom">2dp</item>
+ <item name="android:fontFamily">google-sans-medium</item>
+ <item name="android:textSize">14sp</item>
+ <item name="android:textColor">@android:color/system_neutral1_900</item>
+ <item name="android:background">@drawable/grant_permissions_buttons_bottom</item>
+ </style>
</resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index df3cbf34c8f0..595433ecf523 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1325,6 +1325,7 @@
<java-symbol type="dimen" name="lock_pattern_dot_line_width" />
<java-symbol type="dimen" name="lock_pattern_dot_size" />
<java-symbol type="dimen" name="lock_pattern_dot_size_activated" />
+ <java-symbol type="dimen" name="lock_pattern_dot_hit_factor" />
<java-symbol type="dimen" name="lock_pattern_fade_away_gradient_width" />
<java-symbol type="drawable" name="clock_dial" />
<java-symbol type="drawable" name="clock_hand_hour" />
@@ -2268,6 +2269,7 @@
<java-symbol type="string" name="config_notificationAccessConfirmationActivity" />
<java-symbol type="bool" name="config_killableInputMethods" />
<java-symbol type="bool" name="config_preventImeStartupUnlessTextEditor" />
+ <java-symbol type="array" name="config_nonPreemptibleInputMethods" />
<java-symbol type="layout" name="resolver_list" />
<java-symbol type="id" name="resolver_list" />
@@ -3677,7 +3679,7 @@
<java-symbol type="string" name="notification_channel_network_status" />
<java-symbol type="string" name="notification_channel_network_alerts" />
<java-symbol type="string" name="notification_channel_network_available" />
- <java-symbol type="string" name="config_defaultCloudSearchService" />
+ <java-symbol type="array" name="config_defaultCloudSearchServices" />
<java-symbol type="string" name="notification_channel_vpn" />
<java-symbol type="string" name="notification_channel_device_admin" />
<java-symbol type="string" name="notification_channel_alerts" />
@@ -3883,6 +3885,10 @@
<java-symbol type="string" name="log_access_confirmation_deny" />
<java-symbol type="string" name="log_access_confirmation_title" />
<java-symbol type="string" name="log_access_confirmation_body" />
+ <java-symbol type="layout" name="log_access_user_consent_dialog_permission" />
+ <java-symbol type="id" name="log_access_dialog_title" />
+ <java-symbol type="id" name="log_access_dialog_allow_button" />
+ <java-symbol type="id" name="log_access_dialog_deny_button" />
<java-symbol type="string" name="config_defaultAssistantAccessComponent" />
@@ -4765,5 +4771,6 @@
<java-symbol type="integer" name="config_bg_current_drain_exempted_types" />
<java-symbol type="bool" name="config_bg_current_drain_high_threshold_by_bg_location" />
<java-symbol type="drawable" name="ic_swap_horiz" />
+ <java-symbol type="bool" name="config_notificationForceUserSetOnUpgrade" />
</resources>
diff --git a/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerData.java b/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerData.java
index 6a53f6843d48..19bb718578a0 100644
--- a/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerData.java
+++ b/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerData.java
@@ -188,6 +188,9 @@ public class BatteryConsumerData {
case BatteryConsumer.PROCESS_STATE_FOREGROUND_SERVICE:
label = "FGS";
break;
+ case BatteryConsumer.PROCESS_STATE_CACHED:
+ label = "cached";
+ break;
default:
continue;
}
diff --git a/core/tests/batterystatstests/BatteryUsageStatsProtoTests/src/com/android/internal/os/BatteryUsageStatsPulledTest.java b/core/tests/batterystatstests/BatteryUsageStatsProtoTests/src/com/android/internal/os/BatteryUsageStatsPulledTest.java
index 23b12cf3ea4b..fd08e3c789f7 100644
--- a/core/tests/batterystatstests/BatteryUsageStatsProtoTests/src/com/android/internal/os/BatteryUsageStatsPulledTest.java
+++ b/core/tests/batterystatstests/BatteryUsageStatsProtoTests/src/com/android/internal/os/BatteryUsageStatsPulledTest.java
@@ -242,13 +242,17 @@ public class BatteryUsageStatsPulledTest {
BatteryConsumer.PROCESS_STATE_BACKGROUND);
final BatteryConsumer.Key keyFgs = uidBuilder.getKey(BatteryConsumer.POWER_COMPONENT_CPU,
BatteryConsumer.PROCESS_STATE_FOREGROUND_SERVICE);
+ final BatteryConsumer.Key keyCached = uidBuilder.getKey(BatteryConsumer.POWER_COMPONENT_CPU,
+ BatteryConsumer.PROCESS_STATE_CACHED);
uidBuilder.setConsumedPower(keyFg, 9100, BatteryConsumer.POWER_MODEL_POWER_PROFILE)
.setUsageDurationMillis(keyFg, 8100)
.setConsumedPower(keyBg, 9200, BatteryConsumer.POWER_MODEL_MEASURED_ENERGY)
.setUsageDurationMillis(keyBg, 8200)
.setConsumedPower(keyFgs, 9300, BatteryConsumer.POWER_MODEL_MEASURED_ENERGY)
- .setUsageDurationMillis(keyFgs, 8300);
+ .setUsageDurationMillis(keyFgs, 8300)
+ .setConsumedPower(keyCached, 9400, BatteryConsumer.POWER_MODEL_MEASURED_ENERGY)
+ .setUsageDurationMillis(keyFgs, 8400);
builder.getOrCreateUidBatteryConsumerBuilder(batteryStatsUid1)
.setPackageWithHighestDrain("myPackage1")
diff --git a/core/tests/coretests/res/raw/obb_enc_file100_orig1.obb b/core/tests/coretests/res/raw/obb_enc_file100_orig1.obb
deleted file mode 100644
index 373b8e4bd01f..000000000000
--- a/core/tests/coretests/res/raw/obb_enc_file100_orig1.obb
+++ /dev/null
Binary files differ
diff --git a/core/tests/coretests/res/raw/obb_enc_file100_orig3.obb b/core/tests/coretests/res/raw/obb_enc_file100_orig3.obb
deleted file mode 100644
index aa531d8b35bd..000000000000
--- a/core/tests/coretests/res/raw/obb_enc_file100_orig3.obb
+++ /dev/null
Binary files differ
diff --git a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
index 5c9044c56f95..beadc4464516 100644
--- a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
@@ -424,6 +424,7 @@ public class TransactionParcelTests {
@Override
public void bindApplication(String s, ApplicationInfo applicationInfo,
+ String sdkSandboxClientAppPackage,
ProviderInfoList list, ComponentName componentName, ProfilerInfo profilerInfo,
Bundle bundle, IInstrumentationWatcher iInstrumentationWatcher,
IUiAutomationConnection iUiAutomationConnection, int i, boolean b, boolean b1,
diff --git a/core/tests/coretests/src/android/content/pm/CrossProfileAppsTest.java b/core/tests/coretests/src/android/content/pm/CrossProfileAppsTest.java
index fa657f7a8928..5e076076d2f4 100644
--- a/core/tests/coretests/src/android/content/pm/CrossProfileAppsTest.java
+++ b/core/tests/coretests/src/android/content/pm/CrossProfileAppsTest.java
@@ -27,6 +27,7 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.admin.DevicePolicyManager;
+import android.app.admin.DevicePolicyResourcesManager;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
@@ -66,6 +67,8 @@ public class CrossProfileAppsTest {
@Mock
private DevicePolicyManager mDevicePolicyManager;
@Mock
+ private DevicePolicyResourcesManager mDevicePolicyResourcesManager;
+ @Mock
private ICrossProfileApps mService;
@Mock
private Resources mResources;
@@ -89,6 +92,7 @@ public class CrossProfileAppsTest {
Context.DEVICE_POLICY_SERVICE);
when(mContext.getSystemService(Context.DEVICE_POLICY_SERVICE)).thenReturn(
mDevicePolicyManager);
+ when(mDevicePolicyManager.getResources()).thenReturn(mDevicePolicyResourcesManager);
when(mContext.getPackageManager()).thenReturn(mPackageManager);
}
@@ -113,7 +117,7 @@ public class CrossProfileAppsTest {
setValidTargetProfile(MANAGED_PROFILE);
mCrossProfileApps.getProfileSwitchingLabel(MANAGED_PROFILE);
- verify(mDevicePolicyManager).getString(eq(SWITCH_TO_WORK_LABEL), any());
+ verify(mDevicePolicyResourcesManager).getString(eq(SWITCH_TO_WORK_LABEL), any());
}
@Test
@@ -121,7 +125,7 @@ public class CrossProfileAppsTest {
setValidTargetProfile(PERSONAL_PROFILE);
mCrossProfileApps.getProfileSwitchingLabel(PERSONAL_PROFILE);
- verify(mDevicePolicyManager).getString(eq(SWITCH_TO_PERSONAL_LABEL), any());
+ verify(mDevicePolicyResourcesManager).getString(eq(SWITCH_TO_PERSONAL_LABEL), any());
}
@Test(expected = SecurityException.class)
diff --git a/core/tests/coretests/src/android/graphics/drawable/IconTest.java b/core/tests/coretests/src/android/graphics/drawable/IconTest.java
index 2bdcc284154b..75390a282af9 100644
--- a/core/tests/coretests/src/android/graphics/drawable/IconTest.java
+++ b/core/tests/coretests/src/android/graphics/drawable/IconTest.java
@@ -180,6 +180,61 @@ public class IconTest extends AndroidTestCase {
}
}
+ /**
+ * Icon resource test that ensures we can load and draw non-bitmaps. (In this case,
+ * stat_sys_adb is assumed, and asserted, to be a vector drawable.)
+ */
+ @SmallTest
+ public void testWithStatSysAdbResource() throws Exception {
+ // establish reference bitmap
+ final float dp = getContext().getResources().getDisplayMetrics().density;
+ final int stat_sys_adb_width = (int) (24 * dp);
+ final int stat_sys_adb_height = (int) (24 * dp);
+
+ final Drawable stat_sys_adb = getContext()
+ .getDrawable(com.android.internal.R.drawable.stat_sys_adb);
+ if (!(stat_sys_adb instanceof VectorDrawable)) {
+ fail("stat_sys_adb is a " + stat_sys_adb.toString()
+ + ", not a VectorDrawable; stat_sys_adb malformed");
+ }
+
+ if (stat_sys_adb.getIntrinsicWidth() != stat_sys_adb_width) {
+ fail("intrinsic width of stat_sys_adb is not 24dp; stat_sys_adb malformed");
+ }
+ if (stat_sys_adb.getIntrinsicHeight() != stat_sys_adb_height) {
+ fail("intrinsic height of stat_sys_adb is not 24dp; stat_sys_adb malformed");
+ }
+ final Bitmap referenceBitmap = Bitmap.createBitmap(
+ stat_sys_adb_width,
+ stat_sys_adb_height,
+ Bitmap.Config.ARGB_8888);
+ stat_sys_adb.setBounds(0, 0, stat_sys_adb_width, stat_sys_adb_height);
+ stat_sys_adb.draw(new Canvas(referenceBitmap));
+
+ final Icon im1 = Icon.createWithResource(getContext(),
+ com.android.internal.R.drawable.stat_sys_adb);
+ final Drawable draw1 = im1.loadDrawable(getContext());
+
+ assertEquals(stat_sys_adb.getIntrinsicWidth(), draw1.getIntrinsicWidth());
+ assertEquals(stat_sys_adb.getIntrinsicHeight(), draw1.getIntrinsicHeight());
+ assertEquals(im1.getResId(), com.android.internal.R.drawable.stat_sys_adb);
+
+ final Bitmap test1 = Bitmap.createBitmap(
+ draw1.getIntrinsicWidth(),
+ draw1.getIntrinsicHeight(),
+ Bitmap.Config.ARGB_8888);
+ draw1.setBounds(0, 0, test1.getWidth(), test1.getHeight());
+ draw1.draw(new Canvas(test1));
+
+ final File dir = getContext().getExternalFilesDir(null);
+ test1.compress(Bitmap.CompressFormat.PNG, 100,
+ new FileOutputStream(new File(dir, "testWithVectorDrawableResource-test.png")));
+ if (!equalBitmaps(referenceBitmap, test1)) {
+ findBitmapDifferences(referenceBitmap, test1);
+ fail("testWithFile: file1 differs, check " + dir);
+ }
+ }
+
@SmallTest
public void testWithFile() throws Exception {
final Bitmap bit1 = ((BitmapDrawable) getContext().getDrawable(R.drawable.landscape))
diff --git a/core/tests/coretests/src/android/net/SntpClientTest.java b/core/tests/coretests/src/android/net/SntpClientTest.java
index ba7df1e218d9..267fc2b636d6 100644
--- a/core/tests/coretests/src/android/net/SntpClientTest.java
+++ b/core/tests/coretests/src/android/net/SntpClientTest.java
@@ -295,7 +295,8 @@ public class SntpClientTest {
@Test
public void testDnsResolutionFailure() throws Exception {
- assertFalse(mClient.requestTime("ntp.server.doesnotexist.example", 5000, mNetwork));
+ assertFalse(mClient.requestTime("ntp.server.doesnotexist.example",
+ SntpClient.STANDARD_NTP_PORT, 5000, mNetwork));
}
@Test
diff --git a/core/tests/coretests/src/android/os/IpcDataCacheTest.java b/core/tests/coretests/src/android/os/IpcDataCacheTest.java
new file mode 100644
index 000000000000..fa7d7214d289
--- /dev/null
+++ b/core/tests/coretests/src/android/os/IpcDataCacheTest.java
@@ -0,0 +1,312 @@
+/*
+ * 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.os;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertSame;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.After;
+import org.junit.Test;
+
+/**
+ * Test for verifying the behavior of {@link IpcDataCache}. This test does
+ * not use any actual binder calls - it is entirely self-contained. This test also relies
+ * on the test mode of {@link IpcDataCache} because Android SELinux rules do
+ * not grant test processes the permission to set system properties.
+ * <p>
+ * Build/Install/Run:
+ * atest FrameworksCoreTests:IpcDataCacheTest
+ */
+@SmallTest
+public class IpcDataCacheTest {
+
+ // Configuration for creating caches
+ private static final String MODULE = IpcDataCache.MODULE_TEST;
+ private static final String API = "testApi";
+
+ // This class is a proxy for binder calls. It contains a counter that increments
+ // every time the class is queried.
+ private static class ServerProxy {
+ // The number of times this class was queried.
+ private int mCount = 0;
+
+ // A single query. The key behavior is that the query count is incremented.
+ boolean query(int x) {
+ mCount++;
+ return value(x);
+ }
+
+ // Return the expected value of an input, without incrementing the query count.
+ boolean value(int x) {
+ return x % 3 == 0;
+ }
+
+ // Verify the count.
+ void verify(int x) {
+ assertEquals(x, mCount);
+ }
+ }
+
+ // The functions for querying the server.
+ private static class ServerQuery
+ extends IpcDataCache.QueryHandler<Integer, Boolean> {
+ private final ServerProxy mServer;
+
+ ServerQuery(ServerProxy server) {
+ mServer = server;
+ }
+
+ @Override
+ public Boolean apply(Integer x) {
+ return mServer.query(x);
+ }
+ @Override
+ public boolean shouldBypassCache(Integer x) {
+ return x % 13 == 0;
+ }
+ }
+
+ // Clear the test mode after every test, in case this process is used for other
+ // tests. This also resets the test property map.
+ @After
+ public void tearDown() throws Exception {
+ IpcDataCache.setTestMode(false);
+ }
+
+ // This test is disabled pending an sepolicy change that allows any app to set the
+ // test property.
+ @Test
+ public void testBasicCache() {
+
+ // A stand-in for the binder. The test verifies that calls are passed through to
+ // this class properly.
+ ServerProxy tester = new ServerProxy();
+
+ // Create a cache that uses simple arithmetic to computer its values.
+ IpcDataCache<Integer, Boolean> testCache =
+ new IpcDataCache<>(4, MODULE, API, "testCache1",
+ new ServerQuery(tester));
+
+ IpcDataCache.setTestMode(true);
+ testCache.testPropertyName();
+
+ tester.verify(0);
+ assertEquals(tester.value(3), testCache.query(3));
+ tester.verify(1);
+ assertEquals(tester.value(3), testCache.query(3));
+ tester.verify(2);
+ testCache.invalidateCache();
+ assertEquals(tester.value(3), testCache.query(3));
+ tester.verify(3);
+ assertEquals(tester.value(5), testCache.query(5));
+ tester.verify(4);
+ assertEquals(tester.value(5), testCache.query(5));
+ tester.verify(4);
+ assertEquals(tester.value(3), testCache.query(3));
+ tester.verify(4);
+
+ // Invalidate the cache, and verify that the next read on 3 goes to the server.
+ testCache.invalidateCache();
+ assertEquals(tester.value(3), testCache.query(3));
+ tester.verify(5);
+
+ // Test bypass. The query for 13 always bypasses the cache.
+ assertEquals(tester.value(12), testCache.query(12));
+ assertEquals(tester.value(13), testCache.query(13));
+ assertEquals(tester.value(14), testCache.query(14));
+ tester.verify(8);
+ assertEquals(tester.value(12), testCache.query(12));
+ assertEquals(tester.value(13), testCache.query(13));
+ assertEquals(tester.value(14), testCache.query(14));
+ tester.verify(9);
+ }
+
+ @Test
+ public void testDisableCache() {
+
+ // A stand-in for the binder. The test verifies that calls are passed through to
+ // this class properly.
+ ServerProxy tester = new ServerProxy();
+
+ // Three caches, all using the same system property but one uses a different name.
+ IpcDataCache<Integer, Boolean> cache1 =
+ new IpcDataCache<>(4, MODULE, API, "cacheA",
+ new ServerQuery(tester));
+ IpcDataCache<Integer, Boolean> cache2 =
+ new IpcDataCache<>(4, MODULE, API, "cacheA",
+ new ServerQuery(tester));
+ IpcDataCache<Integer, Boolean> cache3 =
+ new IpcDataCache<>(4, MODULE, API, "cacheB",
+ new ServerQuery(tester));
+
+ // Caches are enabled upon creation.
+ assertEquals(false, cache1.getDisabledState());
+ assertEquals(false, cache2.getDisabledState());
+ assertEquals(false, cache3.getDisabledState());
+
+ // Disable the cache1 instance. Only cache1 is disabled
+ cache1.disableInstance();
+ assertEquals(true, cache1.getDisabledState());
+ assertEquals(false, cache2.getDisabledState());
+ assertEquals(false, cache3.getDisabledState());
+
+ // Disable cache1. This will disable cache1 and cache2 because they share the
+ // same name. cache3 has a different name and will not be disabled.
+ cache1.disableForCurrentProcess();
+ assertEquals(true, cache1.getDisabledState());
+ assertEquals(true, cache2.getDisabledState());
+ assertEquals(false, cache3.getDisabledState());
+
+ // Create a new cache1. Verify that the new instance is disabled.
+ cache1 = new IpcDataCache<>(4, MODULE, API, "cacheA",
+ new ServerQuery(tester));
+ assertEquals(true, cache1.getDisabledState());
+
+ // Remove the record of caches being locally disabled. This is a clean-up step.
+ cache1.forgetDisableLocal();
+ assertEquals(true, cache1.getDisabledState());
+ assertEquals(true, cache2.getDisabledState());
+ assertEquals(false, cache3.getDisabledState());
+
+ // Create a new cache1. Verify that the new instance is not disabled.
+ cache1 = new IpcDataCache<>(4, MODULE, API, "cacheA",
+ new ServerQuery(tester));
+ assertEquals(false, cache1.getDisabledState());
+ }
+
+ private static class TestQuery
+ extends IpcDataCache.QueryHandler<Integer, String> {
+
+ private int mRecomputeCount = 0;
+
+ @Override
+ public String apply(Integer qv) {
+ mRecomputeCount += 1;
+ return "foo" + qv.toString();
+ }
+
+ int getRecomputeCount() {
+ return mRecomputeCount;
+ }
+ }
+
+ private static class TestCache extends IpcDataCache<Integer, String> {
+ private final TestQuery mQuery;
+
+ TestCache() {
+ this(MODULE, API);
+ }
+
+ TestCache(String module, String api) {
+ this(module, api, new TestQuery());
+ }
+
+ TestCache(String module, String api, TestQuery query) {
+ super(4, module, api, "testCache7", query);
+ mQuery = query;
+ setTestMode(true);
+ testPropertyName();
+ }
+
+ int getRecomputeCount() {
+ return mQuery.getRecomputeCount();
+ }
+ }
+
+ @Test
+ public void testCacheRecompute() {
+ TestCache cache = new TestCache();
+ cache.invalidateCache();
+ assertEquals(cache.isDisabled(), false);
+ assertEquals("foo5", cache.query(5));
+ assertEquals(1, cache.getRecomputeCount());
+ assertEquals("foo5", cache.query(5));
+ assertEquals(1, cache.getRecomputeCount());
+ assertEquals("foo6", cache.query(6));
+ assertEquals(2, cache.getRecomputeCount());
+ cache.invalidateCache();
+ assertEquals("foo5", cache.query(5));
+ assertEquals("foo5", cache.query(5));
+ assertEquals(3, cache.getRecomputeCount());
+ // Invalidate the cache with a direct call to the property.
+ IpcDataCache.invalidateCache(MODULE, API);
+ assertEquals("foo5", cache.query(5));
+ assertEquals("foo5", cache.query(5));
+ assertEquals(4, cache.getRecomputeCount());
+ }
+
+ @Test
+ public void testCacheInitialState() {
+ TestCache cache = new TestCache();
+ assertEquals("foo5", cache.query(5));
+ assertEquals("foo5", cache.query(5));
+ assertEquals(2, cache.getRecomputeCount());
+ cache.invalidateCache();
+ assertEquals("foo5", cache.query(5));
+ assertEquals("foo5", cache.query(5));
+ assertEquals(3, cache.getRecomputeCount());
+ }
+
+ @Test
+ public void testCachePropertyUnset() {
+ final String UNSET_API = "otherApi";
+ TestCache cache = new TestCache(MODULE, UNSET_API);
+ assertEquals("foo5", cache.query(5));
+ assertEquals("foo5", cache.query(5));
+ assertEquals(2, cache.getRecomputeCount());
+ }
+
+ @Test
+ public void testCacheDisableState() {
+ TestCache cache = new TestCache();
+ assertEquals("foo5", cache.query(5));
+ assertEquals("foo5", cache.query(5));
+ assertEquals(2, cache.getRecomputeCount());
+ cache.invalidateCache();
+ assertEquals("foo5", cache.query(5));
+ assertEquals("foo5", cache.query(5));
+ assertEquals(3, cache.getRecomputeCount());
+ cache.disableSystemWide();
+ assertEquals("foo5", cache.query(5));
+ assertEquals("foo5", cache.query(5));
+ assertEquals(5, cache.getRecomputeCount());
+ cache.invalidateCache(); // Should not reenable
+ assertEquals("foo5", cache.query(5));
+ assertEquals("foo5", cache.query(5));
+ assertEquals(7, cache.getRecomputeCount());
+ }
+
+ @Test
+ public void testLocalProcessDisable() {
+ TestCache cache = new TestCache();
+ assertEquals(cache.isDisabled(), false);
+ cache.invalidateCache();
+ assertEquals("foo5", cache.query(5));
+ assertEquals(1, cache.getRecomputeCount());
+ assertEquals("foo5", cache.query(5));
+ assertEquals(1, cache.getRecomputeCount());
+ assertEquals(cache.isDisabled(), false);
+ cache.disableForCurrentProcess();
+ assertEquals(cache.isDisabled(), true);
+ assertEquals("foo5", cache.query(5));
+ assertEquals("foo5", cache.query(5));
+ assertEquals(3, cache.getRecomputeCount());
+ }
+}
diff --git a/core/tests/coretests/src/android/os/storage/StorageManagerBaseTest.java b/core/tests/coretests/src/android/os/storage/StorageManagerBaseTest.java
index e6660f32f817..d01d29bda3d6 100644
--- a/core/tests/coretests/src/android/os/storage/StorageManagerBaseTest.java
+++ b/core/tests/coretests/src/android/os/storage/StorageManagerBaseTest.java
@@ -55,11 +55,7 @@ public class StorageManagerBaseTest extends InstrumentationTestCase {
protected static String OBB_FILE_1_CONTENTS_1 = "OneToOneThousandInts.bin";
protected static String OBB_FILE_2 = "obb_file2.obb";
protected static String OBB_FILE_3 = "obb_file3.obb";
- protected static String OBB_FILE_1_PASSWORD = "password1";
- protected static String OBB_FILE_1_ENCRYPTED = "obb_enc_file100_orig1.obb";
protected static String OBB_FILE_2_UNSIGNED = "obb_file2_nosign.obb";
- protected static String OBB_FILE_3_PASSWORD = "password3";
- protected static String OBB_FILE_3_ENCRYPTED = "obb_enc_file100_orig3.obb";
protected static String OBB_FILE_3_BAD_PACKAGENAME = "obb_file3_bad_packagename.obb";
protected static boolean FORCE = true;
@@ -227,22 +223,21 @@ public class StorageManagerBaseTest extends InstrumentationTestCase {
* Mounts an OBB file
*
* @param obbFilePath The full path to the OBB file to mount
- * @param key (optional) The key to use to unencrypt the OBB; pass null for no encryption
* @param expectedState The expected state resulting from trying to mount the OBB
* @return A {@link String} representing the normalized path to OBB file that was mounted
*/
- protected String mountObb(String obbFilePath, String key, int expectedState) {
- return doMountObb(obbFilePath, key, expectedState);
+ protected String mountObb(String obbFilePath, int expectedState) {
+ return doMountObb(obbFilePath, expectedState);
}
/**
- * Mounts an OBB file with default options (no encryption, mounting succeeds)
+ * Mounts an OBB file with default options.
*
* @param obbFilePath The full path to the OBB file to mount
* @return A {@link String} representing the normalized path to OBB file that was mounted
*/
protected String mountObb(String obbFilePath) {
- return doMountObb(obbFilePath, null, OnObbStateChangeListener.MOUNTED);
+ return doMountObb(obbFilePath, OnObbStateChangeListener.MOUNTED);
}
/**
@@ -279,13 +274,13 @@ public class StorageManagerBaseTest extends InstrumentationTestCase {
* @return true if the listener was signaled of a state change by the system; else a fail()
* is triggered if we timed out
*/
- protected String doMountObb_noThrow(String obbFilePath, String key, int expectedState) {
- Log.i(LOG_TAG, "doMountObb() on " + obbFilePath + " using key: " + key);
+ protected String doMountObb_noThrow(String obbFilePath, int expectedState) {
+ Log.i(LOG_TAG, "doMountObb() on " + obbFilePath);
assertTrue ("Null path was passed in for OBB file!", obbFilePath != null);
assertTrue ("Null path was passed in for OBB file!", obbFilePath != null);
ObbListener obbListener = new ObbListener();
- boolean success = mSm.mountObb(obbFilePath, key, obbListener);
+ boolean success = mSm.mountObb(obbFilePath, null, obbListener);
success &= obbFilePath.equals(doWaitForObbStateChange(obbListener));
success &= (expectedState == obbListener.state());
@@ -307,17 +302,16 @@ public class StorageManagerBaseTest extends InstrumentationTestCase {
* Mounts an OBB file without throwing and synchronously waits for it to finish mounting
*
* @param obbFilePath The full path to the OBB file to mount
- * @param key (optional) The key to use to unencrypt the OBB; pass null for no encryption
* @param expectedState The expected state resulting from trying to mount the OBB
* @return A {@link String} representing the actual normalized path to OBB file that was
* mounted, or null if the mounting failed
*/
- protected String doMountObb(String obbFilePath, String key, int expectedState) {
- Log.i(LOG_TAG, "doMountObb() on " + obbFilePath + " using key: " + key);
+ protected String doMountObb(String obbFilePath, int expectedState) {
+ Log.i(LOG_TAG, "doMountObb() on " + obbFilePath);
assertTrue ("Null path was passed in for OBB file!", obbFilePath != null);
ObbListener obbListener = new ObbListener();
- assertTrue("mountObb call failed", mSm.mountObb(obbFilePath, key, obbListener));
+ assertTrue("mountObb call failed", mSm.mountObb(obbFilePath, null, obbListener));
assertTrue("Failed to get OBB mount status change for file: " + obbFilePath,
doWaitForObbStateChange(obbListener));
assertEquals("OBB mount state not what was expected!", expectedState,
diff --git a/core/tests/coretests/src/android/os/storage/StorageManagerIntegrationTest.java b/core/tests/coretests/src/android/os/storage/StorageManagerIntegrationTest.java
index 62f2ac28a601..ecd2f76a5160 100644
--- a/core/tests/coretests/src/android/os/storage/StorageManagerIntegrationTest.java
+++ b/core/tests/coretests/src/android/os/storage/StorageManagerIntegrationTest.java
@@ -83,58 +83,6 @@ public class StorageManagerIntegrationTest extends StorageManagerBaseTest {
}
/**
- * Tests mounting a single encrypted OBB file and verifies its contents.
- */
- @LargeTest
- public void testMountSingleEncryptedObb() throws Exception {
- final File file = createObbFile(OBB_FILE_3_ENCRYPTED, R.raw.obb_enc_file100_orig3);
- String filePath = file.getAbsolutePath();
- mountObb(filePath, OBB_FILE_3_PASSWORD, OnObbStateChangeListener.MOUNTED);
- verifyObb3Contents(filePath);
- unmountObb(filePath, DONT_FORCE);
- }
-
- /**
- * Tests mounting a single encrypted OBB file using an invalid password.
- */
- @LargeTest
- public void testMountSingleEncryptedObbInvalidPassword() throws Exception {
- final File file = createObbFile("bad password@$%#@^*(!&)", R.raw.obb_enc_file100_orig3);
- String filePath = file.getAbsolutePath();
- mountObb(filePath, OBB_FILE_1_PASSWORD, OnObbStateChangeListener.ERROR_COULD_NOT_MOUNT);
- }
-
- /**
- * Tests simultaneously mounting 2 encrypted OBBs with different keys and verifies contents.
- */
- @LargeTest
- public void testMountTwoEncryptedObb() throws Exception {
- File file3 = null;
- File file1 = null;
- try {
- file3 = createObbFile(OBB_FILE_3_ENCRYPTED, R.raw.obb_enc_file100_orig3);
- String filePath3 = file3.getAbsolutePath();
- mountObb(filePath3, OBB_FILE_3_PASSWORD, OnObbStateChangeListener.MOUNTED);
- verifyObb3Contents(filePath3);
-
- file1 = createObbFile(OBB_FILE_1_ENCRYPTED, R.raw.obb_enc_file100_orig1);
- String filePath1 = file1.getAbsolutePath();
- mountObb(filePath1, OBB_FILE_1_PASSWORD, OnObbStateChangeListener.MOUNTED);
- verifyObb1Contents(filePath1);
-
- unmountObb(filePath3, DONT_FORCE);
- unmountObb(filePath1, DONT_FORCE);
- } finally {
- if (file3 != null) {
- file3.delete();
- }
- if (file1 != null) {
- file1.delete();
- }
- }
- }
-
- /**
* Tests mounting a single OBB that isn't signed.
*/
@LargeTest
@@ -142,7 +90,7 @@ public class StorageManagerIntegrationTest extends StorageManagerBaseTest {
final File file = createObbFile(OBB_FILE_2_UNSIGNED, R.raw.obb_file2_nosign);
String filePath = file.getAbsolutePath();
try {
- mountObb(filePath, OBB_FILE_2_UNSIGNED, OnObbStateChangeListener.ERROR_INTERNAL);
+ mountObb(filePath, OnObbStateChangeListener.ERROR_INTERNAL);
fail("mountObb should've failed with an exception");
} catch (IllegalArgumentException e) {
// Expected
@@ -156,8 +104,7 @@ public class StorageManagerIntegrationTest extends StorageManagerBaseTest {
public void testMountBadPackageNameObb() throws Exception {
final File file = createObbFile(OBB_FILE_3_BAD_PACKAGENAME, R.raw.obb_file3_bad_packagename);
String filePath = file.getAbsolutePath();
- mountObb(filePath, OBB_FILE_3_BAD_PACKAGENAME,
- OnObbStateChangeListener.ERROR_PERMISSION_DENIED);
+ mountObb(filePath, OnObbStateChangeListener.ERROR_PERMISSION_DENIED);
}
/**
@@ -169,7 +116,7 @@ public class StorageManagerIntegrationTest extends StorageManagerBaseTest {
String filePath = file.getAbsolutePath();
mountObb(filePath);
verifyObb1Contents(filePath);
- mountObb(filePath, null, OnObbStateChangeListener.ERROR_ALREADY_MOUNTED);
+ mountObb(filePath, OnObbStateChangeListener.ERROR_ALREADY_MOUNTED);
verifyObb1Contents(filePath);
unmountObb(filePath, DONT_FORCE);
}
diff --git a/core/tests/coretests/src/android/view/InsetsControllerTest.java b/core/tests/coretests/src/android/view/InsetsControllerTest.java
index 227a86576113..c504f0cf2d94 100644
--- a/core/tests/coretests/src/android/view/InsetsControllerTest.java
+++ b/core/tests/coretests/src/android/view/InsetsControllerTest.java
@@ -30,6 +30,7 @@ import static android.view.InsetsState.ITYPE_IME;
import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
import static android.view.InsetsState.ITYPE_STATUS_BAR;
import static android.view.InsetsState.LAST_TYPE;
+import static android.view.ViewRootImpl.CAPTION_ON_SHELL;
import static android.view.WindowInsets.Type.ime;
import static android.view.WindowInsets.Type.navigationBars;
import static android.view.WindowInsets.Type.statusBars;
@@ -758,6 +759,11 @@ public class InsetsControllerTest {
@Test
public void testCaptionInsetsStateAssemble() {
+ if (CAPTION_ON_SHELL) {
+ // For this case, the test is covered by WindowContainerInsetsSourceProviderTest, This
+ // test can be removed after the caption is moved to shell completely.
+ return;
+ }
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
mController.onFrameChanged(new Rect(0, 0, 100, 300));
final InsetsState state = new InsetsState(mController.getState(), true);
@@ -769,6 +775,7 @@ public class InsetsControllerTest {
assertEquals(captionFrame, currentState.peekSource(ITYPE_CAPTION_BAR).getFrame());
assertTrue(currentState.equals(state, true /* excludingCaptionInsets*/,
true /* excludeInvisibleIme */));
+ // Test update to remove the caption bar
mController.setCaptionInsetsHeight(0);
mController.onStateChanged(state);
// The caption bar source should not be there at all, because we don't add empty
@@ -779,6 +786,11 @@ public class InsetsControllerTest {
@Test
public void testNotifyCaptionInsetsOnlyChange() {
+ if (CAPTION_ON_SHELL) {
+ // For this case, the test is covered by WindowContainerInsetsSourceProviderTest, This
+ // test can be removed after the caption is moved to shell completely.
+ return;
+ }
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
final InsetsState state = new InsetsState(mController.getState(), true);
reset(mTestHost);
diff --git a/core/tests/coretests/src/android/view/MotionEventTest.java b/core/tests/coretests/src/android/view/MotionEventTest.java
index 78a8f7b3f32e..c4c983d24af9 100644
--- a/core/tests/coretests/src/android/view/MotionEventTest.java
+++ b/core/tests/coretests/src/android/view/MotionEventTest.java
@@ -16,6 +16,7 @@
package android.view;
+import static android.view.InputDevice.SOURCE_CLASS_POINTER;
import static android.view.MotionEvent.ACTION_DOWN;
import static android.view.MotionEvent.ACTION_POINTER_DOWN;
import static android.view.MotionEvent.TOOL_TYPE_FINGER;
@@ -214,4 +215,27 @@ public class MotionEventTest {
rotInvalid.transform(mat);
assertEquals(-1, rotInvalid.getSurfaceRotation());
}
+
+ @Test
+ public void testUsesPointerSourceByDefault() {
+ final MotionEvent event = MotionEvent.obtain(0 /* downTime */, 0 /* eventTime */,
+ ACTION_DOWN, 0 /* x */, 0 /* y */, 0 /* metaState */);
+ assertTrue(event.isFromSource(SOURCE_CLASS_POINTER));
+ }
+
+ @Test
+ public void testLocationOffsetOnlyAppliedToNonPointerSources() {
+ final MotionEvent event = MotionEvent.obtain(0 /* downTime */, 0 /* eventTime */,
+ ACTION_DOWN, 10 /* x */, 20 /* y */, 0 /* metaState */);
+ event.offsetLocation(40, 50);
+
+ // The offset should be applied since a pointer source is used by default.
+ assertEquals(50, (int) event.getX());
+ assertEquals(70, (int) event.getY());
+
+ // The offset should not be applied if the source is changed to a non-pointer source.
+ event.setSource(InputDevice.SOURCE_JOYSTICK);
+ assertEquals(10, (int) event.getX());
+ assertEquals(20, (int) event.getY());
+ }
}
diff --git a/core/tests/coretests/src/android/view/stylus/HandwritingInitiatorTest.java b/core/tests/coretests/src/android/view/stylus/HandwritingInitiatorTest.java
index 1ae9649dfe06..e303934c4aad 100644
--- a/core/tests/coretests/src/android/view/stylus/HandwritingInitiatorTest.java
+++ b/core/tests/coretests/src/android/view/stylus/HandwritingInitiatorTest.java
@@ -60,7 +60,7 @@ import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
public class HandwritingInitiatorTest {
private static final int TOUCH_SLOP = 8;
- private static final long TAP_TIMEOUT = ViewConfiguration.getTapTimeout();
+ private static final long TIMEOUT = ViewConfiguration.getLongPressTimeout();
private static final Rect sHwArea = new Rect(100, 200, 500, 500);
private HandwritingInitiator mHandwritingInitiator;
@@ -177,7 +177,7 @@ public class HandwritingInitiatorTest {
}
@Test
- public void onTouchEvent_notStartHandwriting_when_stylusMove_afterTapTimeOut() {
+ public void onTouchEvent_notStartHandwriting_when_stylusMove_afterTimeOut() {
mHandwritingInitiator.onInputConnectionCreated(mTestView);
final int x1 = 10;
final int y1 = 10;
@@ -187,7 +187,7 @@ public class HandwritingInitiatorTest {
final int x2 = x1 + TOUCH_SLOP * 2;
final int y2 = y1;
- final long time2 = time1 + TAP_TIMEOUT + 10L;
+ final long time2 = time1 + TIMEOUT + 10L;
MotionEvent stylusEvent2 = createStylusEvent(ACTION_MOVE, x2, y2, time2);
mHandwritingInitiator.onTouchEvent(stylusEvent2);
diff --git a/core/tests/coretests/src/android/window/BackNavigationTest.java b/core/tests/coretests/src/android/window/BackNavigationTest.java
index 8fa48ef5494d..94a149b09d54 100644
--- a/core/tests/coretests/src/android/window/BackNavigationTest.java
+++ b/core/tests/coretests/src/android/window/BackNavigationTest.java
@@ -111,12 +111,12 @@ public class BackNavigationTest {
CountDownLatch backRegisteredLatch = new CountDownLatch(1);
mScenario.onActivity(activity -> {
activity.getOnBackInvokedDispatcher().registerOnBackInvokedCallback(
- new OnBackInvokedCallback() {
+ 0, new OnBackInvokedCallback() {
@Override
public void onBackInvoked() {
backInvokedLatch.countDown();
}
- }, 0
+ }
);
backRegisteredLatch.countDown();
});
diff --git a/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java b/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java
index f8c994416f46..212f4ed92b8c 100644
--- a/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java
+++ b/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java
@@ -77,9 +77,9 @@ public class WindowOnBackInvokedDispatcherTest {
ArgumentCaptor.forClass(IOnBackInvokedCallback.class);
mDispatcher.registerOnBackInvokedCallback(
- mCallback1, OnBackInvokedDispatcher.PRIORITY_DEFAULT);
+ OnBackInvokedDispatcher.PRIORITY_DEFAULT, mCallback1);
mDispatcher.registerOnBackInvokedCallback(
- mCallback2, OnBackInvokedDispatcher.PRIORITY_DEFAULT);
+ OnBackInvokedDispatcher.PRIORITY_DEFAULT, mCallback2);
verify(mWindowSession, times(2)).setOnBackInvokedCallback(
Mockito.eq(mWindow),
@@ -102,9 +102,9 @@ public class WindowOnBackInvokedDispatcherTest {
ArgumentCaptor.forClass(IOnBackInvokedCallback.class);
mDispatcher.registerOnBackInvokedCallback(
- mCallback1, OnBackInvokedDispatcher.PRIORITY_OVERLAY);
+ OnBackInvokedDispatcher.PRIORITY_OVERLAY, mCallback1);
mDispatcher.registerOnBackInvokedCallback(
- mCallback2, OnBackInvokedDispatcher.PRIORITY_DEFAULT);
+ OnBackInvokedDispatcher.PRIORITY_DEFAULT, mCallback2);
verify(mWindowSession).setOnBackInvokedCallback(
Mockito.eq(mWindow), captor.capture(),
@@ -118,9 +118,9 @@ public class WindowOnBackInvokedDispatcherTest {
@Test
public void propagatesTopCallback_withRemoval() throws RemoteException {
mDispatcher.registerOnBackInvokedCallback(
- mCallback1, OnBackInvokedDispatcher.PRIORITY_DEFAULT);
+ OnBackInvokedDispatcher.PRIORITY_DEFAULT, mCallback1);
mDispatcher.registerOnBackInvokedCallback(
- mCallback2, OnBackInvokedDispatcher.PRIORITY_DEFAULT);
+ OnBackInvokedDispatcher.PRIORITY_DEFAULT, mCallback2);
reset(mWindowSession);
mDispatcher.unregisterOnBackInvokedCallback(mCallback1);
@@ -139,16 +139,17 @@ public class WindowOnBackInvokedDispatcherTest {
ArgumentCaptor<IOnBackInvokedCallback> captor =
ArgumentCaptor.forClass(IOnBackInvokedCallback.class);
- mDispatcher.registerOnBackInvokedCallback(mCallback1,
- OnBackInvokedDispatcher.PRIORITY_OVERLAY);
+ mDispatcher.registerOnBackInvokedCallback(OnBackInvokedDispatcher.PRIORITY_OVERLAY,
+ mCallback1
+ );
mDispatcher.registerOnBackInvokedCallback(
- mCallback2, OnBackInvokedDispatcher.PRIORITY_DEFAULT);
+ OnBackInvokedDispatcher.PRIORITY_DEFAULT, mCallback2);
mDispatcher.registerOnBackInvokedCallback(
- mCallback1, OnBackInvokedDispatcher.PRIORITY_DEFAULT);
+ OnBackInvokedDispatcher.PRIORITY_DEFAULT, mCallback1);
reset(mWindowSession);
mDispatcher.registerOnBackInvokedCallback(
- mCallback2, OnBackInvokedDispatcher.PRIORITY_OVERLAY);
+ OnBackInvokedDispatcher.PRIORITY_OVERLAY, mCallback2);
verify(mWindowSession).setOnBackInvokedCallback(
Mockito.eq(mWindow),
captor.capture(),
diff --git a/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java b/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java
index 2817728fd9ea..e7a23f262753 100644
--- a/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java
@@ -39,6 +39,7 @@ import static org.hamcrest.MatcherAssert.assertThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.when;
import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.fail;
import android.content.Intent;
import android.content.pm.ResolveInfo;
@@ -52,6 +53,7 @@ import android.widget.TextView;
import androidx.test.InstrumentationRegistry;
import androidx.test.espresso.Espresso;
+import androidx.test.espresso.NoMatchingViewException;
import androidx.test.rule.ActivityTestRule;
import androidx.test.runner.AndroidJUnit4;
@@ -750,6 +752,34 @@ public class ResolverActivityTest {
}
@Test
+ public void testMiniResolver_noCurrentProfileTarget() {
+ ResolverActivity.ENABLE_TABBED_VIEW = true;
+ markWorkProfileUserAvailable();
+ List<ResolvedComponentInfo> personalResolvedComponentInfos =
+ createResolvedComponentsForTest(0);
+ List<ResolvedComponentInfo> workResolvedComponentInfos =
+ createResolvedComponentsForTest(1);
+ setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
+ Intent sendIntent = createSendImageIntent();
+ sendIntent.setType("TestType");
+
+ mActivityRule.launchActivity(sendIntent);
+ waitForIdle();
+
+ // Need to ensure mini resolver doesn't trigger here.
+ assertNotMiniResolver();
+ }
+
+ private void assertNotMiniResolver() {
+ try {
+ onView(withId(R.id.open_cross_profile)).check(matches(isDisplayed()));
+ } catch (NoMatchingViewException e) {
+ return;
+ }
+ fail("Mini resolver present but shouldn't be");
+ }
+
+ @Test
public void testWorkTab_noAppsAvailable_workOff_noAppsAvailableEmptyStateShown() {
// enable the work tab feature flag
ResolverActivity.ENABLE_TABBED_VIEW = true;
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java
index f5cbffb64bb5..7ccb9d963ee6 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java
@@ -17,6 +17,8 @@
package com.android.internal.os;
import static android.os.BatteryStats.NUM_SCREEN_BRIGHTNESS_BINS;
+import static android.os.BatteryStats.POWER_DATA_UNAVAILABLE;
+import static android.os.BatteryStats.RADIO_ACCESS_TECHNOLOGY_COUNT;
import static android.os.BatteryStats.RADIO_ACCESS_TECHNOLOGY_NR;
import static android.os.BatteryStats.STATS_SINCE_CHARGED;
import static android.os.BatteryStats.WAKE_TYPE_PARTIAL;
@@ -24,7 +26,10 @@ import static android.os.BatteryStats.WAKE_TYPE_PARTIAL;
import static com.android.internal.os.BatteryStatsImpl.ExternalStatsSync.UPDATE_CPU;
import static com.android.internal.os.BatteryStatsImpl.ExternalStatsSync.UPDATE_DISPLAY;
+import static org.mockito.Mockito.mock;
+
import android.app.ActivityManager;
+import android.app.usage.NetworkStatsManager;
import android.os.BatteryStats;
import android.os.BatteryStats.HistoryItem;
import android.os.BatteryStats.Uid.Sensor;
@@ -34,6 +39,7 @@ import android.os.WorkSource;
import android.telephony.Annotation;
import android.telephony.CellSignalStrength;
import android.telephony.DataConnectionRealTimeInfo;
+import android.telephony.ModemActivityInfo;
import android.telephony.ServiceState;
import android.telephony.TelephonyManager;
import android.util.SparseIntArray;
@@ -48,6 +54,8 @@ import com.android.internal.power.MeasuredEnergyStats;
import junit.framework.TestCase;
+import org.mockito.Mock;
+
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
@@ -72,6 +80,13 @@ public class BatteryStatsNoteTest extends TestCase {
private static final int ISOLATED_UID = UserHandle.getUid(0, ISOLATED_APP_ID);
private static final WorkSource WS = new WorkSource(UID);
+ enum ModemState {
+ SLEEP, IDLE, RECEIVING, TRANSMITTING
+ }
+
+ @Mock
+ NetworkStatsManager mNetworkStatsManager;
+
/**
* Test BatteryStatsImpl.Uid.noteBluetoothScanResultLocked.
*/
@@ -1173,69 +1188,29 @@ public class BatteryStatsNoteTest extends TestCase {
}
@SmallTest
- public void testGetPerStateActiveRadioDurationMs() {
+ public void testGetPerStateActiveRadioDurationMs_noModemActivity() {
final MockClock clock = new MockClock(); // holds realtime and uptime in ms
final MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clock);
- final int ratCount = BatteryStats.RADIO_ACCESS_TECHNOLOGY_COUNT;
+ final int ratCount = RADIO_ACCESS_TECHNOLOGY_COUNT;
final int frequencyCount = ServiceState.FREQUENCY_RANGE_MMWAVE + 1;
final int txLevelCount = CellSignalStrength.getNumSignalStrengthLevels();
final long[][][] expectedDurationsMs = new long[ratCount][frequencyCount][txLevelCount];
+ final long[][] expectedRxDurationsMs = new long[ratCount][frequencyCount];
+ final long[][][] expectedTxDurationsMs = new long[ratCount][frequencyCount][txLevelCount];
for (int rat = 0; rat < ratCount; rat++) {
for (int freq = 0; freq < frequencyCount; freq++) {
+ // Should have no RX data without Modem Activity Info
+ expectedRxDurationsMs[rat][freq] = POWER_DATA_UNAVAILABLE;
for (int txLvl = 0; txLvl < txLevelCount; txLvl++) {
expectedDurationsMs[rat][freq][txLvl] = 0;
+ // Should have no TX data without Modem Activity Info
+ expectedTxDurationsMs[rat][freq][txLvl] = POWER_DATA_UNAVAILABLE;
}
}
}
- class ModemAndBatteryState {
- public long currentTimeMs = 100;
- public boolean onBattery = false;
- public boolean modemActive = false;
- @Annotation.NetworkType
- public int currentNetworkDataType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
- @BatteryStats.RadioAccessTechnology
- public int currentRat = BatteryStats.RADIO_ACCESS_TECHNOLOGY_OTHER;
- @ServiceState.FrequencyRange
- public int currentFrequencyRange = ServiceState.FREQUENCY_RANGE_UNKNOWN;
- public SparseIntArray currentSignalStrengths = new SparseIntArray();
-
- void setOnBattery(boolean onBattery) {
- this.onBattery = onBattery;
- bi.updateTimeBasesLocked(onBattery, Display.STATE_OFF, currentTimeMs * 1000,
- currentTimeMs * 1000);
- }
-
- void setModemActive(boolean active) {
- modemActive = active;
- final int state = active ? DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH
- : DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
- bi.noteMobileRadioPowerStateLocked(state, currentTimeMs * 1000_000L, UID);
- }
-
- void setRatType(@Annotation.NetworkType int dataType,
- @BatteryStats.RadioAccessTechnology int rat) {
- currentNetworkDataType = dataType;
- currentRat = rat;
- bi.notePhoneDataConnectionStateLocked(dataType, true, ServiceState.STATE_IN_SERVICE,
- currentFrequencyRange);
- }
-
- void setFrequencyRange(@ServiceState.FrequencyRange int frequency) {
- currentFrequencyRange = frequency;
- bi.notePhoneDataConnectionStateLocked(currentNetworkDataType, true,
- ServiceState.STATE_IN_SERVICE, frequency);
- }
-
- void setSignalStrength(@BatteryStats.RadioAccessTechnology int rat, int strength) {
- currentSignalStrengths.put(rat, strength);
- final int size = currentSignalStrengths.size();
- final int newestGenSignalStrength = currentSignalStrengths.valueAt(size - 1);
- bi.notePhoneSignalStrengthLocked(newestGenSignalStrength, currentSignalStrengths);
- }
- }
- final ModemAndBatteryState state = new ModemAndBatteryState();
+ final ModemAndBatteryState state = new ModemAndBatteryState(bi, null);
IntConsumer incrementTime = inc -> {
state.currentTimeMs += inc;
@@ -1253,6 +1228,7 @@ public class BatteryStatsNoteTest extends TestCase {
expectedDurationsMs[currentRat][currentFrequencyRange][currentSignalStrength] += inc;
};
+
state.setOnBattery(false);
state.setModemActive(false);
state.setRatType(TelephonyManager.NETWORK_TYPE_UNKNOWN,
@@ -1260,95 +1236,367 @@ public class BatteryStatsNoteTest extends TestCase {
state.setFrequencyRange(ServiceState.FREQUENCY_RANGE_UNKNOWN);
state.setSignalStrength(BatteryStats.RADIO_ACCESS_TECHNOLOGY_OTHER,
CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN);
- checkPerStateActiveRadioDurations(expectedDurationsMs, bi, state.currentTimeMs);
+ checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+ expectedTxDurationsMs, bi, state.currentTimeMs);
// While not on battery, the timers should not increase.
state.setModemActive(true);
incrementTime.accept(100);
- checkPerStateActiveRadioDurations(expectedDurationsMs, bi, state.currentTimeMs);
+ checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+ expectedTxDurationsMs, bi, state.currentTimeMs);
state.setRatType(TelephonyManager.NETWORK_TYPE_NR, BatteryStats.RADIO_ACCESS_TECHNOLOGY_NR);
incrementTime.accept(200);
- checkPerStateActiveRadioDurations(expectedDurationsMs, bi, state.currentTimeMs);
+ checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+ expectedTxDurationsMs, bi, state.currentTimeMs);
state.setSignalStrength(BatteryStats.RADIO_ACCESS_TECHNOLOGY_NR,
CellSignalStrength.SIGNAL_STRENGTH_GOOD);
incrementTime.accept(500);
- checkPerStateActiveRadioDurations(expectedDurationsMs, bi, state.currentTimeMs);
+ checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+ expectedTxDurationsMs, bi, state.currentTimeMs);
state.setFrequencyRange(ServiceState.FREQUENCY_RANGE_MMWAVE);
incrementTime.accept(300);
- checkPerStateActiveRadioDurations(expectedDurationsMs, bi, state.currentTimeMs);
+ checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+ expectedTxDurationsMs, bi, state.currentTimeMs);
state.setRatType(TelephonyManager.NETWORK_TYPE_LTE,
BatteryStats.RADIO_ACCESS_TECHNOLOGY_LTE);
incrementTime.accept(400);
- checkPerStateActiveRadioDurations(expectedDurationsMs, bi, state.currentTimeMs);
+ checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+ expectedTxDurationsMs, bi, state.currentTimeMs);
state.setSignalStrength(BatteryStats.RADIO_ACCESS_TECHNOLOGY_LTE,
CellSignalStrength.SIGNAL_STRENGTH_MODERATE);
incrementTime.accept(500);
- checkPerStateActiveRadioDurations(expectedDurationsMs, bi, state.currentTimeMs);
+ checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+ expectedTxDurationsMs, bi, state.currentTimeMs);
// When set on battery, currently active state (RAT:LTE, Signal Strength:Moderate) should
// start counting up.
state.setOnBattery(true);
incrementTime.accept(600);
- checkPerStateActiveRadioDurations(expectedDurationsMs, bi, state.currentTimeMs);
-
+ checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+ expectedTxDurationsMs, bi, state.currentTimeMs);
// Changing LTE signal strength should be tracked.
state.setSignalStrength(BatteryStats.RADIO_ACCESS_TECHNOLOGY_LTE,
CellSignalStrength.SIGNAL_STRENGTH_POOR);
incrementTime.accept(700);
- checkPerStateActiveRadioDurations(expectedDurationsMs, bi, state.currentTimeMs);
+ checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+ expectedTxDurationsMs, bi, state.currentTimeMs);
state.setSignalStrength(BatteryStats.RADIO_ACCESS_TECHNOLOGY_LTE,
CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN);
incrementTime.accept(800);
- checkPerStateActiveRadioDurations(expectedDurationsMs, bi, state.currentTimeMs);
+ checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+ expectedTxDurationsMs, bi, state.currentTimeMs);
state.setSignalStrength(BatteryStats.RADIO_ACCESS_TECHNOLOGY_LTE,
CellSignalStrength.SIGNAL_STRENGTH_GOOD);
incrementTime.accept(900);
- checkPerStateActiveRadioDurations(expectedDurationsMs, bi, state.currentTimeMs);
+ checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+ expectedTxDurationsMs, bi, state.currentTimeMs);
state.setSignalStrength(BatteryStats.RADIO_ACCESS_TECHNOLOGY_LTE,
CellSignalStrength.SIGNAL_STRENGTH_GREAT);
incrementTime.accept(1000);
- checkPerStateActiveRadioDurations(expectedDurationsMs, bi, state.currentTimeMs);
+ checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+ expectedTxDurationsMs, bi, state.currentTimeMs);
// Change in the signal strength of nonactive RAT should not affect anything.
state.setSignalStrength(BatteryStats.RADIO_ACCESS_TECHNOLOGY_OTHER,
CellSignalStrength.SIGNAL_STRENGTH_POOR);
incrementTime.accept(1100);
- checkPerStateActiveRadioDurations(expectedDurationsMs, bi, state.currentTimeMs);
+ checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+ expectedTxDurationsMs, bi, state.currentTimeMs);
// Changing to OTHER Rat should start tracking the poor signal strength.
state.setRatType(TelephonyManager.NETWORK_TYPE_CDMA,
BatteryStats.RADIO_ACCESS_TECHNOLOGY_OTHER);
incrementTime.accept(1200);
- checkPerStateActiveRadioDurations(expectedDurationsMs, bi, state.currentTimeMs);
+ checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+ expectedTxDurationsMs, bi, state.currentTimeMs);
// Noting frequency change should not affect non NR Rat.
state.setFrequencyRange(ServiceState.FREQUENCY_RANGE_HIGH);
incrementTime.accept(1300);
- checkPerStateActiveRadioDurations(expectedDurationsMs, bi, state.currentTimeMs);
+ checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+ expectedTxDurationsMs, bi, state.currentTimeMs);
// Now the NR Rat, HIGH frequency range, good signal strength should start counting.
state.setRatType(TelephonyManager.NETWORK_TYPE_NR, BatteryStats.RADIO_ACCESS_TECHNOLOGY_NR);
incrementTime.accept(1400);
- checkPerStateActiveRadioDurations(expectedDurationsMs, bi, state.currentTimeMs);
+ checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+ expectedTxDurationsMs, bi, state.currentTimeMs);
// Noting frequency change should not affect non NR Rat.
state.setFrequencyRange(ServiceState.FREQUENCY_RANGE_LOW);
incrementTime.accept(1500);
- checkPerStateActiveRadioDurations(expectedDurationsMs, bi, state.currentTimeMs);
+ checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+ expectedTxDurationsMs, bi, state.currentTimeMs);
// Modem no longer active, should not be tracking any more.
state.setModemActive(false);
incrementTime.accept(1500);
- checkPerStateActiveRadioDurations(expectedDurationsMs, bi, state.currentTimeMs);
+ checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+ expectedTxDurationsMs, bi, state.currentTimeMs);
+ }
+
+ @SmallTest
+ public void testGetPerStateActiveRadioDurationMs_withModemActivity() {
+ final MockClock clock = new MockClock(); // holds realtime and uptime in ms
+ final MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clock);
+ bi.setPowerProfile(mock(PowerProfile.class));
+ final int ratCount = RADIO_ACCESS_TECHNOLOGY_COUNT;
+ final int frequencyCount = ServiceState.FREQUENCY_RANGE_MMWAVE + 1;
+ final int txLevelCount = CellSignalStrength.getNumSignalStrengthLevels();
+
+ final long[][][] expectedDurationsMs = new long[ratCount][frequencyCount][txLevelCount];
+ final long[][] expectedRxDurationsMs = new long[ratCount][frequencyCount];
+ final long[][][] expectedTxDurationsMs = new long[ratCount][frequencyCount][txLevelCount];
+ for (int rat = 0; rat < ratCount; rat++) {
+ for (int freq = 0; freq < frequencyCount; freq++) {
+ if (rat != RADIO_ACCESS_TECHNOLOGY_NR
+ && freq != ServiceState.FREQUENCY_RANGE_UNKNOWN) {
+ // Only the NR RAT should have per frequency data.
+ expectedRxDurationsMs[rat][freq] = POWER_DATA_UNAVAILABLE;
+ } else {
+ expectedRxDurationsMs[rat][freq] = 0;
+ }
+ expectedRxDurationsMs[rat][freq] = POWER_DATA_UNAVAILABLE;
+
+ for (int txLvl = 0; txLvl < txLevelCount; txLvl++) {
+ expectedDurationsMs[rat][freq][txLvl] = 0;
+
+ if (rat != RADIO_ACCESS_TECHNOLOGY_NR
+ && freq != ServiceState.FREQUENCY_RANGE_UNKNOWN) {
+ // Only the NR RAT should have per frequency data.
+ expectedTxDurationsMs[rat][freq][txLvl] = POWER_DATA_UNAVAILABLE;
+ } else {
+ expectedTxDurationsMs[rat][freq][txLvl] = 0;
+ }
+ expectedTxDurationsMs[rat][freq][txLvl] = POWER_DATA_UNAVAILABLE;
+ }
+ }
+ }
+
+ final ModemActivityInfo mai = new ModemActivityInfo(0L, 0L, 0L, new int[txLevelCount], 0L);
+ final ModemAndBatteryState state = new ModemAndBatteryState(bi, mai);
+
+ IntConsumer incrementTime = inc -> {
+ state.currentTimeMs += inc;
+ clock.realtime = clock.uptime = state.currentTimeMs;
+
+ // If the device is not on battery, no timers should increment.
+ if (!state.onBattery) return;
+ // If the modem is not active, no timers should increment.
+ if (!state.modemActive) return;
+
+ final int currRat = state.currentRat;
+ final int currFreqRange =
+ currRat == RADIO_ACCESS_TECHNOLOGY_NR ? state.currentFrequencyRange : 0;
+ int currSignalStrength = state.currentSignalStrengths.get(currRat);
+
+ expectedDurationsMs[currRat][currFreqRange][currSignalStrength] += inc;
+
+ // Evaluate the HAL provided time in states.
+ switch (state.modemState) {
+ case SLEEP:
+ long sleepMs = state.modemActivityInfo.getSleepTimeMillis();
+ state.modemActivityInfo.setSleepTimeMillis(sleepMs + inc);
+ break;
+ case IDLE:
+ long idleMs = state.modemActivityInfo.getIdleTimeMillis();
+ state.modemActivityInfo.setIdleTimeMillis(idleMs + inc);
+ break;
+ case RECEIVING:
+ long rxMs = state.modemActivityInfo.getReceiveTimeMillis();
+ state.modemActivityInfo.setReceiveTimeMillis(rxMs + inc);
+ expectedRxDurationsMs[currRat][currFreqRange] += inc;
+ break;
+ case TRANSMITTING:
+ int[] txMs = state.modemActivityInfo.getTransmitTimeMillis();
+ txMs[currSignalStrength] += inc;
+ state.modemActivityInfo.setTransmitTimeMillis(txMs);
+ expectedTxDurationsMs[currRat][currFreqRange][currSignalStrength] += inc;
+ break;
+ }
+ };
+
+ state.setOnBattery(false);
+ state.setModemActive(false);
+ state.setRatType(TelephonyManager.NETWORK_TYPE_UNKNOWN,
+ BatteryStats.RADIO_ACCESS_TECHNOLOGY_OTHER);
+ state.setFrequencyRange(ServiceState.FREQUENCY_RANGE_UNKNOWN);
+ state.setSignalStrength(BatteryStats.RADIO_ACCESS_TECHNOLOGY_OTHER,
+ CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN);
+ checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+ expectedTxDurationsMs, bi, state.currentTimeMs);
+
+ // While not on battery, the timers should not increase.
+ state.setModemActive(true);
+ incrementTime.accept(100);
+ checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+ expectedTxDurationsMs, bi, state.currentTimeMs);
+
+ state.setRatType(TelephonyManager.NETWORK_TYPE_NR, BatteryStats.RADIO_ACCESS_TECHNOLOGY_NR);
+ incrementTime.accept(200);
+ checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+ expectedTxDurationsMs, bi, state.currentTimeMs);
+
+ state.setSignalStrength(BatteryStats.RADIO_ACCESS_TECHNOLOGY_NR,
+ CellSignalStrength.SIGNAL_STRENGTH_GOOD);
+ incrementTime.accept(500);
+ checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+ expectedTxDurationsMs, bi, state.currentTimeMs);
+
+ state.setFrequencyRange(ServiceState.FREQUENCY_RANGE_MMWAVE);
+ incrementTime.accept(300);
+ checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+ expectedTxDurationsMs, bi, state.currentTimeMs);
+
+ state.setRatType(TelephonyManager.NETWORK_TYPE_LTE,
+ BatteryStats.RADIO_ACCESS_TECHNOLOGY_LTE);
+ incrementTime.accept(400);
+ checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+ expectedTxDurationsMs, bi, state.currentTimeMs);
+
+ state.setSignalStrength(BatteryStats.RADIO_ACCESS_TECHNOLOGY_LTE,
+ CellSignalStrength.SIGNAL_STRENGTH_MODERATE);
+ incrementTime.accept(500);
+ checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+ expectedTxDurationsMs, bi, state.currentTimeMs);
+
+ // Data will now be available.
+ for (int rat = 0; rat < ratCount; rat++) {
+ for (int freq = 0; freq < frequencyCount; freq++) {
+ if (rat == RADIO_ACCESS_TECHNOLOGY_NR
+ || freq == ServiceState.FREQUENCY_RANGE_UNKNOWN) {
+ // Only the NR RAT should have per frequency data.
+ expectedRxDurationsMs[rat][freq] = 0;
+ }
+ for (int txLvl = 0; txLvl < txLevelCount; txLvl++) {
+ if (rat == RADIO_ACCESS_TECHNOLOGY_NR
+ || freq == ServiceState.FREQUENCY_RANGE_UNKNOWN) {
+ // Only the NR RAT should have per frequency data.
+ expectedTxDurationsMs[rat][freq][txLvl] = 0;
+ }
+ }
+ }
+ }
+
+ // When set on battery, currently active state (RAT:LTE, Signal Strength:Moderate) should
+ // start counting up.
+ state.setOnBattery(true);
+ incrementTime.accept(300);
+ state.setModemState(ModemState.RECEIVING);
+ incrementTime.accept(500);
+ state.setModemState(ModemState.TRANSMITTING);
+ incrementTime.accept(600);
+ state.noteModemControllerActivity();
+ checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+ expectedTxDurationsMs, bi, state.currentTimeMs);
+ // Changing LTE signal strength should be tracked.
+ state.setSignalStrength(BatteryStats.RADIO_ACCESS_TECHNOLOGY_LTE,
+ CellSignalStrength.SIGNAL_STRENGTH_POOR);
+ incrementTime.accept(300);
+ state.setModemState(ModemState.SLEEP);
+ incrementTime.accept(1000);
+ state.setModemState(ModemState.RECEIVING);
+ incrementTime.accept(700);
+ state.noteModemControllerActivity();
+ checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+ expectedTxDurationsMs, bi, state.currentTimeMs);
+
+ state.setSignalStrength(BatteryStats.RADIO_ACCESS_TECHNOLOGY_LTE,
+ CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN);
+ incrementTime.accept(800);
+ state.setModemState(ModemState.TRANSMITTING);
+ incrementTime.accept(222);
+ state.setModemState(ModemState.IDLE);
+ incrementTime.accept(111);
+ state.setModemState(ModemState.RECEIVING);
+ incrementTime.accept(7777);
+ state.noteModemControllerActivity();
+ checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+ expectedTxDurationsMs, bi, state.currentTimeMs);
+
+ state.setSignalStrength(BatteryStats.RADIO_ACCESS_TECHNOLOGY_LTE,
+ CellSignalStrength.SIGNAL_STRENGTH_GOOD);
+ incrementTime.accept(88);
+ state.setModemState(ModemState.TRANSMITTING);
+ incrementTime.accept(900);
+ state.noteModemControllerActivity();
+ checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+ expectedTxDurationsMs, bi, state.currentTimeMs);
+
+ state.setSignalStrength(BatteryStats.RADIO_ACCESS_TECHNOLOGY_LTE,
+ CellSignalStrength.SIGNAL_STRENGTH_GREAT);
+ incrementTime.accept(123);
+ state.setModemState(ModemState.RECEIVING);
+ incrementTime.accept(333);
+ state.setModemState(ModemState.TRANSMITTING);
+ incrementTime.accept(1000);
+ state.setModemState(ModemState.RECEIVING);
+ incrementTime.accept(555);
+ state.noteModemControllerActivity();
+ checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+ expectedTxDurationsMs, bi, state.currentTimeMs);
+
+ // Change in the signal strength of nonactive RAT should not affect anything.
+ state.setSignalStrength(BatteryStats.RADIO_ACCESS_TECHNOLOGY_OTHER,
+ CellSignalStrength.SIGNAL_STRENGTH_POOR);
+ incrementTime.accept(631);
+ state.setModemState(ModemState.TRANSMITTING);
+ incrementTime.accept(321);
+ state.setModemState(ModemState.RECEIVING);
+ incrementTime.accept(99);
+ state.noteModemControllerActivity();
+ checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+ expectedTxDurationsMs, bi, state.currentTimeMs);
+
+ // Changing to OTHER Rat should start tracking the poor signal strength.
+ state.setRatType(TelephonyManager.NETWORK_TYPE_CDMA,
+ BatteryStats.RADIO_ACCESS_TECHNOLOGY_OTHER);
+ incrementTime.accept(1200);
+ state.noteModemControllerActivity();
+ checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+ expectedTxDurationsMs, bi, state.currentTimeMs);
+
+ // Noting frequency change should not affect non NR Rat.
+ state.setFrequencyRange(ServiceState.FREQUENCY_RANGE_HIGH);
+ incrementTime.accept(444);
+ state.setModemState(ModemState.TRANSMITTING);
+ incrementTime.accept(1300);
+ state.noteModemControllerActivity();
+ checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+ expectedTxDurationsMs, bi, state.currentTimeMs);
+
+ // Now the NR Rat, HIGH frequency range, good signal strength should start counting.
+ state.setRatType(TelephonyManager.NETWORK_TYPE_NR, BatteryStats.RADIO_ACCESS_TECHNOLOGY_NR);
+ incrementTime.accept(1400);
+ state.noteModemControllerActivity();
+ checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+ expectedTxDurationsMs, bi, state.currentTimeMs);
+
+ // Frequency changed to low.
+ state.setFrequencyRange(ServiceState.FREQUENCY_RANGE_LOW);
+ incrementTime.accept(852);
+ state.setModemState(ModemState.RECEIVING);
+ incrementTime.accept(157);
+ state.setModemState(ModemState.TRANSMITTING);
+ incrementTime.accept(1500);
+ state.noteModemControllerActivity();
+ checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+ expectedTxDurationsMs, bi, state.currentTimeMs);
+ // Modem no longer active, should not be tracking any more.
+ state.setModemActive(false);
+ incrementTime.accept(1500);
+ state.noteModemControllerActivity();
+ checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+ expectedTxDurationsMs, bi, state.currentTimeMs);
}
private void setFgState(int uid, boolean fgOn, MockBatteryStatsImpl bi) {
@@ -1426,28 +1674,124 @@ public class BatteryStatsNoteTest extends TestCase {
}
private void checkPerStateActiveRadioDurations(long[][][] expectedDurationsMs,
+ long[][] expectedRxDurationsMs, long[][][] expectedTxDurationsMs,
BatteryStatsImpl bi, long currentTimeMs) {
for (int rat = 0; rat < expectedDurationsMs.length; rat++) {
final long[][] expectedRatDurationsMs = expectedDurationsMs[rat];
for (int freq = 0; freq < expectedRatDurationsMs.length; freq++) {
+ final long expectedRxDurationMs = expectedRxDurationsMs[rat][freq];
+
+ // Build a verbose fail message, just in case.
+ final StringBuilder rxFailSb = new StringBuilder();
+ rxFailSb.append("Wrong time in Rx state for RAT:");
+ rxFailSb.append(BatteryStats.RADIO_ACCESS_TECHNOLOGY_NAMES[rat]);
+ rxFailSb.append(", frequency:");
+ rxFailSb.append(ServiceState.frequencyRangeToString(freq));
+ assertEquals(rxFailSb.toString(), expectedRxDurationMs,
+ bi.getActiveRxRadioDurationMs(rat, freq, currentTimeMs));
+
final long[] expectedFreqDurationsMs = expectedRatDurationsMs[freq];
for (int strength = 0; strength < expectedFreqDurationsMs.length; strength++) {
final long expectedSignalStrengthDurationMs = expectedFreqDurationsMs[strength];
+ final long expectedTxDurationMs = expectedTxDurationsMs[rat][freq][strength];
final long actualDurationMs = bi.getActiveRadioDurationMs(rat, freq,
strength, currentTimeMs);
- // Build a verbose fail message, just in case.
- final StringBuilder sb = new StringBuilder();
- sb.append("Wrong time in state for RAT:");
- sb.append(BatteryStats.RADIO_ACCESS_TECHNOLOGY_NAMES[rat]);
- sb.append(", frequency:");
- sb.append(ServiceState.frequencyRangeToString(freq));
- sb.append(", strength:");
- sb.append(strength);
-
- assertEquals(sb.toString(), expectedSignalStrengthDurationMs, actualDurationMs);
+ final StringBuilder failSb = new StringBuilder();
+ failSb.append("Wrong time in state for RAT:");
+ failSb.append(BatteryStats.RADIO_ACCESS_TECHNOLOGY_NAMES[rat]);
+ failSb.append(", frequency:");
+ failSb.append(ServiceState.frequencyRangeToString(freq));
+ failSb.append(", strength:");
+ failSb.append(strength);
+ assertEquals(failSb.toString(), expectedSignalStrengthDurationMs,
+ actualDurationMs);
+
+ final StringBuilder txFailSb = new StringBuilder();
+ txFailSb.append("Wrong time in Tx state for RAT:");
+ txFailSb.append(BatteryStats.RADIO_ACCESS_TECHNOLOGY_NAMES[rat]);
+ txFailSb.append(", frequency:");
+ txFailSb.append(ServiceState.frequencyRangeToString(freq));
+ txFailSb.append(", strength:");
+ txFailSb.append(strength);
+ assertEquals(txFailSb.toString(), expectedTxDurationMs,
+ bi.getActiveTxRadioDurationMs(rat, freq, strength, currentTimeMs));
}
}
}
}
+
+ private class ModemAndBatteryState {
+ public long currentTimeMs = 100;
+ public boolean onBattery = false;
+ public boolean modemActive = false;
+ @Annotation.NetworkType
+ public int currentNetworkDataType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
+ @BatteryStats.RadioAccessTechnology
+ public int currentRat = BatteryStats.RADIO_ACCESS_TECHNOLOGY_OTHER;
+ @ServiceState.FrequencyRange
+ public int currentFrequencyRange = ServiceState.FREQUENCY_RANGE_UNKNOWN;
+ public SparseIntArray currentSignalStrengths = new SparseIntArray();
+ public ModemState modemState = ModemState.SLEEP;
+ public ModemActivityInfo modemActivityInfo;
+
+ private final MockBatteryStatsImpl mBsi;
+
+ ModemAndBatteryState(MockBatteryStatsImpl bsi, ModemActivityInfo mai) {
+ mBsi = bsi;
+ modemActivityInfo = mai;
+ }
+
+ void setOnBattery(boolean onBattery) {
+ this.onBattery = onBattery;
+ mBsi.updateTimeBasesLocked(onBattery, Display.STATE_OFF, currentTimeMs * 1000,
+ currentTimeMs * 1000);
+ mBsi.setOnBatteryInternal(onBattery);
+ noteModemControllerActivity();
+ }
+
+ void setModemActive(boolean active) {
+ modemActive = active;
+ final int state = active ? DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH
+ : DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
+ mBsi.noteMobileRadioPowerStateLocked(state, currentTimeMs * 1000_000L, UID);
+ noteModemControllerActivity();
+ }
+
+ void setRatType(@Annotation.NetworkType int dataType,
+ @BatteryStats.RadioAccessTechnology int rat) {
+ currentNetworkDataType = dataType;
+ currentRat = rat;
+ mBsi.notePhoneDataConnectionStateLocked(dataType, true, ServiceState.STATE_IN_SERVICE,
+ currentFrequencyRange);
+ }
+
+ void setFrequencyRange(@ServiceState.FrequencyRange int frequency) {
+ currentFrequencyRange = frequency;
+ mBsi.notePhoneDataConnectionStateLocked(currentNetworkDataType, true,
+ ServiceState.STATE_IN_SERVICE, frequency);
+ }
+
+ void setSignalStrength(@BatteryStats.RadioAccessTechnology int rat, int strength) {
+ currentSignalStrengths.put(rat, strength);
+ final int size = currentSignalStrengths.size();
+ final int newestGenSignalStrength = currentSignalStrengths.valueAt(size - 1);
+ mBsi.notePhoneSignalStrengthLocked(newestGenSignalStrength, currentSignalStrengths);
+ }
+
+ void setModemState(ModemState state) {
+ modemState = state;
+ }
+
+ void noteModemControllerActivity() {
+ if (modemActivityInfo == null) return;
+ modemActivityInfo.setTimestamp(currentTimeMs);
+ ModemActivityInfo copy = new ModemActivityInfo(modemActivityInfo.getTimestampMillis(),
+ modemActivityInfo.getSleepTimeMillis(), modemActivityInfo.getIdleTimeMillis(),
+ modemActivityInfo.getTransmitTimeMillis().clone(),
+ modemActivityInfo.getReceiveTimeMillis());
+ mBsi.noteModemControllerActivity(copy, POWER_DATA_UNAVAILABLE,
+ currentTimeMs, currentTimeMs, mNetworkStatsManager);
+ }
+ }
}
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsSensorTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsSensorTest.java
index 0e394c1ec7fd..bfb34499984b 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsSensorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsSensorTest.java
@@ -30,6 +30,7 @@ import junit.framework.TestCase;
public class BatteryStatsSensorTest extends TestCase {
private static final int UID = 10500;
+ private static final int UID_2 = 10501; // second uid for testing pool usage
private static final int SENSOR_ID = -10000;
@SmallTest
@@ -239,7 +240,6 @@ public class BatteryStatsSensorTest extends TestCase {
@SmallTest
public void testPooledBackgroundUsage() throws Exception {
- final int UID_2 = 20000; // second uid for testing pool usage
final MockClock clocks = new MockClock();
MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks);
bi.mForceOnBattery = true;
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsTest.java
index 5adc9bdf0d00..483224cf353d 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsTest.java
@@ -20,6 +20,7 @@ import static android.os.BatteryConsumer.POWER_COMPONENT_ANY;
import static android.os.BatteryConsumer.POWER_MODEL_MEASURED_ENERGY;
import static android.os.BatteryConsumer.POWER_MODEL_UNDEFINED;
import static android.os.BatteryConsumer.PROCESS_STATE_BACKGROUND;
+import static android.os.BatteryConsumer.PROCESS_STATE_CACHED;
import static android.os.BatteryConsumer.PROCESS_STATE_FOREGROUND;
import static android.os.BatteryConsumer.PROCESS_STATE_FOREGROUND_SERVICE;
@@ -83,7 +84,7 @@ public class BatteryUsageStatsTest {
final Parcel parcel = Parcel.obtain();
parcel.writeParcelable(outBatteryUsageStats, 0);
- assertThat(parcel.dataSize()).isLessThan(7000);
+ assertThat(parcel.dataSize()).isLessThan(8000);
parcel.setDataPosition(0);
@@ -155,10 +156,11 @@ public class BatteryUsageStatsTest {
assertThat(dump).contains("cpu(fg): 2333 apps: 1333 duration: 3s 332ms");
assertThat(dump).contains("cpu(bg): 2444 apps: 1444 duration: 4s 442ms");
assertThat(dump).contains("cpu(fgs): 2555 apps: 1555 duration: 5s 552ms");
+ assertThat(dump).contains("cpu(cached): 123 apps: 123 duration: 456ms");
assertThat(dump).contains("FOO: 20200 apps: 10200 duration: 20s 400ms");
- assertThat(dump).contains("UID 271: 1200 fg: 1777 bg: 1888 fgs: 1999 ( screen=300 "
- + "cpu=400 (600ms) cpu:fg=1777 (7s 771ms) cpu:bg=1888 (8s 881ms) "
- + "cpu:fgs=1999 (9s 991ms) FOO=500 )");
+ assertThat(dump).contains("UID 271: 1200 fg: 1777 bg: 1888 fgs: 1999 cached: 123 "
+ + "( screen=300 cpu=400 (600ms) cpu:fg=1777 (7s 771ms) cpu:bg=1888 (8s 881ms) "
+ + "cpu:fgs=1999 (9s 991ms) cpu:cached=123 (456ms) FOO=500 )");
assertThat(dump).contains("User 42: 30.0 ( cpu=10.0 (30ms) FOO=20.0 )");
}
@@ -193,13 +195,15 @@ public class BatteryUsageStatsTest {
5321, 7432, 423, BatteryConsumer.POWER_MODEL_POWER_PROFILE, 745,
POWER_MODEL_UNDEFINED,
956, 1167, 1478,
- true, 3554, 3776, 3998, 3554, 15542, 3776, 17762, 3998, 19982);
+ true, 3554, 3776, 3998, 444, 3554, 15542, 3776, 17762, 3998, 19982,
+ 444, 1110);
} else if (uidBatteryConsumer.getUid() == APP_UID2) {
assertUidBatteryConsumer(uidBatteryConsumer, 1332, "bar",
1111, 2222, 333, BatteryConsumer.POWER_MODEL_POWER_PROFILE, 444,
BatteryConsumer.POWER_MODEL_POWER_PROFILE,
555, 666, 777,
- true, 1777, 1888, 1999, 1777, 7771, 1888, 8881, 1999, 9991);
+ true, 1777, 1888, 1999, 321, 1777, 7771, 1888, 8881, 1999, 9991,
+ 321, 654);
} else {
fail("Unexpected UID " + uidBatteryConsumer.getUid());
}
@@ -267,17 +271,17 @@ public class BatteryUsageStatsTest {
1000, 2000,
300, BatteryConsumer.POWER_MODEL_POWER_PROFILE, 400,
BatteryConsumer.POWER_MODEL_POWER_PROFILE, 500, 600, 800,
- 1777, 7771, 1888, 8881, 1999, 9991);
+ 1777, 7771, 1888, 8881, 1999, 9991, 123, 456);
addAggregateBatteryConsumer(builder,
BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_ALL_APPS, 0,
10100, 10200, 10300, 10400,
- 1333, 3331, 1444, 4441, 1555, 5551);
+ 1333, 3331, 1444, 4441, 1555, 5551, 123, 456);
addAggregateBatteryConsumer(builder,
BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE, 30000,
20100, 20200, 20300, 20400,
- 2333, 3332, 2444, 4442, 2555, 5552);
+ 2333, 3332, 2444, 4442, 2555, 5552, 123, 456);
if (includeUserBatteryConsumer) {
builder.getOrCreateUserBatteryConsumerBuilder(USER_ID)
@@ -310,23 +314,23 @@ public class BatteryUsageStatsTest {
4321, 5432,
123, BatteryConsumer.POWER_MODEL_POWER_PROFILE, 345, POWER_MODEL_MEASURED_ENERGY,
456, 567, 678,
- 1777, 7771, 1888, 8881, 1999, 9991);
+ 1777, 7771, 1888, 8881, 1999, 9991, 321, 654);
addUidBatteryConsumer(builder, batteryStats, APP_UID2, "bar",
1111, 2222,
333, BatteryConsumer.POWER_MODEL_POWER_PROFILE, 444,
BatteryConsumer.POWER_MODEL_POWER_PROFILE, 555, 666, 777,
- 1777, 7771, 1888, 8881, 1999, 9991);
+ 1777, 7771, 1888, 8881, 1999, 9991, 321, 654);
addAggregateBatteryConsumer(builder,
BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_ALL_APPS, 0,
10123, 10234, 10345, 10456,
- 4333, 3334, 5444, 4445, 6555, 5556);
+ 4333, 3334, 5444, 4445, 6555, 5556, 321, 654);
addAggregateBatteryConsumer(builder,
BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE, 12345,
20111, 20222, 20333, 20444,
- 7333, 3337, 8444, 4448, 9555, 5559);
+ 7333, 3337, 8444, 4448, 9555, 5559, 123, 456);
return builder;
}
@@ -337,7 +341,7 @@ public class BatteryUsageStatsTest {
int screenPowerModel, double cpuPower, int cpuPowerModel, double customComponentPower,
int cpuDuration, int customComponentDuration, double cpuPowerForeground,
int cpuDurationForeground, double cpuPowerBackground, int cpuDurationBackground,
- double cpuPowerFgs, int cpuDurationFgs) {
+ double cpuPowerFgs, int cpuDurationFgs, double cpuPowerCached, long cpuDurationCached) {
final BatteryStatsImpl.Uid batteryStatsUid = batteryStats.getUidStatsLocked(uid);
final UidBatteryConsumer.Builder uidBuilder =
builder.getOrCreateUidBatteryConsumerBuilder(batteryStatsUid);
@@ -365,6 +369,9 @@ public class BatteryUsageStatsTest {
final BatteryConsumer.Key cpuFgsKey = uidBuilder.getKey(
BatteryConsumer.POWER_COMPONENT_CPU,
BatteryConsumer.PROCESS_STATE_FOREGROUND_SERVICE);
+ final BatteryConsumer.Key cachedKey = uidBuilder.getKey(
+ BatteryConsumer.POWER_COMPONENT_CPU,
+ BatteryConsumer.PROCESS_STATE_CACHED);
uidBuilder
.setConsumedPower(cpuFgKey, cpuPowerForeground,
BatteryConsumer.POWER_MODEL_POWER_PROFILE)
@@ -374,7 +381,10 @@ public class BatteryUsageStatsTest {
.setUsageDurationMillis(cpuBgKey, cpuDurationBackground)
.setConsumedPower(cpuFgsKey, cpuPowerFgs,
BatteryConsumer.POWER_MODEL_POWER_PROFILE)
- .setUsageDurationMillis(cpuFgsKey, cpuDurationFgs);
+ .setUsageDurationMillis(cpuFgsKey, cpuDurationFgs)
+ .setConsumedPower(cachedKey, cpuPowerCached,
+ BatteryConsumer.POWER_MODEL_POWER_PROFILE)
+ .setUsageDurationMillis(cachedKey, cpuDurationCached);
}
}
@@ -382,7 +392,7 @@ public class BatteryUsageStatsTest {
double consumedPower, int cpuPower, int customComponentPower, int cpuDuration,
int customComponentDuration, double cpuPowerForeground, long cpuDurationForeground,
double cpuPowerBackground, long cpuDurationBackground, double cpuPowerFgs,
- long cpuDurationFgs) {
+ long cpuDurationFgs, double cpuPowerCached, long cpuDurationCached) {
final AggregateBatteryConsumer.Builder aggBuilder =
builder.getAggregateBatteryConsumerBuilder(scope)
.setConsumedPower(consumedPower)
@@ -406,6 +416,9 @@ public class BatteryUsageStatsTest {
final BatteryConsumer.Key cpuFgsKey = aggBuilder.getKey(
BatteryConsumer.POWER_COMPONENT_CPU,
BatteryConsumer.PROCESS_STATE_FOREGROUND_SERVICE);
+ final BatteryConsumer.Key cpuCachedKey = aggBuilder.getKey(
+ BatteryConsumer.POWER_COMPONENT_CPU,
+ BatteryConsumer.PROCESS_STATE_CACHED);
aggBuilder
.setConsumedPower(cpuFgKey, cpuPowerForeground,
BatteryConsumer.POWER_MODEL_POWER_PROFILE)
@@ -415,7 +428,10 @@ public class BatteryUsageStatsTest {
.setUsageDurationMillis(cpuBgKey, cpuDurationBackground)
.setConsumedPower(cpuFgsKey, cpuPowerFgs,
BatteryConsumer.POWER_MODEL_POWER_PROFILE)
- .setUsageDurationMillis(cpuFgsKey, cpuDurationFgs);
+ .setUsageDurationMillis(cpuFgsKey, cpuDurationFgs)
+ .setConsumedPower(cpuCachedKey, cpuPowerCached,
+ BatteryConsumer.POWER_MODEL_POWER_PROFILE)
+ .setUsageDurationMillis(cpuCachedKey, cpuDurationCached);
}
}
@@ -432,7 +448,7 @@ public class BatteryUsageStatsTest {
1000, 2000, 300, BatteryConsumer.POWER_MODEL_POWER_PROFILE, 400,
BatteryConsumer.POWER_MODEL_POWER_PROFILE,
500, 600, 800,
- true, 1777, 1888, 1999, 1777, 7771, 1888, 8881, 1999, 9991);
+ true, 1777, 1888, 1999, 123, 1777, 7771, 1888, 8881, 1999, 9991, 123, 456);
} else {
fail("Unexpected UID " + uidBatteryConsumer.getUid());
}
@@ -484,8 +500,10 @@ public class BatteryUsageStatsTest {
int cpuPowerModel, double customComponentPower, int cpuDuration,
int customComponentDuration, boolean processStateDataIncluded,
double totalPowerForeground, double totalPowerBackground, double totalPowerFgs,
- double cpuPowerForeground, int cpuDurationForeground, double cpuPowerBackground,
- int cpuDurationBackground, double cpuPowerFgs, int cpuDurationFgs) {
+ double totalPowerCached, double cpuPowerForeground, int cpuDurationForeground,
+ double cpuPowerBackground,
+ int cpuDurationBackground, double cpuPowerFgs, int cpuDurationFgs,
+ int cpuPowerCached, int cpuDurationCached) {
assertThat(uidBatteryConsumer.getConsumedPower()).isEqualTo(consumedPower);
assertThat(uidBatteryConsumer.getPackageWithHighestDrain()).isEqualTo(
packageWithHighestDrain);
@@ -525,6 +543,10 @@ public class BatteryUsageStatsTest {
new BatteryConsumer.Dimensions(POWER_COMPONENT_ANY,
PROCESS_STATE_FOREGROUND_SERVICE)))
.isEqualTo(totalPowerFgs);
+ assertThat(uidBatteryConsumer.getConsumedPower(
+ new BatteryConsumer.Dimensions(POWER_COMPONENT_ANY,
+ PROCESS_STATE_CACHED)))
+ .isEqualTo(totalPowerCached);
}
final BatteryConsumer.Key cpuFgKey = uidBatteryConsumer.getKey(
@@ -563,6 +585,19 @@ public class BatteryUsageStatsTest {
} else {
assertThat(cpuFgsKey).isNotNull();
}
+
+ final BatteryConsumer.Key cachedKey = uidBatteryConsumer.getKey(
+ BatteryConsumer.POWER_COMPONENT_CPU,
+ BatteryConsumer.PROCESS_STATE_CACHED);
+ if (processStateDataIncluded) {
+ assertThat(cachedKey).isNotNull();
+ assertThat(uidBatteryConsumer.getConsumedPower(cachedKey))
+ .isEqualTo(cpuPowerCached);
+ assertThat(uidBatteryConsumer.getUsageDurationMillis(cachedKey))
+ .isEqualTo(cpuDurationCached);
+ } else {
+ assertThat(cpuFgsKey).isNotNull();
+ }
}
private void assertUserBatteryConsumer(UserBatteryConsumer userBatteryConsumer,
diff --git a/core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java
index 448f6664c2fa..fdbf071b7bba 100644
--- a/core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java
@@ -145,10 +145,14 @@ public class BluetoothPowerCalculatorTest {
final BatteryConsumer.Key fgs = uidConsumer.getKey(
BatteryConsumer.POWER_COMPONENT_BLUETOOTH,
BatteryConsumer.PROCESS_STATE_FOREGROUND_SERVICE);
+ final BatteryConsumer.Key cached = uidConsumer.getKey(
+ BatteryConsumer.POWER_COMPONENT_BLUETOOTH,
+ BatteryConsumer.PROCESS_STATE_CACHED);
assertThat(uidConsumer.getConsumedPower(foreground)).isWithin(PRECISION).of(0.081);
assertThat(uidConsumer.getConsumedPower(background)).isWithin(PRECISION).of(0.0416666);
assertThat(uidConsumer.getConsumedPower(fgs)).isWithin(PRECISION).of(0);
+ assertThat(uidConsumer.getConsumedPower(cached)).isWithin(PRECISION).of(0);
}
@Test
@@ -261,10 +265,14 @@ public class BluetoothPowerCalculatorTest {
final BatteryConsumer.Key fgs = uidConsumer.getKey(
BatteryConsumer.POWER_COMPONENT_BLUETOOTH,
BatteryConsumer.PROCESS_STATE_FOREGROUND_SERVICE);
+ final BatteryConsumer.Key cached = uidConsumer.getKey(
+ BatteryConsumer.POWER_COMPONENT_BLUETOOTH,
+ BatteryConsumer.PROCESS_STATE_CACHED);
assertThat(uidConsumer.getConsumedPower(foreground)).isWithin(PRECISION).of(0.4965352);
assertThat(uidConsumer.getConsumedPower(background)).isWithin(PRECISION).of(0.3255208);
assertThat(uidConsumer.getConsumedPower(fgs)).isWithin(PRECISION).of(0);
+ assertThat(uidConsumer.getConsumedPower(cached)).isWithin(PRECISION).of(0);
}
diff --git a/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java b/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java
index b89e8bce5fc9..625f52a87ecf 100644
--- a/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java
@@ -232,7 +232,7 @@ public final class LooperStatsTest {
assertThat(entry3.handlerClassName).isEqualTo(
"com.android.internal.os.LooperStatsTest$TestHandlerSecond");
assertThat(entry3.messageName).startsWith(
- "com.android.internal.os.LooperStatsTest$$ExternalSyntheticLambda4");
+ "com.android.internal.os.LooperStatsTest$$ExternalSyntheticLambda");
assertThat(entry3.messageCount).isEqualTo(1);
assertThat(entry3.recordedMessageCount).isEqualTo(1);
assertThat(entry3.exceptionCount).isEqualTo(0);
diff --git a/core/tests/coretests/src/com/android/internal/widget/LockPatternViewTest.java b/core/tests/coretests/src/com/android/internal/widget/LockPatternViewTest.java
new file mode 100644
index 000000000000..8ba49663ad09
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/widget/LockPatternViewTest.java
@@ -0,0 +1,247 @@
+/*
+ * 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.internal.widget;
+
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+
+import android.content.Context;
+
+import androidx.test.annotation.UiThreadTest;
+
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Toolbar;
+
+
+import static org.hamcrest.Matchers.contains;
+import static org.hamcrest.Matchers.hasSize;
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.rule.UiThreadTestRule;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.mockito.ArgumentCaptor;
+import org.mockito.ArgumentMatchers;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import com.android.internal.R;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+@RunWith(Parameterized.class)
+@SmallTest
+public class LockPatternViewTest {
+
+ @Rule
+ public UiThreadTestRule uiThreadTestRule = new UiThreadTestRule();
+
+ private final int mViewSize;
+ private final float mDefaultError;
+ private final float mDot1x;
+ private final float mDot1y;
+ private final float mDot2x;
+ private final float mDot2y;
+ private final float mDot3x;
+ private final float mDot3y;
+ private final float mDot5x;
+ private final float mDot5y;
+ private final float mDot7x;
+ private final float mDot7y;
+ private final float mDot9x;
+ private final float mDot9y;
+
+ private Context mContext;
+ private LockPatternView mLockPatternView;
+ @Mock
+ private LockPatternView.OnPatternListener mPatternListener;
+ @Captor
+ private ArgumentCaptor<List<LockPatternView.Cell>> mCellsArgumentCaptor;
+
+ public LockPatternViewTest(int viewSize) {
+ mViewSize = viewSize;
+ float cellSize = viewSize / 3f;
+ mDefaultError = cellSize * 0.2f;
+ mDot1x = cellSize / 2f;
+ mDot1y = cellSize / 2f;
+ mDot2x = cellSize + mDot1x;
+ mDot2y = mDot1y;
+ mDot3x = cellSize + mDot2x;
+ mDot3y = mDot1y;
+ // dot4 is skipped as redundant
+ mDot5x = cellSize + mDot1x;
+ mDot5y = cellSize + mDot1y;
+ // dot6 is skipped as redundant
+ mDot7x = mDot1x;
+ mDot7y = cellSize * 2 + mDot1y;
+ // dot8 is skipped as redundant
+ mDot9x = cellSize * 2 + mDot7x;
+ mDot9y = mDot7y;
+ }
+
+ @Parameterized.Parameters
+ public static Collection primeNumbers() {
+ return Arrays.asList(192, 512, 768, 1024);
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ mContext = InstrumentationRegistry.getContext();
+ mLockPatternView = new LockPatternView(mContext, null);
+ int heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(mViewSize,
+ View.MeasureSpec.EXACTLY);
+ int widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(mViewSize,
+ View.MeasureSpec.EXACTLY);
+ mLockPatternView.measure(widthMeasureSpec, heightMeasureSpec);
+ mLockPatternView.layout(0, 0, mLockPatternView.getMeasuredWidth(),
+ mLockPatternView.getMeasuredHeight());
+ }
+
+ @UiThreadTest
+ @Test
+ public void downStartsPattern() {
+ mLockPatternView.setOnPatternListener(mPatternListener);
+ mLockPatternView.onTouchEvent(
+ MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, mDot1x, mDot1y, 1));
+ verify(mPatternListener).onPatternStart();
+ }
+
+ @UiThreadTest
+ @Test
+ public void up_completesPattern() {
+ mLockPatternView.setOnPatternListener(mPatternListener);
+ mLockPatternView.onTouchEvent(
+ MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, mDot1x, mDot1y, 1));
+ mLockPatternView.onTouchEvent(
+ MotionEvent.obtain(0, 0, MotionEvent.ACTION_UP, mDot1x, mDot1y, 1));
+ verify(mPatternListener).onPatternDetected(any());
+ }
+
+ @UiThreadTest
+ @Test
+ public void moveToDot_hitsDot() {
+ mLockPatternView.setOnPatternListener(mPatternListener);
+ mLockPatternView.onTouchEvent(
+ MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 1f, 1f, 1));
+ mLockPatternView.onTouchEvent(
+ MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, mDot1x, mDot1y, 1));
+ verify(mPatternListener).onPatternStart();
+ }
+
+ @UiThreadTest
+ @Test
+ public void moveOutside_doesNotHitsDot() {
+ mLockPatternView.setOnPatternListener(mPatternListener);
+ mLockPatternView.onTouchEvent(
+ MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 1f, 1f, 1));
+ mLockPatternView.onTouchEvent(
+ MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, 2f, 2f, 1));
+ verify(mPatternListener, never()).onPatternStart();
+ }
+
+ @UiThreadTest
+ @Test
+ public void moveAlongTwoDots_hitsTwo() {
+ mLockPatternView.setOnPatternListener(mPatternListener);
+ mLockPatternView.onTouchEvent(
+ MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 1f, 1f, 1));
+ makeMove(mDot1x, mDot1y, mDot2x, mDot2y, 6);
+ mLockPatternView.onTouchEvent(
+ MotionEvent.obtain(0, 3, MotionEvent.ACTION_UP, mDot2x, mDot2y, 1));
+
+ verify(mPatternListener).onPatternDetected(mCellsArgumentCaptor.capture());
+ List<LockPatternView.Cell> patternCells = mCellsArgumentCaptor.getValue();
+ assertThat(patternCells, hasSize(2));
+ assertThat(patternCells,
+ contains(LockPatternView.Cell.of(0, 0), LockPatternView.Cell.of(0, 1)));
+ }
+
+ @UiThreadTest
+ @Test
+ public void moveAlongTwoDotsDiagonally_hitsTwo() {
+ mLockPatternView.setOnPatternListener(mPatternListener);
+ mLockPatternView.onTouchEvent(
+ MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 1f, 1f, 1));
+ makeMove(mDot1x, mDot1y, mDot5x, mDot5y, 6);
+ mLockPatternView.onTouchEvent(
+ MotionEvent.obtain(0, 3, MotionEvent.ACTION_UP, mDot5x, mDot5y, 1));
+
+ verify(mPatternListener).onPatternDetected(mCellsArgumentCaptor.capture());
+ List<LockPatternView.Cell> patternCells = mCellsArgumentCaptor.getValue();
+ assertThat(patternCells, hasSize(2));
+ assertThat(patternCells,
+ contains(LockPatternView.Cell.of(0, 0), LockPatternView.Cell.of(1, 1)));
+ }
+
+ @UiThreadTest
+ @Test
+ public void moveAlongZPattern_hitsDots() {
+ mLockPatternView.setOnPatternListener(mPatternListener);
+ mLockPatternView.onTouchEvent(
+ MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 1f, 1f, 1));
+ makeMove(mDot1x, mDot1y, mDot3x + mDefaultError, mDot3y, 10);
+ makeMove(mDot3x - mDefaultError, mDot3y, mDot7x, mDot7y, 10);
+ makeMove(mDot7x, mDot7y - mDefaultError, mDot9x, mDot9y - mDefaultError, 10);
+ mLockPatternView.onTouchEvent(
+ MotionEvent.obtain(0, 0, MotionEvent.ACTION_UP, mViewSize - mDefaultError,
+ mViewSize - mDefaultError, 1));
+
+ verify(mPatternListener).onPatternDetected(mCellsArgumentCaptor.capture());
+ List<LockPatternView.Cell> patternCells = mCellsArgumentCaptor.getValue();
+ assertThat(patternCells, hasSize(7));
+ assertThat(patternCells,
+ contains(LockPatternView.Cell.of(0, 0),
+ LockPatternView.Cell.of(0, 1),
+ LockPatternView.Cell.of(0, 2),
+ LockPatternView.Cell.of(1, 1),
+ LockPatternView.Cell.of(2, 0),
+ LockPatternView.Cell.of(2, 1),
+ LockPatternView.Cell.of(2, 2)));
+ }
+
+ private void makeMove(float xFrom, float yFrom, float xTo, float yTo, int numberOfSteps) {
+ for (int i = 0; i < numberOfSteps; i++) {
+ float progress = i / (numberOfSteps - 1f);
+ float rest = 1f - progress;
+ mLockPatternView.onTouchEvent(
+ MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE,
+ /* x= */ xFrom * rest + xTo * progress,
+ /* y= */ yFrom * rest + yTo * progress,
+ 1));
+ }
+ }
+}
diff --git a/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java b/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java
index f8db069b99ce..b006a1681a99 100644
--- a/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java
+++ b/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java
@@ -16,12 +16,15 @@
package android.app.activity;
+import static android.app.ActivityThread.shouldReportChange;
import static android.app.servertransaction.ActivityLifecycleItem.ON_CREATE;
import static android.app.servertransaction.ActivityLifecycleItem.ON_DESTROY;
import static android.app.servertransaction.ActivityLifecycleItem.ON_PAUSE;
import static android.app.servertransaction.ActivityLifecycleItem.ON_RESUME;
import static android.app.servertransaction.ActivityLifecycleItem.ON_START;
import static android.app.servertransaction.ActivityLifecycleItem.ON_STOP;
+import static android.content.pm.ActivityInfo.CONFIG_FONT_SCALE;
+import static android.content.pm.ActivityInfo.CONFIG_SCREEN_SIZE;
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
@@ -31,6 +34,8 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSess
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.clearInvocations;
@@ -56,6 +61,7 @@ import android.os.UserHandle;
import android.platform.test.annotations.Presubmit;
import android.testing.PollingCheck;
import android.view.WindowManagerGlobal;
+import android.window.SizeConfigurationBuckets;
import androidx.test.annotation.UiThreadTest;
import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -195,6 +201,47 @@ public class ActivityThreadClientTest {
}
}
+ @Test
+ public void testShouldReportChange() {
+ final Configuration newConfig = new Configuration();
+ final Configuration currentConfig = new Configuration();
+
+ assertFalse("Must not report change if no public diff",
+ shouldReportChange(0 /* publicDiff */, currentConfig, newConfig,
+ null /* sizeBuckets */, 0 /* handledConfigChanges */));
+
+ final int[] verticalThresholds = {100, 400};
+ final SizeConfigurationBuckets buckets = new SizeConfigurationBuckets(
+ null /* horizontal */,
+ verticalThresholds,
+ null /* smallest */,
+ null /* screenLayoutSize */,
+ false /* screenLayoutLongSet */);
+ currentConfig.screenHeightDp = 200;
+ newConfig.screenHeightDp = 300;
+
+ assertFalse("Must not report changes if the diff is small and not handled",
+ shouldReportChange(CONFIG_SCREEN_SIZE /* publicDiff */, currentConfig,
+ newConfig, buckets, CONFIG_FONT_SCALE /* handledConfigChanges */));
+
+ assertTrue("Must report changes if the small diff is handled",
+ shouldReportChange(CONFIG_SCREEN_SIZE /* publicDiff */, currentConfig, newConfig,
+ buckets, CONFIG_SCREEN_SIZE /* handledConfigChanges */));
+
+ currentConfig.fontScale = 0.8f;
+ newConfig.fontScale = 1.2f;
+
+ assertTrue("Must report handled changes regardless of small unhandled change",
+ shouldReportChange(CONFIG_SCREEN_SIZE | CONFIG_FONT_SCALE /* publicDiff */,
+ currentConfig, newConfig, buckets, CONFIG_FONT_SCALE /* handledConfigChanges */));
+
+ newConfig.screenHeightDp = 500;
+
+ assertFalse("Must not report changes if there's unhandled big changes",
+ shouldReportChange(CONFIG_SCREEN_SIZE | CONFIG_FONT_SCALE /* publicDiff */,
+ currentConfig, newConfig, buckets, CONFIG_FONT_SCALE /* handledConfigChanges */));
+ }
+
private void recreateAndVerifyNoRelaunch(ActivityThread activityThread, TestActivity activity) {
clearInvocations(activityThread);
getInstrumentation().runOnMainSync(() -> activity.recreate());
diff --git a/core/tests/mockingcoretests/src/android/util/TimingsTraceLogTest.java b/core/tests/mockingcoretests/src/android/util/TimingsTraceLogTest.java
index 5dc44d21c6b7..8de919681006 100644
--- a/core/tests/mockingcoretests/src/android/util/TimingsTraceLogTest.java
+++ b/core/tests/mockingcoretests/src/android/util/TimingsTraceLogTest.java
@@ -123,7 +123,7 @@ public class TimingsTraceLogTest {
public void testLogDuration() throws Exception {
TimingsTraceLog log = new TimingsTraceLog(TAG, TRACE_TAG_APP, 10);
log.logDuration("logro", 42);
- verify((MockedVoidMethod) () -> Slog.d(eq(TAG), contains("logro took to complete: 42ms")));
+ verify((MockedVoidMethod) () -> Slog.v(eq(TAG), contains("logro took to complete: 42ms")));
}
@Test
@@ -134,7 +134,7 @@ public class TimingsTraceLogTest {
verify((MockedVoidMethod) () -> Trace.traceBegin(TRACE_TAG_APP, "test"));
verify((MockedVoidMethod) () -> Trace.traceEnd(TRACE_TAG_APP));
- verify((MockedVoidMethod) () -> Slog.d(eq(TAG), matches("test took to complete: \\dms")));
+ verify((MockedVoidMethod) () -> Slog.v(eq(TAG), matches("test took to complete: \\dms")));
}
@Test
@@ -149,8 +149,8 @@ public class TimingsTraceLogTest {
verify((MockedVoidMethod) () -> Trace.traceBegin(TRACE_TAG_APP, "L2"));
verify((MockedVoidMethod) () -> Trace.traceEnd(TRACE_TAG_APP), times(2)); // L1 and L2
- verify((MockedVoidMethod) () -> Slog.d(eq(TAG), matches("L2 took to complete: \\d+ms")));
- verify((MockedVoidMethod) () -> Slog.d(eq(TAG), matches("L1 took to complete: \\d+ms")));
+ verify((MockedVoidMethod) () -> Slog.v(eq(TAG), matches("L2 took to complete: \\d+ms")));
+ verify((MockedVoidMethod) () -> Slog.v(eq(TAG), matches("L1 took to complete: \\d+ms")));
}
@Test
@@ -170,9 +170,9 @@ public class TimingsTraceLogTest {
verify((MockedVoidMethod) () -> Trace.traceBegin(TRACE_TAG_APP, "L3"));
verify((MockedVoidMethod) () -> Trace.traceEnd(TRACE_TAG_APP), times(3));
- verify((MockedVoidMethod) () -> Slog.d(eq(TAG), matches("L2 took to complete: \\d+ms")));
- verify((MockedVoidMethod) () -> Slog.d(eq(TAG), matches("L1 took to complete: \\d+ms")));
- verify((MockedVoidMethod) () -> Slog.d(eq(TAG), matches("L3 took to complete: \\d+ms")),
+ verify((MockedVoidMethod) () -> Slog.v(eq(TAG), matches("L2 took to complete: \\d+ms")));
+ verify((MockedVoidMethod) () -> Slog.v(eq(TAG), matches("L1 took to complete: \\d+ms")));
+ verify((MockedVoidMethod) () -> Slog.v(eq(TAG), matches("L3 took to complete: \\d+ms")),
never());
verify((MockedVoidMethod) () -> Slog.w(TAG, "not tracing duration of 'L3' "
diff --git a/core/tests/utiltests/src/com/android/internal/util/LockPatternUtilsTest.java b/core/tests/utiltests/src/com/android/internal/util/LockPatternUtilsTest.java
index b659f37690a3..940ca96fac4f 100644
--- a/core/tests/utiltests/src/com/android/internal/util/LockPatternUtilsTest.java
+++ b/core/tests/utiltests/src/com/android/internal/util/LockPatternUtilsTest.java
@@ -19,14 +19,20 @@ package com.android.internal.util;
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_MANAGED;
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.anyString;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.content.ComponentName;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.pm.UserInfo;
@@ -50,6 +56,7 @@ import org.junit.runner.RunWith;
import org.mockito.Mockito;
import java.nio.charset.StandardCharsets;
+import java.util.List;
@RunWith(AndroidJUnit4.class)
@SmallTest
@@ -164,6 +171,16 @@ public class LockPatternUtilsTest {
verify(ils).isWeakEscrowTokenValid(eq(testHandle), eq(testToken), eq(testUserId));
}
+ @Test
+ public void testGetEnabledTrustAgentsNotNull() throws RemoteException {
+ int testUserId = 10;
+ ILockSettings ils = createTestLockSettings();
+ when(ils.getString(anyString(), any(), anyInt())).thenReturn("");
+ List<ComponentName> trustAgents = mLockPatternUtils.getEnabledTrustAgents(testUserId);
+ assertNotNull(trustAgents);
+ assertEquals(0, trustAgents.size());
+ }
+
private ILockSettings createTestLockSettings() {
final Context context = spy(new ContextWrapper(InstrumentationRegistry.getTargetContext()));
mLockPatternUtils = spy(new LockPatternUtils(context));
diff --git a/data/etc/Android.bp b/data/etc/Android.bp
index 2a82d8ecf5ee..df51871c57d9 100644
--- a/data/etc/Android.bp
+++ b/data/etc/Android.bp
@@ -71,14 +71,6 @@ prebuilt_etc {
}
prebuilt_etc {
- name: "privapp_whitelist_com.android.cellbroadcastreceiver",
- system_ext_specific: true,
- sub_dir: "permissions",
- src: "com.android.cellbroadcastreceiver.xml",
- filename_from_src: true,
-}
-
-prebuilt_etc {
name: "privapp_whitelist_com.android.contacts",
product_specific: true,
sub_dir: "permissions",
diff --git a/data/etc/com.android.cellbroadcastreceiver.xml b/data/etc/com.android.cellbroadcastreceiver.xml
deleted file mode 100644
index bc62bbc845f3..000000000000
--- a/data/etc/com.android.cellbroadcastreceiver.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2020 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-<permissions>
- <privapp-permissions package="com.android.cellbroadcastreceiver">
- <permission name="android.permission.BROADCAST_CLOSE_SYSTEM_DIALOGS"/>
- <permission name="android.permission.INTERACT_ACROSS_USERS"/>
- <permission name="android.permission.MANAGE_USERS"/>
- <permission name="android.permission.STATUS_BAR"/>
- <permission name="android.permission.MODIFY_PHONE_STATE"/>
- <permission name="android.permission.MODIFY_CELL_BROADCASTS"/>
- <permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
- <permission name="android.permission.RECEIVE_EMERGENCY_BROADCAST"/>
- <permission name="android.permission.START_ACTIVITIES_FROM_BACKGROUND"/>
- </privapp-permissions>
-</permissions>
diff --git a/data/etc/com.android.launcher3.xml b/data/etc/com.android.launcher3.xml
index 598d2027a0e9..36a51341f52d 100644
--- a/data/etc/com.android.launcher3.xml
+++ b/data/etc/com.android.launcher3.xml
@@ -16,6 +16,7 @@
-->
<permissions>
<privapp-permissions package="com.android.launcher3">
+ <permission name="android.permission.ALLOW_SLIPPERY_TOUCHES"/>
<permission name="android.permission.BIND_APPWIDGET"/>
<permission name="android.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS"/>
<permission name="android.permission.GET_ACCOUNTS_PRIVILEGED"/>
diff --git a/data/etc/com.android.systemui.xml b/data/etc/com.android.systemui.xml
index ae350ec547c3..2d1db716b700 100644
--- a/data/etc/com.android.systemui.xml
+++ b/data/etc/com.android.systemui.xml
@@ -17,6 +17,7 @@
<permissions>
<privapp-permissions package="com.android.systemui">
<permission name="android.permission.CAPTURE_AUDIO_OUTPUT"/>
+ <permission name="android.permission.ALLOW_SLIPPERY_TOUCHES"/>
<permission name="android.permission.BATTERY_STATS"/>
<permission name="android.permission.BIND_APPWIDGET"/>
<permission name="android.permission.BLUETOOTH_PRIVILEGED"/>
@@ -75,5 +76,8 @@
<permission name="android.permission.FORCE_STOP_PACKAGES" />
<permission name="android.permission.ACCESS_FPS_COUNTER" />
<permission name="android.permission.CHANGE_CONFIGURATION" />
+ <permission name="android.permission.LOG_COMPAT_CHANGE" />
+ <permission name="android.permission.READ_COMPAT_CHANGE_CONFIG" />
+ <permission name="android.permission.READ_DEVICE_CONFIG" />
</privapp-permissions>
</permissions>
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index 88920c865511..a8293397d7df 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -241,7 +241,7 @@
</split-permission>
<split-permission name="android.permission.READ_EXTERNAL_STORAGE"
targetSdk="33">
- <new-permission name="android.permission.READ_MEDIA_IMAGE" />
+ <new-permission name="android.permission.READ_MEDIA_IMAGES" />
</split-permission>
<split-permission name="android.permission.BLUETOOTH"
targetSdk="31">
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 3c64cf55eb50..a9730785723b 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -38,24 +38,6 @@ applications that come with the platform
<permission name="android.permission.CRYPT_KEEPER"/>
</privapp-permissions>
- <privapp-permissions package="com.android.cellbroadcastreceiver.module">
- <permission name="android.permission.BROADCAST_CLOSE_SYSTEM_DIALOGS"/>
- <permission name="android.permission.INTERACT_ACROSS_USERS"/>
- <permission name="android.permission.MANAGE_USERS"/>
- <permission name="android.permission.STATUS_BAR"/>
- <permission name="android.permission.MODIFY_PHONE_STATE"/>
- <permission name="android.permission.MODIFY_CELL_BROADCASTS"/>
- <permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
- <permission name="android.permission.RECEIVE_EMERGENCY_BROADCAST"/>
- <permission name="android.permission.START_ACTIVITIES_FROM_BACKGROUND"/>
- </privapp-permissions>
-
- <privapp-permissions package="com.android.cellbroadcastservice">
- <permission name="android.permission.MODIFY_PHONE_STATE"/>
- <permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
- <permission name="android.permission.RECEIVE_EMERGENCY_BROADCAST"/>
- </privapp-permissions>
-
<privapp-permissions package="com.android.externalstorage">
<permission name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
<permission name="android.permission.WRITE_MEDIA_STORAGE"/>
@@ -237,27 +219,6 @@ applications that come with the platform
<permission name="android.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS"/>
</privapp-permissions>
- <privapp-permissions package="com.android.providers.media.module">
- <permission name="android.permission.INTERACT_ACROSS_USERS"/>
- <permission name="android.permission.MANAGE_USERS"/>
- <permission name="android.permission.USE_RESERVED_DISK"/>
- <permission name="android.permission.WRITE_MEDIA_STORAGE"/>
- <permission name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
- <permission name="android.permission.WATCH_APPOPS"/>
- <permission name="android.permission.UPDATE_APP_OPS_STATS"/>
- <permission name="android.permission.UPDATE_DEVICE_STATS"/>
- <!-- Permissions required for reading and logging compat changes -->
- <permission name="android.permission.LOG_COMPAT_CHANGE" />
- <permission name="android.permission.READ_COMPAT_CHANGE_CONFIG" />
- <permission name="android.permission.REGISTER_STATS_PULL_ATOM" />
- <!-- Permissions required for reading DeviceConfig -->
- <permission name="android.permission.READ_DEVICE_CONFIG" />
- <permission name="android.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND"/>
- <permission name="android.permission.MODIFY_QUIET_MODE"/>
- <!-- Permissions required to check if an app is in the foreground or not during IO -->
- <permission name="android.permission.PACKAGE_USAGE_STATS"/>
- </privapp-permissions>
-
<privapp-permissions package="com.android.providers.telephony">
<permission name="android.permission.INTERACT_ACROSS_USERS"/>
<permission name="android.permission.MODIFY_PHONE_STATE"/>
@@ -296,6 +257,8 @@ applications that come with the platform
<!-- Needed for test only -->
<permission name="android.permission.BATTERY_PREDICTION"/>
<permission name="android.permission.BATTERY_STATS"/>
+ <!-- BLUETOOTH_PRIVILEGED is needed for test only -->
+ <permission name="android.permission.BLUETOOTH_PRIVILEGED"/>
<permission name="android.permission.BIND_APPWIDGET"/>
<permission name="android.permission.CHANGE_APP_IDLE_STATE"/>
<permission name="android.permission.CHANGE_COMPONENT_ENABLED_STATE"/>
@@ -473,10 +436,11 @@ applications that come with the platform
<permission name="android.permission.WIFI_ACCESS_COEX_UNSAFE_CHANNELS" />
<permission name="android.permission.WIFI_UPDATE_COEX_UNSAFE_CHANNELS" />
<permission name="android.permission.NEARBY_WIFI_DEVICES" />
+ <permission name="android.permission.MANAGE_WIFI_INTERFACES" />
<permission name="android.permission.OVERRIDE_WIFI_CONFIG" />
<!-- Permission needed for CTS test - ConcurrencyTest#testP2pExternalApprover
- P2P external approver API sets require MANAGE_WIFI_AUTO_JOIN permission. -->
- <permission name="android.permission.MANAGE_WIFI_AUTO_JOIN" />
+ P2P external approver API sets require MANAGE_WIFI_NETWORK_SELECTION permission. -->
+ <permission name="android.permission.MANAGE_WIFI_NETWORK_SELECTION" />
<!-- Permission required for CTS test CarrierMessagingServiceWrapperTest -->
<permission name="android.permission.BIND_CARRIER_SERVICES"/>
<!-- Permission required for CTS test - MusicRecognitionManagerTest -->
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index df2b2a395ea7..4449c48d28bb 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -1309,6 +1309,12 @@
"group": "WM_DEBUG_STATES",
"at": "com\/android\/server\/wm\/ActivityRecord.java"
},
+ "-711194343": {
+ "message": "Setting Activity.mLauncherTaskBehind to false. Activity=%s",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_BACK_PREVIEW",
+ "at": "com\/android\/server\/wm\/BackNavigationController.java"
+ },
"-706481945": {
"message": "TaskFragment parent info changed name=%s parentTaskId=%d",
"level": "VERBOSE",
@@ -2251,6 +2257,12 @@
"group": "WM_DEBUG_WINDOW_TRANSITIONS",
"at": "com\/android\/server\/wm\/TransitionController.java"
},
+ "264036181": {
+ "message": "Unable to retrieve task to start recording for display %d",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_CONTENT_RECORDING",
+ "at": "com\/android\/server\/wm\/ContentRecorder.java"
+ },
"269576220": {
"message": "Resuming rotation after drag",
"level": "DEBUG",
@@ -2587,6 +2599,12 @@
"group": "WM_DEBUG_APP_TRANSITIONS",
"at": "com\/android\/server\/wm\/WindowState.java"
},
+ "599897753": {
+ "message": "Previous Activity is %s. Back type is %s",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_BACK_PREVIEW",
+ "at": "com\/android\/server\/wm\/BackNavigationController.java"
+ },
"600140673": {
"message": "checkBootAnimationComplete: Waiting for anim complete",
"level": "INFO",
@@ -2671,12 +2689,6 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
- "664667685": {
- "message": "Activity %s: enableOnBackInvokedCallback=false. Returning null BackNavigationInfo.",
- "level": "DEBUG",
- "group": "WM_DEBUG_BACK_PREVIEW",
- "at": "com\/android\/server\/wm\/BackNavigationController.java"
- },
"665256544": {
"message": "All windows drawn!",
"level": "DEBUG",
@@ -2755,6 +2767,12 @@
"group": "WM_DEBUG_WALLPAPER",
"at": "com\/android\/server\/wm\/WallpaperWindowToken.java"
},
+ "736003885": {
+ "message": "Unable to retrieve the task token to start recording for display %d",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_CONTENT_RECORDING",
+ "at": "com\/android\/server\/wm\/ContentRecorder.java"
+ },
"736692676": {
"message": "Config is relaunching %s",
"level": "VERBOSE",
@@ -2785,6 +2803,12 @@
"group": "WM_DEBUG_RECENTS_ANIMATIONS",
"at": "com\/android\/server\/wm\/RecentsAnimation.java"
},
+ "778774915": {
+ "message": "Unable to record task since feature is disabled %d",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_CONTENT_RECORDING",
+ "at": "com\/android\/server\/wm\/ContentRecorder.java"
+ },
"781471998": {
"message": "moveWindowTokenToDisplay: Cannot move to the original display for token: %s",
"level": "WARN",
@@ -2887,6 +2911,12 @@
"group": "WM_DEBUG_STATES",
"at": "com\/android\/server\/wm\/TaskFragment.java"
},
+ "948208142": {
+ "message": "Setting Activity.mLauncherTaskBehind to true. Activity=%s",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_BACK_PREVIEW",
+ "at": "com\/android\/server\/wm\/BackNavigationController.java"
+ },
"950074526": {
"message": "setLockTaskMode: Can't lock due to auth",
"level": "WARN",
@@ -3103,6 +3133,12 @@
"group": "WM_DEBUG_APP_TRANSITIONS",
"at": "com\/android\/server\/wm\/DisplayContent.java"
},
+ "1172542963": {
+ "message": "onBackNavigationDone backType=%s, task=%s, prevTaskTopActivity=%s",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_BACK_PREVIEW",
+ "at": "com\/android\/server\/wm\/BackNavigationController.java"
+ },
"1178653181": {
"message": "Old wallpaper still the target.",
"level": "VERBOSE",
@@ -3415,11 +3451,11 @@
"group": "WM_DEBUG_APP_TRANSITIONS",
"at": "com\/android\/server\/wm\/ActivityRecord.java"
},
- "1554795024": {
- "message": "Previous Activity is %s",
+ "1544805551": {
+ "message": "Skipping app transition animation. task=%s",
"level": "DEBUG",
"group": "WM_DEBUG_BACK_PREVIEW",
- "at": "com\/android\/server\/wm\/BackNavigationController.java"
+ "at": "com\/android\/server\/wm\/Task.java"
},
"1557732761": {
"message": "For Intent %s bringing to top: %s",
diff --git a/graphics/java/android/graphics/Rect.java b/graphics/java/android/graphics/Rect.java
index 7e68bc06d506..1a522bd5e794 100644
--- a/graphics/java/android/graphics/Rect.java
+++ b/graphics/java/android/graphics/Rect.java
@@ -291,6 +291,14 @@ public final class Rect implements Parcelable {
}
/**
+ * @return {@code true} if the rectangle is valid (left <= right and top <= bottom).
+ * @hide
+ */
+ public boolean isValid() {
+ return left <= right && top <= bottom;
+ }
+
+ /**
* @return the rectangle's width. This does not check for a valid rectangle
* (i.e. left <= right) so the result may be negative.
*/
diff --git a/graphics/java/android/graphics/RuntimeShader.java b/graphics/java/android/graphics/RuntimeShader.java
index 2ff888b06dd8..6abe34b1d675 100644
--- a/graphics/java/android/graphics/RuntimeShader.java
+++ b/graphics/java/android/graphics/RuntimeShader.java
@@ -19,12 +19,228 @@ package android.graphics;
import android.annotation.ColorInt;
import android.annotation.ColorLong;
import android.annotation.NonNull;
+import android.view.Window;
import libcore.util.NativeAllocationRegistry;
/**
- * Shader that calculates per-pixel color via a user defined Android Graphics Shading Language
- * (AGSL) function.
+ * <p>A {@link RuntimeShader} calculates a per-pixel color based on the output of a user defined
+ * Android Graphics Shading Language (AGSL) function.</p>
+ *
+ * <h3>Android Graphics Shading Language</h3>
+ * <p>The AGSL syntax is very similar to OpenGL ES Shading Language, but there are some important
+ * differences that are highlighted here. Most of these differences are summed up in one basic fact:
+ * <b>With GPU shading languages, you are programming a stage of the GPU pipeline. With AGSL, you
+ * are programming a stage of the {@link Canvas} or {@link RenderNode} drawing pipeline.</b></p>
+ *
+ * <p>In particular, a GLSL fragment shader controls the entire behavior of the GPU between the
+ * rasterizer and the blending hardware. That shader does all of the work to compute a color, and
+ * the color it generates is exactly what is fed to the blending stage of the pipeline.</p>
+ *
+ * <p>In contrast, AGSL functions exist as part of a larger pipeline. When you issue a
+ * {@link Canvas} drawing operation, Android (generally) assembles a single GPU fragment shader to
+ * do all of the required work. This shader typically includes several pieces. For example, it might
+ * include:</p>
+ * <ul>
+ * <li>Evaluating whether a pixel falls inside or outside of the shape being drawn (or on the
+ * border, where it might apply antialiasing).</li>
+ * <li>Evaluating whether a pixel falls inside or outside of the clipping region (again, with
+ * possible antialiasing logic for border pixels).</li>
+ * <li>Logic for the {@link Shader}, {@link ColorFilter}, and {@link BlendMode} on the
+ * {@link Paint}.</li>
+ * <li>Color space conversion code, as part of Android’s color management.</li>
+ * </ul>
+ *
+ * <p>A {@link RuntimeShader}, like other {@link Shader} types, effectively contributes a function
+ * to the GPU’s fragment shader.</p>
+ *
+ * <h3>AGSL Shader Execution</h3>
+ * <p>Just like a GLSL shader, an AGSL shader begins execution in a main function. Unlike GLSL, the
+ * function receives as an input parameter the position of the pixel within the {@link Canvas} or
+ * {@link RenderNode} coordinate space (similar to gl_fragCoord) and returns the color to be shaded
+ * as a vec4 (similar to out vec4 color or gl_FragColor in GLSL).</p>
+ *
+ * <pre class="prettyprint">
+ * vec4 main(vec2 canvas_coordinates);
+ * </pre>
+ *
+ * <p>AGSL and GLSL use different coordinate spaces by default. In GLSL, the fragment coordinate
+ * (fragCoord) is relative to the lower left. AGSL matches the screen coordinate system of the
+ * Android {@link Canvas} which has its origin as the upper left corner. This means that the
+ * coordinates provided as a parameter in the main function are local to the canvas with the
+ * exception of any {@link Shader#getLocalMatrix(Matrix)} transformations applied to this shader.
+ * Additionally, if the shader is invoked by another using {@link #setInputShader(String, Shader)},
+ * then that parent shader may modify the input coordinates arbitrarily.</p>
+ *
+ * <h3>AGSL and Color Spaces</h3>
+ * <p>Android Graphics and by extension {@link RuntimeShader} are color managed. The working
+ * {@link ColorSpace} for an AGSL shader is defined to be the color space of the destination, which
+ * in most cases is determined by {@link Window#setColorMode(int)}.</p>
+ *
+ * <p>When authoring an AGSL shader, you won’t know what the working color space is. For many
+ * effects, this is fine because by default color inputs are automatically converted into the
+ * working color space. For certain effects, it may be important to do some math in a fixed, known
+ * color space. A common example is lighting – to get physically accurate lighting, math should be
+ * done in a linear color space. To help with this, AGSL provides two intrinsic functions that
+ * convert colors between the working color space and the
+ * {@link ColorSpace.Named#LINEAR_EXTENDED_SRGB} color space:
+ *
+ * <pre class="prettyprint">
+ * vec3 toLinearSrgb(vec3 color);
+ * vec3 fromLinearSrgb(vec3 color);</pre>
+ *
+ * <h3>AGSL and Premultiplied Alpha</h3>
+ * <p>When dealing with transparent colors, there are two (common) possible representations:
+ * straight (unassociated) alpha and premultiplied (associated) alpha. In ASGL the color returned
+ * by the main function is expected to be premultiplied. AGSL’s use of premultiplied alpha
+ * implies:
+ * </p>
+ *
+ * <ul>
+ * <li>If your AGSL shader will return transparent colors, be sure to multiply the RGB by A. The
+ * resulting color should be [R*A, G*A, B*A, A], not [R, G, B, A].</li>
+ * <li>For more complex shaders, you must understand which of your colors are premultiplied vs.
+ * straight. Many operations don’t make sense if you mix both kinds of color together.</li>
+ * </ul>
+ *
+ * <h3>Uniforms</h3>
+ * <p>AGSL, like GLSL, exposes the concept of uniforms. An AGSL uniform is defined as a read-only,
+ * global variable that is accessible by the AGSL code and is initialized by a number of setter
+ * methods on {@link RuntimeShader}. AGSL exposes two primitive uniform data types (float, int) and
+ * two specialized types (colors, shaders) that are outlined below.</p>
+ *
+ * <h4>Primitive Uniforms</h4>
+ * <p>There are two primitive uniform types supported by AGSL, float and int. For these types and
+ * uniforms representing a grouping of these types, like arrays and matrices, there are
+ * corresponding {@link RuntimeShader} methods to initialize them.
+ * <table border="2" width="85%" align="center" cellpadding="5">
+ * <thead>
+ * <tr><th>Java Type</th> <th>AGSL Type</th> <th>Method</th> </tr>
+ * </thead>
+ *
+ * <tbody>
+ * <tr>
+ * <td rowspan="4">Floats</td>
+ * <td>float</td>
+ * <td>{@link RuntimeShader#setFloatUniform(String, float)}</td>
+ * </tr>
+ * <tr>
+ * <td>vec2</td>
+ * <td>{@link RuntimeShader#setFloatUniform(String, float, float)}</td>
+ * </tr>
+ * <tr>
+ * <td>vec3</td>
+ * <td>{@link RuntimeShader#setFloatUniform(String, float, float, float)}</td>
+ * </tr>
+ * <tr>
+ * <td>vec4</td>
+ * <td>{@link RuntimeShader#setFloatUniform(String, float, float, float, float)}</td>
+ * </tr>
+ * <tr>
+ * <td rowspan="4">Integers</td>
+ * <td>int</td>
+ * <td>{@link RuntimeShader#setIntUniform(String, int)}</td>
+ * </tr>
+ * <tr>
+ * <td>ivec2</td>
+ * <td>{@link RuntimeShader#setIntUniform(String, int, int)}</td>
+ * </tr>
+ * <tr>
+ * <td>ivec3</td>
+ * <td>{@link RuntimeShader#setIntUniform(String, int, int, int)}</td>
+ * </tr>
+ * <tr>
+ * <td>ivec4</td>
+ * <td>{@link RuntimeShader#setIntUniform(String, int, int, int, int)}</td>
+ * </tr>
+ * <tr>
+ * <td rowspan="2">Matrices and Arrays</td>
+ * <td>mat2, mat3, and mat4, and float[]</td>
+ * <td>{@link RuntimeShader#setFloatUniform(String, float[])}</td>
+ * </tr>
+ * <tr>
+ * <td>int[]</td>
+ * <td>{@link RuntimeShader#setIntUniform(String, int[])}</td>
+ * </tr>
+ * </tbody>
+ * </table>
+ *
+ * For example, a simple AGSL shader making use of a float uniform to modulate the transparency
+ * of the output color would look like:</p>
+ *
+ * <pre class="prettyprint">
+ * uniform float alpha;
+ * vec4 main(vec2 canvas_coordinates) {
+ * vec3 red = vec3(1.0, 0.0, 0.0);
+ * return vec4(red * alpha, alpha);
+ * }</pre>
+ *
+ * <p>After creating a {@link RuntimeShader} with that program the uniform can then be initialized
+ * and updated per frame by calling {@link RuntimeShader#setFloatUniform(String, float)} with the
+ * value of alpha. The value of a primitive uniform defaults to 0 if it is declared in the AGSL
+ * shader but not initialized.</p>
+ *
+ * <h4>Color Uniforms</h4>
+ * <p>AGSL doesn't know if uniform variables contain colors, it won't automatically convert them to
+ * the working colorspace of the shader at runtime. However, you can label your vec4 uniform with
+ * the "layout(color)" qualifier which lets Android know that the uniform will be used as a color.
+ * Doing so allows AGSL to transform the uniform value to the working color space. In AGSL, declare
+ * the uniform like this:
+ *
+ * <pre class="prettyprint">
+ * layout(color) uniform vec4 inputColorA;
+ * layout(color) uniform vec4 inputColorB;
+ * vec4 main(vec2 canvas_coordinates) {
+ * // blend the two colors together and return the resulting color
+ * return mix(inputColorA, inputColorB, 0.5);
+ * }</pre>
+ *
+ * <p>After creating a {@link RuntimeShader} with that program the uniforms can
+ * then be initialized and updated per frame by calling
+ * {@link RuntimeShader#setColorUniform(String, int)},
+ * {@link RuntimeShader#setColorUniform(String, long)}, or
+ * {@link RuntimeShader#setColorUniform(String, Color)} with the desired colors. The value of a
+ * color uniform is undefined if it is declared in the AGSL shader but not initialized.</p>
+ *
+ * <h4>Shader Uniforms</h4>
+ * In GLSL, a fragment shader can sample a texture. For AGSL instead of sampling textures you can
+ * sample from any {@link Shader}, which includes but is not limited to {@link BitmapShader}. To
+ * make it clear that you are operating on an {@link Shader} object there is no "sample"
+ * method. Instead, the shader uniform has an "eval()" method. This distinction enables AGSL shaders
+ * to sample from existing bitmap and gradient shaders as well as other {@link RuntimeShader}
+ * objects. In AGSL, declare the uniform like this:
+ *
+ * <pre class="prettyprint">
+ * uniform shader myShader;
+ * vec4 main(vec2 canvas_coordinates) {
+ * // swap the red and blue color channels when sampling from myShader
+ * return myShader.sample(canvas_coordinates).bgra;
+ * }</pre>
+ *
+ * <p>After creating a {@link RuntimeShader} with that program the shader uniform can
+ * then be initialized and updated per frame by calling
+ * {@link RuntimeShader#setInputShader(String, Shader)} with the desired shader. The value of a
+ * shader uniform is undefined if it is declared in the AGSL shader but not initialized.</p>
+ *
+ * <p>Although most {@link BitmapShader}s contain colors that should be color managed, some contain
+ * data that isn’t actually colors. This includes bitmaps storing normals, material properties
+ * (e.g. roughness), heightmaps, or any other purely mathematical data that happens to be stored in
+ * a bitmap. When using these kinds of shaders in AGSL, you probably want to initialize them with
+ * {@link #setInputBuffer(String, BitmapShader)}. Shaders initialized this way work much like
+ * a regular {@link BitmapShader} (including filtering and tiling), with a few major differences:
+ * <ul>
+ * <li>No color space transformation is applied (the color space of the bitmap is ignored).</li>
+ * <li>Bitmaps that return false for {@link Bitmap#isPremultiplied()} are not automatically
+ * premultiplied.</li>
+ * </ul>
+ *
+ * <p>In addition, when sampling from a {@link BitmapShader} be aware that the shader does not use
+ * normalized coordinates (like a texture in GLSL). It uses (0, 0) in the upper-left corner, and
+ * (width, height) in the bottom-right corner. Normally, this is exactly what you want. If you’re
+ * evaluating the shader with coordinates based on the ones passed to your AGSL program, the scale
+ * is correct. However, if you want to adjust those coordinates (to do some kind of re-mapping of
+ * the bitmap), remember that the coordinates are local to the canvas.</p>
+ *
*/
public class RuntimeShader extends Shader {
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index 61f7facf0916..a2f5301e353f 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -329,7 +329,7 @@ public class Typeface {
FontFamily.Builder familyBuilder = null;
for (final FontFileResourceEntry fontFile : filesEntry.getEntries()) {
final Font.Builder fontBuilder = new Font.Builder(mgr, fontFile.getFileName(),
- false /* isAsset */, 0 /* cookie */)
+ false /* isAsset */, AssetManager.COOKIE_UNKNOWN)
.setTtcIndex(fontFile.getTtcIndex())
.setFontVariationSettings(fontFile.getVariationSettings());
if (fontFile.getWeight() != Typeface.RESOLVE_BY_FONT_TABLE) {
diff --git a/graphics/java/android/graphics/drawable/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java
index ffaa4ea51452..bfa6ce5d36c5 100644
--- a/graphics/java/android/graphics/drawable/RippleDrawable.java
+++ b/graphics/java/android/graphics/drawable/RippleDrawable.java
@@ -1000,7 +1000,7 @@ public class RippleDrawable extends LayerDrawable {
}
private int clampAlpha(@ColorInt int color) {
- if (Color.alpha(color) > 128) {
+ if (Color.alpha(color) < 128) {
return (color & 0x00FFFFFF) | 0x80000000;
}
return color;
@@ -1098,19 +1098,16 @@ public class RippleDrawable extends LayerDrawable {
}
// Draw the appropriate mask anchored to (0,0).
+ final int saveCount = mMaskCanvas.save();
final int left = bounds.left;
final int top = bounds.top;
- if (mState.mRippleStyle == STYLE_SOLID) {
- mMaskCanvas.translate(-left, -top);
- }
+ mMaskCanvas.translate(-left, -top);
if (maskType == MASK_EXPLICIT) {
drawMask(mMaskCanvas);
} else if (maskType == MASK_CONTENT) {
drawContent(mMaskCanvas);
}
- if (mState.mRippleStyle == STYLE_SOLID) {
- mMaskCanvas.translate(left, top);
- }
+ mMaskCanvas.restoreToCount(saveCount);
if (mState.mRippleStyle == STYLE_PATTERNED) {
for (int i = 0; i < mRunningAnimations.size(); i++) {
mRunningAnimations.get(i).getProperties().getShader().setShader(mMaskShader);
@@ -1210,9 +1207,13 @@ public class RippleDrawable extends LayerDrawable {
updateMaskShaderIfNeeded();
// Position the shader to account for canvas translation.
- if (mMaskShader != null && mState.mRippleStyle == STYLE_SOLID) {
+ if (mMaskShader != null) {
final Rect bounds = getBounds();
- mMaskMatrix.setTranslate(bounds.left - x, bounds.top - y);
+ if (mState.mRippleStyle == STYLE_PATTERNED) {
+ mMaskMatrix.setTranslate(bounds.left, bounds.top);
+ } else {
+ mMaskMatrix.setTranslate(bounds.left - x, bounds.top - y);
+ }
mMaskShader.setLocalMatrix(mMaskMatrix);
}
diff --git a/graphics/java/android/graphics/fonts/Font.java b/graphics/java/android/graphics/fonts/Font.java
index cd7936d50dff..abd0be9c2872 100644
--- a/graphics/java/android/graphics/fonts/Font.java
+++ b/graphics/java/android/graphics/fonts/Font.java
@@ -179,7 +179,7 @@ public final class Font {
*/
public Builder(@NonNull AssetManager am, @NonNull String path) {
try {
- mBuffer = createBuffer(am, path, true /* is asset */, 0 /* cookie */);
+ mBuffer = createBuffer(am, path, true /* is asset */, AssetManager.COOKIE_UNKNOWN);
} catch (IOException e) {
mException = e;
}
diff --git a/graphics/java/android/graphics/text/LineBreakConfig.java b/graphics/java/android/graphics/text/LineBreakConfig.java
index cffdf28dbc27..d083e444e996 100644
--- a/graphics/java/android/graphics/text/LineBreakConfig.java
+++ b/graphics/java/android/graphics/text/LineBreakConfig.java
@@ -26,7 +26,7 @@ import java.util.Objects;
/**
* Indicates the strategies can be used when calculating the text wrapping.
*
- * See <a href="https://drafts.csswg.org/css-text/#line-break-property">the line-break property</a>
+ * See <a href="https://www.w3.org/TR/css-text-3/#line-break-property">the line-break property</a>
*/
public final class LineBreakConfig {
@@ -78,39 +78,96 @@ public final class LineBreakConfig {
@Retention(RetentionPolicy.SOURCE)
public @interface LineBreakWordStyle {}
- private @LineBreakStyle int mLineBreakStyle = LINE_BREAK_STYLE_NONE;
- private @LineBreakWordStyle int mLineBreakWordStyle = LINE_BREAK_WORD_STYLE_NONE;
-
- public LineBreakConfig() {
+ /**
+ * A builder for creating {@link LineBreakConfig}.
+ */
+ public static final class Builder {
+ // The line break style for the LineBreakConfig.
+ private @LineBreakStyle int mLineBreakStyle = LineBreakConfig.LINE_BREAK_STYLE_NONE;
+
+ // The line break word style for the LineBreakConfig.
+ private @LineBreakWordStyle int mLineBreakWordStyle =
+ LineBreakConfig.LINE_BREAK_WORD_STYLE_NONE;
+
+ /**
+ * Builder constructor with line break parameters.
+ */
+ public Builder() {
+ }
+
+ /**
+ * Set the line break style.
+ *
+ * @param lineBreakStyle the new line break style.
+ * @return this Builder
+ */
+ public @NonNull Builder setLineBreakStyle(@LineBreakStyle int lineBreakStyle) {
+ mLineBreakStyle = lineBreakStyle;
+ return this;
+ }
+
+ /**
+ * Set the line break word style.
+ *
+ * @param lineBreakWordStyle the new line break word style.
+ * @return this Builder
+ */
+ public @NonNull Builder setLineBreakWordStyle(@LineBreakWordStyle int lineBreakWordStyle) {
+ mLineBreakWordStyle = lineBreakWordStyle;
+ return this;
+ }
+
+ /**
+ * Build the {@link LineBreakConfig}
+ *
+ * @return the LineBreakConfig instance.
+ */
+ public @NonNull LineBreakConfig build() {
+ return new LineBreakConfig(mLineBreakStyle, mLineBreakWordStyle);
+ }
}
/**
- * Set the line break configuration.
+ * Create the LineBreakConfig instance.
*
- * @param lineBreakConfig the new line break configuration.
+ * @param lineBreakStyle the line break style for text wrapping.
+ * @param lineBreakWordStyle the line break word style for text wrapping.
+ * @return the {@link LineBreakConfig} instance.
+ * @hide
*/
- public void set(@NonNull LineBreakConfig lineBreakConfig) {
- Objects.requireNonNull(lineBreakConfig);
- mLineBreakStyle = lineBreakConfig.getLineBreakStyle();
- mLineBreakWordStyle = lineBreakConfig.getLineBreakWordStyle();
+ public static @NonNull LineBreakConfig getLineBreakConfig(@LineBreakStyle int lineBreakStyle,
+ @LineBreakWordStyle int lineBreakWordStyle) {
+ LineBreakConfig.Builder builder = new LineBreakConfig.Builder();
+ return builder.setLineBreakStyle(lineBreakStyle)
+ .setLineBreakWordStyle(lineBreakWordStyle)
+ .build();
}
+ /** @hide */
+ public static final LineBreakConfig NONE =
+ new Builder().setLineBreakStyle(LINE_BREAK_STYLE_NONE)
+ .setLineBreakWordStyle(LINE_BREAK_WORD_STYLE_NONE).build();
+
+ private final @LineBreakStyle int mLineBreakStyle;
+ private final @LineBreakWordStyle int mLineBreakWordStyle;
+
/**
- * Get the line break style.
- *
- * @return The current line break style to be used for the text wrapping.
+ * Constructor with the line break parameters.
+ * Use the {@link LineBreakConfig.Builder} to create the LineBreakConfig instance.
*/
- public @LineBreakStyle int getLineBreakStyle() {
- return mLineBreakStyle;
+ private LineBreakConfig(@LineBreakStyle int lineBreakStyle,
+ @LineBreakWordStyle int lineBreakWordStyle) {
+ mLineBreakStyle = lineBreakStyle;
+ mLineBreakWordStyle = lineBreakWordStyle;
}
/**
- * Set the line break style.
+ * Get the line break style.
*
- * @param lineBreakStyle the new line break style.
+ * @return The current line break style to be used for the text wrapping.
*/
- public void setLineBreakStyle(@LineBreakStyle int lineBreakStyle) {
- mLineBreakStyle = lineBreakStyle;
+ public @LineBreakStyle int getLineBreakStyle() {
+ return mLineBreakStyle;
}
/**
@@ -122,15 +179,6 @@ public final class LineBreakConfig {
return mLineBreakWordStyle;
}
- /**
- * Set the line break word style.
- *
- * @param lineBreakWordStyle the new line break word style.
- */
- public void setLineBreakWordStyle(@LineBreakWordStyle int lineBreakWordStyle) {
- mLineBreakWordStyle = lineBreakWordStyle;
- }
-
@Override
public boolean equals(Object o) {
if (o == null) return false;
diff --git a/identity/java/android/security/identity/CredentialDataRequest.java b/identity/java/android/security/identity/CredentialDataRequest.java
index 2a47a02405e0..3482384a1fd9 100644
--- a/identity/java/android/security/identity/CredentialDataRequest.java
+++ b/identity/java/android/security/identity/CredentialDataRequest.java
@@ -153,7 +153,15 @@ public class CredentialDataRequest {
/**
* Sets whether to allow using an authentication key which use count has been exceeded.
*
- * By default this is set to true.
+ * <p>This is useful in situations where the application hasn't had a chance to renew
+ * authentication keys, for example if the device hasn't been connected to the Internet or
+ * if the issuing authority server has been down.
+ *
+ * <p>The reason this could be useful is that the privacy risk of reusing an authentication
+ * key for a credential presentation could be significantly smaller compared to the
+ * inconvenience of not being able to present the credential at all.
+ *
+ * <p>By default this is set to true.
*
* @param allowUsingExhaustedKeys whether to allow using an authentication key which use
* count has been exceeded if no other key is available.
@@ -167,7 +175,16 @@ public class CredentialDataRequest {
/**
* Sets whether to allow using an authentication key which is expired.
*
- * By default this is set to false.
+ * <p>This is useful in situations where the application hasn't had a chance to renew
+ * authentication keys, for example if the device hasn't been connected to the Internet or
+ * if the issuing authority server has been down.
+ *
+ * <p>The reason this could be useful is that many verifiers are likely to accept a
+ * credential presentation using an expired authentication key (the credential itself
+ * wouldn't be expired) and it's likely better for the holder to be able to do this than
+ * not present their credential at all.
+ *
+ * <p>By default this is set to false.
*
* @param allowUsingExpiredKeys whether to allow using an authentication key which is
* expired if no other key is available.
@@ -181,7 +198,12 @@ public class CredentialDataRequest {
/**
* Sets whether to increment the use-count for the authentication key used.
*
- * By default this is set to true.
+ * <p>Not incrementing the use-count for an authentication key is useful in situations
+ * where the authentication key is known with certainty to not be leaked. For example,
+ * consider an application doing a credential presentation for the sole purpose of
+ * displaying the credential data to the user (not for verification).
+ *
+ * <p>By default this is set to true.
*
* @param incrementUseCount whether to increment the use count of the authentication
* key used.
diff --git a/identity/java/android/security/identity/PresentationSession.java b/identity/java/android/security/identity/PresentationSession.java
index afaafce32798..6cde611fcd63 100644
--- a/identity/java/android/security/identity/PresentationSession.java
+++ b/identity/java/android/security/identity/PresentationSession.java
@@ -26,6 +26,9 @@ import java.security.PublicKey;
/**
* Class for presenting multiple documents to a remote verifier.
*
+ * <p>This should be used for all interactions with a remote verifier instead of the now deprecated
+ * {@link IdentityCredential#getEntries(byte[], Map, byte[], byte[])} method.
+ *
* Use {@link IdentityCredentialStore#createPresentationSession(int)} to create a {@link
* PresentationSession} instance.
*/
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
index 31dd10a8ed53..e7961c94928c 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
@@ -108,6 +108,16 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
}
}
+ /**
+ * XDH represents Curve 25519 providers.
+ */
+ public static class XDH extends AndroidKeyStoreKeyPairGeneratorSpi {
+ // XDH is treated as EC.
+ public XDH() {
+ super(KeymasterDefs.KM_ALGORITHM_EC);
+ }
+ }
+
/*
* These must be kept in sync with system/security/keystore/defaults.h
*/
@@ -242,6 +252,23 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
} catch (NullPointerException | IllegalArgumentException e) {
throw new InvalidAlgorithmParameterException(e);
}
+ } else if (params instanceof NamedParameterSpec) {
+ NamedParameterSpec namedSpec = (NamedParameterSpec) params;
+ // Android Keystore cannot support initialization from a NamedParameterSpec
+ // because an alias for the key is needed (a KeyGenParameterSpec cannot be
+ // constructed).
+ if (namedSpec.getName().equalsIgnoreCase(NamedParameterSpec.X25519.getName())
+ || namedSpec.getName().equalsIgnoreCase(
+ NamedParameterSpec.ED25519.getName())) {
+ throw new IllegalArgumentException(
+ "This KeyPairGenerator cannot be initialized using NamedParameterSpec."
+ + " use " + KeyGenParameterSpec.class.getName() + " or "
+ + KeyPairGeneratorSpec.class.getName());
+ } else {
+ throw new InvalidAlgorithmParameterException(
+ "Unsupported algorithm specified via NamedParameterSpec: "
+ + namedSpec.getName());
+ }
} else {
throw new InvalidAlgorithmParameterException(
"Unsupported params class: " + params.getClass().getName()
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java b/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
index 358104fffbf6..d31499e8b36d 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
@@ -83,16 +83,12 @@ public class AndroidKeyStoreProvider extends Provider {
// java.security.KeyPairGenerator
put("KeyPairGenerator.EC", PACKAGE_NAME + ".AndroidKeyStoreKeyPairGeneratorSpi$EC");
put("KeyPairGenerator.RSA", PACKAGE_NAME + ".AndroidKeyStoreKeyPairGeneratorSpi$RSA");
- put("KeyPairGenerator." + X25519_ALIAS,
- PACKAGE_NAME + ".AndroidKeyStoreKeyPairGeneratorSpi$RSA");
- put("KeyPairGenerator." + ED25519_OID,
- PACKAGE_NAME + ".AndroidKeyStoreKeyPairGeneratorSpi$RSA");
+ put("KeyPairGenerator.XDH", PACKAGE_NAME + ".AndroidKeyStoreKeyPairGeneratorSpi$XDH");
// java.security.KeyFactory
putKeyFactoryImpl("EC");
putKeyFactoryImpl("RSA");
- putKeyFactoryImpl(X25519_ALIAS);
- putKeyFactoryImpl(ED25519_OID);
+ putKeyFactoryImpl("XDH");
// javax.crypto.KeyGenerator
put("KeyGenerator.AES", PACKAGE_NAME + ".AndroidKeyStoreKeyGeneratorSpi$AES");
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/common/CommonDisplayFeature.java b/libs/WindowManager/Jetpack/src/androidx/window/common/CommonFoldingFeature.java
index eb9429747b66..1c49881904e4 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/common/CommonDisplayFeature.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/common/CommonFoldingFeature.java
@@ -18,17 +18,73 @@ package androidx.window.common;
import static androidx.window.util.ExtensionHelper.isZero;
+import android.annotation.IntDef;
import android.annotation.Nullable;
import android.graphics.Rect;
+import android.util.Log;
import androidx.annotation.NonNull;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-/** Wrapper for both Extension and Sidecar versions of DisplayFeature. */
-final class CommonDisplayFeature implements DisplayFeature {
+/** A representation of a folding feature for both Extension and Sidecar.
+ * For Sidecar this is the same as combining {@link androidx.window.sidecar.SidecarDeviceState} and
+ * {@link androidx.window.sidecar.SidecarDisplayFeature}. For Extensions this is the mirror of
+ * {@link androidx.window.extensions.layout.FoldingFeature}.
+ */
+public final class CommonFoldingFeature {
+
+ private static final boolean DEBUG = false;
+
+ public static final String TAG = CommonFoldingFeature.class.getSimpleName();
+
+ /**
+ * A common type to represent a hinge where the screen is continuous.
+ */
+ public static final int COMMON_TYPE_FOLD = 1;
+
+ /**
+ * A common type to represent a hinge where there is a physical gap separating multiple
+ * displays.
+ */
+ public static final int COMMON_TYPE_HINGE = 2;
+
+ @IntDef({COMMON_TYPE_FOLD, COMMON_TYPE_HINGE})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Type {
+ }
+
+ /**
+ * A common state to represent when the state is not known. One example is if the device is
+ * closed. We do not emit this value for developers but is useful for implementation reasons.
+ */
+ public static final int COMMON_STATE_UNKNOWN = -1;
+
+ /**
+ * A common state to represent a FLAT hinge. This is needed because the definitions in Sidecar
+ * and Extensions do not match exactly.
+ */
+ public static final int COMMON_STATE_FLAT = 3;
+ /**
+ * A common state to represent a HALF_OPENED hinge. This is needed because the definitions in
+ * Sidecar and Extensions do not match exactly.
+ */
+ public static final int COMMON_STATE_HALF_OPENED = 2;
+
+ /**
+ * The possible states for a folding hinge.
+ */
+ @IntDef({COMMON_STATE_UNKNOWN, COMMON_STATE_FLAT, COMMON_STATE_HALF_OPENED})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface State {
+ }
+
private static final Pattern FEATURE_PATTERN =
Pattern.compile("([a-z]+)-\\[(\\d+),(\\d+),(\\d+),(\\d+)]-?(flat|half-opened)?");
@@ -38,17 +94,49 @@ final class CommonDisplayFeature implements DisplayFeature {
private static final String PATTERN_STATE_FLAT = "flat";
private static final String PATTERN_STATE_HALF_OPENED = "half-opened";
- // TODO(b/183049815): Support feature strings that include the state of the feature.
+ /**
+ * Parse a {@link List} of {@link CommonFoldingFeature} from a {@link String}.
+ * @param value a {@link String} representation of multiple {@link CommonFoldingFeature}
+ * separated by a ":".
+ * @param hingeState a global fallback value for a {@link CommonFoldingFeature} if one is not
+ * specified in the input.
+ * @throws IllegalArgumentException if the provided string is improperly formatted or could not
+ * otherwise be parsed.
+ * @see #FEATURE_PATTERN
+ * @return {@link List} of {@link CommonFoldingFeature}.
+ */
+ static List<CommonFoldingFeature> parseListFromString(@NonNull String value,
+ @State int hingeState) {
+ List<CommonFoldingFeature> features = new ArrayList<>();
+ String[] featureStrings = value.split(";");
+ for (String featureString : featureStrings) {
+ CommonFoldingFeature feature;
+ try {
+ feature = CommonFoldingFeature.parseFromString(featureString, hingeState);
+ } catch (IllegalArgumentException e) {
+ if (DEBUG) {
+ Log.w(TAG, "Failed to parse display feature: " + featureString, e);
+ }
+ continue;
+ }
+ features.add(feature);
+ }
+ return features;
+ }
/**
* Parses a display feature from a string.
*
+ * @param string A {@link String} representation of a {@link CommonFoldingFeature}.
+ * @param hingeState A fallback value for the {@link State} if it is not specified in the input.
* @throws IllegalArgumentException if the provided string is improperly formatted or could not
* otherwise be parsed.
+ * @return {@link CommonFoldingFeature} represented by the {@link String} value.
* @see #FEATURE_PATTERN
*/
@NonNull
- static CommonDisplayFeature parseFromString(@NonNull String string) {
+ private static CommonFoldingFeature parseFromString(@NonNull String string,
+ @State int hingeState) {
Matcher featureMatcher = FEATURE_PATTERN.matcher(string);
if (!featureMatcher.matches()) {
throw new IllegalArgumentException("Malformed feature description format: " + string);
@@ -59,10 +147,10 @@ final class CommonDisplayFeature implements DisplayFeature {
int type;
switch (featureType) {
case FEATURE_TYPE_FOLD:
- type = 1 /* TYPE_FOLD */;
+ type = COMMON_TYPE_FOLD;
break;
case FEATURE_TYPE_HINGE:
- type = 2 /* TYPE_HINGE */;
+ type = COMMON_TYPE_HINGE;
break;
default: {
throw new IllegalArgumentException("Malformed feature type: " + featureType);
@@ -79,7 +167,7 @@ final class CommonDisplayFeature implements DisplayFeature {
}
String stateString = featureMatcher.group(6);
stateString = stateString == null ? "" : stateString;
- Integer state;
+ final int state;
switch (stateString) {
case PATTERN_STATE_FLAT:
state = COMMON_STATE_FLAT;
@@ -88,10 +176,10 @@ final class CommonDisplayFeature implements DisplayFeature {
state = COMMON_STATE_HALF_OPENED;
break;
default:
- state = null;
+ state = hingeState;
break;
}
- return new CommonDisplayFeature(type, state, featureRect);
+ return new CommonFoldingFeature(type, state, featureRect);
} catch (NumberFormatException e) {
throw new IllegalArgumentException("Malformed feature description: " + string, e);
}
@@ -99,11 +187,11 @@ final class CommonDisplayFeature implements DisplayFeature {
private final int mType;
@Nullable
- private final Integer mState;
+ private final int mState;
@NonNull
private final Rect mRect;
- CommonDisplayFeature(int type, @Nullable Integer state, @NonNull Rect rect) {
+ CommonFoldingFeature(int type, int state, @NonNull Rect rect) {
assertValidState(state);
this.mType = type;
this.mState = state;
@@ -114,16 +202,19 @@ final class CommonDisplayFeature implements DisplayFeature {
this.mRect = rect;
}
+ /** Returns the type of the feature. */
+ @Type
public int getType() {
return mType;
}
- /** Returns the state of the feature, or {@code null} if the feature has no state. */
- @Nullable
- public Integer getState() {
+ /** Returns the state of the feature.*/
+ @State
+ public int getState() {
return mState;
}
+ /** Returns the bounds of the feature. */
@NonNull
public Rect getRect() {
return mRect;
@@ -133,7 +224,7 @@ final class CommonDisplayFeature implements DisplayFeature {
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
- CommonDisplayFeature that = (CommonDisplayFeature) o;
+ CommonFoldingFeature that = (CommonFoldingFeature) o;
return mType == that.mType
&& Objects.equals(mState, that.mState)
&& mRect.equals(that.mRect);
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/common/DeviceStateManagerPostureProducer.java b/libs/WindowManager/Jetpack/src/androidx/window/common/DeviceStateManagerFoldingFeatureProducer.java
index fa9a5a8b7a1b..6987401525b4 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/common/DeviceStateManagerPostureProducer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/common/DeviceStateManagerFoldingFeatureProducer.java
@@ -18,11 +18,15 @@ package androidx.window.common;
import static android.hardware.devicestate.DeviceStateManager.INVALID_DEVICE_STATE;
+import static androidx.window.common.CommonFoldingFeature.COMMON_STATE_UNKNOWN;
+import static androidx.window.common.CommonFoldingFeature.parseListFromString;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.hardware.devicestate.DeviceStateManager;
import android.hardware.devicestate.DeviceStateManager.DeviceStateCallback;
+import android.text.TextUtils;
import android.util.Log;
import android.util.SparseIntArray;
@@ -30,6 +34,7 @@ import androidx.window.util.BaseDataProducer;
import com.android.internal.R;
+import java.util.List;
import java.util.Optional;
/**
@@ -37,10 +42,13 @@ import java.util.Optional;
* by mapping the state returned from {@link DeviceStateManager} to values provided in the resources
* config at {@link R.array#config_device_state_postures}.
*/
-public final class DeviceStateManagerPostureProducer extends BaseDataProducer<Integer> {
- private static final String TAG = "ConfigDevicePostureProducer";
+public final class DeviceStateManagerFoldingFeatureProducer extends
+ BaseDataProducer<List<CommonFoldingFeature>> {
+ private static final String TAG =
+ DeviceStateManagerFoldingFeatureProducer.class.getSimpleName();
private static final boolean DEBUG = false;
+ private final Context mContext;
private final SparseIntArray mDeviceStateToPostureMap = new SparseIntArray();
private int mCurrentDeviceState = INVALID_DEVICE_STATE;
@@ -50,7 +58,8 @@ public final class DeviceStateManagerPostureProducer extends BaseDataProducer<In
notifyDataChanged();
};
- public DeviceStateManagerPostureProducer(@NonNull Context context) {
+ public DeviceStateManagerFoldingFeatureProducer(@NonNull Context context) {
+ mContext = context;
String[] deviceStatePosturePairs = context.getResources()
.getStringArray(R.array.config_device_state_postures);
for (String deviceStatePosturePair : deviceStatePosturePairs) {
@@ -86,8 +95,17 @@ public final class DeviceStateManagerPostureProducer extends BaseDataProducer<In
@Override
@Nullable
- public Optional<Integer> getData() {
- final int posture = mDeviceStateToPostureMap.get(mCurrentDeviceState, -1);
- return posture != -1 ? Optional.of(posture) : Optional.empty();
+ public Optional<List<CommonFoldingFeature>> getData() {
+ final int globalHingeState = globalHingeState();
+ String displayFeaturesString = mContext.getResources().getString(
+ R.string.config_display_features);
+ if (TextUtils.isEmpty(displayFeaturesString)) {
+ return Optional.empty();
+ }
+ return Optional.of(parseListFromString(displayFeaturesString, globalHingeState));
+ }
+
+ private int globalHingeState() {
+ return mDeviceStateToPostureMap.get(mCurrentDeviceState, COMMON_STATE_UNKNOWN);
}
}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/common/DisplayFeature.java b/libs/WindowManager/Jetpack/src/androidx/window/common/DisplayFeature.java
deleted file mode 100644
index 573641857b99..000000000000
--- a/libs/WindowManager/Jetpack/src/androidx/window/common/DisplayFeature.java
+++ /dev/null
@@ -1,60 +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 androidx.window.common;
-
-import android.annotation.IntDef;
-import android.annotation.Nullable;
-import android.graphics.Rect;
-
-import androidx.annotation.NonNull;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/** Wrapper for both Extension and Sidecar versions of DisplayFeature. */
-public interface DisplayFeature {
- /** Returns the type of the feature. */
- int getType();
-
- /** Returns the state of the feature, or {@code null} if the feature has no state. */
- @Nullable
- @State
- Integer getState();
-
- /** Returns the bounds of the feature. */
- @NonNull
- Rect getRect();
-
- /**
- * A common state to represent a FLAT hinge. This is needed because the definitions in Sidecar
- * and Extensions do not match exactly.
- */
- int COMMON_STATE_FLAT = 3;
- /**
- * A common state to represent a HALF_OPENED hinge. This is needed because the definitions in
- * Sidecar and Extensions do not match exactly.
- */
- int COMMON_STATE_HALF_OPENED = 2;
-
- /**
- * The possible states for a folding hinge.
- */
- @IntDef({COMMON_STATE_FLAT, COMMON_STATE_HALF_OPENED})
- @Retention(RetentionPolicy.SOURCE)
- @interface State {}
-
-}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/common/EmptyLifecycleCallbacksAdapter.java b/libs/WindowManager/Jetpack/src/androidx/window/common/EmptyLifecycleCallbacksAdapter.java
new file mode 100644
index 000000000000..d923a46c3b5d
--- /dev/null
+++ b/libs/WindowManager/Jetpack/src/androidx/window/common/EmptyLifecycleCallbacksAdapter.java
@@ -0,0 +1,55 @@
+/*
+ * 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.common;
+
+import android.app.Activity;
+import android.app.Application;
+import android.os.Bundle;
+
+/**
+ * An empty implementation of {@link Application.ActivityLifecycleCallbacks} derived classes can
+ * implement the methods necessary.
+ */
+public class EmptyLifecycleCallbacksAdapter implements Application.ActivityLifecycleCallbacks {
+ @Override
+ public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
+ }
+
+ @Override
+ public void onActivityStarted(Activity activity) {
+ }
+
+ @Override
+ public void onActivityResumed(Activity activity) {
+ }
+
+ @Override
+ public void onActivityPaused(Activity activity) {
+ }
+
+ @Override
+ public void onActivityStopped(Activity activity) {
+ }
+
+ @Override
+ public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
+ }
+
+ @Override
+ public void onActivityDestroyed(Activity activity) {
+ }
+}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/common/ResourceConfigDisplayFeatureProducer.java b/libs/WindowManager/Jetpack/src/androidx/window/common/ResourceConfigDisplayFeatureProducer.java
deleted file mode 100644
index cd2cadc082e1..000000000000
--- a/libs/WindowManager/Jetpack/src/androidx/window/common/ResourceConfigDisplayFeatureProducer.java
+++ /dev/null
@@ -1,74 +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 androidx.window.common;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.Context;
-import android.text.TextUtils;
-import android.util.Log;
-
-import androidx.window.util.BaseDataProducer;
-
-import com.android.internal.R;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Optional;
-
-/**
- * Implementation of {@link androidx.window.util.DataProducer} that produces
- * {@link CommonDisplayFeature} parsed from a string stored in the resources config at
- * {@link R.string#config_display_features}.
- */
-public final class ResourceConfigDisplayFeatureProducer extends
- BaseDataProducer<List<DisplayFeature>> {
- private static final boolean DEBUG = false;
- private static final String TAG = "ResourceConfigDisplayFeatureProducer";
-
- private final Context mContext;
-
- public ResourceConfigDisplayFeatureProducer(@NonNull Context context) {
- mContext = context;
- }
-
- @Override
- @Nullable
- public Optional<List<DisplayFeature>> getData() {
- String displayFeaturesString = mContext.getResources().getString(
- R.string.config_display_features);
- if (TextUtils.isEmpty(displayFeaturesString)) {
- return Optional.empty();
- }
-
- List<DisplayFeature> features = new ArrayList<>();
- String[] featureStrings = displayFeaturesString.split(";");
- for (String featureString : featureStrings) {
- CommonDisplayFeature feature;
- try {
- feature = CommonDisplayFeature.parseFromString(featureString);
- } catch (IllegalArgumentException e) {
- if (DEBUG) {
- Log.w(TAG, "Failed to parse display feature: " + featureString, e);
- }
- continue;
- }
- features.add(feature);
- }
- return Optional.of(features);
- }
-}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/common/SettingsDevicePostureProducer.java b/libs/WindowManager/Jetpack/src/androidx/window/common/SettingsDevicePostureProducer.java
deleted file mode 100644
index 2026df3fa979..000000000000
--- a/libs/WindowManager/Jetpack/src/androidx/window/common/SettingsDevicePostureProducer.java
+++ /dev/null
@@ -1,96 +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 androidx.window.common;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.database.ContentObserver;
-import android.net.Uri;
-import android.os.Handler;
-import android.os.Looper;
-import android.provider.Settings;
-
-import androidx.window.util.BaseDataProducer;
-
-import java.util.Optional;
-
-/**
- * Implementation of {@link androidx.window.util.DataProducer} that provides the device posture
- * as an {@link Integer} from a value stored in {@link Settings}.
- */
-public final class SettingsDevicePostureProducer extends BaseDataProducer<Integer> {
- private static final String DEVICE_POSTURE = "device_posture";
-
- private final Uri mDevicePostureUri =
- Settings.Global.getUriFor(DEVICE_POSTURE);
-
- private final ContentResolver mResolver;
- private final ContentObserver mObserver;
- private boolean mRegisteredObservers;
-
- public SettingsDevicePostureProducer(@NonNull Context context) {
- mResolver = context.getContentResolver();
- mObserver = new SettingsObserver();
- }
-
- @Override
- @Nullable
- public Optional<Integer> getData() {
- int posture = Settings.Global.getInt(mResolver, DEVICE_POSTURE, -1);
- return posture == -1 ? Optional.empty() : Optional.of(posture);
- }
-
- /**
- * Registers settings observers, if needed. When settings observers are registered for this
- * producer callbacks for changes in data will be triggered.
- */
- public void registerObserversIfNeeded() {
- if (mRegisteredObservers) {
- return;
- }
- mRegisteredObservers = true;
- mResolver.registerContentObserver(mDevicePostureUri, false /* notifyForDescendants */,
- mObserver /* ContentObserver */);
- }
-
- /**
- * Unregisters settings observers, if needed. When settings observers are unregistered for this
- * producer callbacks for changes in data will not be triggered.
- */
- public void unregisterObserversIfNeeded() {
- if (!mRegisteredObservers) {
- return;
- }
- mRegisteredObservers = false;
- mResolver.unregisterContentObserver(mObserver);
- }
-
- private final class SettingsObserver extends ContentObserver {
- SettingsObserver() {
- super(new Handler(Looper.getMainLooper()));
- }
-
- @Override
- public void onChange(boolean selfChange, Uri uri) {
- if (mDevicePostureUri.equals(uri)) {
- notifyDataChanged();
- }
- }
- }
-}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/common/SettingsDisplayFeatureProducer.java b/libs/WindowManager/Jetpack/src/androidx/window/common/SettingsDisplayFeatureProducer.java
index 040662657a74..e9d213e06fa9 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/common/SettingsDisplayFeatureProducer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/common/SettingsDisplayFeatureProducer.java
@@ -16,8 +16,10 @@
package androidx.window.common;
+import static androidx.window.common.CommonFoldingFeature.COMMON_STATE_UNKNOWN;
+import static androidx.window.common.CommonFoldingFeature.parseListFromString;
+
import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.content.ContentResolver;
import android.content.Context;
import android.database.ContentObserver;
@@ -26,22 +28,19 @@ import android.os.Handler;
import android.os.Looper;
import android.provider.Settings;
import android.text.TextUtils;
-import android.util.Log;
import androidx.window.util.BaseDataProducer;
-import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
import java.util.Optional;
/**
* Implementation of {@link androidx.window.util.DataProducer} that produces
- * {@link CommonDisplayFeature} parsed from a string stored in {@link Settings}.
+ * {@link CommonFoldingFeature} parsed from a string stored in {@link Settings}.
*/
public final class SettingsDisplayFeatureProducer
- extends BaseDataProducer<List<DisplayFeature>> {
- private static final boolean DEBUG = false;
- private static final String TAG = "SettingsDisplayFeatureProducer";
+ extends BaseDataProducer<List<CommonFoldingFeature>> {
private static final String DISPLAY_FEATURES = "display_features";
private final Uri mDisplayFeaturesUri =
@@ -57,32 +56,17 @@ public final class SettingsDisplayFeatureProducer
}
@Override
- @Nullable
- public Optional<List<DisplayFeature>> getData() {
+ @NonNull
+ public Optional<List<CommonFoldingFeature>> getData() {
String displayFeaturesString = Settings.Global.getString(mResolver, DISPLAY_FEATURES);
if (displayFeaturesString == null) {
return Optional.empty();
}
- List<DisplayFeature> features = new ArrayList<>();
if (TextUtils.isEmpty(displayFeaturesString)) {
- return Optional.of(features);
- }
- String[] featureStrings = displayFeaturesString.split(";");
-
- for (String featureString : featureStrings) {
- CommonDisplayFeature feature;
- try {
- feature = CommonDisplayFeature.parseFromString(featureString);
- } catch (IllegalArgumentException e) {
- if (DEBUG) {
- Log.w(TAG, "Failed to parse display feature: " + featureString, e);
- }
- continue;
- }
- features.add(feature);
+ return Optional.of(Collections.emptyList());
}
- return Optional.of(features);
+ return Optional.of(parseListFromString(displayFeaturesString, COMMON_STATE_UNKNOWN));
}
/**
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 6d8383372461..2aa695346c89 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
@@ -28,7 +28,6 @@ import android.app.Activity;
import android.app.ActivityClient;
import android.app.ActivityOptions;
import android.app.ActivityThread;
-import android.app.Application.ActivityLifecycleCallbacks;
import android.app.Instrumentation;
import android.content.Context;
import android.content.Intent;
@@ -41,6 +40,8 @@ import android.os.Looper;
import android.window.TaskFragmentInfo;
import android.window.WindowContainerTransaction;
+import androidx.window.common.EmptyLifecycleCallbacksAdapter;
+
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
@@ -500,7 +501,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
final TaskFragmentContainer container = getContainerWithActivity(
activity.getActivityToken());
// Don't launch placeholder if the container is occluded.
- if (container != getTopActiveContainer()) {
+ if (container != null && container != getTopActiveContainer()) {
return false;
}
@@ -763,11 +764,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
return shouldRetainAssociatedContainer(finishingContainer, associatedContainer);
}
- private final class LifecycleCallbacks implements ActivityLifecycleCallbacks {
-
- @Override
- public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
- }
+ private final class LifecycleCallbacks extends EmptyLifecycleCallbacksAdapter {
@Override
public void onActivityPostCreated(Activity activity, Bundle savedInstanceState) {
@@ -779,30 +776,6 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
}
@Override
- public void onActivityStarted(Activity activity) {
- }
-
- @Override
- public void onActivityResumed(Activity activity) {
- }
-
- @Override
- public void onActivityPaused(Activity activity) {
- }
-
- @Override
- public void onActivityStopped(Activity activity) {
- }
-
- @Override
- public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
- }
-
- @Override
- public void onActivityDestroyed(Activity activity) {
- }
-
- @Override
public void onActivityConfigurationChanged(Activity activity) {
SplitController.this.onActivityConfigurationChanged(activity);
}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationAdapter.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationAdapter.java
index 89d7a407e459..b3becad3dc5a 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationAdapter.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationAdapter.java
@@ -33,6 +33,12 @@ import androidx.annotation.NonNull;
* The base adapter can be used for {@link RemoteAnimationTarget} that is simple open/close.
*/
class TaskFragmentAnimationAdapter {
+
+ /**
+ * If {@link #mOverrideLayer} is set to this value, we don't want to override the surface layer.
+ */
+ private static final int LAYER_NO_OVERRIDE = -1;
+
final Animation mAnimation;
final RemoteAnimationTarget mTarget;
final SurfaceControl mLeash;
@@ -42,6 +48,7 @@ class TaskFragmentAnimationAdapter {
final float[] mVecs = new float[4];
final Rect mRect = new Rect();
private boolean mIsFirstFrame = true;
+ private int mOverrideLayer = LAYER_NO_OVERRIDE;
TaskFragmentAnimationAdapter(@NonNull Animation animation,
@NonNull RemoteAnimationTarget target) {
@@ -58,10 +65,21 @@ class TaskFragmentAnimationAdapter {
mLeash = leash;
}
+ /**
+ * Surface layer to be set at the first frame of the animation. We will not set the layer if it
+ * is set to {@link #LAYER_NO_OVERRIDE}.
+ */
+ final void overrideLayer(int layer) {
+ mOverrideLayer = layer;
+ }
+
/** Called on frame update. */
final void onAnimationUpdate(@NonNull SurfaceControl.Transaction t, long currentPlayTime) {
if (mIsFirstFrame) {
t.show(mLeash);
+ if (mOverrideLayer != LAYER_NO_OVERRIDE) {
+ t.setLayer(mLeash, mOverrideLayer);
+ }
mIsFirstFrame = false;
}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationRunner.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationRunner.java
index 46bdf6d0e689..1ac33173668b 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationRunner.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationRunner.java
@@ -25,6 +25,7 @@ import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_CHANGE;
import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_CLOSE;
import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_OPEN;
import static android.view.WindowManager.TRANSIT_OLD_TASK_OPEN;
+import static android.view.WindowManagerPolicyConstants.TYPE_LAYER_OFFSET;
import android.animation.Animator;
import android.animation.ValueAnimator;
@@ -181,18 +182,22 @@ class TaskFragmentAnimationRunner extends IRemoteAnimationRunner.Stub {
private List<TaskFragmentAnimationAdapter> createOpenAnimationAdapters(
@NonNull RemoteAnimationTarget[] targets) {
- return createOpenCloseAnimationAdapters(targets,
+ return createOpenCloseAnimationAdapters(targets, true /* isOpening */,
mAnimationSpec::loadOpenAnimation);
}
private List<TaskFragmentAnimationAdapter> createCloseAnimationAdapters(
@NonNull RemoteAnimationTarget[] targets) {
- return createOpenCloseAnimationAdapters(targets,
+ return createOpenCloseAnimationAdapters(targets, false /* isOpening */,
mAnimationSpec::loadCloseAnimation);
}
+ /**
+ * Creates {@link TaskFragmentAnimationAdapter} for OPEN and CLOSE types of transition.
+ * @param isOpening {@code true} for OPEN type, {@code false} for CLOSE type.
+ */
private List<TaskFragmentAnimationAdapter> createOpenCloseAnimationAdapters(
- @NonNull RemoteAnimationTarget[] targets,
+ @NonNull RemoteAnimationTarget[] targets, boolean isOpening,
@NonNull BiFunction<RemoteAnimationTarget, Rect, Animation> animationProvider) {
// We need to know if the target window is only a partial of the whole animation screen.
// If so, we will need to adjust it to make the whole animation screen looks like one.
@@ -210,14 +215,25 @@ class TaskFragmentAnimationRunner extends IRemoteAnimationRunner.Stub {
}
}
+ // For OPEN transition, open windows should be above close windows.
+ // For CLOSE transition, open windows should be below close windows.
+ int offsetLayer = TYPE_LAYER_OFFSET;
final List<TaskFragmentAnimationAdapter> adapters = new ArrayList<>();
for (RemoteAnimationTarget target : openingTargets) {
- adapters.add(createOpenCloseAnimationAdapter(target, animationProvider,
- openingWholeScreenBounds));
+ final TaskFragmentAnimationAdapter adapter = createOpenCloseAnimationAdapter(target,
+ animationProvider, openingWholeScreenBounds);
+ if (isOpening) {
+ adapter.overrideLayer(offsetLayer++);
+ }
+ adapters.add(adapter);
}
for (RemoteAnimationTarget target : closingTargets) {
- adapters.add(createOpenCloseAnimationAdapter(target, animationProvider,
- closingWholeScreenBounds));
+ final TaskFragmentAnimationAdapter adapter = createOpenCloseAnimationAdapter(target,
+ animationProvider, closingWholeScreenBounds);
+ if (!isOpening) {
+ adapter.overrideLayer(offsetLayer++);
+ }
+ adapters.add(adapter);
}
return adapters;
}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java
index fe9ce971d4d9..a4fbdbc493f5 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java
@@ -18,28 +18,30 @@ package androidx.window.extensions.layout;
import static android.view.Display.DEFAULT_DISPLAY;
-import static androidx.window.common.DisplayFeature.COMMON_STATE_FLAT;
-import static androidx.window.common.DisplayFeature.COMMON_STATE_HALF_OPENED;
+import static androidx.window.common.CommonFoldingFeature.COMMON_STATE_FLAT;
+import static androidx.window.common.CommonFoldingFeature.COMMON_STATE_HALF_OPENED;
import static androidx.window.util.ExtensionHelper.rotateRectToDisplayRotation;
import static androidx.window.util.ExtensionHelper.transformToWindowSpaceRect;
import android.annotation.Nullable;
import android.app.Activity;
+import android.app.Application;
import android.content.Context;
import android.graphics.Rect;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.util.ArrayMap;
import android.util.Log;
import androidx.annotation.NonNull;
-import androidx.window.common.DeviceStateManagerPostureProducer;
-import androidx.window.common.DisplayFeature;
-import androidx.window.common.ResourceConfigDisplayFeatureProducer;
-import androidx.window.common.SettingsDevicePostureProducer;
+import androidx.window.common.CommonFoldingFeature;
+import androidx.window.common.DeviceStateManagerFoldingFeatureProducer;
+import androidx.window.common.EmptyLifecycleCallbacksAdapter;
import androidx.window.common.SettingsDisplayFeatureProducer;
import androidx.window.util.DataProducer;
import androidx.window.util.PriorityDataProducer;
import java.util.ArrayList;
-import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
@@ -56,36 +58,27 @@ import java.util.function.Consumer;
*/
public class WindowLayoutComponentImpl implements WindowLayoutComponent {
private static final String TAG = "SampleExtension";
- private static WindowLayoutComponent sInstance;
private final Map<Activity, Consumer<WindowLayoutInfo>> mWindowLayoutChangeListeners =
- new HashMap<>();
-
- private final SettingsDevicePostureProducer mSettingsDevicePostureProducer;
- private final DataProducer<Integer> mDevicePostureProducer;
+ new ArrayMap<>();
private final SettingsDisplayFeatureProducer mSettingsDisplayFeatureProducer;
- private final DataProducer<List<DisplayFeature>> mDisplayFeatureProducer;
+ private final DataProducer<List<CommonFoldingFeature>> mFoldingFeatureProducer;
public WindowLayoutComponentImpl(Context context) {
- mSettingsDevicePostureProducer = new SettingsDevicePostureProducer(context);
- mDevicePostureProducer = new PriorityDataProducer<>(List.of(
- mSettingsDevicePostureProducer,
- new DeviceStateManagerPostureProducer(context)
- ));
-
+ ((Application) context.getApplicationContext())
+ .registerActivityLifecycleCallbacks(new NotifyOnConfigurationChanged());
mSettingsDisplayFeatureProducer = new SettingsDisplayFeatureProducer(context);
- mDisplayFeatureProducer = new PriorityDataProducer<>(List.of(
+ mFoldingFeatureProducer = new PriorityDataProducer<>(List.of(
mSettingsDisplayFeatureProducer,
- new ResourceConfigDisplayFeatureProducer(context)
+ new DeviceStateManagerFoldingFeatureProducer(context)
));
-
- mDevicePostureProducer.addDataChangedCallback(this::onDisplayFeaturesChanged);
- mDisplayFeatureProducer.addDataChangedCallback(this::onDisplayFeaturesChanged);
+ mFoldingFeatureProducer.addDataChangedCallback(this::onDisplayFeaturesChanged);
}
/**
* Adds a listener interested in receiving updates to {@link WindowLayoutInfo}
+ *
* @param activity hosting a {@link android.view.Window}
* @param consumer interested in receiving updates to {@link WindowLayoutInfo}
*/
@@ -97,6 +90,7 @@ public class WindowLayoutComponentImpl implements WindowLayoutComponent {
/**
* Removes a listener no longer interested in receiving updates.
+ *
* @param consumer no longer interested in receiving updates to {@link WindowLayoutInfo}
*/
public void removeWindowLayoutInfoListener(
@@ -118,43 +112,34 @@ public class WindowLayoutComponentImpl implements WindowLayoutComponent {
return mWindowLayoutChangeListeners.keySet();
}
- protected boolean hasListeners() {
- return !mWindowLayoutChangeListeners.isEmpty();
+ @NonNull
+ private boolean isListeningForLayoutChanges(IBinder token) {
+ for (Activity activity: getActivitiesListeningForLayoutChanges()) {
+ if (token.equals(activity.getWindow().getAttributes().token)) {
+ return true;
+ }
+ }
+ return false;
}
- /**
- * Calculate the {@link DisplayFeature.State} from the feature or the device posture producer.
- * If the given {@link DisplayFeature.State} is not valid then {@code null} will be returned.
- * The {@link FoldingFeature} should be ignored in the case of an invalid
- * {@link DisplayFeature.State}.
- *
- * @param feature a {@link DisplayFeature} to provide the feature state if present.
- * @return {@link DisplayFeature.State} of the hinge if present or the state from the posture
- * produce if present.
- */
- @Nullable
- private Integer getFeatureState(DisplayFeature feature) {
- Integer featureState = feature.getState();
- Optional<Integer> posture = mDevicePostureProducer.getData();
- Integer state = featureState == null ? posture.orElse(null) : featureState;
- return convertToExtensionState(state);
+ protected boolean hasListeners() {
+ return !mWindowLayoutChangeListeners.isEmpty();
}
/**
* A convenience method to translate from the common feature state to the extensions feature
- * state. More specifically, translates from {@link DisplayFeature.State} to
+ * state. More specifically, translates from {@link CommonFoldingFeature.State} to
* {@link FoldingFeature.STATE_FLAT} or {@link FoldingFeature.STATE_HALF_OPENED}. If it is not
* possible to translate, then we will return a {@code null} value.
*
- * @param state if it matches a value in {@link DisplayFeature.State}, {@code null} otherwise.
- * @return a {@link FoldingFeature.STATE_FLAT} or {@link FoldingFeature.STATE_HALF_OPENED} if
- * the given state matches a value in {@link DisplayFeature.State} and {@code null} otherwise.
+ * @param state if it matches a value in {@link CommonFoldingFeature.State}, {@code null}
+ * otherwise. @return a {@link FoldingFeature.STATE_FLAT} or
+ * {@link FoldingFeature.STATE_HALF_OPENED} if the given state matches a value in
+ * {@link CommonFoldingFeature.State} and {@code null} otherwise.
*/
@Nullable
- private Integer convertToExtensionState(@Nullable Integer state) {
- if (state == null) { // The null check avoids a NullPointerException.
- return null;
- } else if (state == COMMON_STATE_FLAT) {
+ private Integer convertToExtensionState(int state) {
+ if (state == COMMON_STATE_FLAT) {
return FoldingFeature.STATE_FLAT;
} else if (state == COMMON_STATE_HALF_OPENED) {
return FoldingFeature.STATE_HALF_OPENED;
@@ -172,33 +157,30 @@ public class WindowLayoutComponentImpl implements WindowLayoutComponent {
@NonNull
private WindowLayoutInfo getWindowLayoutInfo(@NonNull Activity activity) {
- List<androidx.window.extensions.layout.DisplayFeature> displayFeatures =
- getDisplayFeatures(activity);
+ List<DisplayFeature> displayFeatures = getDisplayFeatures(activity);
return new WindowLayoutInfo(displayFeatures);
}
/**
- * Translate from the {@link DisplayFeature} to
- * {@link androidx.window.extensions.layout.DisplayFeature} for a given {@link Activity}. If a
- * {@link DisplayFeature} is not valid then it will be omitted.
+ * Translate from the {@link CommonFoldingFeature} to
+ * {@link DisplayFeature} for a given {@link Activity}. If a
+ * {@link CommonFoldingFeature} is not valid then it will be omitted.
*
* For a {@link FoldingFeature} the bounds are localized into the {@link Activity} window
- * coordinate space and the state is calculated either from {@link DisplayFeature#getState()} or
- * {@link #mDisplayFeatureProducer}. The state from {@link #mDisplayFeatureProducer} may not be
- * valid since {@link #mDisplayFeatureProducer} is a general state controller. If the state is
- * not valid, the {@link FoldingFeature} is omitted from the {@link List} of
- * {@link androidx.window.extensions.layout.DisplayFeature}. If the bounds are not valid,
- * constructing a {@link FoldingFeature} will throw an {@link IllegalArgumentException} since
- * this can cause negative UI effects down stream.
+ * coordinate space and the state is calculated from {@link CommonFoldingFeature#getState()}.
+ * The state from {@link #mFoldingFeatureProducer} may not be valid since
+ * {@link #mFoldingFeatureProducer} is a general state controller. If the state is not valid,
+ * the {@link FoldingFeature} is omitted from the {@link List} of {@link DisplayFeature}. If the
+ * bounds are not valid, constructing a {@link FoldingFeature} will throw an
+ * {@link IllegalArgumentException} since this can cause negative UI effects down stream.
*
* @param activity a proxy for the {@link android.view.Window} that contains the
- * {@link androidx.window.extensions.layout.DisplayFeature}.
- * @return a {@link List} of valid {@link androidx.window.extensions.layout.DisplayFeature} that
+ * {@link DisplayFeature}.
+ * @return a {@link List} of valid {@link DisplayFeature} that
* are within the {@link android.view.Window} of the {@link Activity}
*/
- private List<androidx.window.extensions.layout.DisplayFeature> getDisplayFeatures(
- @NonNull Activity activity) {
- List<androidx.window.extensions.layout.DisplayFeature> features = new ArrayList<>();
+ private List<DisplayFeature> getDisplayFeatures(@NonNull Activity activity) {
+ List<DisplayFeature> features = new ArrayList<>();
int displayId = activity.getDisplay().getDisplayId();
if (displayId != DEFAULT_DISPLAY) {
Log.w(TAG, "This sample doesn't support display features on secondary displays");
@@ -211,11 +193,10 @@ public class WindowLayoutComponentImpl implements WindowLayoutComponent {
return features;
}
- Optional<List<DisplayFeature>> storedFeatures = mDisplayFeatureProducer.getData();
+ Optional<List<CommonFoldingFeature>> storedFeatures = mFoldingFeatureProducer.getData();
if (storedFeatures.isPresent()) {
-
- for (DisplayFeature baseFeature : storedFeatures.get()) {
- Integer state = getFeatureState(baseFeature);
+ for (CommonFoldingFeature baseFeature : storedFeatures.get()) {
+ Integer state = convertToExtensionState(baseFeature.getState());
if (state == null) {
continue;
}
@@ -223,8 +204,7 @@ public class WindowLayoutComponentImpl implements WindowLayoutComponent {
rotateRectToDisplayRotation(displayId, featureRect);
transformToWindowSpaceRect(activity, featureRect);
- features.add(new FoldingFeature(featureRect, baseFeature.getType(),
- getFeatureState(baseFeature)));
+ features.add(new FoldingFeature(featureRect, baseFeature.getType(), state));
}
}
return features;
@@ -232,13 +212,31 @@ public class WindowLayoutComponentImpl implements WindowLayoutComponent {
private void updateRegistrations() {
if (hasListeners()) {
- mSettingsDevicePostureProducer.registerObserversIfNeeded();
mSettingsDisplayFeatureProducer.registerObserversIfNeeded();
} else {
- mSettingsDevicePostureProducer.unregisterObserversIfNeeded();
mSettingsDisplayFeatureProducer.unregisterObserversIfNeeded();
}
-
onDisplayFeaturesChanged();
}
+
+ private final class NotifyOnConfigurationChanged extends EmptyLifecycleCallbacksAdapter {
+ @Override
+ public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
+ super.onActivityCreated(activity, savedInstanceState);
+ onDisplayFeaturesChangedIfListening(activity);
+ }
+
+ @Override
+ public void onActivityConfigurationChanged(Activity activity) {
+ super.onActivityConfigurationChanged(activity);
+ onDisplayFeaturesChangedIfListening(activity);
+ }
+
+ private void onDisplayFeaturesChangedIfListening(Activity activity) {
+ IBinder token = activity.getWindow().getAttributes().token;
+ if (token == null || isListeningForLayoutChanges(token)) {
+ onDisplayFeaturesChanged();
+ }
+ }
+ }
}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SampleSidecarImpl.java b/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SampleSidecarImpl.java
index aa949f126154..c7b709347060 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SampleSidecarImpl.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SampleSidecarImpl.java
@@ -23,16 +23,17 @@ import static androidx.window.util.ExtensionHelper.transformToWindowSpaceRect;
import android.app.Activity;
import android.app.ActivityThread;
+import android.app.Application;
import android.content.Context;
import android.graphics.Rect;
+import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
import androidx.annotation.NonNull;
-import androidx.window.common.DeviceStateManagerPostureProducer;
-import androidx.window.common.DisplayFeature;
-import androidx.window.common.ResourceConfigDisplayFeatureProducer;
-import androidx.window.common.SettingsDevicePostureProducer;
+import androidx.window.common.CommonFoldingFeature;
+import androidx.window.common.DeviceStateManagerFoldingFeatureProducer;
+import androidx.window.common.EmptyLifecycleCallbacksAdapter;
import androidx.window.common.SettingsDisplayFeatureProducer;
import androidx.window.util.DataProducer;
import androidx.window.util.PriorityDataProducer;
@@ -48,36 +49,25 @@ import java.util.Optional;
*/
class SampleSidecarImpl extends StubSidecar {
private static final String TAG = "SampleSidecar";
- private static final boolean DEBUG = false;
- private final SettingsDevicePostureProducer mSettingsDevicePostureProducer;
- private final DataProducer<Integer> mDevicePostureProducer;
+ private final DataProducer<List<CommonFoldingFeature>> mFoldingFeatureProducer;
- private final SettingsDisplayFeatureProducer mSettingsDisplayFeatureProducer;
- private final DataProducer<List<DisplayFeature>> mDisplayFeatureProducer;
+ private final SettingsDisplayFeatureProducer mSettingsFoldingFeatureProducer;
SampleSidecarImpl(Context context) {
- mSettingsDevicePostureProducer = new SettingsDevicePostureProducer(context);
- mDevicePostureProducer = new PriorityDataProducer<>(List.of(
- mSettingsDevicePostureProducer,
- new DeviceStateManagerPostureProducer(context)
+ ((Application) context.getApplicationContext())
+ .registerActivityLifecycleCallbacks(new NotifyOnConfigurationChanged());
+ mSettingsFoldingFeatureProducer = new SettingsDisplayFeatureProducer(context);
+ mFoldingFeatureProducer = new PriorityDataProducer<>(List.of(
+ mSettingsFoldingFeatureProducer,
+ new DeviceStateManagerFoldingFeatureProducer(context)
));
- mSettingsDisplayFeatureProducer = new SettingsDisplayFeatureProducer(context);
- mDisplayFeatureProducer = new PriorityDataProducer<>(List.of(
- mSettingsDisplayFeatureProducer,
- new ResourceConfigDisplayFeatureProducer(context)
- ));
-
- mDevicePostureProducer.addDataChangedCallback(this::onDevicePostureChanged);
- mDisplayFeatureProducer.addDataChangedCallback(this::onDisplayFeaturesChanged);
- }
-
- private void onDevicePostureChanged() {
- updateDeviceState(getDeviceState());
+ mFoldingFeatureProducer.addDataChangedCallback(this::onDisplayFeaturesChanged);
}
private void onDisplayFeaturesChanged() {
+ updateDeviceState(getDeviceState());
for (IBinder windowToken : getWindowsListeningForLayoutChanges()) {
SidecarWindowLayoutInfo newLayout = getWindowLayoutInfo(windowToken);
updateWindowLayout(windowToken, newLayout);
@@ -87,27 +77,21 @@ class SampleSidecarImpl extends StubSidecar {
@NonNull
@Override
public SidecarDeviceState getDeviceState() {
- Optional<Integer> posture = mDevicePostureProducer.getData();
-
SidecarDeviceState deviceState = new SidecarDeviceState();
- deviceState.posture = posture.orElse(deviceStateFromFeature());
+ deviceState.posture = deviceStateFromFeature();
return deviceState;
}
private int deviceStateFromFeature() {
- List<DisplayFeature> storedFeatures = mDisplayFeatureProducer.getData()
+ List<CommonFoldingFeature> storedFeatures = mFoldingFeatureProducer.getData()
.orElse(Collections.emptyList());
for (int i = 0; i < storedFeatures.size(); i++) {
- DisplayFeature feature = storedFeatures.get(i);
- final int state = feature.getState() == null ? -1 : feature.getState();
- if (DEBUG && feature.getState() == null) {
- Log.d(TAG, "feature#getState was null for DisplayFeature: " + feature);
- }
-
+ CommonFoldingFeature feature = storedFeatures.get(i);
+ final int state = feature.getState();
switch (state) {
- case DisplayFeature.COMMON_STATE_FLAT:
+ case CommonFoldingFeature.COMMON_STATE_FLAT:
return SidecarDeviceState.POSTURE_OPENED;
- case DisplayFeature.COMMON_STATE_HALF_OPENED:
+ case CommonFoldingFeature.COMMON_STATE_HALF_OPENED:
return SidecarDeviceState.POSTURE_HALF_OPENED;
}
}
@@ -127,22 +111,22 @@ class SampleSidecarImpl extends StubSidecar {
}
private List<SidecarDisplayFeature> getDisplayFeatures(@NonNull Activity activity) {
- List<SidecarDisplayFeature> features = new ArrayList<SidecarDisplayFeature>();
int displayId = activity.getDisplay().getDisplayId();
if (displayId != DEFAULT_DISPLAY) {
Log.w(TAG, "This sample doesn't support display features on secondary displays");
- return features;
+ return Collections.emptyList();
}
if (activity.isInMultiWindowMode()) {
// It is recommended not to report any display features in multi-window mode, since it
// won't be possible to synchronize the display feature positions with window movement.
- return features;
+ return Collections.emptyList();
}
- Optional<List<DisplayFeature>> storedFeatures = mDisplayFeatureProducer.getData();
+ Optional<List<CommonFoldingFeature>> storedFeatures = mFoldingFeatureProducer.getData();
+ List<SidecarDisplayFeature> features = new ArrayList<>();
if (storedFeatures.isPresent()) {
- for (DisplayFeature baseFeature : storedFeatures.get()) {
+ for (CommonFoldingFeature baseFeature : storedFeatures.get()) {
SidecarDisplayFeature feature = new SidecarDisplayFeature();
Rect featureRect = baseFeature.getRect();
rotateRectToDisplayRotation(displayId, featureRect);
@@ -152,17 +136,37 @@ class SampleSidecarImpl extends StubSidecar {
features.add(feature);
}
}
- return features;
+ return Collections.unmodifiableList(features);
}
@Override
protected void onListenersChanged() {
if (hasListeners()) {
- mSettingsDevicePostureProducer.registerObserversIfNeeded();
- mSettingsDisplayFeatureProducer.registerObserversIfNeeded();
+ mSettingsFoldingFeatureProducer.registerObserversIfNeeded();
+ onDisplayFeaturesChanged();
} else {
- mSettingsDevicePostureProducer.unregisterObserversIfNeeded();
- mSettingsDisplayFeatureProducer.unregisterObserversIfNeeded();
+ mSettingsFoldingFeatureProducer.unregisterObserversIfNeeded();
+ }
+ }
+
+ private final class NotifyOnConfigurationChanged extends EmptyLifecycleCallbacksAdapter {
+ @Override
+ public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
+ super.onActivityCreated(activity, savedInstanceState);
+ onDisplayFeaturesChangedForActivity(activity);
+ }
+
+ @Override
+ public void onActivityConfigurationChanged(Activity activity) {
+ super.onActivityConfigurationChanged(activity);
+ onDisplayFeaturesChangedForActivity(activity);
+ }
+
+ private void onDisplayFeaturesChangedForActivity(@NonNull Activity activity) {
+ IBinder token = activity.getWindow().getAttributes().token;
+ if (token == null || mWindowLayoutChangeListenerTokens.contains(token)) {
+ onDisplayFeaturesChanged();
+ }
}
}
}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/sidecar/StubSidecar.java b/libs/WindowManager/Jetpack/src/androidx/window/sidecar/StubSidecar.java
index 199c37315c07..b9c808a6569b 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/sidecar/StubSidecar.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/sidecar/StubSidecar.java
@@ -30,7 +30,7 @@ import java.util.Set;
abstract class StubSidecar implements SidecarInterface {
private SidecarCallback mSidecarCallback;
- private final Set<IBinder> mWindowLayoutChangeListenerTokens = new HashSet<>();
+ final Set<IBinder> mWindowLayoutChangeListenerTokens = new HashSet<>();
private boolean mDeviceStateChangeListenerRegistered;
StubSidecar() {
diff --git a/libs/WindowManager/OWNERS b/libs/WindowManager/OWNERS
index 2c61df96eb03..780e4c1632f7 100644
--- a/libs/WindowManager/OWNERS
+++ b/libs/WindowManager/OWNERS
@@ -1,3 +1,6 @@
set noparent
include /services/core/java/com/android/server/wm/OWNERS
+
+# Give submodule owners in shell resource approval
+per-file Shell/res*/*/*.xml = hwwang@google.com, lbill@google.com, madym@google.com
diff --git a/packages/SystemUI/res/layout/communal_host_view.xml b/libs/WindowManager/Shell/res/color/letterbox_education_dismiss_button_background_ripple.xml
index cd9c26065dc1..43cba1a37bc8 100644
--- a/packages/SystemUI/res/layout/communal_host_view.xml
+++ b/libs/WindowManager/Shell/res/color/letterbox_education_dismiss_button_background_ripple.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- ~ 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.
@@ -14,10 +14,6 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-
-<!-- This is a view that shows general status information in Keyguard. -->
-<com.android.systemui.communal.CommunalHostView
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/communal_host"
- android:layout_width="match_parent"
- android:layout_height="match_parent"/> \ No newline at end of file
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:color="@android:color/system_neutral1_900" android:alpha="0.6" />
+</selector> \ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/color/tv_pip_menu_close_icon.xml b/libs/WindowManager/Shell/res/color/tv_pip_menu_close_icon.xml
new file mode 100644
index 000000000000..ce8640df0093
--- /dev/null
+++ b/libs/WindowManager/Shell/res/color/tv_pip_menu_close_icon.xml
@@ -0,0 +1,19 @@
+<?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.
+ -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:color="@color/tv_pip_menu_icon_unfocused" />
+</selector> \ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/color/tv_pip_menu_close_icon_bg.xml b/libs/WindowManager/Shell/res/color/tv_pip_menu_close_icon_bg.xml
new file mode 100644
index 000000000000..6cbf66f00df7
--- /dev/null
+++ b/libs/WindowManager/Shell/res/color/tv_pip_menu_close_icon_bg.xml
@@ -0,0 +1,21 @@
+<?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.
+ -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_focused="true"
+ android:color="@color/tv_pip_menu_close_icon_bg_focused" />
+ <item android:color="@color/tv_pip_menu_close_icon_bg_unfocused" />
+</selector> \ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/drawable/letterbox_education_dismiss_button_background_ripple.xml b/libs/WindowManager/Shell/res/drawable/letterbox_education_dismiss_button_background_ripple.xml
index 0d8a8faa9798..42572d64b96f 100644
--- a/libs/WindowManager/Shell/res/drawable/letterbox_education_dismiss_button_background_ripple.xml
+++ b/libs/WindowManager/Shell/res/drawable/letterbox_education_dismiss_button_background_ripple.xml
@@ -15,6 +15,6 @@
~ limitations under the License.
-->
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
- android:color="@android:color/system_accent1_10">
+ android:color="@color/letterbox_education_dismiss_button_background_ripple">
<item android:drawable="@drawable/letterbox_education_dismiss_button_background"/>
</ripple> \ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/values-af/strings_tv.xml b/libs/WindowManager/Shell/res/values-af/strings_tv.xml
index f552b81d9b77..c87bec093cca 100644
--- a/libs/WindowManager/Shell/res/values-af/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-af/strings_tv.xml
@@ -24,4 +24,5 @@
<string name="pip_move" msgid="1544227837964635439">"Skuif PIP"</string>
<string name="pip_expand" msgid="7605396312689038178">"Vou PIP uit"</string>
<string name="pip_collapse" msgid="5732233773786896094">"Vou PIP in"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Dubbeldruk "<annotation icon="home_icon">" TUIS "</annotation>" vir kontroles"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-am/strings_tv.xml b/libs/WindowManager/Shell/res/values-am/strings_tv.xml
index 6b6fe9fb8045..d23353858de6 100644
--- a/libs/WindowManager/Shell/res/values-am/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-am/strings_tv.xml
@@ -24,4 +24,5 @@
<string name="pip_move" msgid="1544227837964635439">"ፒአይፒ ውሰድ"</string>
<string name="pip_expand" msgid="7605396312689038178">"ፒአይፒን ዘርጋ"</string>
<string name="pip_collapse" msgid="5732233773786896094">"ፒአይፒን ሰብስብ"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" ለመቆጣጠሪያዎች "<annotation icon="home_icon">"መነሻ"</annotation>"ን ሁለቴ ይጫኑ"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ar/strings_tv.xml b/libs/WindowManager/Shell/res/values-ar/strings_tv.xml
index a85d7b1c8da5..a1ceda5fc987 100644
--- a/libs/WindowManager/Shell/res/values-ar/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-ar/strings_tv.xml
@@ -24,4 +24,5 @@
<string name="pip_move" msgid="1544227837964635439">"‏نقل نافذة داخل النافذة (PIP)"</string>
<string name="pip_expand" msgid="7605396312689038178">"‏توسيع نافذة داخل النافذة (PIP)"</string>
<string name="pip_collapse" msgid="5732233773786896094">"‏تصغير نافذة داخل النافذة (PIP)"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" انقر مرتين على "<annotation icon="home_icon">" الصفحة الرئيسية "</annotation>" للوصول لعناصر التحكم."</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-as/strings_tv.xml b/libs/WindowManager/Shell/res/values-as/strings_tv.xml
index 9e2f5502bbfe..8d7bd9f6a27e 100644
--- a/libs/WindowManager/Shell/res/values-as/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-as/strings_tv.xml
@@ -24,4 +24,5 @@
<string name="pip_move" msgid="1544227837964635439">"পিপ স্থানান্তৰ কৰক"</string>
<string name="pip_expand" msgid="7605396312689038178">"পিপ বিস্তাৰ কৰক"</string>
<string name="pip_collapse" msgid="5732233773786896094">"পিপ সংকোচন কৰক"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" নিয়ন্ত্ৰণৰ বাবে "<annotation icon="home_icon">" গৃহপৃষ্ঠা "</annotation>" বুটামত দুবাৰ হেঁচক"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-az/strings_tv.xml b/libs/WindowManager/Shell/res/values-az/strings_tv.xml
index 670b02fa52c8..87c46fa41a01 100644
--- a/libs/WindowManager/Shell/res/values-az/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-az/strings_tv.xml
@@ -24,4 +24,5 @@
<string name="pip_move" msgid="1544227837964635439">"PIP tətbiq edin"</string>
<string name="pip_expand" msgid="7605396312689038178">"PIP-ni genişləndirin"</string>
<string name="pip_collapse" msgid="5732233773786896094">"PIP-ni yığcamlaşdırın"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Nizamlayıcılar üçün "<annotation icon="home_icon">" ƏSAS SƏHİFƏ "</annotation>" süçimini iki dəfə basın"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-b+sr+Latn/strings_tv.xml b/libs/WindowManager/Shell/res/values-b+sr+Latn/strings_tv.xml
index de23d71f1a28..c87f30611a07 100644
--- a/libs/WindowManager/Shell/res/values-b+sr+Latn/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-b+sr+Latn/strings_tv.xml
@@ -24,4 +24,5 @@
<string name="pip_move" msgid="1544227837964635439">"Premesti sliku u slici"</string>
<string name="pip_expand" msgid="7605396312689038178">"Proširi sliku u slici"</string>
<string name="pip_collapse" msgid="5732233773786896094">"Skupi sliku u slici"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Dvaput pritisnite "<annotation icon="home_icon">" HOME "</annotation>" za kontrole"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-be/strings_tv.xml b/libs/WindowManager/Shell/res/values-be/strings_tv.xml
index 03de88c8b975..3566bc372820 100644
--- a/libs/WindowManager/Shell/res/values-be/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-be/strings_tv.xml
@@ -24,4 +24,5 @@
<string name="pip_move" msgid="1544227837964635439">"Перамясціць PIP"</string>
<string name="pip_expand" msgid="7605396312689038178">"Разгарнуць відарыс у відарысе"</string>
<string name="pip_collapse" msgid="5732233773786896094">"Згарнуць відарыс у відарысе"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Двойчы націсніце "<annotation icon="home_icon">" ГАЛОЎНЫ ЭКРАН "</annotation>" для пераходу ў налады"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-bg/strings_tv.xml b/libs/WindowManager/Shell/res/values-bg/strings_tv.xml
index 38e1ef861be9..91049fd2cf02 100644
--- a/libs/WindowManager/Shell/res/values-bg/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-bg/strings_tv.xml
@@ -24,4 +24,5 @@
<string name="pip_move" msgid="1544227837964635439">"„Картина в картина“: Преместв."</string>
<string name="pip_expand" msgid="7605396312689038178">"Разгъване на прозореца за PIP"</string>
<string name="pip_collapse" msgid="5732233773786896094">"Свиване на прозореца за PIP"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" За достъп до контролите натиснете 2 пъти "<annotation icon="home_icon">"НАЧАЛО"</annotation></string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-bn/strings_tv.xml b/libs/WindowManager/Shell/res/values-bn/strings_tv.xml
index 0b24328d8c7c..792708d128a5 100644
--- a/libs/WindowManager/Shell/res/values-bn/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-bn/strings_tv.xml
@@ -24,4 +24,5 @@
<string name="pip_move" msgid="1544227837964635439">"PIP সরান"</string>
<string name="pip_expand" msgid="7605396312689038178">"PIP বড় করুন"</string>
<string name="pip_collapse" msgid="5732233773786896094">"PIP আড়াল করুন"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" কন্ট্রোলের জন্য "<annotation icon="home_icon">" হোম "</annotation>" বোতামে ডবল প্রেস করুন"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-bs/strings_tv.xml b/libs/WindowManager/Shell/res/values-bs/strings_tv.xml
index 63e23c2edace..b7f0dca1b5a5 100644
--- a/libs/WindowManager/Shell/res/values-bs/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-bs/strings_tv.xml
@@ -24,4 +24,5 @@
<string name="pip_move" msgid="1544227837964635439">"Pokreni sliku u slici"</string>
<string name="pip_expand" msgid="7605396312689038178">"Proširi sliku u slici"</string>
<string name="pip_collapse" msgid="5732233773786896094">"Suzi sliku u slici"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Dvaput pritisnite "<annotation icon="home_icon">" POČETNI EKRAN "</annotation>" za kontrole"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ca/strings.xml b/libs/WindowManager/Shell/res/values-ca/strings.xml
index 2ec1db4e990b..8a522b3e6397 100644
--- a/libs/WindowManager/Shell/res/values-ca/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ca/strings.xml
@@ -27,7 +27,7 @@
<string name="pip_play" msgid="3496151081459417097">"Reprodueix"</string>
<string name="pip_pause" msgid="690688849510295232">"Posa en pausa"</string>
<string name="pip_skip_to_next" msgid="8403429188794867653">"Ves al següent"</string>
- <string name="pip_skip_to_prev" msgid="7172158111196394092">"Torna a l\'anterior"</string>
+ <string name="pip_skip_to_prev" msgid="7172158111196394092">"Ves a l\'anterior"</string>
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Canvia la mida"</string>
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Amaga"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Deixa d\'amagar"</string>
diff --git a/libs/WindowManager/Shell/res/values-ca/strings_tv.xml b/libs/WindowManager/Shell/res/values-ca/strings_tv.xml
index e35390ad2abb..1c560c7afa06 100644
--- a/libs/WindowManager/Shell/res/values-ca/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-ca/strings_tv.xml
@@ -24,4 +24,5 @@
<string name="pip_move" msgid="1544227837964635439">"Mou pantalla en pantalla"</string>
<string name="pip_expand" msgid="7605396312689038178">"Desplega pantalla en pantalla"</string>
<string name="pip_collapse" msgid="5732233773786896094">"Replega pantalla en pantalla"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Prem dos cops "<annotation icon="home_icon">" INICI "</annotation>" per accedir als controls"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-cs/strings_tv.xml b/libs/WindowManager/Shell/res/values-cs/strings_tv.xml
index 9b38537eaa36..9a8cc2b4d70e 100644
--- a/libs/WindowManager/Shell/res/values-cs/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-cs/strings_tv.xml
@@ -24,4 +24,5 @@
<string name="pip_move" msgid="1544227837964635439">"Přesunout PIP"</string>
<string name="pip_expand" msgid="7605396312689038178">"Rozbalit PIP"</string>
<string name="pip_collapse" msgid="5732233773786896094">"Sbalit PIP"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Ovládací prvky zobrazíte dvojitým stisknutím "<annotation icon="home_icon">"tlačítka plochy"</annotation></string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-da/strings_tv.xml b/libs/WindowManager/Shell/res/values-da/strings_tv.xml
index 2f3b359f40e5..cba660ac723c 100644
--- a/libs/WindowManager/Shell/res/values-da/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-da/strings_tv.xml
@@ -24,4 +24,5 @@
<string name="pip_move" msgid="1544227837964635439">"Flyt PIP"</string>
<string name="pip_expand" msgid="7605396312689038178">"Udvid PIP"</string>
<string name="pip_collapse" msgid="5732233773786896094">"Skjul PIP"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Tryk to gange på "<annotation icon="home_icon">" HJEM "</annotation>" for at se indstillinger"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-de/strings_tv.xml b/libs/WindowManager/Shell/res/values-de/strings_tv.xml
index 07fc28dc0583..02a1b66eb63f 100644
--- a/libs/WindowManager/Shell/res/values-de/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-de/strings_tv.xml
@@ -24,4 +24,5 @@
<string name="pip_move" msgid="1544227837964635439">"BiB verschieben"</string>
<string name="pip_expand" msgid="7605396312689038178">"BiB maximieren"</string>
<string name="pip_collapse" msgid="5732233773786896094">"BiB minimieren"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Für Steuerelemente zweimal "<annotation icon="home_icon">"STARTBILDSCHIRMTASTE"</annotation>" drücken"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-el/strings_tv.xml b/libs/WindowManager/Shell/res/values-el/strings_tv.xml
index 1eba0b7caa0c..24cd030cd754 100644
--- a/libs/WindowManager/Shell/res/values-el/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-el/strings_tv.xml
@@ -24,4 +24,5 @@
<string name="pip_move" msgid="1544227837964635439">"Μετακίνηση PIP"</string>
<string name="pip_expand" msgid="7605396312689038178">"Ανάπτυξη PIP"</string>
<string name="pip_collapse" msgid="5732233773786896094">"Σύμπτυξη PIP"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Πατήστε δύο φορές "<annotation icon="home_icon">" ΑΡΧΙΚΗ ΟΘΟΝΗ "</annotation>" για στοιχεία ελέγχου"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-en-rAU/strings_tv.xml b/libs/WindowManager/Shell/res/values-en-rAU/strings_tv.xml
index 79a8b95263f2..82257b42814d 100644
--- a/libs/WindowManager/Shell/res/values-en-rAU/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-en-rAU/strings_tv.xml
@@ -24,4 +24,5 @@
<string name="pip_move" msgid="1544227837964635439">"Move PIP"</string>
<string name="pip_expand" msgid="7605396312689038178">"Expand PIP"</string>
<string name="pip_collapse" msgid="5732233773786896094">"Collapse PIP"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Double-press "<annotation icon="home_icon">" HOME "</annotation>" for controls"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-en-rCA/strings_tv.xml b/libs/WindowManager/Shell/res/values-en-rCA/strings_tv.xml
index 79a8b95263f2..82257b42814d 100644
--- a/libs/WindowManager/Shell/res/values-en-rCA/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-en-rCA/strings_tv.xml
@@ -24,4 +24,5 @@
<string name="pip_move" msgid="1544227837964635439">"Move PIP"</string>
<string name="pip_expand" msgid="7605396312689038178">"Expand PIP"</string>
<string name="pip_collapse" msgid="5732233773786896094">"Collapse PIP"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Double-press "<annotation icon="home_icon">" HOME "</annotation>" for controls"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-en-rGB/strings_tv.xml b/libs/WindowManager/Shell/res/values-en-rGB/strings_tv.xml
index 79a8b95263f2..82257b42814d 100644
--- a/libs/WindowManager/Shell/res/values-en-rGB/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-en-rGB/strings_tv.xml
@@ -24,4 +24,5 @@
<string name="pip_move" msgid="1544227837964635439">"Move PIP"</string>
<string name="pip_expand" msgid="7605396312689038178">"Expand PIP"</string>
<string name="pip_collapse" msgid="5732233773786896094">"Collapse PIP"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Double-press "<annotation icon="home_icon">" HOME "</annotation>" for controls"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-en-rIN/strings_tv.xml b/libs/WindowManager/Shell/res/values-en-rIN/strings_tv.xml
index 79a8b95263f2..82257b42814d 100644
--- a/libs/WindowManager/Shell/res/values-en-rIN/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-en-rIN/strings_tv.xml
@@ -24,4 +24,5 @@
<string name="pip_move" msgid="1544227837964635439">"Move PIP"</string>
<string name="pip_expand" msgid="7605396312689038178">"Expand PIP"</string>
<string name="pip_collapse" msgid="5732233773786896094">"Collapse PIP"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Double-press "<annotation icon="home_icon">" HOME "</annotation>" for controls"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-en-rXC/strings_tv.xml b/libs/WindowManager/Shell/res/values-en-rXC/strings_tv.xml
index 8925f183188c..a6e494cfed3c 100644
--- a/libs/WindowManager/Shell/res/values-en-rXC/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-en-rXC/strings_tv.xml
@@ -24,4 +24,5 @@
<string name="pip_move" msgid="1544227837964635439">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‎‏‎‏‏‎‏‏‏‎‎‎‏‏‎‎‏‏‎‎‎‎‏‎‎‏‎‏‏‏‎‏‏‎‎‎‏‎‎‏‏‎‏‏‎‎‏‏‎‏‎‎‏‎‏‏‏‏‎Move PIP‎‏‎‎‏‎"</string>
<string name="pip_expand" msgid="7605396312689038178">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‏‏‎‎‎‏‎‏‏‏‏‎‎‏‎‏‏‏‎‏‎‎‏‏‎‏‎‏‏‏‎‎‏‏‏‏‎‎‏‎‏‎‏‎‏‎‎‏‏‎‏‏‎‎‎‏‎‎Expand PIP‎‏‎‎‏‎"</string>
<string name="pip_collapse" msgid="5732233773786896094">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‏‏‏‎‎‎‏‏‎‎‏‏‏‏‏‏‎‎‎‎‏‏‏‏‏‏‎‎‏‎‎‎‎‎‎‎‎‏‎‎‎‎‏‎‎‏‎‏‏‎‏‏‎‏‏‏‏‎‎Collapse PIP‎‏‎‎‏‎"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" ‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‏‎‏‏‏‏‏‎‎‏‎‎‎‏‏‏‎‏‏‎‎‏‎‏‎‎‏‏‏‏‎‎‎‏‏‏‎‏‏‏‎‏‎‎‎‎‎‎‏‎‏‏‎‏‏‏‎‏‎ Double press ‎‏‎‎‏‏‎"<annotation icon="home_icon">"‎‏‎‎‏‏‏‎ HOME ‎‏‎‎‏‏‎"</annotation>"‎‏‎‎‏‏‏‎ for controls‎‏‎‎‏‎"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-es-rUS/strings_tv.xml b/libs/WindowManager/Shell/res/values-es-rUS/strings_tv.xml
index 1b1a41910242..458f6b15b857 100644
--- a/libs/WindowManager/Shell/res/values-es-rUS/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-es-rUS/strings_tv.xml
@@ -24,4 +24,5 @@
<string name="pip_move" msgid="1544227837964635439">"Mover PIP"</string>
<string name="pip_expand" msgid="7605396312689038178">"Maximizar PIP"</string>
<string name="pip_collapse" msgid="5732233773786896094">"Minimizar PIP"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Presiona dos veces "<annotation icon="home_icon">"INICIO"</annotation>" para ver los controles"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-es/strings_tv.xml b/libs/WindowManager/Shell/res/values-es/strings_tv.xml
index 29ff1c6105bb..0a690984dac5 100644
--- a/libs/WindowManager/Shell/res/values-es/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-es/strings_tv.xml
@@ -24,4 +24,5 @@
<string name="pip_move" msgid="1544227837964635439">"Mover imagen en imagen"</string>
<string name="pip_expand" msgid="7605396312689038178">"Mostrar imagen en imagen"</string>
<string name="pip_collapse" msgid="5732233773786896094">"Ocultar imagen en imagen"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Pulsa dos veces "<annotation icon="home_icon">"INICIO"</annotation>" para ver los controles"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-et/strings_tv.xml b/libs/WindowManager/Shell/res/values-et/strings_tv.xml
index f528bb2065b9..dc0232303a70 100644
--- a/libs/WindowManager/Shell/res/values-et/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-et/strings_tv.xml
@@ -24,4 +24,5 @@
<string name="pip_move" msgid="1544227837964635439">"Teisalda PIP-režiimi"</string>
<string name="pip_expand" msgid="7605396312689038178">"Laienda PIP-akent"</string>
<string name="pip_collapse" msgid="5732233773786896094">"Ahenda PIP-aken"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Nuppude nägemiseks vajutage 2 korda nuppu "<annotation icon="home_icon">"AVAKUVA"</annotation></string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-eu/strings_tv.xml b/libs/WindowManager/Shell/res/values-eu/strings_tv.xml
index 72f9980a97c3..bce06da2c66f 100644
--- a/libs/WindowManager/Shell/res/values-eu/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-eu/strings_tv.xml
@@ -24,4 +24,5 @@
<string name="pip_move" msgid="1544227837964635439">"Mugitu pantaila txiki gainjarria"</string>
<string name="pip_expand" msgid="7605396312689038178">"Zabaldu pantaila txiki gainjarria"</string>
<string name="pip_collapse" msgid="5732233773786896094">"Tolestu pantaila txiki gainjarria"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Kontrolatzeko aukerak atzitzeko, sakatu birritan "<annotation icon="home_icon">" HASIERA "</annotation></string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-fa/strings_tv.xml b/libs/WindowManager/Shell/res/values-fa/strings_tv.xml
index 5fa59beae1a5..ff9a03c6cefb 100644
--- a/libs/WindowManager/Shell/res/values-fa/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-fa/strings_tv.xml
@@ -24,4 +24,5 @@
<string name="pip_move" msgid="1544227837964635439">"‏انتقال PIP (تصویر در تصویر)"</string>
<string name="pip_expand" msgid="7605396312689038178">"گسترده کردن «تصویر در تصویر»"</string>
<string name="pip_collapse" msgid="5732233773786896094">"جمع کردن «تصویر در تصویر»"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" برای کنترل‌ها، دکمه "<annotation icon="home_icon">"صفحه اصلی"</annotation>" را دوبار فشار دهید"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-fi/strings_tv.xml b/libs/WindowManager/Shell/res/values-fi/strings_tv.xml
index 217a85ceb791..3e8bf9032780 100644
--- a/libs/WindowManager/Shell/res/values-fi/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-fi/strings_tv.xml
@@ -24,4 +24,5 @@
<string name="pip_move" msgid="1544227837964635439">"Siirrä PIP"</string>
<string name="pip_expand" msgid="7605396312689038178">"Laajenna PIP"</string>
<string name="pip_collapse" msgid="5732233773786896094">"Tiivistä PIP"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Asetukset: paina "<annotation icon="home_icon">"ALOITUSNÄYTTÖPAINIKETTA"</annotation>" kahdesti"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-fr-rCA/strings_tv.xml b/libs/WindowManager/Shell/res/values-fr-rCA/strings_tv.xml
index b6f401fae144..66e13b89c64b 100644
--- a/libs/WindowManager/Shell/res/values-fr-rCA/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-fr-rCA/strings_tv.xml
@@ -24,4 +24,5 @@
<string name="pip_move" msgid="1544227837964635439">"Déplacer l\'image incrustée"</string>
<string name="pip_expand" msgid="7605396312689038178">"Développer l\'image incrustée"</string>
<string name="pip_collapse" msgid="5732233773786896094">"Réduire l\'image incrustée"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Appuyez deux fois sur "<annotation icon="home_icon">" ACCUEIL "</annotation>" pour les commandes"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-fr/strings_tv.xml b/libs/WindowManager/Shell/res/values-fr/strings_tv.xml
index ffa4a229b9f2..ed9baf5b6215 100644
--- a/libs/WindowManager/Shell/res/values-fr/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-fr/strings_tv.xml
@@ -24,4 +24,5 @@
<string name="pip_move" msgid="1544227837964635439">"Déplacer le PIP"</string>
<string name="pip_expand" msgid="7605396312689038178">"Développer la fenêtre PIP"</string>
<string name="pip_collapse" msgid="5732233773786896094">"Réduire la fenêtre PIP"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Menu de commandes : appuyez deux fois sur "<annotation icon="home_icon">"ACCUEIL"</annotation></string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-gl/strings_tv.xml b/libs/WindowManager/Shell/res/values-gl/strings_tv.xml
index 3a7ed890961c..a057434d7853 100644
--- a/libs/WindowManager/Shell/res/values-gl/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-gl/strings_tv.xml
@@ -24,4 +24,5 @@
<string name="pip_move" msgid="1544227837964635439">"Mover pantalla superposta"</string>
<string name="pip_expand" msgid="7605396312689038178">"Despregar pantalla superposta"</string>
<string name="pip_collapse" msgid="5732233773786896094">"Contraer pantalla superposta"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Preme "<annotation icon="home_icon">"INICIO"</annotation>" dúas veces para acceder aos controis"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-gu/strings_tv.xml b/libs/WindowManager/Shell/res/values-gu/strings_tv.xml
index 7a9bb25d63c2..d9525910e4c6 100644
--- a/libs/WindowManager/Shell/res/values-gu/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-gu/strings_tv.xml
@@ -24,4 +24,5 @@
<string name="pip_move" msgid="1544227837964635439">"PIP ખસેડો"</string>
<string name="pip_expand" msgid="7605396312689038178">"PIP મોટી કરો"</string>
<string name="pip_collapse" msgid="5732233773786896094">"PIP નાની કરો"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" નિયંત્રણો માટે "<annotation icon="home_icon">" હોમ "</annotation>" બટન પર બે વાર દબાવો"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-hi/strings_tv.xml b/libs/WindowManager/Shell/res/values-hi/strings_tv.xml
index 5776f8190868..d897ac73f80d 100644
--- a/libs/WindowManager/Shell/res/values-hi/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-hi/strings_tv.xml
@@ -24,4 +24,5 @@
<string name="pip_move" msgid="1544227837964635439">"पीआईपी को दूसरी जगह लेकर जाएं"</string>
<string name="pip_expand" msgid="7605396312689038178">"पीआईपी विंडो को बड़ा करें"</string>
<string name="pip_collapse" msgid="5732233773786896094">"पीआईपी विंडो को छोटा करें"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" कंट्रोल मेन्यू पर जाने के लिए, "<annotation icon="home_icon">" होम बटन"</annotation>" दो बार दबाएं"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-hr/strings_tv.xml b/libs/WindowManager/Shell/res/values-hr/strings_tv.xml
index e4d69442c5c0..8f5f3164c4d7 100644
--- a/libs/WindowManager/Shell/res/values-hr/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-hr/strings_tv.xml
@@ -24,4 +24,5 @@
<string name="pip_move" msgid="1544227837964635439">"Premjesti PIP"</string>
<string name="pip_expand" msgid="7605396312689038178">"Proširi PIP"</string>
<string name="pip_collapse" msgid="5732233773786896094">"Sažmi PIP"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Dvaput pritisnite "<annotation icon="home_icon">"POČETNI ZASLON"</annotation>" za kontrole"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-hu/strings_tv.xml b/libs/WindowManager/Shell/res/values-hu/strings_tv.xml
index 43beeeaa44f5..fc8d79589121 100644
--- a/libs/WindowManager/Shell/res/values-hu/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-hu/strings_tv.xml
@@ -24,4 +24,5 @@
<string name="pip_move" msgid="1544227837964635439">"PIP áthelyezése"</string>
<string name="pip_expand" msgid="7605396312689038178">"Kép a képben kibontása"</string>
<string name="pip_collapse" msgid="5732233773786896094">"Kép a képben összecsukása"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Vezérlők: "<annotation icon="home_icon">" KEZDŐKÉPERNYŐ "</annotation>" gomb kétszer megnyomva"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-hy/strings_tv.xml b/libs/WindowManager/Shell/res/values-hy/strings_tv.xml
index e439d5c6fbbd..f5665b8dd166 100644
--- a/libs/WindowManager/Shell/res/values-hy/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-hy/strings_tv.xml
@@ -24,4 +24,5 @@
<string name="pip_move" msgid="1544227837964635439">"Տեղափոխել PIP-ը"</string>
<string name="pip_expand" msgid="7605396312689038178">"Ծավալել PIP-ը"</string>
<string name="pip_collapse" msgid="5732233773786896094">"Ծալել PIP-ը"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Կարգավորումների համար կրկնակի սեղմեք "<annotation icon="home_icon">"ԳԼԽԱՎՈՐ ԷԿՐԱՆ"</annotation></string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-in/strings_tv.xml b/libs/WindowManager/Shell/res/values-in/strings_tv.xml
index 25cb7567e33e..a1535653f679 100644
--- a/libs/WindowManager/Shell/res/values-in/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-in/strings_tv.xml
@@ -24,4 +24,5 @@
<string name="pip_move" msgid="1544227837964635439">"Pindahkan PIP"</string>
<string name="pip_expand" msgid="7605396312689038178">"Luaskan PIP"</string>
<string name="pip_collapse" msgid="5732233773786896094">"Ciutkan PIP"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Tekan dua kali "<annotation icon="home_icon">" HOME "</annotation>" untuk membuka kontrol"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-is/strings_tv.xml b/libs/WindowManager/Shell/res/values-is/strings_tv.xml
index 56b973996ea9..70ca1afe3aea 100644
--- a/libs/WindowManager/Shell/res/values-is/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-is/strings_tv.xml
@@ -24,4 +24,5 @@
<string name="pip_move" msgid="1544227837964635439">"Færa innfellda mynd"</string>
<string name="pip_expand" msgid="7605396312689038178">"Stækka innfellda mynd"</string>
<string name="pip_collapse" msgid="5732233773786896094">"Minnka innfellda mynd"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Ýttu tvisvar á "<annotation icon="home_icon">" HEIM "</annotation>" til að opna stillingar"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-it/strings_tv.xml b/libs/WindowManager/Shell/res/values-it/strings_tv.xml
index 735c5cd6c065..cda627517872 100644
--- a/libs/WindowManager/Shell/res/values-it/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-it/strings_tv.xml
@@ -24,4 +24,5 @@
<string name="pip_move" msgid="1544227837964635439">"Sposta PIP"</string>
<string name="pip_expand" msgid="7605396312689038178">"Espandi PIP"</string>
<string name="pip_collapse" msgid="5732233773786896094">"Comprimi PIP"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Premi due volte "<annotation icon="home_icon">" HOME "</annotation>" per aprire i controlli"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-iw/strings_tv.xml b/libs/WindowManager/Shell/res/values-iw/strings_tv.xml
index e4e0bf6002b0..30ce97b998ca 100644
--- a/libs/WindowManager/Shell/res/values-iw/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-iw/strings_tv.xml
@@ -24,4 +24,5 @@
<string name="pip_move" msgid="1544227837964635439">"‏העברת תמונה בתוך תמונה (PIP)"</string>
<string name="pip_expand" msgid="7605396312689038178">"הרחבת חלון תמונה-בתוך-תמונה"</string>
<string name="pip_collapse" msgid="5732233773786896094">"כיווץ של חלון תמונה-בתוך-תמונה"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" לחיצה כפולה על "<annotation icon="home_icon">" הלחצן הראשי "</annotation>" תציג את אמצעי הבקרה"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ja/strings_tv.xml b/libs/WindowManager/Shell/res/values-ja/strings_tv.xml
index c8326a6552c4..e58e7bf6fabc 100644
--- a/libs/WindowManager/Shell/res/values-ja/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-ja/strings_tv.xml
@@ -24,4 +24,5 @@
<string name="pip_move" msgid="1544227837964635439">"PIP を移動"</string>
<string name="pip_expand" msgid="7605396312689038178">"PIP を開く"</string>
<string name="pip_collapse" msgid="5732233773786896094">"PIP を閉じる"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" コントロールにアクセス: "<annotation icon="home_icon">" ホーム "</annotation>" を 2 回押します"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ka/strings_tv.xml b/libs/WindowManager/Shell/res/values-ka/strings_tv.xml
index 025e5a554de1..b09686646c8b 100644
--- a/libs/WindowManager/Shell/res/values-ka/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-ka/strings_tv.xml
@@ -24,4 +24,5 @@
<string name="pip_move" msgid="1544227837964635439">"PIP გადატანა"</string>
<string name="pip_expand" msgid="7605396312689038178">"PIP-ის გაშლა"</string>
<string name="pip_collapse" msgid="5732233773786896094">"PIP-ის ჩაკეცვა"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" მართვის საშუალებებზე წვდომისთვის ორმაგად დააჭირეთ "<annotation icon="home_icon">" მთავარ ღილაკს "</annotation></string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-kk/strings_tv.xml b/libs/WindowManager/Shell/res/values-kk/strings_tv.xml
index 27afe2ec4131..7bade0dff0d9 100644
--- a/libs/WindowManager/Shell/res/values-kk/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-kk/strings_tv.xml
@@ -24,4 +24,5 @@
<string name="pip_move" msgid="1544227837964635439">"PIP клипін жылжыту"</string>
<string name="pip_expand" msgid="7605396312689038178">"PIP терезесін жаю"</string>
<string name="pip_collapse" msgid="5732233773786896094">"PIP терезесін жию"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Басқару элементтері: "<annotation icon="home_icon">" НЕГІЗГІ ЭКРАН "</annotation>" түймесін екі рет басыңыз."</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-km/strings_tv.xml b/libs/WindowManager/Shell/res/values-km/strings_tv.xml
index 86bad2776c37..721be1fc1650 100644
--- a/libs/WindowManager/Shell/res/values-km/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-km/strings_tv.xml
@@ -24,4 +24,5 @@
<string name="pip_move" msgid="1544227837964635439">"ផ្លាស់ទី PIP"</string>
<string name="pip_expand" msgid="7605396312689038178">"ពង្រីក PIP"</string>
<string name="pip_collapse" msgid="5732233773786896094">"បង្រួម PIP"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" ចុចពីរដងលើ"<annotation icon="home_icon">"ប៊ូតុងដើម"</annotation>" ដើម្បីបើកផ្ទាំងគ្រប់គ្រង"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-kn/strings_tv.xml b/libs/WindowManager/Shell/res/values-kn/strings_tv.xml
index 3fbfdaa85a70..8310c8a1169c 100644
--- a/libs/WindowManager/Shell/res/values-kn/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-kn/strings_tv.xml
@@ -24,4 +24,5 @@
<string name="pip_move" msgid="1544227837964635439">"PIP ಅನ್ನು ಸರಿಸಿ"</string>
<string name="pip_expand" msgid="7605396312689038178">"ಚಿತ್ರದಲ್ಲಿ ಚಿತ್ರವನ್ನು ವಿಸ್ತರಿಸಿ"</string>
<string name="pip_collapse" msgid="5732233773786896094">"ಚಿತ್ರದಲ್ಲಿ ಚಿತ್ರವನ್ನು ಕುಗ್ಗಿಸಿ"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" ಕಂಟ್ರೋಲ್‌ಗಳಿಗಾಗಿ "<annotation icon="home_icon">" ಹೋಮ್ "</annotation>" ಅನ್ನು ಎರಡು ಬಾರಿ ಒತ್ತಿ"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ko/strings_tv.xml b/libs/WindowManager/Shell/res/values-ko/strings_tv.xml
index fa8c898011fc..a3e055a515a1 100644
--- a/libs/WindowManager/Shell/res/values-ko/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-ko/strings_tv.xml
@@ -24,4 +24,5 @@
<string name="pip_move" msgid="1544227837964635439">"PIP 이동"</string>
<string name="pip_expand" msgid="7605396312689038178">"PIP 펼치기"</string>
<string name="pip_collapse" msgid="5732233773786896094">"PIP 접기"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" 제어 메뉴에 액세스하려면 "<annotation icon="home_icon">" 홈 "</annotation>"을 두 번 누르세요."</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ky/strings_tv.xml b/libs/WindowManager/Shell/res/values-ky/strings_tv.xml
index 6e2b810e9b8b..887ac52c8e43 100644
--- a/libs/WindowManager/Shell/res/values-ky/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-ky/strings_tv.xml
@@ -24,4 +24,5 @@
<string name="pip_move" msgid="1544227837964635439">"PIP\'ти жылдыруу"</string>
<string name="pip_expand" msgid="7605396312689038178">"PIP\'ти жайып көрсөтүү"</string>
<string name="pip_collapse" msgid="5732233773786896094">"PIP\'ти жыйыштыруу"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Башкаруу элементтерин ачуу үчүн "<annotation icon="home_icon">" БАШКЫ БЕТ "</annotation>" баскычын эки жолу басыңыз"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-land/styles.xml b/libs/WindowManager/Shell/res/values-land/styles.xml
index 0ed9368aa067..e89f65bef792 100644
--- a/libs/WindowManager/Shell/res/values-land/styles.xml
+++ b/libs/WindowManager/Shell/res/values-land/styles.xml
@@ -16,7 +16,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android">
<style name="DockedDividerBackground">
- <item name="android:layout_width">10dp</item>
+ <item name="android:layout_width">@dimen/split_divider_bar_width</item>
<item name="android:layout_height">match_parent</item>
<item name="android:layout_gravity">center_horizontal</item>
<item name="android:background">@color/split_divider_background</item>
diff --git a/libs/WindowManager/Shell/res/values-lo/strings_tv.xml b/libs/WindowManager/Shell/res/values-lo/strings_tv.xml
index 3d4505d77d75..91c4a033356d 100644
--- a/libs/WindowManager/Shell/res/values-lo/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-lo/strings_tv.xml
@@ -24,4 +24,5 @@
<string name="pip_move" msgid="1544227837964635439">"ຍ້າຍ PIP"</string>
<string name="pip_expand" msgid="7605396312689038178">"ຂະຫຍາຍ PIP"</string>
<string name="pip_collapse" msgid="5732233773786896094">"ຫຍໍ້ PIP ລົງ"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" ກົດ "<annotation icon="home_icon">" HOME "</annotation>" ສອງເທື່ອສຳລັບການຄວບຄຸມ"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-lt/strings_tv.xml b/libs/WindowManager/Shell/res/values-lt/strings_tv.xml
index f907055872ca..04265ca01b48 100644
--- a/libs/WindowManager/Shell/res/values-lt/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-lt/strings_tv.xml
@@ -24,4 +24,5 @@
<string name="pip_move" msgid="1544227837964635439">"Perkelti PIP"</string>
<string name="pip_expand" msgid="7605396312689038178">"Iškleisti PIP"</string>
<string name="pip_collapse" msgid="5732233773786896094">"Sutraukti PIP"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Jei reikia valdiklių, dukart paspauskite "<annotation icon="home_icon">"PAGRINDINIS"</annotation></string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-lv/strings_tv.xml b/libs/WindowManager/Shell/res/values-lv/strings_tv.xml
index 04d9409cb3ac..8c6191e00833 100644
--- a/libs/WindowManager/Shell/res/values-lv/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-lv/strings_tv.xml
@@ -24,4 +24,5 @@
<string name="pip_move" msgid="1544227837964635439">"Pārvietot attēlu attēlā"</string>
<string name="pip_expand" msgid="7605396312689038178">"Izvērst “Attēls attēlā” logu"</string>
<string name="pip_collapse" msgid="5732233773786896094">"Sakļaut “Attēls attēlā” logu"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Atvērt vadīklas: divreiz nospiediet pogu "<annotation icon="home_icon">"SĀKUMS"</annotation></string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-mk/strings_tv.xml b/libs/WindowManager/Shell/res/values-mk/strings_tv.xml
index e9ee13884afc..beef1fef862b 100644
--- a/libs/WindowManager/Shell/res/values-mk/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-mk/strings_tv.xml
@@ -24,4 +24,5 @@
<string name="pip_move" msgid="1544227837964635439">"Премести PIP"</string>
<string name="pip_expand" msgid="7605396312689038178">"Прошири ја сликата во слика"</string>
<string name="pip_collapse" msgid="5732233773786896094">"Собери ја сликата во слика"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Притиснете двапати на "<annotation icon="home_icon">" HOME "</annotation>" за контроли"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ml/strings_tv.xml b/libs/WindowManager/Shell/res/values-ml/strings_tv.xml
index 1ed6b6e566de..c2a532d09647 100644
--- a/libs/WindowManager/Shell/res/values-ml/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-ml/strings_tv.xml
@@ -24,4 +24,5 @@
<string name="pip_move" msgid="1544227837964635439">"PIP നീക്കുക"</string>
<string name="pip_expand" msgid="7605396312689038178">"PIP വികസിപ്പിക്കുക"</string>
<string name="pip_collapse" msgid="5732233773786896094">"PIP ചുരുക്കുക"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" നിയന്ത്രണങ്ങൾക്കായി "<annotation icon="home_icon">" ഹോം "</annotation>" രണ്ട് തവണ അമർത്തുക"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-mn/strings_tv.xml b/libs/WindowManager/Shell/res/values-mn/strings_tv.xml
index d4a6942ae9dc..bf8c59b57359 100644
--- a/libs/WindowManager/Shell/res/values-mn/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-mn/strings_tv.xml
@@ -24,4 +24,5 @@
<string name="pip_move" msgid="1544227837964635439">"PIP-г зөөх"</string>
<string name="pip_expand" msgid="7605396312689038178">"PIP-г дэлгэх"</string>
<string name="pip_collapse" msgid="5732233773786896094">"PIP-г хураах"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Хяналтад хандах бол "<annotation icon="home_icon">" HOME "</annotation>" дээр хоёр дарна уу"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-mr/strings_tv.xml b/libs/WindowManager/Shell/res/values-mr/strings_tv.xml
index 940f9832eb4a..5d519b7afe9a 100644
--- a/libs/WindowManager/Shell/res/values-mr/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-mr/strings_tv.xml
@@ -24,4 +24,5 @@
<string name="pip_move" msgid="1544227837964635439">"PIP हलवा"</string>
<string name="pip_expand" msgid="7605396312689038178">"PIP चा विस्तार करा"</string>
<string name="pip_collapse" msgid="5732233773786896094">"PIP कोलॅप्स करा"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" नियंत्रणांसाठी "<annotation icon="home_icon">" होम "</annotation>" दोनदा दाबा"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ms/strings_tv.xml b/libs/WindowManager/Shell/res/values-ms/strings_tv.xml
index f4b180c8fe74..08642c47c91a 100644
--- a/libs/WindowManager/Shell/res/values-ms/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-ms/strings_tv.xml
@@ -24,4 +24,5 @@
<string name="pip_move" msgid="1544227837964635439">"Alihkan PIP"</string>
<string name="pip_expand" msgid="7605396312689038178">"Kembangkan PIP"</string>
<string name="pip_collapse" msgid="5732233773786896094">"Kuncupkan PIP"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Tekan dua kali "<annotation icon="home_icon">" LAMAN UTAMA "</annotation>" untuk mengakses kawalan"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-my/strings_tv.xml b/libs/WindowManager/Shell/res/values-my/strings_tv.xml
index 4b2a5ecbce0c..e01daee115ca 100644
--- a/libs/WindowManager/Shell/res/values-my/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-my/strings_tv.xml
@@ -24,4 +24,5 @@
<string name="pip_move" msgid="1544227837964635439">"PIP ရွှေ့ရန်"</string>
<string name="pip_expand" msgid="7605396312689038178">"PIP ကို ချဲ့ရန်"</string>
<string name="pip_collapse" msgid="5732233773786896094">"PIP ကို လျှော့ပြပါ"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" ထိန်းချုပ်မှုအတွက် "<annotation icon="home_icon">" ပင်မခလုတ် "</annotation>" နှစ်ချက်နှိပ်ပါ"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-nb/strings_tv.xml b/libs/WindowManager/Shell/res/values-nb/strings_tv.xml
index be74eeb78bba..65ed0b7f5bff 100644
--- a/libs/WindowManager/Shell/res/values-nb/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-nb/strings_tv.xml
@@ -24,4 +24,5 @@
<string name="pip_move" msgid="1544227837964635439">"Flytt BIB"</string>
<string name="pip_expand" msgid="7605396312689038178">"Vis BIB"</string>
<string name="pip_collapse" msgid="5732233773786896094">"Skjul BIB"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Dobbelttrykk på "<annotation icon="home_icon">"HJEM"</annotation>" for å åpne kontroller"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ne/strings_tv.xml b/libs/WindowManager/Shell/res/values-ne/strings_tv.xml
index a36cad696159..d33fed67efb6 100644
--- a/libs/WindowManager/Shell/res/values-ne/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-ne/strings_tv.xml
@@ -24,4 +24,5 @@
<string name="pip_move" msgid="1544227837964635439">"PIP सार्नुहोस्"</string>
<string name="pip_expand" msgid="7605396312689038178">"PIP विन्डो एक्स्पान्ड गर्नु…"</string>
<string name="pip_collapse" msgid="5732233773786896094">"PIP विन्डो कोल्याप्स गर्नुहोस्"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" कन्ट्रोल मेनु खोल्न "<annotation icon="home_icon">" होम "</annotation>" बटन दुई पटक थिच्नुहोस्"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-nl/strings_tv.xml b/libs/WindowManager/Shell/res/values-nl/strings_tv.xml
index eb7ec606b0fa..9763c5665ab2 100644
--- a/libs/WindowManager/Shell/res/values-nl/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-nl/strings_tv.xml
@@ -24,4 +24,5 @@
<string name="pip_move" msgid="1544227837964635439">"SIS verplaatsen"</string>
<string name="pip_expand" msgid="7605396312689038178">"SIS uitvouwen"</string>
<string name="pip_collapse" msgid="5732233773786896094">"SIS samenvouwen"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Druk twee keer op "<annotation icon="home_icon">" HOME "</annotation>" voor bedieningselementen"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-or/strings_tv.xml b/libs/WindowManager/Shell/res/values-or/strings_tv.xml
index e48199f9de50..e0344855bd1f 100644
--- a/libs/WindowManager/Shell/res/values-or/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-or/strings_tv.xml
@@ -24,4 +24,5 @@
<string name="pip_move" msgid="1544227837964635439">"PIPକୁ ମୁଭ କରନ୍ତୁ"</string>
<string name="pip_expand" msgid="7605396312689038178">"PIPକୁ ବିସ୍ତାର କରନ୍ତୁ"</string>
<string name="pip_collapse" msgid="5732233773786896094">"PIPକୁ ସଙ୍କୁଚିତ କରନ୍ତୁ"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" ନିୟନ୍ତ୍ରଣଗୁଡ଼ିକ ପାଇଁ "<annotation icon="home_icon">" ହୋମ ବଟନ "</annotation>"କୁ ଦୁଇଥର ଦବାନ୍ତୁ"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-pa/strings_tv.xml b/libs/WindowManager/Shell/res/values-pa/strings_tv.xml
index 891107e765f6..9c01ac3f3cc0 100644
--- a/libs/WindowManager/Shell/res/values-pa/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-pa/strings_tv.xml
@@ -24,4 +24,5 @@
<string name="pip_move" msgid="1544227837964635439">"PIP ਨੂੰ ਲਿਜਾਓ"</string>
<string name="pip_expand" msgid="7605396312689038178">"PIP ਦਾ ਵਿਸਤਾਰ ਕਰੋ"</string>
<string name="pip_collapse" msgid="5732233773786896094">"PIP ਨੂੰ ਸਮੇਟੋ"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" ਕੰਟਰੋਲਾਂ ਲਈ "<annotation icon="home_icon">" ਹੋਮ ਬਟਨ "</annotation>" ਨੂੰ ਦੋ ਵਾਰ ਦਬਾਓ"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-pl/strings_tv.xml b/libs/WindowManager/Shell/res/values-pl/strings_tv.xml
index 7b5d08acd504..b922e2d5a6ba 100644
--- a/libs/WindowManager/Shell/res/values-pl/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-pl/strings_tv.xml
@@ -24,4 +24,5 @@
<string name="pip_move" msgid="1544227837964635439">"Przenieś PIP"</string>
<string name="pip_expand" msgid="7605396312689038178">"Rozwiń PIP"</string>
<string name="pip_collapse" msgid="5732233773786896094">"Zwiń PIP"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Naciśnij dwukrotnie "<annotation icon="home_icon">"EKRAN GŁÓWNY"</annotation>", aby wyświetlić ustawienia"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-pt-rBR/strings_tv.xml b/libs/WindowManager/Shell/res/values-pt-rBR/strings_tv.xml
index b669f161c625..cc4eb3c32c1f 100644
--- a/libs/WindowManager/Shell/res/values-pt-rBR/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-pt-rBR/strings_tv.xml
@@ -24,4 +24,5 @@
<string name="pip_move" msgid="1544227837964635439">"Mover picture-in-picture"</string>
<string name="pip_expand" msgid="7605396312689038178">"Abrir picture-in-picture"</string>
<string name="pip_collapse" msgid="5732233773786896094">"Fechar picture-in-picture"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Pressione o botão "<annotation icon="home_icon">"home"</annotation>" duas vezes para acessar os controles"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-pt-rPT/strings_tv.xml b/libs/WindowManager/Shell/res/values-pt-rPT/strings_tv.xml
index 6c1fa5905d1a..c4ae78d89ba8 100644
--- a/libs/WindowManager/Shell/res/values-pt-rPT/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-pt-rPT/strings_tv.xml
@@ -24,4 +24,5 @@
<string name="pip_move" msgid="1544227837964635439">"Mover Ecrã no ecrã"</string>
<string name="pip_expand" msgid="7605396312689038178">"Expandir Ecrã no ecrã"</string>
<string name="pip_collapse" msgid="5732233773786896094">"Reduzir Ecrã no ecrã"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Prima duas vezes "<annotation icon="home_icon">" PÁGINA INICIAL "</annotation>" para controlos"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-pt/strings_tv.xml b/libs/WindowManager/Shell/res/values-pt/strings_tv.xml
index b669f161c625..cc4eb3c32c1f 100644
--- a/libs/WindowManager/Shell/res/values-pt/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-pt/strings_tv.xml
@@ -24,4 +24,5 @@
<string name="pip_move" msgid="1544227837964635439">"Mover picture-in-picture"</string>
<string name="pip_expand" msgid="7605396312689038178">"Abrir picture-in-picture"</string>
<string name="pip_collapse" msgid="5732233773786896094">"Fechar picture-in-picture"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Pressione o botão "<annotation icon="home_icon">"home"</annotation>" duas vezes para acessar os controles"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ro/strings_tv.xml b/libs/WindowManager/Shell/res/values-ro/strings_tv.xml
index 8ecf8c5a1593..86a30f49df15 100644
--- a/libs/WindowManager/Shell/res/values-ro/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-ro/strings_tv.xml
@@ -24,4 +24,5 @@
<string name="pip_move" msgid="1544227837964635439">"Mutați fereastra PIP"</string>
<string name="pip_expand" msgid="7605396312689038178">"Extindeți fereastra PIP"</string>
<string name="pip_collapse" msgid="5732233773786896094">"Restrângeți fereastra PIP"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Apăsați de două ori "<annotation icon="home_icon">"butonul ecran de pornire"</annotation>" pentru comenzi"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ru/strings_tv.xml b/libs/WindowManager/Shell/res/values-ru/strings_tv.xml
index 19f7a00c758b..08623e1e69c5 100644
--- a/libs/WindowManager/Shell/res/values-ru/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-ru/strings_tv.xml
@@ -24,4 +24,5 @@
<string name="pip_move" msgid="1544227837964635439">"Переместить PIP"</string>
<string name="pip_expand" msgid="7605396312689038178">"Развернуть PIP"</string>
<string name="pip_collapse" msgid="5732233773786896094">"Свернуть PIP"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Элементы управления: дважды нажмите "<annotation icon="home_icon">" кнопку главного экрана "</annotation></string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-si/strings_tv.xml b/libs/WindowManager/Shell/res/values-si/strings_tv.xml
index 7444369cbc95..fbb0ebba0623 100644
--- a/libs/WindowManager/Shell/res/values-si/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-si/strings_tv.xml
@@ -24,4 +24,5 @@
<string name="pip_move" msgid="1544227837964635439">"PIP ගෙන යන්න"</string>
<string name="pip_expand" msgid="7605396312689038178">"PIP දිග හරින්න"</string>
<string name="pip_collapse" msgid="5732233773786896094">"PIP හකුළන්න"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" පාලන සඳහා "<annotation icon="home_icon">" මුල් පිටුව "</annotation>" දෙවරක් ඔබන්න"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-sk/strings_tv.xml b/libs/WindowManager/Shell/res/values-sk/strings_tv.xml
index 1a8edf183c75..81cb0eafc759 100644
--- a/libs/WindowManager/Shell/res/values-sk/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-sk/strings_tv.xml
@@ -24,4 +24,5 @@
<string name="pip_move" msgid="1544227837964635439">"Presunúť obraz v obraze"</string>
<string name="pip_expand" msgid="7605396312689038178">"Rozbaliť obraz v obraze"</string>
<string name="pip_collapse" msgid="5732233773786896094">"Zbaliť obraz v obraze"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Ovládanie zobraz. dvoj. stlač. "<annotation icon="home_icon">" TLAČIDLA PLOCHY "</annotation></string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-sl/strings_tv.xml b/libs/WindowManager/Shell/res/values-sl/strings_tv.xml
index c4c04c24fc49..060aaa0ce647 100644
--- a/libs/WindowManager/Shell/res/values-sl/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-sl/strings_tv.xml
@@ -24,4 +24,5 @@
<string name="pip_move" msgid="1544227837964635439">"Premakni sliko v sliki"</string>
<string name="pip_expand" msgid="7605396312689038178">"Razširi sliko v sliki"</string>
<string name="pip_collapse" msgid="5732233773786896094">"Strni sliko v sliki"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Za kontrolnike dvakrat pritisnite gumb za "<annotation icon="home_icon">" ZAČETNI ZASLON "</annotation></string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-sq/strings_tv.xml b/libs/WindowManager/Shell/res/values-sq/strings_tv.xml
index 2771b89a63eb..9bfdb6a3edd8 100644
--- a/libs/WindowManager/Shell/res/values-sq/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-sq/strings_tv.xml
@@ -24,4 +24,5 @@
<string name="pip_move" msgid="1544227837964635439">"Zhvendos PIP"</string>
<string name="pip_expand" msgid="7605396312689038178">"Zgjero PIP"</string>
<string name="pip_collapse" msgid="5732233773786896094">"Palos PIP"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Trokit dy herë "<annotation icon="home_icon">" KREU "</annotation>" për kontrollet"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-sr/strings_tv.xml b/libs/WindowManager/Shell/res/values-sr/strings_tv.xml
index 32440302d6d2..6bc5c87bab48 100644
--- a/libs/WindowManager/Shell/res/values-sr/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-sr/strings_tv.xml
@@ -24,4 +24,5 @@
<string name="pip_move" msgid="1544227837964635439">"Премести слику у слици"</string>
<string name="pip_expand" msgid="7605396312689038178">"Прошири слику у слици"</string>
<string name="pip_collapse" msgid="5732233773786896094">"Скупи слику у слици"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Двапут притисните "<annotation icon="home_icon">" HOME "</annotation>" за контроле"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-sv/strings_tv.xml b/libs/WindowManager/Shell/res/values-sv/strings_tv.xml
index 842c8053e494..b3465ab1db85 100644
--- a/libs/WindowManager/Shell/res/values-sv/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-sv/strings_tv.xml
@@ -24,4 +24,5 @@
<string name="pip_move" msgid="1544227837964635439">"Flytta BIB"</string>
<string name="pip_expand" msgid="7605396312689038178">"Utöka bild-i-bild"</string>
<string name="pip_collapse" msgid="5732233773786896094">"Komprimera bild-i-bild"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Tryck snabbt två gånger på "<annotation icon="home_icon">" HEM "</annotation>" för kontroller"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-sw/strings_tv.xml b/libs/WindowManager/Shell/res/values-sw/strings_tv.xml
index 8728fd9360c2..baff49ed821a 100644
--- a/libs/WindowManager/Shell/res/values-sw/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-sw/strings_tv.xml
@@ -24,4 +24,5 @@
<string name="pip_move" msgid="1544227837964635439">"Kuhamisha PIP"</string>
<string name="pip_expand" msgid="7605396312689038178">"Panua PIP"</string>
<string name="pip_collapse" msgid="5732233773786896094">"Kunja PIP"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Bonyeza mara mbili kitufe cha "<annotation icon="home_icon">" UKURASA WA KWANZA "</annotation>" kupata vidhibiti"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ta/strings_tv.xml b/libs/WindowManager/Shell/res/values-ta/strings_tv.xml
index e325b1a6c32d..4439e299c919 100644
--- a/libs/WindowManager/Shell/res/values-ta/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-ta/strings_tv.xml
@@ -24,4 +24,5 @@
<string name="pip_move" msgid="1544227837964635439">"PIPபை நகர்த்து"</string>
<string name="pip_expand" msgid="7605396312689038178">"PIPபை விரிவாக்கு"</string>
<string name="pip_collapse" msgid="5732233773786896094">"PIPபைச் சுருக்கு"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" கட்டுப்பாடுகள்: "<annotation icon="home_icon">" முகப்பு "</annotation>" பட்டனை இருமுறை அழுத்துக"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-te/strings_tv.xml b/libs/WindowManager/Shell/res/values-te/strings_tv.xml
index 1381e6771936..35579346615f 100644
--- a/libs/WindowManager/Shell/res/values-te/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-te/strings_tv.xml
@@ -24,4 +24,5 @@
<string name="pip_move" msgid="1544227837964635439">"PIPను తరలించండి"</string>
<string name="pip_expand" msgid="7605396312689038178">"PIPని విస్తరించండి"</string>
<string name="pip_collapse" msgid="5732233773786896094">"PIPని కుదించండి"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" కంట్రోల్స్ కోసం "<annotation icon="home_icon">" HOME "</annotation>" బటన్ రెండుసార్లు నొక్కండి"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-television/config.xml b/libs/WindowManager/Shell/res/values-television/config.xml
index 552048e8be9a..86ca65526336 100644
--- a/libs/WindowManager/Shell/res/values-television/config.xml
+++ b/libs/WindowManager/Shell/res/values-television/config.xml
@@ -33,4 +33,14 @@
<!-- The default gravity for the picture-in-picture window.
Currently, this maps to Gravity.BOTTOM | Gravity.RIGHT -->
<integer name="config_defaultPictureInPictureGravity">0x55</integer>
+
+ <!-- Fraction of screen width/height restricted keep clear areas can move the PiP. -->
+ <fraction name="config_pipMaxRestrictedMoveDistance">15%</fraction>
+
+ <!-- Duration (in milliseconds) the PiP stays stashed before automatically unstashing. -->
+ <integer name="config_pipStashDuration">5000</integer>
+
+ <!-- Time (duration in milliseconds) that the shell waits for an app to close the PiP by itself
+ if a custom action is present before closing it. -->
+ <integer name="config_pipForceCloseDelay">5000</integer>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-television/dimen.xml b/libs/WindowManager/Shell/res/values-television/dimen.xml
new file mode 100644
index 000000000000..14e89f8b08df
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-television/dimen.xml
@@ -0,0 +1,24 @@
+<?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.
+ -->
+
+<!-- These resources are around just to allow their values to be customized
+ for TV products. Do not translate. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+ <!-- Padding between PIP and keep clear areas that caused it to move. -->
+ <dimen name="pip_keep_clear_area_padding">16dp</dimen>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-th/strings_tv.xml b/libs/WindowManager/Shell/res/values-th/strings_tv.xml
index 6f0001890961..0a07d157ec6f 100644
--- a/libs/WindowManager/Shell/res/values-th/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-th/strings_tv.xml
@@ -24,4 +24,5 @@
<string name="pip_move" msgid="1544227837964635439">"ย้าย PIP"</string>
<string name="pip_expand" msgid="7605396312689038178">"ขยาย PIP"</string>
<string name="pip_collapse" msgid="5732233773786896094">"ยุบ PIP"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" กดปุ่ม "<annotation icon="home_icon">" หน้าแรก "</annotation>" สองครั้งเพื่อเปิดการควบคุม"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-tl/strings_tv.xml b/libs/WindowManager/Shell/res/values-tl/strings_tv.xml
index 868b27874cc3..9a11a38fa492 100644
--- a/libs/WindowManager/Shell/res/values-tl/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-tl/strings_tv.xml
@@ -24,4 +24,5 @@
<string name="pip_move" msgid="1544227837964635439">"Ilipat ang PIP"</string>
<string name="pip_expand" msgid="7605396312689038178">"I-expand ang PIP"</string>
<string name="pip_collapse" msgid="5732233773786896094">"I-collapse ang PIP"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" I-double press ang "<annotation icon="home_icon">" HOME "</annotation>" para sa mga kontrol"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-tr/strings_tv.xml b/libs/WindowManager/Shell/res/values-tr/strings_tv.xml
index 9ffad78df41d..bf4bc6f1fff7 100644
--- a/libs/WindowManager/Shell/res/values-tr/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-tr/strings_tv.xml
@@ -24,4 +24,5 @@
<string name="pip_move" msgid="1544227837964635439">"PIP\'yi taşı"</string>
<string name="pip_expand" msgid="7605396312689038178">"PIP penceresini genişlet"</string>
<string name="pip_collapse" msgid="5732233773786896094">"PIP penceresini daralt"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Kontroller için "<annotation icon="home_icon">" ANA SAYFA "</annotation>"\'ya iki kez basın"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-uk/strings_tv.xml b/libs/WindowManager/Shell/res/values-uk/strings_tv.xml
index 24c169807e58..7e9f54e68f54 100644
--- a/libs/WindowManager/Shell/res/values-uk/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-uk/strings_tv.xml
@@ -24,4 +24,5 @@
<string name="pip_move" msgid="1544227837964635439">"Перемістити картинку в картинці"</string>
<string name="pip_expand" msgid="7605396312689038178">"Розгорнути картинку в картинці"</string>
<string name="pip_collapse" msgid="5732233773786896094">"Згорнути картинку в картинці"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Відкрити елементи керування: двічі натисніть "<annotation icon="home_icon">"HOME"</annotation></string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ur/strings_tv.xml b/libs/WindowManager/Shell/res/values-ur/strings_tv.xml
index c05729a123ed..c2ef69ff1488 100644
--- a/libs/WindowManager/Shell/res/values-ur/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-ur/strings_tv.xml
@@ -24,4 +24,5 @@
<string name="pip_move" msgid="1544227837964635439">"‏PIP کو منتقل کریں"</string>
<string name="pip_expand" msgid="7605396312689038178">"‏PIP کو پھیلائیں"</string>
<string name="pip_collapse" msgid="5732233773786896094">"‏PIP کو سکیڑیں"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" کنٹرولز کے لیے "<annotation icon="home_icon">"ہوم "</annotation>" بٹن کو دو بار دبائیں"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-uz/strings_tv.xml b/libs/WindowManager/Shell/res/values-uz/strings_tv.xml
index 43ab5ac11a80..9ab95c80aa25 100644
--- a/libs/WindowManager/Shell/res/values-uz/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-uz/strings_tv.xml
@@ -24,4 +24,5 @@
<string name="pip_move" msgid="1544227837964635439">"PIPni siljitish"</string>
<string name="pip_expand" msgid="7605396312689038178">"PIP funksiyasini yoyish"</string>
<string name="pip_collapse" msgid="5732233773786896094">"PIP funksiyasini yopish"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Boshqaruv uchun "<annotation icon="home_icon">"ASOSIY"</annotation>" tugmani ikki marta bosing"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-vi/strings_tv.xml b/libs/WindowManager/Shell/res/values-vi/strings_tv.xml
index 368280c210bc..146376d3cab6 100644
--- a/libs/WindowManager/Shell/res/values-vi/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-vi/strings_tv.xml
@@ -24,4 +24,5 @@
<string name="pip_move" msgid="1544227837964635439">"Di chuyển PIP (Ảnh trong ảnh)"</string>
<string name="pip_expand" msgid="7605396312689038178">"Mở rộng PIP (Ảnh trong ảnh)"</string>
<string name="pip_collapse" msgid="5732233773786896094">"Thu gọn PIP (Ảnh trong ảnh)"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Nhấn đúp vào nút "<annotation icon="home_icon">" MÀN HÌNH CHÍNH "</annotation>" để mở trình đơn điều khiển"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-zh-rCN/strings_tv.xml b/libs/WindowManager/Shell/res/values-zh-rCN/strings_tv.xml
index e5d879a24a6f..55407d2c699d 100644
--- a/libs/WindowManager/Shell/res/values-zh-rCN/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-zh-rCN/strings_tv.xml
@@ -24,4 +24,5 @@
<string name="pip_move" msgid="1544227837964635439">"移动画中画窗口"</string>
<string name="pip_expand" msgid="7605396312689038178">"展开 PIP"</string>
<string name="pip_collapse" msgid="5732233773786896094">"收起 PIP"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" 按两次"<annotation icon="home_icon">"主屏幕"</annotation>"按钮可查看相关控件"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-zh-rHK/strings_tv.xml b/libs/WindowManager/Shell/res/values-zh-rHK/strings_tv.xml
index 8ee5f11a76d8..15e278d8ecc2 100644
--- a/libs/WindowManager/Shell/res/values-zh-rHK/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-zh-rHK/strings_tv.xml
@@ -24,4 +24,5 @@
<string name="pip_move" msgid="1544227837964635439">"移動畫中畫"</string>
<string name="pip_expand" msgid="7605396312689038178">"展開畫中畫"</string>
<string name="pip_collapse" msgid="5732233773786896094">"收合畫中畫"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" 按兩下"<annotation icon="home_icon">" 主畫面按鈕"</annotation>"即可顯示控制項"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-zh-rTW/strings_tv.xml b/libs/WindowManager/Shell/res/values-zh-rTW/strings_tv.xml
index b23ecdee3575..0b17b31d23d0 100644
--- a/libs/WindowManager/Shell/res/values-zh-rTW/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-zh-rTW/strings_tv.xml
@@ -24,4 +24,5 @@
<string name="pip_move" msgid="1544227837964635439">"移動子母畫面"</string>
<string name="pip_expand" msgid="7605396312689038178">"展開子母畫面"</string>
<string name="pip_collapse" msgid="5732233773786896094">"收合子母畫面"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" 按兩下"<annotation icon="home_icon">"主畫面按鈕"</annotation>"即可顯示控制選項"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-zu/strings_tv.xml b/libs/WindowManager/Shell/res/values-zu/strings_tv.xml
index b14ee992b2ad..dad8c8128222 100644
--- a/libs/WindowManager/Shell/res/values-zu/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-zu/strings_tv.xml
@@ -24,4 +24,5 @@
<string name="pip_move" msgid="1544227837964635439">"Hambisa i-PIP"</string>
<string name="pip_expand" msgid="7605396312689038178">"Nweba i-PIP"</string>
<string name="pip_collapse" msgid="5732233773786896094">"Goqa i-PIP"</string>
+ <string name="pip_edu_text" msgid="3672999496647508701">" Chofoza kabili "<annotation icon="home_icon">" IKHAYA"</annotation>" mayelana nezilawuli"</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values/colors_tv.xml b/libs/WindowManager/Shell/res/values/colors_tv.xml
index 08d3cef10428..64b146ec3a83 100644
--- a/libs/WindowManager/Shell/res/values/colors_tv.xml
+++ b/libs/WindowManager/Shell/res/values/colors_tv.xml
@@ -16,8 +16,10 @@
-->
<resources>
<color name="tv_pip_menu_icon_focused">#0E0E0F</color>
- <color name="tv_pip_menu_icon_unfocused">#E8EAED</color>
+ <color name="tv_pip_menu_icon_unfocused">#F8F9FA</color>
<color name="tv_pip_menu_icon_disabled">#80868B</color>
+ <color name="tv_pip_menu_close_icon_bg_focused">#D93025</color>
+ <color name="tv_pip_menu_close_icon_bg_unfocused">#D69F261F</color>
<color name="tv_pip_menu_icon_bg_focused">#E8EAED</color>
<color name="tv_pip_menu_icon_bg_unfocused">#990E0E0F</color>
<color name="tv_pip_menu_focus_border">#E8EAED</color>
diff --git a/libs/WindowManager/Shell/res/values/strings_tv.xml b/libs/WindowManager/Shell/res/values/strings_tv.xml
index c7b8a130e141..09ed9b8e52ee 100644
--- a/libs/WindowManager/Shell/res/values/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values/strings_tv.xml
@@ -39,5 +39,10 @@
<!-- Button to collapse/shrink the picture-in-picture (PIP) window [CHAR LIMIT=30] -->
<string name="pip_collapse">Collapse PIP</string>
+
+ <!-- Educative text instructing the user to double press the HOME button to access the pip
+ controls menu [CHAR LIMIT=50] -->
+ <string name="pip_edu_text"> Double press <annotation icon="home_icon"> HOME </annotation> for
+ controls </string>
</resources>
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 908a31dc3e4e..8483f070d06a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellCommandHandlerImpl.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellCommandHandlerImpl.java
@@ -21,6 +21,7 @@ import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSIT
import com.android.wm.shell.apppairs.AppPairsController;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.hidedisplaycutout.HideDisplayCutoutController;
+import com.android.wm.shell.kidsmode.KidsModeTaskOrganizer;
import com.android.wm.shell.legacysplitscreen.LegacySplitScreenController;
import com.android.wm.shell.onehanded.OneHandedController;
import com.android.wm.shell.pip.Pip;
@@ -46,11 +47,13 @@ public final class ShellCommandHandlerImpl {
private final Optional<AppPairsController> mAppPairsOptional;
private final Optional<RecentTasksController> mRecentTasks;
private final ShellTaskOrganizer mShellTaskOrganizer;
+ private final KidsModeTaskOrganizer mKidsModeTaskOrganizer;
private final ShellExecutor mMainExecutor;
private final HandlerImpl mImpl = new HandlerImpl();
public ShellCommandHandlerImpl(
ShellTaskOrganizer shellTaskOrganizer,
+ KidsModeTaskOrganizer kidsModeTaskOrganizer,
Optional<LegacySplitScreenController> legacySplitScreenOptional,
Optional<SplitScreenController> splitScreenOptional,
Optional<Pip> pipOptional,
@@ -60,6 +63,7 @@ public final class ShellCommandHandlerImpl {
Optional<RecentTasksController> recentTasks,
ShellExecutor mainExecutor) {
mShellTaskOrganizer = shellTaskOrganizer;
+ mKidsModeTaskOrganizer = kidsModeTaskOrganizer;
mRecentTasks = recentTasks;
mLegacySplitScreenOptional = legacySplitScreenOptional;
mSplitScreenOptional = splitScreenOptional;
@@ -92,6 +96,9 @@ public final class ShellCommandHandlerImpl {
pw.println();
pw.println();
mRecentTasks.ifPresent(recentTasks -> recentTasks.dump(pw, ""));
+ pw.println();
+ pw.println();
+ mKidsModeTaskOrganizer.dump(pw, "");
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java
index c3ce3627fb0b..b729fe1e55dc 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java
@@ -29,6 +29,7 @@ import com.android.wm.shell.draganddrop.DragAndDropController;
import com.android.wm.shell.freeform.FreeformTaskListener;
import com.android.wm.shell.fullscreen.FullscreenTaskListener;
import com.android.wm.shell.fullscreen.FullscreenUnfoldController;
+import com.android.wm.shell.kidsmode.KidsModeTaskOrganizer;
import com.android.wm.shell.pip.phone.PipTouchHandler;
import com.android.wm.shell.recents.RecentTasksController;
import com.android.wm.shell.splitscreen.SplitScreenController;
@@ -48,6 +49,7 @@ public class ShellInitImpl {
private final DisplayInsetsController mDisplayInsetsController;
private final DragAndDropController mDragAndDropController;
private final ShellTaskOrganizer mShellTaskOrganizer;
+ private final KidsModeTaskOrganizer mKidsModeTaskOrganizer;
private final Optional<BubbleController> mBubblesOptional;
private final Optional<SplitScreenController> mSplitScreenOptional;
private final Optional<AppPairsController> mAppPairsOptional;
@@ -68,6 +70,7 @@ public class ShellInitImpl {
DisplayInsetsController displayInsetsController,
DragAndDropController dragAndDropController,
ShellTaskOrganizer shellTaskOrganizer,
+ KidsModeTaskOrganizer kidsModeTaskOrganizer,
Optional<BubbleController> bubblesOptional,
Optional<SplitScreenController> splitScreenOptional,
Optional<AppPairsController> appPairsOptional,
@@ -84,6 +87,7 @@ public class ShellInitImpl {
mDisplayInsetsController = displayInsetsController;
mDragAndDropController = dragAndDropController;
mShellTaskOrganizer = shellTaskOrganizer;
+ mKidsModeTaskOrganizer = kidsModeTaskOrganizer;
mBubblesOptional = bubblesOptional;
mSplitScreenOptional = splitScreenOptional;
mAppPairsOptional = appPairsOptional;
@@ -136,6 +140,9 @@ public class ShellInitImpl {
mFullscreenUnfoldController.ifPresent(FullscreenUnfoldController::init);
mRecentTasks.ifPresent(RecentTasksController::init);
+
+ // Initialize kids mode task organizer
+ mKidsModeTaskOrganizer.initialize(mStartingWindow);
}
@ExternalThread
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
index 91ea436f81b6..31f0ef0192ae 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
@@ -98,16 +98,22 @@ public class ShellTaskOrganizer extends TaskOrganizer implements
default void onTaskInfoChanged(RunningTaskInfo taskInfo) {}
default void onTaskVanished(RunningTaskInfo taskInfo) {}
default void onBackPressedOnTaskRoot(RunningTaskInfo taskInfo) {}
- /** Whether this task listener supports compat UI. */
+ /** Whether this task listener supports compat UI. */
default boolean supportCompatUI() {
// All TaskListeners should support compat UI except PIP.
return true;
}
- /** Attaches the a child window surface to the task surface. */
+ /** Attaches a child window surface to the task surface. */
default void attachChildSurfaceToTask(int taskId, SurfaceControl.Builder b) {
throw new IllegalStateException(
"This task listener doesn't support child surface attachment.");
}
+ /** Reparents a child window surface to the task surface. */
+ default void reparentChildSurfaceToTask(int taskId, SurfaceControl sc,
+ SurfaceControl.Transaction t) {
+ throw new IllegalStateException(
+ "This task listener doesn't support child surface reparent.");
+ }
default void dump(@NonNull PrintWriter pw, String prefix) {};
}
@@ -159,8 +165,12 @@ public class ShellTaskOrganizer extends TaskOrganizer implements
private StartingWindowController mStartingWindow;
/**
- * In charge of showing compat UI. Can be {@code null} if device doesn't support size
- * compat.
+ * In charge of showing compat UI. Can be {@code null} if the device doesn't support size
+ * compat or if this isn't the main {@link ShellTaskOrganizer}.
+ *
+ * <p>NOTE: only the main {@link ShellTaskOrganizer} should have a {@link CompatUIController},
+ * and register itself as a {@link CompatUIController.CompatUICallback}. Subclasses should be
+ * initialized with a {@code null} {@link CompatUIController}.
*/
@Nullable
private final CompatUIController mCompatUI;
@@ -190,8 +200,8 @@ public class ShellTaskOrganizer extends TaskOrganizer implements
}
@VisibleForTesting
- ShellTaskOrganizer(ITaskOrganizerController taskOrganizerController, ShellExecutor mainExecutor,
- Context context, @Nullable CompatUIController compatUI,
+ protected ShellTaskOrganizer(ITaskOrganizerController taskOrganizerController,
+ ShellExecutor mainExecutor, Context context, @Nullable CompatUIController compatUI,
Optional<RecentTasksController> recentTasks) {
super(taskOrganizerController, mainExecutor);
mCompatUI = compatUI;
@@ -620,6 +630,23 @@ public class ShellTaskOrganizer extends TaskOrganizer implements
updateCameraCompatControlState(info.getTaskInfo().token, state);
}
+ /** Reparents a child window surface to the task surface. */
+ public void reparentChildSurfaceToTask(int taskId, SurfaceControl sc,
+ SurfaceControl.Transaction t) {
+ final TaskListener taskListener;
+ synchronized (mLock) {
+ taskListener = mTasks.contains(taskId)
+ ? getTaskListener(mTasks.get(taskId).getTaskInfo())
+ : null;
+ }
+ if (taskListener == null) {
+ ProtoLog.w(WM_SHELL_TASK_ORG, "Failed to find Task to reparent surface taskId=%d",
+ taskId);
+ return;
+ }
+ taskListener.reparentChildSurfaceToTask(taskId, sc, t);
+ }
+
private void logSizeCompatRestartButtonEventReported(@NonNull TaskAppearedInfo info,
int event) {
ActivityInfo topActivityInfo = info.getTaskInfo().topActivityInfo;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/TaskView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/TaskView.java
index 54e743f72cc6..ca4ef07eb1db 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/TaskView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/TaskView.java
@@ -367,10 +367,20 @@ public class TaskView extends SurfaceView implements SurfaceHolder.Callback,
@Override
public void attachChildSurfaceToTask(int taskId, SurfaceControl.Builder b) {
- if (mTaskInfo.taskId != taskId) {
+ b.setParent(findTaskSurface(taskId));
+ }
+
+ @Override
+ public void reparentChildSurfaceToTask(int taskId, SurfaceControl sc,
+ SurfaceControl.Transaction t) {
+ t.reparent(sc, findTaskSurface(taskId));
+ }
+
+ private SurfaceControl findTaskSurface(int taskId) {
+ if (mTaskInfo == null || mTaskLeash == null || mTaskInfo.taskId != taskId) {
throw new IllegalArgumentException("There is no surface for taskId=" + taskId);
}
- b.setParent(mTaskLeash);
+ return mTaskLeash;
}
@Override
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 e344c3bea42b..33eec335bca3 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
@@ -275,12 +275,22 @@ class AppPair implements ShellTaskOrganizer.TaskListener, SplitLayout.SplitLayou
@Override
public void attachChildSurfaceToTask(int taskId, SurfaceControl.Builder b) {
+ b.setParent(findTaskSurface(taskId));
+ }
+
+ @Override
+ public void reparentChildSurfaceToTask(int taskId, SurfaceControl sc,
+ SurfaceControl.Transaction t) {
+ t.reparent(sc, findTaskSurface(taskId));
+ }
+
+ private SurfaceControl findTaskSurface(int taskId) {
if (getRootTaskId() == taskId) {
- b.setParent(mRootTaskLeash);
+ return mRootTaskLeash;
} else if (getTaskId1() == taskId) {
- b.setParent(mTaskLeash1);
+ return mTaskLeash1;
} else if (getTaskId2() == taskId) {
- b.setParent(mTaskLeash2);
+ return mTaskLeash2;
} else {
throw new IllegalArgumentException("There is no surface for taskId=" + taskId);
}
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 8d5fdfbc8cb0..08cb252cdf43 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
@@ -52,14 +52,17 @@ import com.android.wm.shell.common.annotations.ShellMainThread;
*/
public class BackAnimationController implements RemoteCallable<BackAnimationController> {
- private static final String BACK_PREDICTABILITY_PROP = "persist.debug.back_predictability";
- public static final boolean IS_ENABLED = SystemProperties
- .getInt(BACK_PREDICTABILITY_PROP, 0) > 0;
private static final String BACK_PREDICTABILITY_PROGRESS_THRESHOLD_PROP =
"persist.debug.back_predictability_progress_threshold";
+ // By default, enable new back dispatching without any animations.
+ private static final int BACK_PREDICTABILITY_PROP =
+ SystemProperties.getInt("persist.debug.back_predictability", 1);
+ public static final boolean IS_ENABLED = BACK_PREDICTABILITY_PROP > 0;
private static final int PROGRESS_THRESHOLD = SystemProperties
.getInt(BACK_PREDICTABILITY_PROGRESS_THRESHOLD_PROP, -1);
private static final String TAG = "BackAnimationController";
+ @VisibleForTesting
+ boolean mEnableAnimations = (BACK_PREDICTABILITY_PROP & (1 << 1)) != 0;
/**
* Location of the initial touch event of the back gesture.
@@ -255,7 +258,7 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
backNavigationInfo.getTaskWindowConfiguration());
}
mTransaction.apply();
- } else if (backType == BackNavigationInfo.TYPE_RETURN_TO_HOME) {
+ } else if (shouldDispatchToLauncher(backType)) {
targetCallback = mBackToLauncherCallback;
} else if (backType == BackNavigationInfo.TYPE_CALLBACK) {
targetCallback = mBackNavigationInfo.getOnBackInvokedCallback();
@@ -309,7 +312,7 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
BackEvent backEvent = new BackEvent(0, 0, progress, swipeEdge, animationTarget);
IOnBackInvokedCallback targetCallback = null;
- if (backType == BackNavigationInfo.TYPE_RETURN_TO_HOME) {
+ if (shouldDispatchToLauncher(backType)) {
targetCallback = mBackToLauncherCallback;
} else if (backType == BackNavigationInfo.TYPE_CROSS_TASK
|| backType == BackNavigationInfo.TYPE_CROSS_ACTIVITY) {
@@ -330,8 +333,7 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
return;
}
int backType = mBackNavigationInfo.getType();
- boolean shouldDispatchToLauncher = backType == BackNavigationInfo.TYPE_RETURN_TO_HOME
- && mBackToLauncherCallback != null;
+ boolean shouldDispatchToLauncher = shouldDispatchToLauncher(backType);
IOnBackInvokedCallback targetCallback = shouldDispatchToLauncher
? mBackToLauncherCallback
: mBackNavigationInfo.getOnBackInvokedCallback();
@@ -356,6 +358,17 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
}
}
+ private boolean shouldDispatchToLauncher(int backType) {
+ return backType == BackNavigationInfo.TYPE_RETURN_TO_HOME
+ && mBackToLauncherCallback != null
+ && mEnableAnimations;
+ }
+
+ @VisibleForTesting
+ void setEnableAnimations(boolean shouldEnable) {
+ mEnableAnimations = shouldEnable;
+ }
+
private static void dispatchOnBackStarted(IOnBackInvokedCallback callback) {
if (callback == null) {
return;
@@ -468,7 +481,7 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
return;
}
RemoteAnimationTarget animationTarget = backNavigationInfo.getDepartingAnimationTarget();
- if (animationTarget != null && mTriggerBack) {
+ if (animationTarget != null) {
if (animationTarget.leash != null && animationTarget.leash.isValid()) {
mTransaction.remove(animationTarget.leash);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BadgedImageView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BadgedImageView.java
index 79e624212f4b..3876533a922e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BadgedImageView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BadgedImageView.java
@@ -173,8 +173,8 @@ public class BadgedImageView extends ConstraintLayout {
}
@Override
- public void onDraw(Canvas canvas) {
- super.onDraw(canvas);
+ public void dispatchDraw(Canvas canvas) {
+ super.dispatchDraw(canvas);
if (!shouldDrawDot()) {
return;
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 d0138a488295..d2a1c55d1c29 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
@@ -383,23 +383,15 @@ public class BubbleController {
mTaskStackListener.addListener(new TaskStackListenerCallback() {
@Override
public void onTaskMovedToFront(int taskId) {
- if (mSysuiProxy == null) {
- return;
- }
-
- mSysuiProxy.isNotificationShadeExpand((expand) -> {
- mMainExecutor.execute(() -> {
- int expandedId = INVALID_TASK_ID;
- if (mStackView != null && mStackView.getExpandedBubble() != null
- && isStackExpanded() && !mStackView.isExpansionAnimating()
- && !expand) {
- expandedId = mStackView.getExpandedBubble().getTaskId();
- }
-
- if (expandedId != INVALID_TASK_ID && expandedId != taskId) {
- mBubbleData.setExpanded(false);
- }
- });
+ mMainExecutor.execute(() -> {
+ int expandedId = INVALID_TASK_ID;
+ if (mStackView != null && mStackView.getExpandedBubble() != null
+ && isStackExpanded() && !mStackView.isExpansionAnimating()) {
+ expandedId = mStackView.getExpandedBubble().getTaskId();
+ }
+ if (expandedId != INVALID_TASK_ID && expandedId != taskId) {
+ mBubbleData.setExpanded(false);
+ }
});
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
index 58f79f3600de..13d12b3589c0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
@@ -1049,10 +1049,17 @@ public class BubbleStackView extends FrameLayout
private final Runnable mAnimateTemporarilyInvisibleImmediate = () -> {
if (mTemporarilyInvisible && mFlyout.getVisibility() != View.VISIBLE) {
+ // To calculate a distance, bubble stack needs to be moved to become hidden,
+ // we need to take into account that the bubble stack is positioned on the edge
+ // of the available screen rect, which can be offset by system bars and cutouts.
if (mStackAnimationController.isStackOnLeftSide()) {
- animate().translationX(-mBubbleSize).start();
+ int availableRectOffsetX =
+ mPositioner.getAvailableRect().left - mPositioner.getScreenRect().left;
+ animate().translationX(-(mBubbleSize + availableRectOffsetX)).start();
} else {
- animate().translationX(mBubbleSize).start();
+ int availableRectOffsetX =
+ mPositioner.getAvailableRect().right - mPositioner.getScreenRect().right;
+ animate().translationX(mBubbleSize - availableRectOffsetX).start();
}
} else {
animate().translationX(0).start();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayController.java
index d22fb5039052..4ba32e93fb3d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayController.java
@@ -110,6 +110,14 @@ public class DisplayController {
}
/**
+ * Get the InsetsState of a display.
+ */
+ public InsetsState getInsetsState(int displayId) {
+ final DisplayRecord r = mDisplays.get(displayId);
+ return r != null ? r.mInsetsState : null;
+ }
+
+ /**
* Updates the insets for a given display.
*/
public void updateDisplayInsets(int displayId, InsetsState state) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java
index 51067a45381c..8d1afa4a1304 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java
@@ -344,7 +344,7 @@ public class SystemWindows {
@Override
public void resized(ClientWindowFrames frames, boolean reportDraw,
MergedConfiguration newMergedConfiguration, boolean forceLayout,
- boolean alwaysConsumeSystemBars, int displayId) {}
+ boolean alwaysConsumeSystemBars, int displayId, int syncSeqId, int resizeMode) {}
@Override
public void insetsChanged(InsetsState insetsState, boolean willMove, boolean willResize) {}
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 b52c8d118711..daba7742661c 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
@@ -98,6 +98,7 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
private WindowContainerToken mWinToken2;
private int mDividePosition;
private boolean mInitialized = false;
+ private boolean mFreezeDividerWindow = false;
private int mOrientation;
private int mRotation;
@@ -225,11 +226,6 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
mDividerSnapAlgorithm = getSnapAlgorithm(mContext, mRootBounds, null);
initDividerPosition(mTempRect);
- if (mInitialized) {
- release();
- init();
- }
-
return true;
}
@@ -298,20 +294,37 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
}
/** Releases the surface holding the current {@link DividerView}. */
- public void release() {
+ public void release(SurfaceControl.Transaction t) {
if (!mInitialized) return;
mInitialized = false;
- mSplitWindowManager.release();
+ mSplitWindowManager.release(t);
mDisplayImeController.removePositionProcessor(mImePositionProcessor);
mImePositionProcessor.reset();
}
+ public void release() {
+ release(null /* t */);
+ }
+
+ /** Releases and re-inflates {@link DividerView} on the root surface. */
+ public void update(SurfaceControl.Transaction t) {
+ if (!mInitialized) return;
+ mSplitWindowManager.release(t);
+ mImePositionProcessor.reset();
+ mSplitWindowManager.init(this, mInsetsState);
+ }
+
@Override
public void insetsChanged(InsetsState insetsState) {
mInsetsState.set(insetsState);
if (!mInitialized) {
return;
}
+ if (mFreezeDividerWindow) {
+ // DO NOT change its layout before transition actually run because it might cause
+ // flicker.
+ return;
+ }
mSplitWindowManager.onInsetsChanged(insetsState);
}
@@ -323,6 +336,10 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
}
}
+ public void setFreezeDividerWindow(boolean freezeDividerWindow) {
+ mFreezeDividerWindow = freezeDividerWindow;
+ }
+
/**
* Updates bounds with the passing position. Usually used to update recording bounds while
* performing animation or dragging divider bar to resize the splits.
@@ -515,7 +532,9 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
}
private int getSmallestWidthDp(Rect bounds) {
- final int minWidth = Math.min(bounds.width(), bounds.height());
+ mTempRect.set(bounds);
+ mTempRect.inset(getDisplayInsets(mContext));
+ final int minWidth = Math.min(mTempRect.width(), mTempRect.height());
final float density = mContext.getResources().getDisplayMetrics().density;
return (int) (minWidth / density);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java
index 4903f9d46dc7..833d9d50701c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java
@@ -58,6 +58,9 @@ public final class SplitWindowManager extends WindowlessWindowManager {
private SurfaceControl mLeash;
private DividerView mDividerView;
+ // Used to "pass" a transaction to WWM.remove so that view removal can be synchronized.
+ private SurfaceControl.Transaction mSyncTransaction = null;
+
public interface ParentContainerCallbacks {
void attachToParentSurface(SurfaceControl.Builder b);
void onLeashReady(SurfaceControl leash);
@@ -130,22 +133,38 @@ public final class SplitWindowManager extends WindowlessWindowManager {
* Releases the surface control of the current {@link DividerView} and tear down the view
* hierarchy.
*/
- void release() {
+ void release(@Nullable SurfaceControl.Transaction t) {
if (mDividerView != null) {
mDividerView = null;
}
if (mViewHost != null){
+ mSyncTransaction = t;
mViewHost.release();
+ mSyncTransaction = null;
mViewHost = null;
}
if (mLeash != null) {
- new SurfaceControl.Transaction().remove(mLeash).apply();
+ if (t == null) {
+ new SurfaceControl.Transaction().remove(mLeash).apply();
+ } else {
+ t.remove(mLeash);
+ }
mLeash = null;
}
}
+ @Override
+ protected void removeSurface(SurfaceControl sc) {
+ // This gets called via SurfaceControlViewHost.release()
+ if (mSyncTransaction != null) {
+ mSyncTransaction.remove(sc);
+ } else {
+ super.removeSurface(sc);
+ }
+ }
+
void setInteractive(boolean interactive) {
if (mDividerView == null) return;
mDividerView.setInteractive(interactive);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUI.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUI.java
index 99dbfe01964c..b87cf47dd93f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUI.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUI.java
@@ -24,9 +24,12 @@ import com.android.wm.shell.common.annotations.ExternalThread;
@ExternalThread
public interface CompatUI {
/**
- * Called when the keyguard occluded state changes. Removes all compat UIs if the
- * keyguard is now occluded.
- * @param occluded indicates if the keyguard is now occluded.
+ * Called when the keyguard showing state changes. Removes all compat UIs if the
+ * keyguard is now showing.
+ *
+ * <p>Note that if the keyguard is occluded it will also be considered showing.
+ *
+ * @param showing indicates if the keyguard is now showing.
*/
- void onKeyguardOccludedChanged(boolean occluded);
+ void onKeyguardShowingChanged(boolean showing);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java
index ee4d5ed018bf..99b32a677abe 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java
@@ -42,6 +42,7 @@ import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.annotations.ExternalThread;
import com.android.wm.shell.compatui.CompatUIWindowManager.CompatUIHintsState;
import com.android.wm.shell.compatui.letterboxedu.LetterboxEduWindowManager;
+import com.android.wm.shell.transition.Transitions;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
@@ -50,6 +51,8 @@ import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Predicate;
+import dagger.Lazy;
+
/**
* Controller to show/update compat UI components on Tasks based on whether the foreground
* activities are in compatibility mode.
@@ -102,6 +105,7 @@ public class CompatUIController implements OnDisplaysChangedListener,
private final DisplayImeController mImeController;
private final SyncTransactionQueue mSyncQueue;
private final ShellExecutor mMainExecutor;
+ private final Lazy<Transitions> mTransitionsLazy;
private final CompatUIImpl mImpl = new CompatUIImpl();
private CompatUICallback mCallback;
@@ -109,22 +113,24 @@ public class CompatUIController implements OnDisplaysChangedListener,
// Only show each hint once automatically in the process life.
private final CompatUIHintsState mCompatUIHintsState;
- // Indicates if the keyguard is currently occluded, in which case compat UIs shouldn't
+ // Indicates if the keyguard is currently showing, in which case compat UIs shouldn't
// be shown.
- private boolean mKeyguardOccluded;
+ private boolean mKeyguardShowing;
public CompatUIController(Context context,
DisplayController displayController,
DisplayInsetsController displayInsetsController,
DisplayImeController imeController,
SyncTransactionQueue syncQueue,
- ShellExecutor mainExecutor) {
+ ShellExecutor mainExecutor,
+ Lazy<Transitions> transitionsLazy) {
mContext = context;
mDisplayController = displayController;
mDisplayInsetsController = displayInsetsController;
mImeController = imeController;
mSyncQueue = syncQueue;
mMainExecutor = mainExecutor;
+ mTransitionsLazy = transitionsLazy;
mDisplayController.addDisplayWindowListener(this);
mImeController.addPositionProcessor(this);
mCompatUIHintsState = new CompatUIHintsState();
@@ -218,14 +224,14 @@ public class CompatUIController implements OnDisplaysChangedListener,
}
@VisibleForTesting
- void onKeyguardOccludedChanged(boolean occluded) {
- mKeyguardOccluded = occluded;
- // Hide the compat UIs when keyguard is occluded.
+ void onKeyguardShowingChanged(boolean showing) {
+ mKeyguardShowing = showing;
+ // Hide the compat UIs when keyguard is showing.
forAllLayouts(layout -> layout.updateVisibility(showOnDisplay(layout.getDisplayId())));
}
private boolean showOnDisplay(int displayId) {
- return !mKeyguardOccluded && !isImeShowingOnDisplay(displayId);
+ return !mKeyguardShowing && !isImeShowingOnDisplay(displayId);
}
private boolean isImeShowingOnDisplay(int displayId) {
@@ -302,6 +308,7 @@ public class CompatUIController implements OnDisplaysChangedListener,
ShellTaskOrganizer.TaskListener taskListener) {
return new LetterboxEduWindowManager(context, taskInfo,
mSyncQueue, taskListener, mDisplayController.getDisplayLayout(taskInfo.displayId),
+ mTransitionsLazy.get(),
this::onLetterboxEduDismissed);
}
@@ -372,9 +379,9 @@ public class CompatUIController implements OnDisplaysChangedListener,
@ExternalThread
private class CompatUIImpl implements CompatUI {
@Override
- public void onKeyguardOccludedChanged(boolean occluded) {
+ public void onKeyguardShowingChanged(boolean showing) {
mMainExecutor.execute(() -> {
- CompatUIController.this.onKeyguardOccludedChanged(occluded);
+ CompatUIController.this.onKeyguardShowingChanged(showing);
});
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduAnimationController.java
index 03986ee3b6d2..3061eab17d24 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduAnimationController.java
@@ -18,6 +18,7 @@ package com.android.wm.shell.compatui.letterboxedu;
import static com.android.internal.R.styleable.WindowAnimation_windowEnterAnimation;
import static com.android.internal.R.styleable.WindowAnimation_windowExitAnimation;
+import static com.android.wm.shell.transition.Transitions.ENABLE_SHELL_TRANSITIONS;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -42,7 +43,9 @@ import com.android.internal.policy.TransitionAnimation;
class LetterboxEduAnimationController {
private static final String TAG = "LetterboxEduAnimation";
- private static final int ENTER_ANIM_START_DELAY_MILLIS = 500;
+ // If shell transitions are enabled, startEnterAnimation will be called after all transitions
+ // have finished, and therefore the start delay should be shorter.
+ private static final int ENTER_ANIM_START_DELAY_MILLIS = ENABLE_SHELL_TRANSITIONS ? 300 : 500;
private final TransitionAnimation mTransitionAnimation;
private final String mPackageName;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduDialogLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduDialogLayout.java
index 2da6a6bc70c0..2e0b09e9d230 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduDialogLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduDialogLayout.java
@@ -21,6 +21,7 @@ import android.content.Context;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.View;
+import android.widget.TextView;
import androidx.constraintlayout.widget.ConstraintLayout;
@@ -37,7 +38,9 @@ class LetterboxEduDialogLayout extends ConstraintLayout {
// The alpha of a background is a number between 0 (fully transparent) to 255 (fully opaque).
// 204 is simply 255 * 0.8.
static final int BACKGROUND_DIM_ALPHA = 204;
+
private View mDialogContainer;
+ private TextView mDialogTitle;
private Drawable mBackgroundDim;
public LetterboxEduDialogLayout(Context context) {
@@ -61,6 +64,10 @@ class LetterboxEduDialogLayout extends ConstraintLayout {
return mDialogContainer;
}
+ TextView getDialogTitle() {
+ return mDialogTitle;
+ }
+
Drawable getBackgroundDim() {
return mBackgroundDim;
}
@@ -84,6 +91,7 @@ class LetterboxEduDialogLayout extends ConstraintLayout {
protected void onFinishInflate() {
super.onFinishInflate();
mDialogContainer = findViewById(R.id.letterbox_education_dialog_container);
+ mDialogTitle = findViewById(R.id.letterbox_education_dialog_title);
mBackgroundDim = getBackground().mutate();
// Set the alpha of the background dim to 0 for enter animation.
mBackgroundDim.setAlpha(0);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduWindowManager.java
index 30b9f0838e10..cc3a3b2206f3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduWindowManager.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduWindowManager.java
@@ -28,6 +28,7 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup.MarginLayoutParams;
import android.view.WindowManager;
+import android.view.accessibility.AccessibilityEvent;
import com.android.internal.annotations.VisibleForTesting;
import com.android.wm.shell.R;
@@ -35,6 +36,7 @@ import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.compatui.CompatUIWindowManagerAbstract;
+import com.android.wm.shell.transition.Transitions;
/**
* Window manager for the Letterbox Education.
@@ -62,6 +64,8 @@ public class LetterboxEduWindowManager extends CompatUIWindowManagerAbstract {
private final LetterboxEduAnimationController mAnimationController;
+ private final Transitions mTransitions;
+
// Remember the last reported state in case visibility changes due to keyguard or IME updates.
private boolean mEligibleForLetterboxEducation;
@@ -79,17 +83,19 @@ public class LetterboxEduWindowManager extends CompatUIWindowManagerAbstract {
public LetterboxEduWindowManager(Context context, TaskInfo taskInfo,
SyncTransactionQueue syncQueue, ShellTaskOrganizer.TaskListener taskListener,
- DisplayLayout displayLayout, Runnable onDismissCallback) {
- this(context, taskInfo, syncQueue, taskListener, displayLayout, onDismissCallback,
- new LetterboxEduAnimationController(context));
+ DisplayLayout displayLayout, Transitions transitions,
+ Runnable onDismissCallback) {
+ this(context, taskInfo, syncQueue, taskListener, displayLayout, transitions,
+ onDismissCallback, new LetterboxEduAnimationController(context));
}
@VisibleForTesting
LetterboxEduWindowManager(Context context, TaskInfo taskInfo,
SyncTransactionQueue syncQueue, ShellTaskOrganizer.TaskListener taskListener,
- DisplayLayout displayLayout, Runnable onDismissCallback,
+ DisplayLayout displayLayout, Transitions transitions, Runnable onDismissCallback,
LetterboxEduAnimationController animationController) {
super(context, taskInfo, syncQueue, taskListener, displayLayout);
+ mTransitions = transitions;
mOnDismissCallback = onDismissCallback;
mAnimationController = animationController;
mEligibleForLetterboxEducation = taskInfo.topActivityEligibleForLetterboxEducation;
@@ -131,8 +137,8 @@ public class LetterboxEduWindowManager extends CompatUIWindowManagerAbstract {
mLayout = inflateLayout();
updateDialogMargins();
- mAnimationController.startEnterAnimation(mLayout, /* endCallback= */
- this::setDismissOnClickListener);
+ // startEnterAnimation will be called immediately if shell-transitions are disabled.
+ mTransitions.runOnIdle(this::startEnterAnimation);
return mLayout;
}
@@ -157,11 +163,23 @@ public class LetterboxEduWindowManager extends CompatUIWindowManagerAbstract {
R.layout.letterbox_education_dialog_layout, null);
}
- private void setDismissOnClickListener() {
+ private void startEnterAnimation() {
+ if (mLayout == null) {
+ // Dialog has already been released.
+ return;
+ }
+ mAnimationController.startEnterAnimation(mLayout, /* endCallback= */
+ this::onDialogEnterAnimationEnded);
+ }
+
+ private void onDialogEnterAnimationEnded() {
if (mLayout == null) {
+ // Dialog has already been released.
return;
}
mLayout.setDismissOnClickListener(this::onDismiss);
+ // Focus on the dialog title for accessibility.
+ mLayout.getDialogTitle().sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
}
private void onDismiss() {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvPipModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvPipModule.java
index 491dff08187f..1dd5ebcd993e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvPipModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvPipModule.java
@@ -27,7 +27,6 @@ import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.SystemWindows;
import com.android.wm.shell.common.TaskStackListenerImpl;
import com.android.wm.shell.common.annotations.ShellMainThread;
-import com.android.wm.shell.legacysplitscreen.LegacySplitScreenController;
import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.pip.PipAnimationController;
import com.android.wm.shell.pip.PipMediaController;
@@ -70,7 +69,8 @@ public abstract class TvPipModule {
TaskStackListenerImpl taskStackListener,
DisplayController displayController,
WindowManagerShellWrapper windowManagerShellWrapper,
- @ShellMainThread ShellExecutor mainExecutor) {
+ @ShellMainThread ShellExecutor mainExecutor,
+ @ShellMainThread Handler mainHandler) {
return Optional.of(
TvPipController.create(
context,
@@ -84,7 +84,8 @@ public abstract class TvPipModule {
taskStackListener,
displayController,
windowManagerShellWrapper,
- mainExecutor));
+ mainExecutor,
+ mainHandler));
}
@WMSingleton
@@ -163,15 +164,14 @@ public abstract class TvPipModule {
PipAnimationController pipAnimationController,
PipTransitionController pipTransitionController,
PipSurfaceTransactionHelper pipSurfaceTransactionHelper,
- Optional<LegacySplitScreenController> splitScreenOptional,
- Optional<SplitScreenController> newSplitScreenOptional,
+ Optional<SplitScreenController> splitScreenControllerOptional,
DisplayController displayController,
PipUiEventLogger pipUiEventLogger, ShellTaskOrganizer shellTaskOrganizer,
@ShellMainThread ShellExecutor mainExecutor) {
return new PipTaskOrganizer(context,
syncTransactionQueue, pipTransitionState, tvPipBoundsState, tvPipBoundsAlgorithm,
tvPipMenuController, pipAnimationController, pipSurfaceTransactionHelper,
- pipTransitionController, splitScreenOptional, newSplitScreenOptional,
+ pipTransitionController, splitScreenControllerOptional,
displayController, pipUiEventLogger, shellTaskOrganizer, mainExecutor);
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
index 0362b3fba36b..026eeb09d741 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
@@ -68,6 +68,7 @@ import com.android.wm.shell.fullscreen.FullscreenTaskListener;
import com.android.wm.shell.fullscreen.FullscreenUnfoldController;
import com.android.wm.shell.hidedisplaycutout.HideDisplayCutout;
import com.android.wm.shell.hidedisplaycutout.HideDisplayCutoutController;
+import com.android.wm.shell.kidsmode.KidsModeTaskOrganizer;
import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
import com.android.wm.shell.legacysplitscreen.LegacySplitScreenController;
import com.android.wm.shell.onehanded.OneHanded;
@@ -95,6 +96,7 @@ import com.android.wm.shell.unfold.ShellUnfoldProgressProvider;
import java.util.Optional;
import dagger.BindsOptionalOf;
+import dagger.Lazy;
import dagger.Module;
import dagger.Provides;
@@ -184,7 +186,21 @@ public abstract class WMShellBaseModule {
@WMSingleton
@Provides
- static Optional<CompatUI> provideCompatUI(CompatUIController compatUIController) {
+ static KidsModeTaskOrganizer provideKidsModeTaskOrganizer(
+ @ShellMainThread ShellExecutor mainExecutor,
+ @ShellMainThread Handler mainHandler,
+ Context context,
+ SyncTransactionQueue syncTransactionQueue,
+ DisplayController displayController,
+ DisplayInsetsController displayInsetsController,
+ Optional<RecentTasksController> recentTasksOptional
+ ) {
+ return new KidsModeTaskOrganizer(mainExecutor, mainHandler, context, syncTransactionQueue,
+ displayController, displayInsetsController, recentTasksOptional);
+ }
+
+ @WMSingleton
+ @Provides static Optional<CompatUI> provideCompatUI(CompatUIController compatUIController) {
return Optional.of(compatUIController.asCompatUI());
}
@@ -193,9 +209,9 @@ public abstract class WMShellBaseModule {
static CompatUIController provideCompatUIController(Context context,
DisplayController displayController, DisplayInsetsController displayInsetsController,
DisplayImeController imeController, SyncTransactionQueue syncQueue,
- @ShellMainThread ShellExecutor mainExecutor) {
+ @ShellMainThread ShellExecutor mainExecutor, Lazy<Transitions> transitionsLazy) {
return new CompatUIController(context, displayController, displayInsetsController,
- imeController, syncQueue, mainExecutor);
+ imeController, syncQueue, mainExecutor, transitionsLazy);
}
@WMSingleton
@@ -637,6 +653,7 @@ public abstract class WMShellBaseModule {
DisplayInsetsController displayInsetsController,
DragAndDropController dragAndDropController,
ShellTaskOrganizer shellTaskOrganizer,
+ KidsModeTaskOrganizer kidsModeTaskOrganizer,
Optional<BubbleController> bubblesOptional,
Optional<SplitScreenController> splitScreenOptional,
Optional<AppPairsController> appPairsOptional,
@@ -653,6 +670,7 @@ public abstract class WMShellBaseModule {
displayInsetsController,
dragAndDropController,
shellTaskOrganizer,
+ kidsModeTaskOrganizer,
bubblesOptional,
splitScreenOptional,
appPairsOptional,
@@ -680,6 +698,7 @@ public abstract class WMShellBaseModule {
@Provides
static ShellCommandHandlerImpl provideShellCommandHandlerImpl(
ShellTaskOrganizer shellTaskOrganizer,
+ KidsModeTaskOrganizer kidsModeTaskOrganizer,
Optional<LegacySplitScreenController> legacySplitScreenOptional,
Optional<SplitScreenController> splitScreenOptional,
Optional<Pip> pipOptional,
@@ -688,7 +707,7 @@ public abstract class WMShellBaseModule {
Optional<AppPairsController> appPairsOptional,
Optional<RecentTasksController> recentTasksOptional,
@ShellMainThread ShellExecutor mainExecutor) {
- return new ShellCommandHandlerImpl(shellTaskOrganizer,
+ return new ShellCommandHandlerImpl(shellTaskOrganizer, kidsModeTaskOrganizer,
legacySplitScreenOptional, splitScreenOptional, pipOptional, oneHandedOptional,
hideDisplayCutout, appPairsOptional, recentTasksOptional, mainExecutor);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
index 7879e7a5bb00..73f393140cbc 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
@@ -285,15 +285,14 @@ public class WMShellModule {
PipAnimationController pipAnimationController,
PipSurfaceTransactionHelper pipSurfaceTransactionHelper,
PipTransitionController pipTransitionController,
- Optional<LegacySplitScreenController> splitScreenOptional,
- Optional<SplitScreenController> newSplitScreenOptional,
+ Optional<SplitScreenController> splitScreenControllerOptional,
DisplayController displayController,
PipUiEventLogger pipUiEventLogger, ShellTaskOrganizer shellTaskOrganizer,
@ShellMainThread ShellExecutor mainExecutor) {
return new PipTaskOrganizer(context,
syncTransactionQueue, pipTransitionState, pipBoundsState, pipBoundsAlgorithm,
menuPhoneController, pipAnimationController, pipSurfaceTransactionHelper,
- pipTransitionController, splitScreenOptional, newSplitScreenOptional,
+ pipTransitionController, splitScreenControllerOptional,
displayController, pipUiEventLogger, shellTaskOrganizer, mainExecutor);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java
index 52ff21bc3172..fef9be36a35f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java
@@ -110,6 +110,24 @@ public class FreeformTaskListener implements ShellTaskOrganizer.TaskListener {
}
@Override
+ public void attachChildSurfaceToTask(int taskId, SurfaceControl.Builder b) {
+ b.setParent(findTaskSurface(taskId));
+ }
+
+ @Override
+ public void reparentChildSurfaceToTask(int taskId, SurfaceControl sc,
+ SurfaceControl.Transaction t) {
+ t.reparent(sc, findTaskSurface(taskId));
+ }
+
+ private SurfaceControl findTaskSurface(int taskId) {
+ if (!mTasks.contains(taskId)) {
+ throw new IllegalArgumentException("There is no surface for taskId=" + taskId);
+ }
+ return mTasks.get(taskId).mLeash;
+ }
+
+ @Override
public void dump(PrintWriter pw, String prefix) {
final String innerPrefix = prefix + " ";
pw.println(prefix + this);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenTaskListener.java
index 6e38e421d4b6..73e6cba43ec0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenTaskListener.java
@@ -133,10 +133,20 @@ public class FullscreenTaskListener implements ShellTaskOrganizer.TaskListener {
@Override
public void attachChildSurfaceToTask(int taskId, SurfaceControl.Builder b) {
+ b.setParent(findTaskSurface(taskId));
+ }
+
+ @Override
+ public void reparentChildSurfaceToTask(int taskId, SurfaceControl sc,
+ SurfaceControl.Transaction t) {
+ t.reparent(sc, findTaskSurface(taskId));
+ }
+
+ private SurfaceControl findTaskSurface(int taskId) {
if (!mDataByTaskId.contains(taskId)) {
throw new IllegalArgumentException("There is no surface for taskId=" + taskId);
}
- b.setParent(mDataByTaskId.get(taskId).surface);
+ return mDataByTaskId.get(taskId).surface;
}
@Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/kidsmode/KidsModeTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/kidsmode/KidsModeTaskOrganizer.java
new file mode 100644
index 000000000000..003c55977841
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/kidsmode/KidsModeTaskOrganizer.java
@@ -0,0 +1,337 @@
+/*
+ * 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.kidsmode;
+
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.view.Display.DEFAULT_DISPLAY;
+
+import android.app.ActivityManager;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.graphics.Rect;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.IBinder;
+import android.view.InsetsSource;
+import android.view.InsetsState;
+import android.view.SurfaceControl;
+import android.window.ITaskOrganizerController;
+import android.window.TaskAppearedInfo;
+import android.window.WindowContainerToken;
+import android.window.WindowContainerTransaction;
+
+import androidx.annotation.NonNull;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.policy.ForceShowNavigationBarSettingsObserver;
+import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.common.DisplayInsetsController;
+import com.android.wm.shell.common.DisplayLayout;
+import com.android.wm.shell.common.ShellExecutor;
+import com.android.wm.shell.common.SyncTransactionQueue;
+import com.android.wm.shell.recents.RecentTasksController;
+import com.android.wm.shell.startingsurface.StartingWindowController;
+
+import java.io.PrintWriter;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+
+/**
+ * A dedicated task organizer when kids mode is enabled.
+ * - Creates a root task with bounds that exclude the navigation bar area
+ * - Launch all task into the root task except for Launcher
+ */
+public class KidsModeTaskOrganizer extends ShellTaskOrganizer {
+ private static final String TAG = "KidsModeTaskOrganizer";
+
+ private static final int[] CONTROLLED_ACTIVITY_TYPES =
+ {ACTIVITY_TYPE_UNDEFINED, ACTIVITY_TYPE_STANDARD};
+ private static final int[] CONTROLLED_WINDOWING_MODES =
+ {WINDOWING_MODE_FULLSCREEN, WINDOWING_MODE_UNDEFINED};
+
+ private final Handler mMainHandler;
+ private final Context mContext;
+ private final SyncTransactionQueue mSyncQueue;
+ private final DisplayController mDisplayController;
+ private final DisplayInsetsController mDisplayInsetsController;
+
+ @VisibleForTesting
+ ActivityManager.RunningTaskInfo mLaunchRootTask;
+ @VisibleForTesting
+ SurfaceControl mLaunchRootLeash;
+ @VisibleForTesting
+ final IBinder mCookie = new Binder();
+
+ private final InsetsState mInsetsState = new InsetsState();
+ private int mDisplayWidth;
+ private int mDisplayHeight;
+
+ private ForceShowNavigationBarSettingsObserver mForceShowNavigationBarSettingsObserver;
+ private boolean mEnabled;
+
+ DisplayController.OnDisplaysChangedListener mOnDisplaysChangedListener =
+ new DisplayController.OnDisplaysChangedListener() {
+ @Override
+ public void onDisplayConfigurationChanged(int displayId, Configuration newConfig) {
+ if (displayId != DEFAULT_DISPLAY) {
+ return;
+ }
+ final DisplayLayout displayLayout =
+ mDisplayController.getDisplayLayout(DEFAULT_DISPLAY);
+ if (displayLayout == null) {
+ return;
+ }
+ final int displayWidth = displayLayout.width();
+ final int displayHeight = displayLayout.height();
+ if (displayWidth == mDisplayWidth || displayHeight == mDisplayHeight) {
+ return;
+ }
+ mDisplayWidth = displayWidth;
+ mDisplayHeight = displayHeight;
+ updateBounds();
+ }
+ };
+
+ DisplayInsetsController.OnInsetsChangedListener mOnInsetsChangedListener =
+ new DisplayInsetsController.OnInsetsChangedListener() {
+ @Override
+ public void insetsChanged(InsetsState insetsState) {
+ // Update bounds only when the insets of navigation bar or task bar is changed.
+ if (Objects.equals(insetsState.peekSource(InsetsState.ITYPE_NAVIGATION_BAR),
+ mInsetsState.peekSource(InsetsState.ITYPE_NAVIGATION_BAR))
+ && Objects.equals(insetsState.peekSource(
+ InsetsState.ITYPE_EXTRA_NAVIGATION_BAR),
+ mInsetsState.peekSource(InsetsState.ITYPE_EXTRA_NAVIGATION_BAR))) {
+ return;
+ }
+ mInsetsState.set(insetsState);
+ updateBounds();
+ }
+ };
+
+ @VisibleForTesting
+ KidsModeTaskOrganizer(
+ ITaskOrganizerController taskOrganizerController,
+ ShellExecutor mainExecutor,
+ Handler mainHandler,
+ Context context,
+ SyncTransactionQueue syncTransactionQueue,
+ DisplayController displayController,
+ DisplayInsetsController displayInsetsController,
+ Optional<RecentTasksController> recentTasks,
+ ForceShowNavigationBarSettingsObserver forceShowNavigationBarSettingsObserver) {
+ super(taskOrganizerController, mainExecutor, context, /* compatUI= */ null, recentTasks);
+ mContext = context;
+ mMainHandler = mainHandler;
+ mSyncQueue = syncTransactionQueue;
+ mDisplayController = displayController;
+ mDisplayInsetsController = displayInsetsController;
+ mForceShowNavigationBarSettingsObserver = forceShowNavigationBarSettingsObserver;
+ }
+
+ public KidsModeTaskOrganizer(
+ ShellExecutor mainExecutor,
+ Handler mainHandler,
+ Context context,
+ SyncTransactionQueue syncTransactionQueue,
+ DisplayController displayController,
+ DisplayInsetsController displayInsetsController,
+ Optional<RecentTasksController> recentTasks) {
+ super(mainExecutor, context, /* compatUI= */ null, recentTasks);
+ mContext = context;
+ mMainHandler = mainHandler;
+ mSyncQueue = syncTransactionQueue;
+ mDisplayController = displayController;
+ mDisplayInsetsController = displayInsetsController;
+ }
+
+ /**
+ * Initializes kids mode status.
+ */
+ public void initialize(StartingWindowController startingWindowController) {
+ initStartingWindow(startingWindowController);
+ if (mForceShowNavigationBarSettingsObserver == null) {
+ mForceShowNavigationBarSettingsObserver = new ForceShowNavigationBarSettingsObserver(
+ mMainHandler, mContext);
+ }
+ mForceShowNavigationBarSettingsObserver.setOnChangeRunnable(() -> updateKidsModeState());
+ updateKidsModeState();
+ mForceShowNavigationBarSettingsObserver.register();
+ }
+
+ @Override
+ public void onTaskAppeared(ActivityManager.RunningTaskInfo taskInfo, SurfaceControl leash) {
+ if (mEnabled && mLaunchRootTask == null && taskInfo.launchCookies != null
+ && taskInfo.launchCookies.contains(mCookie)) {
+ mLaunchRootTask = taskInfo;
+ mLaunchRootLeash = leash;
+ updateTask();
+ }
+ super.onTaskAppeared(taskInfo, leash);
+
+ mSyncQueue.runInSync(t -> {
+ // Reset several properties back to fullscreen (PiP, for example, leaves all these
+ // properties in a bad state).
+ t.setCrop(leash, null);
+ t.setPosition(leash, 0, 0);
+ t.setAlpha(leash, 1f);
+ t.setMatrix(leash, 1, 0, 0, 1);
+ t.show(leash);
+ });
+ }
+
+ @Override
+ public void onTaskInfoChanged(ActivityManager.RunningTaskInfo taskInfo) {
+ if (mLaunchRootTask != null && mLaunchRootTask.taskId == taskInfo.taskId
+ && !taskInfo.equals(mLaunchRootTask)) {
+ mLaunchRootTask = taskInfo;
+ }
+
+ super.onTaskInfoChanged(taskInfo);
+ }
+
+ @VisibleForTesting
+ void updateKidsModeState() {
+ final boolean enabled = mForceShowNavigationBarSettingsObserver.isEnabled();
+ if (mEnabled == enabled) {
+ return;
+ }
+ mEnabled = enabled;
+ if (mEnabled) {
+ enable();
+ } else {
+ disable();
+ }
+ }
+
+ @VisibleForTesting
+ void enable() {
+ final DisplayLayout displayLayout = mDisplayController.getDisplayLayout(DEFAULT_DISPLAY);
+ if (displayLayout != null) {
+ mDisplayWidth = displayLayout.width();
+ mDisplayHeight = displayLayout.height();
+ }
+ mInsetsState.set(mDisplayController.getInsetsState(DEFAULT_DISPLAY));
+ mDisplayInsetsController.addInsetsChangedListener(DEFAULT_DISPLAY,
+ mOnInsetsChangedListener);
+ mDisplayController.addDisplayWindowListener(mOnDisplaysChangedListener);
+ List<TaskAppearedInfo> taskAppearedInfos = registerOrganizer();
+ for (int i = 0; i < taskAppearedInfos.size(); i++) {
+ final TaskAppearedInfo info = taskAppearedInfos.get(i);
+ onTaskAppeared(info.getTaskInfo(), info.getLeash());
+ }
+ createRootTask(DEFAULT_DISPLAY, WINDOWING_MODE_FULLSCREEN, mCookie);
+ updateTask();
+ }
+
+ @VisibleForTesting
+ void disable() {
+ mDisplayInsetsController.removeInsetsChangedListener(DEFAULT_DISPLAY,
+ mOnInsetsChangedListener);
+ mDisplayController.removeDisplayWindowListener(mOnDisplaysChangedListener);
+ updateTask();
+ final WindowContainerToken token = mLaunchRootTask.token;
+ if (token != null) {
+ deleteRootTask(token);
+ }
+ mLaunchRootTask = null;
+ mLaunchRootLeash = null;
+ unregisterOrganizer();
+ }
+
+ private void updateTask() {
+ updateTask(getWindowContainerTransaction());
+ }
+
+ private void updateTask(WindowContainerTransaction wct) {
+ if (mLaunchRootTask == null || mLaunchRootLeash == null) {
+ return;
+ }
+ final Rect taskBounds = calculateBounds();
+ final WindowContainerToken rootToken = mLaunchRootTask.token;
+ wct.setBounds(rootToken, mEnabled ? taskBounds : null);
+ wct.setLaunchRoot(rootToken,
+ mEnabled ? CONTROLLED_WINDOWING_MODES : null,
+ mEnabled ? CONTROLLED_ACTIVITY_TYPES : null);
+ wct.reparentTasks(
+ mEnabled ? null : rootToken /* currentParent */,
+ mEnabled ? rootToken : null /* newParent */,
+ CONTROLLED_WINDOWING_MODES,
+ CONTROLLED_ACTIVITY_TYPES,
+ true /* onTop */);
+ wct.reorder(rootToken, mEnabled /* onTop */);
+ mSyncQueue.queue(wct);
+ final SurfaceControl rootLeash = mLaunchRootLeash;
+ mSyncQueue.runInSync(t -> {
+ t.setPosition(rootLeash, taskBounds.left, taskBounds.top);
+ t.setWindowCrop(rootLeash, taskBounds.width(), taskBounds.height());
+ });
+ }
+
+ private Rect calculateBounds() {
+ final Rect bounds = new Rect(0, 0, mDisplayWidth, mDisplayHeight);
+ final InsetsSource navBarSource = mInsetsState.peekSource(InsetsState.ITYPE_NAVIGATION_BAR);
+ final InsetsSource taskBarSource = mInsetsState.peekSource(
+ InsetsState.ITYPE_EXTRA_NAVIGATION_BAR);
+ if (navBarSource != null && !navBarSource.getFrame().isEmpty()) {
+ bounds.inset(navBarSource.calculateInsets(bounds, false /* ignoreVisibility */));
+ } else if (taskBarSource != null && !taskBarSource.getFrame().isEmpty()) {
+ bounds.inset(taskBarSource.calculateInsets(bounds, false /* ignoreVisibility */));
+ } else {
+ bounds.setEmpty();
+ }
+ return bounds;
+ }
+
+ private void updateBounds() {
+ if (mLaunchRootTask == null) {
+ return;
+ }
+ final WindowContainerTransaction wct = getWindowContainerTransaction();
+ final Rect taskBounds = calculateBounds();
+ wct.setBounds(mLaunchRootTask.token, taskBounds);
+ mSyncQueue.queue(wct);
+ final SurfaceControl finalLeash = mLaunchRootLeash;
+ mSyncQueue.runInSync(t -> {
+ t.setPosition(finalLeash, taskBounds.left, taskBounds.top);
+ t.setWindowCrop(finalLeash, taskBounds.width(), taskBounds.height());
+ });
+ }
+
+ @VisibleForTesting
+ WindowContainerTransaction getWindowContainerTransaction() {
+ return new WindowContainerTransaction();
+ }
+
+ @Override
+ public void dump(@NonNull PrintWriter pw, String prefix) {
+ final String innerPrefix = prefix + " ";
+ pw.println(prefix + TAG);
+ pw.println(innerPrefix + " mEnabled=" + mEnabled);
+ pw.println(innerPrefix + " mLaunchRootTask=" + mLaunchRootTask);
+ pw.println(innerPrefix + " mLaunchRootLeash=" + mLaunchRootLeash);
+ pw.println(innerPrefix + " mDisplayWidth=" + mDisplayWidth);
+ pw.println(innerPrefix + " mDisplayHeight=" + mDisplayHeight);
+ pw.println(innerPrefix + " mInsetsState=" + mInsetsState);
+ super.dump(pw, innerPrefix);
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenTaskListener.java
index 86bf3ff1cea9..d2f42c39acd5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenTaskListener.java
@@ -343,10 +343,20 @@ class LegacySplitScreenTaskListener implements ShellTaskOrganizer.TaskListener {
@Override
public void attachChildSurfaceToTask(int taskId, SurfaceControl.Builder b) {
+ b.setParent(findTaskSurface(taskId));
+ }
+
+ @Override
+ public void reparentChildSurfaceToTask(int taskId, SurfaceControl sc,
+ SurfaceControl.Transaction t) {
+ t.reparent(sc, findTaskSurface(taskId));
+ }
+
+ private SurfaceControl findTaskSurface(int taskId) {
if (!mLeashByTaskId.contains(taskId)) {
throw new IllegalArgumentException("There is no surface for taskId=" + taskId);
}
- b.setParent(mLeashByTaskId.get(taskId));
+ return mLeashByTaskId.get(taskId);
}
@Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/IPip.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/IPip.aidl
index ddc85f758916..e03421dd58ac 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/IPip.aidl
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/IPip.aidl
@@ -47,12 +47,13 @@ interface IPip {
/**
* Notifies the swiping Activity to PiP onto home transition is finished
*
+ * @param taskId the Task id that the Activity and overlay are currently in.
* @param componentName ComponentName represents the Activity
* @param destinationBounds the destination bounds the PiP window lands into
* @param overlay an optional overlay to fade out after entering PiP
*/
- oneway void stopSwipePipToHome(in ComponentName componentName, in Rect destinationBounds,
- in SurfaceControl overlay) = 2;
+ oneway void stopSwipePipToHome(int taskId, in ComponentName componentName,
+ in Rect destinationBounds, in SurfaceControl overlay) = 2;
/**
* Sets listener to get pinned stack animation callbacks.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PinnedStackListenerForwarder.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PinnedStackListenerForwarder.java
index 3fefc4a0e0bf..87eca74acd0b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PinnedStackListenerForwarder.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PinnedStackListenerForwarder.java
@@ -72,9 +72,10 @@ public class PinnedStackListenerForwarder {
}
}
- private void onActionsChanged(ParceledListSlice<RemoteAction> actions) {
+ private void onActionsChanged(ParceledListSlice<RemoteAction> actions,
+ RemoteAction closeAction) {
for (PinnedTaskListener listener : mListeners) {
- listener.onActionsChanged(actions);
+ listener.onActionsChanged(actions, closeAction);
}
}
@@ -113,9 +114,10 @@ public class PinnedStackListenerForwarder {
}
@Override
- public void onActionsChanged(ParceledListSlice<RemoteAction> actions) {
+ public void onActionsChanged(ParceledListSlice<RemoteAction> actions,
+ RemoteAction closeAction) {
mMainExecutor.execute(() -> {
- PinnedStackListenerForwarder.this.onActionsChanged(actions);
+ PinnedStackListenerForwarder.this.onActionsChanged(actions, closeAction);
});
}
@@ -152,7 +154,8 @@ public class PinnedStackListenerForwarder {
public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) {}
- public void onActionsChanged(ParceledListSlice<RemoteAction> actions) {}
+ public void onActionsChanged(ParceledListSlice<RemoteAction> actions,
+ RemoteAction closeAction) {}
public void onActivityHidden(ComponentName componentName) {}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java
index 797df413d262..7397e5273753 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java
@@ -74,7 +74,7 @@ public class PipBoundsAlgorithm {
/**
* TODO: move the resources to SysUI package.
*/
- protected void reloadResources(Context context) {
+ private void reloadResources(Context context) {
final Resources res = context.getResources();
mDefaultAspectRatio = res.getFloat(
R.dimen.config_pictureInPictureDefaultAspectRatio);
@@ -194,7 +194,7 @@ public class PipBoundsAlgorithm {
public float getAspectRatioOrDefault(
@android.annotation.Nullable PictureInPictureParams params) {
return params != null && params.hasSetAspectRatio()
- ? params.getAspectRatio()
+ ? params.getAspectRatioFloat()
: getDefaultAspectRatio();
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java
index 210ea54baf58..17d7f5d0d567 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java
@@ -29,14 +29,15 @@ import android.graphics.Point;
import android.graphics.Rect;
import android.os.RemoteException;
import android.util.ArraySet;
-import android.util.Log;
import android.util.Size;
import android.view.Display;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.protolog.common.ProtoLog;
import com.android.internal.util.function.TriConsumer;
import com.android.wm.shell.R;
import com.android.wm.shell.common.DisplayLayout;
+import com.android.wm.shell.protolog.ShellProtoLogGroup;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
@@ -54,11 +55,15 @@ public class PipBoundsState {
public static final int STASH_TYPE_NONE = 0;
public static final int STASH_TYPE_LEFT = 1;
public static final int STASH_TYPE_RIGHT = 2;
+ public static final int STASH_TYPE_BOTTOM = 3;
+ public static final int STASH_TYPE_TOP = 4;
@IntDef(prefix = { "STASH_TYPE_" }, value = {
STASH_TYPE_NONE,
STASH_TYPE_LEFT,
- STASH_TYPE_RIGHT
+ STASH_TYPE_RIGHT,
+ STASH_TYPE_BOTTOM,
+ STASH_TYPE_TOP
})
@Retention(RetentionPolicy.SOURCE)
public @interface StashType {}
@@ -223,7 +228,8 @@ public class PipBoundsState {
new PictureInPictureUiState(stashedState != STASH_TYPE_NONE /* isStashed */)
);
} catch (RemoteException e) {
- Log.e(TAG, "Unable to set alert PiP state change.");
+ ProtoLog.e(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: Unable to set alert PiP state change.", TAG);
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipMenuController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipMenuController.java
index caa1f017082b..f6ff294b4328 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipMenuController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipMenuController.java
@@ -66,7 +66,7 @@ public interface PipMenuController {
/**
* Given a set of actions, update the menu.
*/
- void setAppActions(ParceledListSlice<RemoteAction> appActions);
+ void setAppActions(ParceledListSlice<RemoteAction> appActions, RemoteAction closeAction);
/**
* Resize the PiP menu with the given bounds. The PiP SurfaceControl is given if there is a
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 1eb9501ac076..5d6b041f9006 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
@@ -18,7 +18,6 @@ package com.android.wm.shell.pip;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
-import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.util.RotationUtils.deltaRotation;
import static android.util.RotationUtils.rotateBounds;
@@ -63,7 +62,6 @@ import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.RemoteException;
import android.os.SystemClock;
-import android.util.Log;
import android.util.Rational;
import android.view.Display;
import android.view.Surface;
@@ -73,6 +71,7 @@ import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.R;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.animation.Interpolators;
@@ -81,8 +80,8 @@ import com.android.wm.shell.common.ScreenshotUtils;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.annotations.ShellMainThread;
-import com.android.wm.shell.legacysplitscreen.LegacySplitScreenController;
import com.android.wm.shell.pip.phone.PipMotionHelper;
+import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.splitscreen.SplitScreenController;
import com.android.wm.shell.transition.Transitions;
@@ -133,7 +132,6 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
private final int mExitAnimationDuration;
private final int mCrossFadeAnimationDuration;
private final PipSurfaceTransactionHelper mSurfaceTransactionHelper;
- private final Optional<LegacySplitScreenController> mLegacySplitScreenOptional;
private final Optional<SplitScreenController> mSplitScreenOptional;
protected final ShellTaskOrganizer mTaskOrganizer;
protected final ShellExecutor mMainExecutor;
@@ -249,7 +247,8 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
* An optional overlay used to mask content changing between an app in/out of PiP, only set if
* {@link PipTransitionState#getInSwipePipToHomeTransition()} is true.
*/
- private SurfaceControl mSwipePipToHomeOverlay;
+ @Nullable
+ SurfaceControl mSwipePipToHomeOverlay;
public PipTaskOrganizer(Context context,
@NonNull SyncTransactionQueue syncTransactionQueue,
@@ -260,7 +259,6 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
@NonNull PipAnimationController pipAnimationController,
@NonNull PipSurfaceTransactionHelper surfaceTransactionHelper,
@NonNull PipTransitionController pipTransitionController,
- Optional<LegacySplitScreenController> legacySplitScreenOptional,
Optional<SplitScreenController> splitScreenOptional,
@NonNull DisplayController displayController,
@NonNull PipUiEventLogger pipUiEventLogger,
@@ -283,7 +281,6 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
mPipAnimationController = pipAnimationController;
mPipUiEventLoggerLogger = pipUiEventLogger;
mSurfaceControlTransactionFactory = SurfaceControl.Transaction::new;
- mLegacySplitScreenOptional = legacySplitScreenOptional;
mSplitScreenOptional = splitScreenOptional;
mTaskOrganizer = shellTaskOrganizer;
mMainExecutor = mainExecutor;
@@ -356,12 +353,24 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
* Callback when launcher finishes swipe-pip-to-home operation.
* Expect {@link #onTaskAppeared(ActivityManager.RunningTaskInfo, SurfaceControl)} afterwards.
*/
- public void stopSwipePipToHome(ComponentName componentName, Rect destinationBounds,
+ public void stopSwipePipToHome(int taskId, ComponentName componentName, Rect destinationBounds,
SurfaceControl overlay) {
// do nothing if there is no startSwipePipToHome being called before
- if (mPipTransitionState.getInSwipePipToHomeTransition()) {
- mPipBoundsState.setBounds(destinationBounds);
- mSwipePipToHomeOverlay = overlay;
+ if (!mPipTransitionState.getInSwipePipToHomeTransition()) {
+ return;
+ }
+ mPipBoundsState.setBounds(destinationBounds);
+ mSwipePipToHomeOverlay = overlay;
+ if (ENABLE_SHELL_TRANSITIONS) {
+ // With Shell transition, the overlay was attached to the remote transition leash, which
+ // will be removed when the current transition is finished, so we need to reparent it
+ // to the actual Task surface now.
+ // PipTransition is responsible to fade it out and cleanup when finishing the enter PIP
+ // transition.
+ final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+ mTaskOrganizer.reparentChildSurfaceToTask(taskId, overlay, t);
+ t.setLayer(overlay, Integer.MAX_VALUE);
+ t.apply();
}
}
@@ -395,8 +404,10 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
if (!mPipTransitionState.isInPip()
|| mPipTransitionState.getTransitionState() == PipTransitionState.EXITING_PIP
|| mToken == null) {
- Log.wtf(TAG, "Not allowed to exitPip in current state"
- + " mState=" + mPipTransitionState.getTransitionState() + " mToken=" + mToken);
+ ProtoLog.wtf(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: Not allowed to exitPip in current state"
+ + " mState=%d mToken=%s", TAG, mPipTransitionState.getTransitionState(),
+ mToken);
return;
}
@@ -438,11 +449,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
tx.setWindowCrop(mLeash, destinationBounds.width(), destinationBounds.height());
// We set to fullscreen here for now, but later it will be set to UNDEFINED for
// the proper windowing mode to take place. See #applyWindowingModeChangeOnExit.
- wct.setActivityWindowingMode(mToken,
- direction == TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN
- && !requestEnterSplit
- ? WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
- : WINDOWING_MODE_FULLSCREEN);
+ wct.setActivityWindowingMode(mToken, WINDOWING_MODE_FULLSCREEN);
wct.setBounds(mToken, destinationBounds);
wct.setBoundsChangeTransaction(mToken, tx);
}
@@ -489,20 +496,17 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
wct.setWindowingMode(mToken, getOutPipWindowingMode());
// Simply reset the activity mode set prior to the animation running.
wct.setActivityWindowingMode(mToken, WINDOWING_MODE_UNDEFINED);
- mLegacySplitScreenOptional.ifPresent(splitScreen -> {
- if (direction == TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN) {
- wct.reparent(mToken, splitScreen.getSecondaryRoot(), true /* onTop */);
- }
- });
}
/**
* Removes PiP immediately.
*/
public void removePip() {
- if (!mPipTransitionState.isInPip() || mToken == null) {
- Log.wtf(TAG, "Not allowed to removePip in current state"
- + " mState=" + mPipTransitionState.getTransitionState() + " mToken=" + mToken);
+ if (!mPipTransitionState.isInPip() || mToken == null) {
+ ProtoLog.wtf(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: Not allowed to removePip in current state"
+ + " mState=%d mToken=%s", TAG, mPipTransitionState.getTransitionState(),
+ mToken);
return;
}
@@ -539,7 +543,9 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
ActivityTaskManager.getService().removeRootTasksInWindowingModes(
new int[]{ WINDOWING_MODE_PINNED });
} catch (RemoteException e) {
- Log.e(TAG, "Failed to remove PiP", e);
+ ProtoLog.e(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: Failed to remove PiP, %s",
+ TAG, e);
}
}
@@ -568,7 +574,9 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
if (!mWaitForFixedRotation) {
onEndOfSwipePipToHomeTransition();
} else {
- Log.d(TAG, "Defer onTaskAppeared-SwipePipToHome until end of fixed rotation.");
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: Defer onTaskAppeared-SwipePipToHome until end of fixed rotation.",
+ TAG);
}
return;
}
@@ -576,7 +584,8 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
if (mOneShotAnimationType == ANIM_TYPE_ALPHA
&& SystemClock.uptimeMillis() - mLastOneShotAlphaAnimationTime
> ONE_SHOT_ALPHA_ANIMATION_TIMEOUT_MS) {
- Log.d(TAG, "Alpha animation is expired. Use bounds animation.");
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: Alpha animation is expired. Use bounds animation.", TAG);
mOneShotAnimationType = ANIM_TYPE_BOUNDS;
}
@@ -613,8 +622,9 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
private void onTaskAppearedWithFixedRotation() {
if (mOneShotAnimationType == ANIM_TYPE_ALPHA) {
- Log.d(TAG, "Defer entering PiP alpha animation, fixed rotation is ongoing");
- // If deferred, hide the surface till fixed rotation is completed.
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: Defer entering PiP alpha animation, fixed rotation is ongoing", TAG);
+ // If deferred, hside the surface till fixed rotation is completed.
final SurfaceControl.Transaction tx =
mSurfaceControlTransactionFactory.getTransaction();
tx.setAlpha(mLeash, 0f);
@@ -671,7 +681,6 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
private void onEndOfSwipePipToHomeTransition() {
if (Transitions.ENABLE_SHELL_TRANSITIONS) {
- mSwipePipToHomeOverlay = null;
return;
}
@@ -763,7 +772,8 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
final WindowContainerToken token = info.token;
Objects.requireNonNull(token, "Requires valid WindowContainerToken");
if (token.asBinder() != mToken.asBinder()) {
- Log.wtf(TAG, "Unrecognized token: " + token);
+ ProtoLog.wtf(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: Unrecognized token: %s", TAG, token);
return;
}
onExitPipFinished(info);
@@ -788,8 +798,9 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
Objects.requireNonNull(mToken, "onTaskInfoChanged requires valid existing mToken");
if (mPipTransitionState.getTransitionState() != PipTransitionState.ENTERED_PIP
&& mPipTransitionState.getTransitionState() != PipTransitionState.EXITING_PIP) {
- Log.d(TAG, "Defer onTaskInfoChange in current state: "
- + mPipTransitionState.getTransitionState());
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: Defer onTaskInfoChange in current state: %d", TAG,
+ mPipTransitionState.getTransitionState());
// Defer applying PiP parameters if the task is entering PiP to avoid disturbing
// the animation.
mDeferredTaskInfo = info;
@@ -800,7 +811,8 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
mPipBoundsAlgorithm.getMinimalSize(info.topActivityInfo));
final PictureInPictureParams newParams = info.pictureInPictureParams;
if (newParams == null || !applyPictureInPictureParams(newParams)) {
- Log.d(TAG, "Ignored onTaskInfoChanged with PiP param: " + newParams);
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: Ignored onTaskInfoChanged with PiP param: %s", TAG, newParams);
return;
}
// Aspect ratio changed, re-calculate bounds if valid.
@@ -823,6 +835,24 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
}
@Override
+ public void attachChildSurfaceToTask(int taskId, SurfaceControl.Builder b) {
+ b.setParent(findTaskSurface(taskId));
+ }
+
+ @Override
+ public void reparentChildSurfaceToTask(int taskId, SurfaceControl sc,
+ SurfaceControl.Transaction t) {
+ t.reparent(sc, findTaskSurface(taskId));
+ }
+
+ private SurfaceControl findTaskSurface(int taskId) {
+ if (mTaskInfo == null || mLeash == null || mTaskInfo.taskId != taskId) {
+ throw new IllegalArgumentException("There is no surface for taskId=" + taskId);
+ }
+ return mLeash;
+ }
+
+ @Override
public void onFixedRotationStarted(int displayId, int newRotation) {
mNextRotation = newRotation;
mWaitForFixedRotation = true;
@@ -877,9 +907,13 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
clearWaitForFixedRotation();
}
- /** Called when exiting PIP tranisiton is finished to do the state cleanup. */
+ /** Called when exiting PIP transition is finished to do the state cleanup. */
void onExitPipFinished(TaskInfo info) {
clearWaitForFixedRotation();
+ if (mSwipePipToHomeOverlay != null) {
+ removeContentOverlay(mSwipePipToHomeOverlay, null /* callback */);
+ mSwipePipToHomeOverlay = null;
+ }
mPipTransitionState.setInSwipePipToHomeTransition(false);
mPictureInPictureParams = null;
mPipTransitionState.setTransitionState(PipTransitionState.UNDEFINED);
@@ -895,7 +929,8 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
private void fadeExistingPip(boolean show) {
if (mLeash == null || !mLeash.isValid()) {
- Log.w(TAG, "Invalid leash on fadeExistingPip: " + mLeash);
+ ProtoLog.w(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: Invalid leash on fadeExistingPip: %s", TAG, mLeash);
return;
}
final float alphaStart = show ? 0 : 1;
@@ -942,11 +977,13 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
if ((mPipTransitionState.getInSwipePipToHomeTransition()
|| waitForFixedRotationOnEnteringPip) && fromRotation) {
if (DEBUG) {
- Log.d(TAG, "Skip onMovementBoundsChanged on rotation change"
- + " InSwipePipToHomeTransition="
- + mPipTransitionState.getInSwipePipToHomeTransition()
- + " mWaitForFixedRotation=" + mWaitForFixedRotation
- + " getTransitionState=" + mPipTransitionState.getTransitionState());
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: Skip onMovementBoundsChanged on rotation change"
+ + " InSwipePipToHomeTransition=%b"
+ + " mWaitForFixedRotation=%b"
+ + " getTransitionState=%d", TAG,
+ mPipTransitionState.getInSwipePipToHomeTransition(), mWaitForFixedRotation,
+ mPipTransitionState.getTransitionState());
}
return;
}
@@ -1034,13 +1071,13 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
*/
private boolean applyPictureInPictureParams(@NonNull PictureInPictureParams params) {
final Rational currentAspectRatio =
- mPictureInPictureParams != null ? mPictureInPictureParams.getAspectRatioRational()
+ mPictureInPictureParams != null ? mPictureInPictureParams.getAspectRatio()
: null;
final boolean aspectRatioChanged = !Objects.equals(currentAspectRatio,
- params.getAspectRatioRational());
+ params.getAspectRatio());
mPictureInPictureParams = params;
if (aspectRatioChanged) {
- mPipBoundsState.setAspectRatio(params.getAspectRatio());
+ mPipBoundsState.setAspectRatio(params.getAspectRatioFloat());
}
return aspectRatioChanged;
}
@@ -1061,7 +1098,8 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
@PipAnimationController.TransitionDirection int direction,
Consumer<Rect> updateBoundsCallback) {
if (mWaitForFixedRotation) {
- Log.d(TAG, "skip scheduleAnimateResizePip, entering pip deferred");
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: skip scheduleAnimateResizePip, entering pip deferred", TAG);
return;
}
scheduleAnimateResizePip(mPipBoundsState.getBounds(), toBounds, 0 /* startingAngle */,
@@ -1075,7 +1113,8 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
public void scheduleAnimateResizePip(Rect fromBounds, Rect toBounds, int duration,
float startingAngle, Consumer<Rect> updateBoundsCallback) {
if (mWaitForFixedRotation) {
- Log.d(TAG, "skip scheduleAnimateResizePip, entering pip deferred");
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: skip scheduleAnimateResizePip, entering pip deferred", TAG);
return;
}
scheduleAnimateResizePip(fromBounds, toBounds, startingAngle, null /* sourceHintRect */,
@@ -1113,7 +1152,8 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
public void scheduleResizePip(Rect toBounds, Consumer<Rect> updateBoundsCallback) {
// Could happen when exitPip
if (mToken == null || mLeash == null) {
- Log.w(TAG, "Abort animation, invalid leash");
+ ProtoLog.w(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: Abort animation, invalid leash", TAG);
return;
}
mPipBoundsState.setBounds(toBounds);
@@ -1148,12 +1188,14 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
Consumer<Rect> updateBoundsCallback) {
// Could happen when exitPip
if (mToken == null || mLeash == null) {
- Log.w(TAG, "Abort animation, invalid leash");
+ ProtoLog.w(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: Abort animation, invalid leash", TAG);
return;
}
if (startBounds.isEmpty() || toBounds.isEmpty()) {
- Log.w(TAG, "Attempted to user resize PIP to or from empty bounds, aborting.");
+ ProtoLog.w(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: Attempted to user resize PIP to or from empty bounds, aborting.", TAG);
return;
}
@@ -1228,7 +1270,8 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
return;
}
if (mWaitForFixedRotation) {
- Log.d(TAG, "skip scheduleOffsetPip, entering pip deferred");
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: skip scheduleOffsetPip, entering pip deferred", TAG);
return;
}
offsetPip(originalBounds, 0 /* xOffset */, offset, duration);
@@ -1241,7 +1284,8 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
private void offsetPip(Rect originalBounds, int xOffset, int yOffset, int durationMs) {
if (mTaskInfo == null) {
- Log.w(TAG, "mTaskInfo is not set");
+ ProtoLog.w(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, "%s: mTaskInfo is not set",
+ TAG);
return;
}
final Rect destinationBounds = new Rect(originalBounds);
@@ -1386,7 +1430,8 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
float startingAngle) {
// Could happen when exitPip
if (mToken == null || mLeash == null) {
- Log.w(TAG, "Abort animation, invalid leash");
+ ProtoLog.w(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: Abort animation, invalid leash", TAG);
return null;
}
final int rotationDelta = mWaitForFixedRotation
@@ -1453,36 +1498,21 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
}
/**
- * Sync with {@link LegacySplitScreenController} or {@link SplitScreenController} on destination
- * bounds if PiP is going to split screen.
+ * Sync with {@link SplitScreenController} on destination bounds if PiP is going to
+ * split screen.
*
* @param destinationBoundsOut contain the updated destination bounds if applicable
* @return {@code true} if destinationBounds is altered for split screen
*/
private boolean syncWithSplitScreenBounds(Rect destinationBoundsOut, boolean enterSplit) {
- if (enterSplit && mSplitScreenOptional.isPresent()) {
- final Rect topLeft = new Rect();
- final Rect bottomRight = new Rect();
- mSplitScreenOptional.get().getStageBounds(topLeft, bottomRight);
- final boolean isPipTopLeft = isPipTopLeft();
- destinationBoundsOut.set(isPipTopLeft ? topLeft : bottomRight);
- return true;
- }
-
- if (!mLegacySplitScreenOptional.isPresent()) {
+ if (!enterSplit || !mSplitScreenOptional.isPresent()) {
return false;
}
-
- LegacySplitScreenController legacySplitScreen = mLegacySplitScreenOptional.get();
- if (!legacySplitScreen.isDividerVisible()) {
- // fail early if system is not in split screen mode
- return false;
- }
-
- // PiP window will go to split-secondary mode instead of fullscreen, populates the
- // split screen bounds here.
- destinationBoundsOut.set(legacySplitScreen.getDividerView()
- .getNonMinimizedSplitScreenSecondaryBounds());
+ final Rect topLeft = new Rect();
+ final Rect bottomRight = new Rect();
+ mSplitScreenOptional.get().getStageBounds(topLeft, bottomRight);
+ final boolean isPipTopLeft = isPipTopLeft();
+ destinationBoundsOut.set(isPipTopLeft ? topLeft : bottomRight);
return true;
}
@@ -1501,7 +1531,8 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
if (mPipTransitionState.getTransitionState() == PipTransitionState.UNDEFINED) {
// Could happen if onTaskVanished happens during the animation since we may have
// set a start delay on this animation.
- Log.d(TAG, "Task vanished, skip fadeOutAndRemoveOverlay");
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: Task vanished, skip fadeOutAndRemoveOverlay", TAG);
animation.removeAllListeners();
animation.removeAllUpdateListeners();
animation.cancel();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
index f01457bc4c95..e5a755c35add 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
@@ -50,7 +50,6 @@ import android.graphics.Matrix;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.IBinder;
-import android.util.Log;
import android.view.Surface;
import android.view.SurfaceControl;
import android.window.TransitionInfo;
@@ -61,8 +60,10 @@ import android.window.WindowContainerTransaction;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.R;
import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.splitscreen.SplitScreenController;
import com.android.wm.shell.transition.CounterRotatorHelper;
import com.android.wm.shell.transition.Transitions;
@@ -151,7 +152,7 @@ public class PipTransition extends PipTransitionController {
@NonNull SurfaceControl.Transaction startTransaction,
@NonNull SurfaceControl.Transaction finishTransaction,
@NonNull Transitions.TransitionFinishCallback finishCallback) {
- final TransitionInfo.Change currentPipChange = findCurrentPipChange(info);
+ final TransitionInfo.Change currentPipTaskChange = findCurrentPipTaskChange(info);
final TransitionInfo.Change fixedRotationChange = findFixedRotationChange(info);
mInFixedRotation = fixedRotationChange != null;
mEndFixedRotation = mInFixedRotation
@@ -165,28 +166,34 @@ public class PipTransition extends PipTransitionController {
mExitTransition = null;
mHasFadeOut = false;
if (mFinishCallback != null) {
- mFinishCallback.onTransitionFinished(null, null);
- mFinishCallback = null;
+ callFinishCallback(null /* wct */);
mFinishTransaction = null;
throw new RuntimeException("Previous callback not called, aborting exit PIP.");
}
- if (currentPipChange == null) {
- throw new RuntimeException("Cannot find the pip window for exit-pip transition.");
+ // PipTaskChange can be null if the PIP task has been detached, for example, when the
+ // task contains multiple activities, the PIP will be moved to a new PIP task when
+ // entering, and be moved back when exiting. In that case, the PIP task will be removed
+ // immediately.
+ final TaskInfo pipTaskInfo = currentPipTaskChange != null
+ ? currentPipTaskChange.getTaskInfo()
+ : mPipOrganizer.getTaskInfo();
+ if (pipTaskInfo == null) {
+ throw new RuntimeException("Cannot find the pip task for exit-pip transition.");
}
switch (type) {
case TRANSIT_EXIT_PIP:
startExitAnimation(info, startTransaction, finishTransaction, finishCallback,
- currentPipChange);
+ pipTaskInfo, currentPipTaskChange);
break;
case TRANSIT_EXIT_PIP_TO_SPLIT:
startExitToSplitAnimation(info, startTransaction, finishTransaction,
- finishCallback, currentPipChange);
+ finishCallback, pipTaskInfo);
break;
case TRANSIT_REMOVE_PIP:
removePipImmediately(info, startTransaction, finishTransaction, finishCallback,
- currentPipChange);
+ pipTaskInfo);
break;
default:
throw new IllegalStateException("mExitTransition with unexpected transit type="
@@ -199,9 +206,9 @@ public class PipTransition extends PipTransitionController {
// The previous PIP Task is no longer in PIP, but this is not an exit transition (This can
// happen when a new activity requests enter PIP). In this case, we just show this Task in
// its end state, and play other animation as normal.
- if (currentPipChange != null
- && currentPipChange.getTaskInfo().getWindowingMode() != WINDOWING_MODE_PINNED) {
- resetPrevPip(currentPipChange, startTransaction);
+ if (currentPipTaskChange != null
+ && currentPipTaskChange.getTaskInfo().getWindowingMode() != WINDOWING_MODE_PINNED) {
+ resetPrevPip(currentPipTaskChange, startTransaction);
}
// Entering PIP.
@@ -211,8 +218,9 @@ public class PipTransition extends PipTransitionController {
// For transition that we don't animate, but contains the PIP leash, we need to update the
// PIP surface, otherwise it will be reset after the transition.
- if (currentPipChange != null) {
- updatePipForUnhandledTransition(currentPipChange, startTransaction, finishTransaction);
+ if (currentPipTaskChange != null) {
+ updatePipForUnhandledTransition(currentPipTaskChange, startTransaction,
+ finishTransaction);
}
// Fade in the fadeout PIP when the fixed rotation is finished.
@@ -223,6 +231,11 @@ public class PipTransition extends PipTransitionController {
return false;
}
+ /** Helper to identify whether this handler is currently the one playing an animation */
+ private boolean isAnimatingLocally() {
+ return mFinishTransaction != null;
+ }
+
@Nullable
@Override
public WindowContainerTransaction handleRequest(@NonNull IBinder transition,
@@ -273,9 +286,11 @@ public class PipTransition extends PipTransitionController {
if (enteringPip) {
mPipTransitionState.setTransitionState(ENTERED_PIP);
}
- // If there is an expected exit transition, then the exit will be "merged" into this
- // transition so don't fire the finish-callback in that case.
- if (mExitTransition == null && mFinishCallback != null) {
+ // If we have an exit transition, but aren't playing a transition locally, it
+ // means we're expecting the exit transition will be "merged" into another transition
+ // (likely a remote like launcher), so don't fire the finish-callback here -- wait until
+ // the exit transition is merged.
+ if ((mExitTransition == null || isAnimatingLocally()) && mFinishCallback != null) {
WindowContainerTransaction wct = new WindowContainerTransaction();
prepareFinishResizeTransaction(taskInfo, destinationBounds,
direction, wct);
@@ -296,12 +311,19 @@ public class PipTransition extends PipTransitionController {
mSurfaceTransactionHelper.crop(mFinishTransaction, leash, finishBounds);
}
mFinishTransaction = null;
- mFinishCallback.onTransitionFinished(wct, null /* callback */);
- mFinishCallback = null;
+ callFinishCallback(wct);
}
finishResizeForMenu(destinationBounds);
}
+ private void callFinishCallback(WindowContainerTransaction wct) {
+ // Need to unset mFinishCallback first because onTransitionFinished can re-enter this
+ // handler if there is a pending PiP animation.
+ final Transitions.TransitionFinishCallback finishCallback = mFinishCallback;
+ mFinishCallback = null;
+ finishCallback.onTransitionFinished(wct, null /* callback */);
+ }
+
@Override
public void forceFinishTransition() {
if (mFinishCallback == null) return;
@@ -321,7 +343,7 @@ public class PipTransition extends PipTransitionController {
}
@Nullable
- private TransitionInfo.Change findCurrentPipChange(@NonNull TransitionInfo info) {
+ private TransitionInfo.Change findCurrentPipTaskChange(@NonNull TransitionInfo info) {
if (mCurrentPipTaskToken == null) {
return null;
}
@@ -349,9 +371,30 @@ public class PipTransition extends PipTransitionController {
@NonNull SurfaceControl.Transaction startTransaction,
@NonNull SurfaceControl.Transaction finishTransaction,
@NonNull Transitions.TransitionFinishCallback finishCallback,
- @NonNull TransitionInfo.Change pipChange) {
+ @NonNull TaskInfo taskInfo, @Nullable TransitionInfo.Change pipTaskChange) {
+ TransitionInfo.Change pipChange = pipTaskChange;
+ if (pipChange == null) {
+ // The pipTaskChange is null, this can happen if we are reparenting the PIP activity
+ // back to its original Task. In that case, we should animate the activity leash
+ // instead, which should be the only non-task, independent, TRANSIT_CHANGE window.
+ for (int i = info.getChanges().size() - 1; i >= 0; --i) {
+ final TransitionInfo.Change change = info.getChanges().get(i);
+ if (change.getTaskInfo() == null && change.getMode() == TRANSIT_CHANGE
+ && TransitionInfo.isIndependent(change, info)) {
+ pipChange = change;
+ break;
+ }
+ }
+ }
+ if (pipChange == null) {
+ ProtoLog.w(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: No window of exiting PIP is found. Can't play expand animation", TAG);
+ removePipImmediately(info, startTransaction, finishTransaction, finishCallback,
+ taskInfo);
+ return;
+ }
mFinishCallback = (wct, wctCB) -> {
- mPipOrganizer.onExitPipFinished(pipChange.getTaskInfo());
+ mPipOrganizer.onExitPipFinished(taskInfo);
finishCallback.onTransitionFinished(wct, wctCB);
};
mFinishTransaction = finishTransaction;
@@ -371,7 +414,7 @@ public class PipTransition extends PipTransitionController {
if (displayRotationChange != null) {
// Exiting PIP to fullscreen with orientation change.
startExpandAndRotationAnimation(info, startTransaction, finishTransaction,
- displayRotationChange, pipChange);
+ displayRotationChange, taskInfo, pipChange);
return;
}
}
@@ -412,15 +455,14 @@ public class PipTransition extends PipTransitionController {
} else {
rotationDelta = Surface.ROTATION_0;
}
- startExpandAnimation(pipChange.getTaskInfo(), pipChange.getLeash(), destinationBounds,
- rotationDelta);
+ startExpandAnimation(taskInfo, pipChange.getLeash(), destinationBounds, rotationDelta);
}
private void startExpandAndRotationAnimation(@NonNull TransitionInfo info,
@NonNull SurfaceControl.Transaction startTransaction,
@NonNull SurfaceControl.Transaction finishTransaction,
@NonNull TransitionInfo.Change displayRotationChange,
- @NonNull TransitionInfo.Change pipChange) {
+ @NonNull TaskInfo taskInfo, @NonNull TransitionInfo.Change pipChange) {
final int rotateDelta = deltaRotation(displayRotationChange.getStartRotation(),
displayRotationChange.getEndRotation());
@@ -458,7 +500,7 @@ public class PipTransition extends PipTransitionController {
// Expand and rotate the pip window to fullscreen.
final PipAnimationController.PipTransitionAnimator animator =
- mPipAnimationController.getAnimator(pipChange.getTaskInfo(), pipChange.getLeash(),
+ mPipAnimationController.getAnimator(taskInfo, pipChange.getLeash(),
startBounds, startBounds, endBounds, null, TRANSITION_DIRECTION_LEAVE_PIP,
0 /* startingAngle */, pipRotateDelta);
animator.setTransitionDirection(TRANSITION_DIRECTION_LEAVE_PIP)
@@ -484,11 +526,11 @@ public class PipTransition extends PipTransitionController {
@NonNull SurfaceControl.Transaction startTransaction,
@NonNull SurfaceControl.Transaction finishTransaction,
@NonNull Transitions.TransitionFinishCallback finishCallback,
- @NonNull TransitionInfo.Change pipChange) {
+ @NonNull TaskInfo taskInfo) {
startTransaction.apply();
finishTransaction.setWindowCrop(info.getChanges().get(0).getLeash(),
mPipBoundsState.getDisplayBounds());
- mPipOrganizer.onExitPipFinished(pipChange.getTaskInfo());
+ mPipOrganizer.onExitPipFinished(taskInfo);
finishCallback.onTransitionFinished(null, null);
}
@@ -543,8 +585,7 @@ public class PipTransition extends PipTransitionController {
mHasFadeOut = false;
if (mFinishCallback != null) {
- mFinishCallback.onTransitionFinished(null /* wct */, null /* callback */);
- mFinishCallback = null;
+ callFinishCallback(null /* wct */);
mFinishTransaction = null;
throw new RuntimeException("Previous callback not called, aborting entering PIP.");
}
@@ -603,11 +644,18 @@ public class PipTransition extends PipTransitionController {
&& taskInfo.pictureInPictureParams.isAutoEnterEnabled()
&& mPipTransitionState.getInSwipePipToHomeTransition()) {
mOneShotAnimationType = ANIM_TYPE_BOUNDS;
- SurfaceControl.Transaction tx = new SurfaceControl.Transaction();
- tx.setMatrix(leash, Matrix.IDENTITY_MATRIX, new float[9])
+ final SurfaceControl swipePipToHomeOverlay = mPipOrganizer.mSwipePipToHomeOverlay;
+ startTransaction.setMatrix(leash, Matrix.IDENTITY_MATRIX, new float[9])
.setPosition(leash, destinationBounds.left, destinationBounds.top)
.setWindowCrop(leash, destinationBounds.width(), destinationBounds.height());
- startTransaction.merge(tx);
+ if (swipePipToHomeOverlay != null) {
+ // Launcher fade in the overlay on top of the fullscreen Task. It is possible we
+ // reparent the PIP activity to a new PIP task (in case there are other activities
+ // in the original Task), so we should also reparent the overlay to the PIP task.
+ startTransaction.reparent(swipePipToHomeOverlay, leash)
+ .setLayer(swipePipToHomeOverlay, Integer.MAX_VALUE);
+ mPipOrganizer.mSwipePipToHomeOverlay = null;
+ }
startTransaction.apply();
if (rotationDelta != Surface.ROTATION_0 && mInFixedRotation) {
// For fixed rotation, set the destination bounds to the new rotation coordinates
@@ -617,6 +665,10 @@ public class PipTransition extends PipTransitionController {
mPipBoundsState.setBounds(destinationBounds);
onFinishResize(taskInfo, destinationBounds, TRANSITION_DIRECTION_TO_PIP, null /* tx */);
sendOnPipTransitionFinished(TRANSITION_DIRECTION_TO_PIP);
+ if (swipePipToHomeOverlay != null) {
+ mPipOrganizer.fadeOutAndRemoveOverlay(swipePipToHomeOverlay,
+ null /* callback */, false /* withStartDelay */);
+ }
mPipTransitionState.setInSwipePipToHomeTransition(false);
return true;
}
@@ -677,11 +729,11 @@ public class PipTransition extends PipTransitionController {
}
}
- private void startExitToSplitAnimation(TransitionInfo info,
- SurfaceControl.Transaction startTransaction,
- SurfaceControl.Transaction finishTransaction,
- Transitions.TransitionFinishCallback finishCallback,
- TransitionInfo.Change pipChange) {
+ private void startExitToSplitAnimation(@NonNull TransitionInfo info,
+ @NonNull SurfaceControl.Transaction startTransaction,
+ @NonNull SurfaceControl.Transaction finishTransaction,
+ @NonNull Transitions.TransitionFinishCallback finishCallback,
+ @NonNull TaskInfo taskInfo) {
final int changeSize = info.getChanges().size();
if (changeSize < 4) {
throw new RuntimeException(
@@ -709,15 +761,15 @@ public class PipTransition extends PipTransitionController {
mSplitScreenOptional.get().finishEnterSplitScreen(startTransaction);
startTransaction.apply();
- mPipOrganizer.onExitPipFinished(pipChange.getTaskInfo());
+ mPipOrganizer.onExitPipFinished(taskInfo);
finishCallback.onTransitionFinished(null, null);
}
- private void resetPrevPip(@NonNull TransitionInfo.Change prevPipChange,
+ private void resetPrevPip(@NonNull TransitionInfo.Change prevPipTaskChange,
@NonNull SurfaceControl.Transaction startTransaction) {
- final SurfaceControl leash = prevPipChange.getLeash();
- final Rect bounds = prevPipChange.getEndAbsBounds();
- final Point offset = prevPipChange.getEndRelOffset();
+ final SurfaceControl leash = prevPipTaskChange.getLeash();
+ final Rect bounds = prevPipTaskChange.getEndAbsBounds();
+ final Point offset = prevPipTaskChange.getEndRelOffset();
bounds.offset(-offset.x, -offset.y);
startTransaction.setWindowCrop(leash, null);
@@ -725,7 +777,7 @@ public class PipTransition extends PipTransitionController {
startTransaction.setCornerRadius(leash, 0);
startTransaction.setPosition(leash, bounds.left, bounds.top);
- if (mHasFadeOut && prevPipChange.getTaskInfo().isVisible()) {
+ if (mHasFadeOut && prevPipTaskChange.getTaskInfo().isVisible()) {
if (mPipAnimationController.getCurrentAnimator() != null) {
mPipAnimationController.getCurrentAnimator().cancel();
}
@@ -733,7 +785,7 @@ public class PipTransition extends PipTransitionController {
}
mHasFadeOut = false;
mCurrentPipTaskToken = null;
- mPipOrganizer.onExitPipFinished(prevPipChange.getTaskInfo());
+ mPipOrganizer.onExitPipFinished(prevPipTaskChange.getTaskInfo());
}
private void updatePipForUnhandledTransition(@NonNull TransitionInfo.Change pipChange,
@@ -757,7 +809,8 @@ public class PipTransition extends PipTransitionController {
final SurfaceControl leash = mPipOrganizer.getSurfaceControl();
final TaskInfo taskInfo = mPipOrganizer.getTaskInfo();
if (leash == null || !leash.isValid() || taskInfo == null) {
- Log.w(TAG, "Invalid leash on fadeExistingPip: " + leash);
+ ProtoLog.w(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: Invalid leash on fadeExistingPip: %s", TAG, leash);
return;
}
final float alphaStart = show ? 0 : 1;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipUtils.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipUtils.java
index da6d9804b29d..d7b69adf1241 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipUtils.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipUtils.java
@@ -24,9 +24,11 @@ import android.app.ActivityTaskManager.RootTaskInfo;
import android.content.ComponentName;
import android.content.Context;
import android.os.RemoteException;
-import android.util.Log;
import android.util.Pair;
+import com.android.internal.protolog.common.ProtoLog;
+import com.android.wm.shell.protolog.ShellProtoLogGroup;
+
/** A class that includes convenience methods. */
public class PipUtils {
private static final String TAG = "PipUtils";
@@ -51,7 +53,8 @@ public class PipUtils {
}
}
} catch (RemoteException e) {
- Log.w(TAG, "Unable to get pinned stack.");
+ ProtoLog.w(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: Unable to get pinned stack.", TAG);
}
return new Pair<>(null, 0);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java
index 71cff025a7a8..5e4c12ed37ed 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java
@@ -29,7 +29,6 @@ import android.graphics.RectF;
import android.os.Debug;
import android.os.Handler;
import android.os.RemoteException;
-import android.util.Log;
import android.util.Size;
import android.view.MotionEvent;
import android.view.SurfaceControl;
@@ -37,6 +36,7 @@ import android.view.SyncRtSurfaceTransactionApplier;
import android.view.SyncRtSurfaceTransactionApplier.SurfaceParams;
import android.view.WindowManagerGlobal;
+import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SystemWindows;
import com.android.wm.shell.pip.PipBoundsState;
@@ -44,6 +44,7 @@ import com.android.wm.shell.pip.PipMediaController;
import com.android.wm.shell.pip.PipMediaController.ActionListener;
import com.android.wm.shell.pip.PipMenuController;
import com.android.wm.shell.pip.PipUiEventLogger;
+import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.splitscreen.SplitScreenController;
import java.io.PrintWriter;
@@ -285,13 +286,15 @@ public class PhonePipMenuController implements PipMenuController {
private void showMenuInternal(int menuState, Rect stackBounds, boolean allowMenuTimeout,
boolean willResizeMenu, boolean withDelay, boolean showResizeHandle) {
if (DEBUG) {
- Log.d(TAG, "showMenu() state=" + menuState
- + " isMenuVisible=" + isMenuVisible()
- + " allowMenuTimeout=" + allowMenuTimeout
- + " willResizeMenu=" + willResizeMenu
- + " withDelay=" + withDelay
- + " showResizeHandle=" + showResizeHandle
- + " callers=\n" + Debug.getCallers(5, " "));
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: showMenu() state=%s"
+ + " isMenuVisible=%s"
+ + " allowMenuTimeout=%s"
+ + " willResizeMenu=%s"
+ + " withDelay=%s"
+ + " showResizeHandle=%s"
+ + " callers=\n%s", TAG, menuState, isMenuVisible(), allowMenuTimeout,
+ willResizeMenu, withDelay, showResizeHandle, Debug.getCallers(5, " "));
}
if (!maybeCreateSyncApplier()) {
@@ -383,7 +386,8 @@ public class PhonePipMenuController implements PipMenuController {
private boolean maybeCreateSyncApplier() {
if (mPipMenuView == null || mPipMenuView.getViewRootImpl() == null) {
- Log.v(TAG, "Not going to move PiP, either menu or its parent is not created.");
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: Not going to move PiP, either menu or its parent is not created.", TAG);
return false;
}
@@ -400,7 +404,8 @@ public class PhonePipMenuController implements PipMenuController {
public void pokeMenu() {
final boolean isMenuVisible = isMenuVisible();
if (DEBUG) {
- Log.d(TAG, "pokeMenu() isMenuVisible=" + isMenuVisible);
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: pokeMenu() isMenuVisible=%b", TAG, isMenuVisible);
}
if (isMenuVisible) {
mPipMenuView.pokeMenu();
@@ -410,7 +415,8 @@ public class PhonePipMenuController implements PipMenuController {
private void fadeOutMenu() {
final boolean isMenuVisible = isMenuVisible();
if (DEBUG) {
- Log.d(TAG, "fadeOutMenu() isMenuVisible=" + isMenuVisible);
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: fadeOutMenu() isMenuVisible=%b", TAG, isMenuVisible);
}
if (isMenuVisible) {
mPipMenuView.fadeOutMenu();
@@ -436,11 +442,14 @@ public class PhonePipMenuController implements PipMenuController {
public void hideMenu(@PipMenuView.AnimationType int animationType, boolean resize) {
final boolean isMenuVisible = isMenuVisible();
if (DEBUG) {
- Log.d(TAG, "hideMenu() state=" + mMenuState
- + " isMenuVisible=" + isMenuVisible
- + " animationType=" + animationType
- + " resize=" + resize
- + " callers=\n" + Debug.getCallers(5, " "));
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: hideMenu() state=%s"
+ + " isMenuVisible=%s"
+ + " animationType=%s"
+ + " resize=%s"
+ + " callers=\n%s", TAG, mMenuState, isMenuVisible,
+ animationType, resize,
+ Debug.getCallers(5, " "));
}
if (isMenuVisible) {
mPipMenuView.hideMenu(resize, animationType);
@@ -465,7 +474,8 @@ public class PhonePipMenuController implements PipMenuController {
* Sets the menu actions to the actions provided by the current PiP menu.
*/
@Override
- public void setAppActions(ParceledListSlice<RemoteAction> appActions) {
+ public void setAppActions(ParceledListSlice<RemoteAction> appActions,
+ RemoteAction closeAction) {
mAppActions = appActions;
updateMenuActions();
}
@@ -516,9 +526,11 @@ public class PhonePipMenuController implements PipMenuController {
*/
void onMenuStateChangeStart(int menuState, boolean resize, Runnable callback) {
if (DEBUG) {
- Log.d(TAG, "onMenuStateChangeStart() mMenuState=" + mMenuState
- + " menuState=" + menuState + " resize=" + resize
- + " callers=\n" + Debug.getCallers(5, " "));
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: onMenuStateChangeStart() mMenuState=%s"
+ + " menuState=%s resize=%s"
+ + " callers=\n%s", TAG, mMenuState, menuState, resize,
+ Debug.getCallers(5, " "));
}
if (menuState != mMenuState) {
@@ -538,7 +550,8 @@ public class PhonePipMenuController implements PipMenuController {
mSystemWindows.getFocusGrantToken(mPipMenuView),
menuState != MENU_STATE_NONE /* grantFocus */);
} catch (RemoteException e) {
- Log.e(TAG, "Unable to update focus as menu appears/disappears", e);
+ ProtoLog.e(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: Unable to update focus as menu appears/disappears, %s", TAG, e);
}
}
}
@@ -584,9 +597,11 @@ public class PhonePipMenuController implements PipMenuController {
public void updateMenuLayout(Rect bounds) {
final boolean isMenuVisible = isMenuVisible();
if (DEBUG) {
- Log.d(TAG, "updateMenuLayout() state=" + mMenuState
- + " isMenuVisible=" + isMenuVisible
- + " callers=\n" + Debug.getCallers(5, " "));
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: updateMenuLayout() state=%s"
+ + " isMenuVisible=%s"
+ + " callers=\n%s", TAG, mMenuState, isMenuVisible,
+ Debug.getCallers(5, " "));
}
if (isMenuVisible) {
mPipMenuView.updateMenuLayout(bounds);
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 d3dc91515921..e86ebaaabbfe 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
@@ -46,10 +46,8 @@ import android.graphics.Rect;
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
-import android.util.Log;
import android.util.Pair;
import android.util.Size;
-import android.util.Slog;
import android.view.DisplayInfo;
import android.view.SurfaceControl;
import android.view.WindowManagerGlobal;
@@ -61,6 +59,7 @@ import androidx.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.jank.InteractionJankMonitor;
+import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.R;
import com.android.wm.shell.WindowManagerShellWrapper;
import com.android.wm.shell.common.DisplayChangeController;
@@ -85,6 +84,7 @@ import com.android.wm.shell.pip.PipSnapAlgorithm;
import com.android.wm.shell.pip.PipTaskOrganizer;
import com.android.wm.shell.pip.PipTransitionController;
import com.android.wm.shell.pip.PipUtils;
+import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.transition.Transitions;
import java.io.PrintWriter;
@@ -246,8 +246,9 @@ public class PipController implements PipTransitionController.PipTransitionCallb
}
@Override
- public void onActionsChanged(ParceledListSlice<RemoteAction> actions) {
- mMenuController.setAppActions(actions);
+ public void onActionsChanged(ParceledListSlice<RemoteAction> actions,
+ RemoteAction closeAction) {
+ mMenuController.setAppActions(actions, closeAction);
}
@Override
@@ -282,7 +283,8 @@ public class PipController implements PipTransitionController.PipTransitionCallb
Optional<OneHandedController> oneHandedController,
ShellExecutor mainExecutor) {
if (!context.getPackageManager().hasSystemFeature(FEATURE_PICTURE_IN_PICTURE)) {
- Slog.w(TAG, "Device doesn't support Pip feature");
+ ProtoLog.w(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: Device doesn't support Pip feature", TAG);
return null;
}
@@ -375,7 +377,8 @@ public class PipController implements PipTransitionController.PipTransitionCallb
try {
mWindowManagerShellWrapper.addPinnedStackListener(mPinnedTaskListener);
} catch (RemoteException e) {
- Slog.e(TAG, "Failed to register pinned stack listener", e);
+ ProtoLog.e(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: Failed to register pinned stack listener, %s", TAG, e);
}
try {
@@ -387,7 +390,8 @@ public class PipController implements PipTransitionController.PipTransitionCallb
mPipInputConsumer.registerInputConsumer();
}
} catch (RemoteException | UnsupportedOperationException e) {
- Log.e(TAG, "Failed to register pinned stack listener", e);
+ ProtoLog.e(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: Failed to register pinned stack listener, %s", TAG, e);
e.printStackTrace();
}
@@ -592,9 +596,9 @@ public class PipController implements PipTransitionController.PipTransitionCallb
return entryBounds;
}
- private void stopSwipePipToHome(ComponentName componentName, Rect destinationBounds,
+ private void stopSwipePipToHome(int taskId, ComponentName componentName, Rect destinationBounds,
SurfaceControl overlay) {
- mPipTaskOrganizer.stopSwipePipToHome(componentName, destinationBounds, overlay);
+ mPipTaskOrganizer.stopSwipePipToHome(taskId, componentName, destinationBounds, overlay);
}
private String getTransitionTag(int direction) {
@@ -724,7 +728,8 @@ public class PipController implements PipTransitionController.PipTransitionCallb
.getRootTaskInfo(WINDOWING_MODE_PINNED, ACTIVITY_TYPE_UNDEFINED);
if (pinnedTaskInfo == null) return false;
} catch (RemoteException e) {
- Log.e(TAG, "Failed to get RootTaskInfo for pinned task", e);
+ ProtoLog.e(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: Failed to get RootTaskInfo for pinned task, %s", TAG, e);
return false;
}
final PipSnapAlgorithm pipSnapAlgorithm = mPipBoundsAlgorithm.getSnapAlgorithm();
@@ -870,7 +875,8 @@ public class PipController implements PipTransitionController.PipTransitionCallb
PipController.this.dump(pw);
});
} catch (InterruptedException e) {
- Slog.e(TAG, "Failed to dump PipController in 2s");
+ ProtoLog.e(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: Failed to dump PipController in 2s", TAG);
}
}
}
@@ -923,11 +929,12 @@ public class PipController implements PipTransitionController.PipTransitionCallb
}
@Override
- public void stopSwipePipToHome(ComponentName componentName, Rect destinationBounds,
- SurfaceControl overlay) {
+ public void stopSwipePipToHome(int taskId, ComponentName componentName,
+ Rect destinationBounds, SurfaceControl overlay) {
executeRemoteCallWithTaskPermission(mController, "stopSwipePipToHome",
(controller) -> {
- controller.stopSwipePipToHome(componentName, destinationBounds, overlay);
+ controller.stopSwipePipToHome(taskId, componentName, destinationBounds,
+ overlay);
});
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDismissTargetHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDismissTargetHandler.java
index 3115f8afde3b..11633a91e8c6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDismissTargetHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDismissTargetHandler.java
@@ -253,11 +253,11 @@ public class PipDismissTargetHandler implements ViewTreeObserver.OnPreDrawListen
private WindowManager.LayoutParams getDismissTargetLayoutParams() {
final Point windowSize = new Point();
mWindowManager.getDefaultDisplay().getRealSize(windowSize);
-
+ int height = Math.min(windowSize.y, mDismissAreaHeight);
final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
WindowManager.LayoutParams.MATCH_PARENT,
- mDismissAreaHeight,
- 0, windowSize.y - mDismissAreaHeight,
+ height,
+ 0, windowSize.y - height,
WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
| WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
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 6e3a20d5f2b2..0f3ff36601fb 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
@@ -22,14 +22,15 @@ import android.os.Binder;
import android.os.IBinder;
import android.os.Looper;
import android.os.RemoteException;
-import android.util.Log;
import android.view.BatchedInputEventReceiver;
import android.view.Choreographer;
import android.view.IWindowManager;
import android.view.InputChannel;
import android.view.InputEvent;
+import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.common.ShellExecutor;
+import com.android.wm.shell.protolog.ShellProtoLogGroup;
import java.io.PrintWriter;
@@ -141,11 +142,13 @@ public class PipInputConsumer {
mWindowManager.destroyInputConsumer(mName, DEFAULT_DISPLAY);
mWindowManager.createInputConsumer(mToken, mName, DEFAULT_DISPLAY, inputChannel);
} catch (RemoteException e) {
- Log.e(TAG, "Failed to create input consumer", e);
+ ProtoLog.e(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: Failed to create input consumer, %s", TAG, e);
}
mMainExecutor.execute(() -> {
// Choreographer.getSfInstance() 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());
if (mRegistrationListener != null) {
@@ -165,7 +168,8 @@ public class PipInputConsumer {
// TODO(b/113087003): Support Picture-in-picture in multi-display.
mWindowManager.destroyInputConsumer(mName, DEFAULT_DISPLAY);
} catch (RemoteException e) {
- Log.e(TAG, "Failed to destroy input consumer", e);
+ ProtoLog.e(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: Failed to destroy input consumer, %s", TAG, e);
}
mInputEventReceiver.dispose();
mInputEventReceiver = null;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java
index 225305bd5178..c0fa8c0a8898 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java
@@ -47,7 +47,6 @@ import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.UserHandle;
-import android.util.Log;
import android.util.Pair;
import android.util.Size;
import android.view.KeyEvent;
@@ -60,11 +59,13 @@ import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
+import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.R;
import com.android.wm.shell.animation.Interpolators;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.pip.PipUiEventLogger;
import com.android.wm.shell.pip.PipUtils;
+import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.splitscreen.SplitScreenController;
import java.lang.annotation.Retention;
@@ -423,7 +424,7 @@ public class PipMenuView extends FrameLayout {
/**
* @return Estimated minimum {@link Size} to hold the actions.
- * See also {@link #updateActionViews(Rect)}
+ * See also {@link #updateActionViews(Rect)}
*/
Size getEstimatedMinMenuSize() {
final int pipActionSize = getResources().getDimensionPixelSize(R.dimen.pip_action_size);
@@ -505,7 +506,8 @@ public class PipMenuView extends FrameLayout {
try {
action.getActionIntent().send();
} catch (CanceledException e) {
- Log.w(TAG, "Failed to send action", e);
+ ProtoLog.w(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: Failed to send action, %s", TAG, e);
}
});
}
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 96fd59f0c911..fa0f0925a08a 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
@@ -34,12 +34,12 @@ import android.graphics.PointF;
import android.graphics.Rect;
import android.os.Debug;
import android.os.Looper;
-import android.util.Log;
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;
import com.android.wm.shell.animation.FloatProperties;
import com.android.wm.shell.animation.PhysicsAnimator;
@@ -49,6 +49,7 @@ import com.android.wm.shell.pip.PipBoundsState;
import com.android.wm.shell.pip.PipSnapAlgorithm;
import com.android.wm.shell.pip.PipTaskOrganizer;
import com.android.wm.shell.pip.PipTransitionController;
+import com.android.wm.shell.protolog.ShellProtoLogGroup;
import java.util.function.Consumer;
@@ -94,6 +95,8 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
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());
}
@@ -354,8 +357,9 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
*/
private void expandLeavePip(boolean skipAnimation, boolean enterSplit) {
if (DEBUG) {
- Log.d(TAG, "exitPip: skipAnimation=" + skipAnimation
- + " callers=\n" + Debug.getCallers(5, " "));
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: exitPip: skipAnimation=%s"
+ + " callers=\n%s", TAG, skipAnimation, Debug.getCallers(5, " "));
}
cancelPhysicsAnimation();
mMenuController.hideMenu(ANIM_TYPE_NONE, false /* resize */);
@@ -368,7 +372,8 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
@Override
public void dismissPip() {
if (DEBUG) {
- Log.d(TAG, "removePip: callers=\n" + Debug.getCallers(5, " "));
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: removePip: callers=\n%s", TAG, Debug.getCallers(5, " "));
}
cancelPhysicsAnimation();
mMenuController.hideMenu(ANIM_TYPE_DISMISS, false /* resize */);
@@ -552,8 +557,10 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
*/
void animateToOffset(Rect originalBounds, int offset) {
if (DEBUG) {
- Log.d(TAG, "animateToOffset: originalBounds=" + originalBounds + " offset=" + offset
- + " callers=\n" + Debug.getCallers(5, " "));
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: animateToOffset: originalBounds=%s offset=%s"
+ + " callers=\n%s", TAG, originalBounds, offset,
+ Debug.getCallers(5, " "));
}
cancelPhysicsAnimation();
mPipTaskOrganizer.scheduleOffsetPip(originalBounds, offset, SHIFT_DURATION,
@@ -671,8 +678,9 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
*/
private void resizePipUnchecked(Rect toBounds) {
if (DEBUG) {
- Log.d(TAG, "resizePipUnchecked: toBounds=" + toBounds
- + " callers=\n" + Debug.getCallers(5, " "));
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: resizePipUnchecked: toBounds=%s"
+ + " callers=\n%s", TAG, toBounds, Debug.getCallers(5, " "));
}
if (!toBounds.equals(getBounds())) {
mPipTaskOrganizer.scheduleResizePip(toBounds, mUpdateBoundsCallback);
@@ -684,8 +692,10 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
*/
private void resizeAndAnimatePipUnchecked(Rect toBounds, int duration) {
if (DEBUG) {
- Log.d(TAG, "resizeAndAnimatePipUnchecked: toBounds=" + toBounds
- + " duration=" + duration + " callers=\n" + Debug.getCallers(5, " "));
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: resizeAndAnimatePipUnchecked: toBounds=%s"
+ + " duration=%s callers=\n%s", TAG, toBounds, duration,
+ Debug.getCallers(5, " "));
}
// Intentionally resize here even if the current bounds match the destination bounds.
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 c816f18c2fc2..abf1a9500e6d 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,6 +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());
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
index 350f2856e2bc..147a272f4645 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
@@ -35,7 +35,6 @@ import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.Rect;
import android.provider.DeviceConfig;
-import android.util.Log;
import android.util.Size;
import android.view.InputEvent;
import android.view.MotionEvent;
@@ -46,6 +45,7 @@ import android.view.accessibility.AccessibilityNodeInfo;
import android.view.accessibility.AccessibilityWindowInfo;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.R;
import com.android.wm.shell.common.FloatingContentCoordinator;
import com.android.wm.shell.common.ShellExecutor;
@@ -54,6 +54,7 @@ import com.android.wm.shell.pip.PipBoundsAlgorithm;
import com.android.wm.shell.pip.PipBoundsState;
import com.android.wm.shell.pip.PipTaskOrganizer;
import com.android.wm.shell.pip.PipUiEventLogger;
+import com.android.wm.shell.protolog.ShellProtoLogGroup;
import java.io.PrintWriter;
@@ -1010,7 +1011,8 @@ public class PipTouchHandler {
}
final Size estimatedMinMenuSize = mMenuController.getEstimatedMinMenuSize();
if (estimatedMinMenuSize == null) {
- Log.wtf(TAG, "Failed to get estimated menu size");
+ ProtoLog.wtf(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: Failed to get estimated menu size", TAG);
return false;
}
final Rect currentBounds = mPipBoundsState.getBounds();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchState.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchState.java
index 53303ff2b679..d7d69f27f9f8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchState.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchState.java
@@ -17,15 +17,15 @@
package com.android.wm.shell.pip.phone;
import android.graphics.PointF;
-import android.os.Handler;
-import android.util.Log;
import android.view.Display;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.ViewConfiguration;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.common.ShellExecutor;
+import com.android.wm.shell.protolog.ShellProtoLogGroup;
import java.io.PrintWriter;
@@ -104,7 +104,8 @@ public class PipTouchState {
mActivePointerId = ev.getPointerId(0);
if (DEBUG) {
- Log.e(TAG, "Setting active pointer id on DOWN: " + mActivePointerId);
+ ProtoLog.e(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: Setting active pointer id on DOWN: %d", TAG, mActivePointerId);
}
mLastTouch.set(ev.getRawX(), ev.getRawY());
mDownTouch.set(mLastTouch);
@@ -131,7 +132,8 @@ public class PipTouchState {
addMovementToVelocityTracker(ev);
int pointerIndex = ev.findPointerIndex(mActivePointerId);
if (pointerIndex == -1) {
- Log.e(TAG, "Invalid active pointer id on MOVE: " + mActivePointerId);
+ ProtoLog.e(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: Invalid active pointer id on MOVE: %d", TAG, mActivePointerId);
break;
}
@@ -168,8 +170,9 @@ public class PipTouchState {
final int newPointerIndex = (pointerIndex == 0) ? 1 : 0;
mActivePointerId = ev.getPointerId(newPointerIndex);
if (DEBUG) {
- Log.e(TAG,
- "Relinquish active pointer id on POINTER_UP: " + mActivePointerId);
+ ProtoLog.e(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: Relinquish active pointer id on POINTER_UP: %d",
+ TAG, mActivePointerId);
}
mLastTouch.set(ev.getRawX(newPointerIndex), ev.getRawY(newPointerIndex));
}
@@ -189,7 +192,8 @@ public class PipTouchState {
int pointerIndex = ev.findPointerIndex(mActivePointerId);
if (pointerIndex == -1) {
- Log.e(TAG, "Invalid active pointer id on UP: " + mActivePointerId);
+ ProtoLog.e(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: Invalid active pointer id on UP: %d", TAG, mActivePointerId);
break;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsAlgorithm.java
index 8ab78e64e2f6..d6dacd14f536 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsAlgorithm.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsAlgorithm.java
@@ -28,15 +28,22 @@ import static com.android.wm.shell.pip.tv.TvPipBoundsState.ORIENTATION_VERTICAL;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Rect;
-import android.util.Log;
+import android.os.SystemClock;
+import android.util.ArraySet;
import android.util.Size;
import android.view.Gravity;
import androidx.annotation.NonNull;
+import com.android.internal.protolog.common.ProtoLog;
+import com.android.wm.shell.R;
import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.pip.PipBoundsAlgorithm;
import com.android.wm.shell.pip.PipSnapAlgorithm;
+import com.android.wm.shell.pip.tv.TvPipKeepClearAlgorithm.Placement;
+import com.android.wm.shell.protolog.ShellProtoLogGroup;
+
+import java.util.Set;
/**
* Contains pip bounds calculations that are specific to TV.
@@ -46,91 +53,148 @@ public class TvPipBoundsAlgorithm extends PipBoundsAlgorithm {
private static final String TAG = TvPipBoundsAlgorithm.class.getSimpleName();
private static final boolean DEBUG = TvPipController.DEBUG;
- private final @android.annotation.NonNull TvPipBoundsState mTvPipBoundsState;
+ private final @NonNull TvPipBoundsState mTvPipBoundsState;
private int mFixedExpandedHeightInPx;
private int mFixedExpandedWidthInPx;
+ private final TvPipKeepClearAlgorithm mKeepClearAlgorithm;
+
public TvPipBoundsAlgorithm(Context context,
@NonNull TvPipBoundsState tvPipBoundsState,
@NonNull PipSnapAlgorithm pipSnapAlgorithm) {
super(context, tvPipBoundsState, pipSnapAlgorithm);
this.mTvPipBoundsState = tvPipBoundsState;
+ this.mKeepClearAlgorithm = new TvPipKeepClearAlgorithm(SystemClock::uptimeMillis);
+ reloadResources(context);
}
- @Override
- protected void reloadResources(Context context) {
- super.reloadResources(context);
+ private void reloadResources(Context context) {
final Resources res = context.getResources();
mFixedExpandedHeightInPx = res.getDimensionPixelSize(
com.android.internal.R.dimen.config_pictureInPictureExpandedHorizontalHeight);
mFixedExpandedWidthInPx = res.getDimensionPixelSize(
com.android.internal.R.dimen.config_pictureInPictureExpandedVerticalWidth);
+ mKeepClearAlgorithm.setPipAreaPadding(
+ res.getDimensionPixelSize(R.dimen.pip_keep_clear_area_padding));
+ mKeepClearAlgorithm.setMaxRestrictedDistanceFraction(
+ res.getFraction(R.fraction.config_pipMaxRestrictedMoveDistance, 1, 1));
+ mKeepClearAlgorithm.setStashDuration(res.getInteger(R.integer.config_pipStashDuration));
+ }
+
+ @Override
+ public void onConfigurationChanged(Context context) {
+ super.onConfigurationChanged(context);
+ reloadResources(context);
}
/** Returns the destination bounds to place the PIP window on entry. */
@Override
public Rect getEntryDestinationBounds() {
- if (DEBUG) Log.d(TAG, "getEntryDestinationBounds()");
- if (mTvPipBoundsState.getTvExpandedAspectRatio() != 0
+ if (DEBUG) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: getEntryDestinationBounds()", TAG);
+ }
+ if (mTvPipBoundsState.isTvExpandedPipSupported()
+ && mTvPipBoundsState.getDesiredTvExpandedAspectRatio() != 0
&& !mTvPipBoundsState.isTvPipManuallyCollapsed()) {
- updatePositionOnExpandToggled(Gravity.NO_GRAVITY, true);
+ updateExpandedPipSize();
+ updateGravityOnExpandToggled(Gravity.NO_GRAVITY, true);
+ mTvPipBoundsState.setTvPipExpanded(true);
}
- return getTvPipBounds(true);
+ return getTvPipBounds().getBounds();
}
/** Returns the current bounds adjusted to the new aspect ratio, if valid. */
@Override
public Rect getAdjustedDestinationBounds(Rect currentBounds, float newAspectRatio) {
- if (DEBUG) Log.d(TAG, "getAdjustedDestinationBounds: " + newAspectRatio);
- return getTvPipBounds(mTvPipBoundsState.isTvPipExpanded());
+ if (DEBUG) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: getAdjustedDestinationBounds: %f", TAG, newAspectRatio);
+ }
+ return getTvPipBounds().getBounds();
}
/**
- * The normal bounds at a different position on the screen.
+ * Calculates the PiP bounds.
*/
- public Rect getTvNormalBounds() {
- Rect normalBounds = getNormalBounds();
- Rect insetBounds = new Rect();
+ public Placement getTvPipBounds() {
+ final Size pipSize = getPipSize();
+ final Rect displayBounds = mTvPipBoundsState.getDisplayBounds();
+ final Size screenSize = new Size(displayBounds.width(), displayBounds.height());
+ final Rect insetBounds = new Rect();
getInsetBounds(insetBounds);
+ Set<Rect> restrictedKeepClearAreas = mTvPipBoundsState.getRestrictedKeepClearAreas();
+ Set<Rect> unrestrictedKeepClearAreas = mTvPipBoundsState.getUnrestrictedKeepClearAreas();
+
if (mTvPipBoundsState.isImeShowing()) {
- if (DEBUG) Log.d(TAG, "IME showing, height: " + mTvPipBoundsState.getImeHeight());
- insetBounds.bottom -= mTvPipBoundsState.getImeHeight();
+ if (DEBUG) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: IME showing, height: %d",
+ TAG, mTvPipBoundsState.getImeHeight());
+ }
+
+ final Rect imeBounds = new Rect(
+ 0,
+ insetBounds.bottom - mTvPipBoundsState.getImeHeight(),
+ insetBounds.right,
+ insetBounds.bottom);
+
+ unrestrictedKeepClearAreas = new ArraySet<>(unrestrictedKeepClearAreas);
+ unrestrictedKeepClearAreas.add(imeBounds);
}
- Rect result = new Rect();
- Gravity.apply(mTvPipBoundsState.getTvPipGravity(), normalBounds.width(),
- normalBounds.height(), insetBounds, result);
+ mKeepClearAlgorithm.setGravity(mTvPipBoundsState.getTvPipGravity());
+ mKeepClearAlgorithm.setScreenSize(screenSize);
+ mKeepClearAlgorithm.setMovementBounds(insetBounds);
+ mKeepClearAlgorithm.setStashOffset(mTvPipBoundsState.getStashOffset());
+
+ final Placement placement = mKeepClearAlgorithm.calculatePipPosition(
+ pipSize,
+ restrictedKeepClearAreas,
+ unrestrictedKeepClearAreas);
if (DEBUG) {
- Log.d(TAG, "normalBounds: " + normalBounds.toShortString());
- Log.d(TAG, "insetBounds: " + insetBounds.toShortString());
- Log.d(TAG, "gravity: " + Gravity.toString(mTvPipBoundsState.getTvPipGravity()));
- Log.d(TAG, "resultBounds: " + result.toShortString());
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: screenSize: %s", TAG, screenSize);
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: stashOffset: %d", TAG, mTvPipBoundsState.getStashOffset());
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: insetBounds: %s", TAG, insetBounds.toShortString());
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: pipSize: %s", TAG, pipSize);
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: gravity: %s", TAG, Gravity.toString(mTvPipBoundsState.getTvPipGravity()));
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: restrictedKeepClearAreas: %s", TAG, restrictedKeepClearAreas);
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: unrestrictedKeepClearAreas: %s", TAG, unrestrictedKeepClearAreas);
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: placement: %s", TAG, placement);
}
- mTvPipBoundsState.setTvPipExpanded(false);
-
- return result;
+ return placement;
}
/**
- * @return previous gravity if it is to be saved, or Gravity.NO_GRAVITY if not.
+ * @return previous gravity if it is to be saved, or {@link Gravity#NO_GRAVITY} if not.
*/
- int updatePositionOnExpandToggled(int previousGravity, boolean expanding) {
+ int updateGravityOnExpandToggled(int previousGravity, boolean expanding) {
if (DEBUG) {
- Log.d(TAG, "updatePositionOnExpandToggle(), expanding: " + expanding
- + ", mOrientation: " + mTvPipBoundsState.getTvFixedPipOrientation()
- + ", previous gravity: " + Gravity.toString(previousGravity));
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: updateGravityOnExpandToggled(), expanding: %b"
+ + ", mOrientation: %d, previous gravity: %s",
+ TAG, expanding, mTvPipBoundsState.getTvFixedPipOrientation(),
+ Gravity.toString(previousGravity));
}
- if (!mTvPipBoundsState.isTvExpandedPipEnabled()) {
+ if (!mTvPipBoundsState.isTvExpandedPipSupported()) {
return Gravity.NO_GRAVITY;
}
if (expanding && mTvPipBoundsState.getTvFixedPipOrientation() == ORIENTATION_UNDETERMINED) {
- float expandedRatio = mTvPipBoundsState.getTvExpandedAspectRatio();
+ float expandedRatio = mTvPipBoundsState.getDesiredTvExpandedAspectRatio();
if (expandedRatio == 0) {
return Gravity.NO_GRAVITY;
}
@@ -139,7 +203,6 @@ public class TvPipBoundsAlgorithm extends PipBoundsAlgorithm {
} else {
mTvPipBoundsState.setTvFixedPipOrientation(ORIENTATION_HORIZONTAL);
}
-
}
int gravityToSave = Gravity.NO_GRAVITY;
@@ -175,16 +238,22 @@ public class TvPipBoundsAlgorithm extends PipBoundsAlgorithm {
}
}
mTvPipBoundsState.setTvPipGravity(updatedGravity);
- if (DEBUG) Log.d(TAG, "new gravity: " + Gravity.toString(updatedGravity));
+ if (DEBUG) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: new gravity: %s", TAG, Gravity.toString(updatedGravity));
+ }
return gravityToSave;
}
/**
- * @return true if position changed
+ * @return true if gravity changed
*/
- boolean updatePosition(int keycode) {
- if (DEBUG) Log.d(TAG, "updatePosition, keycode: " + keycode);
+ boolean updateGravity(int keycode) {
+ if (DEBUG) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: updateGravity, keycode: %d", TAG, keycode);
+ }
// Check if position change is valid
if (mTvPipBoundsState.isTvPipExpanded()) {
@@ -241,32 +310,42 @@ public class TvPipBoundsAlgorithm extends PipBoundsAlgorithm {
if (updatedGravity != currentGravity) {
mTvPipBoundsState.setTvPipGravity(updatedGravity);
- if (DEBUG) Log.d(TAG, "new gravity: " + Gravity.toString(updatedGravity));
+ if (DEBUG) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: new gravity: %s", TAG, Gravity.toString(updatedGravity));
+ }
return true;
}
return false;
}
- /**
- * Calculates the PiP bounds.
- */
- public Rect getTvPipBounds(boolean expandedIfPossible) {
- if (DEBUG) {
- Log.d(TAG, "getExpandedBoundsIfPossible with gravity "
- + Gravity.toString(mTvPipBoundsState.getTvPipGravity())
- + ", fixed orientation: " + mTvPipBoundsState.getTvFixedPipOrientation());
+ private Size getPipSize() {
+ final boolean isExpanded =
+ mTvPipBoundsState.isTvExpandedPipSupported() && mTvPipBoundsState.isTvPipExpanded()
+ && mTvPipBoundsState.getDesiredTvExpandedAspectRatio() != 0;
+ if (isExpanded) {
+ return mTvPipBoundsState.getTvExpandedSize();
+ } else {
+ final Rect normalBounds = getNormalBounds();
+ return new Size(normalBounds.width(), normalBounds.height());
}
+ }
- if (!mTvPipBoundsState.isTvExpandedPipEnabled() || !expandedIfPossible) {
- return getTvNormalBounds();
- }
+ /**
+ * Updates {@link TvPipBoundsState#getTvExpandedSize()} based on
+ * {@link TvPipBoundsState#getDesiredTvExpandedAspectRatio()}, the screen size.
+ */
+ void updateExpandedPipSize() {
+ final DisplayLayout displayLayout = mTvPipBoundsState.getDisplayLayout();
+ final float expandedRatio =
+ mTvPipBoundsState.getDesiredTvExpandedAspectRatio(); // width / height
- DisplayLayout displayLayout = mTvPipBoundsState.getDisplayLayout();
- float expandedRatio = mTvPipBoundsState.getTvExpandedAspectRatio(); // width / height
- Size expandedSize;
+ final Size expandedSize;
if (expandedRatio == 0) {
- Log.d(TAG, "Expanded mode not supported");
- return getTvNormalBounds();
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: updateExpandedPipSize(): Expanded mode aspect ratio"
+ + " of 0 not supported", TAG);
+ return;
} else if (expandedRatio < 1) {
// vertical
if (mTvPipBoundsState.getTvFixedPipOrientation() == ORIENTATION_HORIZONTAL) {
@@ -276,10 +355,16 @@ public class TvPipBoundsAlgorithm extends PipBoundsAlgorithm {
float aspectRatioHeight = mFixedExpandedWidthInPx / expandedRatio;
if (maxHeight > aspectRatioHeight) {
- if (DEBUG) Log.d(TAG, "Accommodate aspect ratio");
+ if (DEBUG) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: Accommodate aspect ratio", TAG);
+ }
expandedSize = new Size(mFixedExpandedWidthInPx, (int) aspectRatioHeight);
} else {
- if (DEBUG) Log.d(TAG, "Aspect ratio is too extreme, use max size");
+ if (DEBUG) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: Aspect ratio is too extreme, use max size", TAG);
+ }
expandedSize = new Size(mFixedExpandedWidthInPx, maxHeight);
}
}
@@ -291,35 +376,30 @@ public class TvPipBoundsAlgorithm extends PipBoundsAlgorithm {
int maxWidth = displayLayout.width() - (2 * mScreenEdgeInsets.x);
float aspectRatioWidth = mFixedExpandedHeightInPx * expandedRatio;
if (maxWidth > aspectRatioWidth) {
- if (DEBUG) Log.d(TAG, "Accommodate aspect ratio");
+ if (DEBUG) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: Accommodate aspect ratio", TAG);
+ }
expandedSize = new Size((int) aspectRatioWidth, mFixedExpandedHeightInPx);
} else {
- if (DEBUG) Log.d(TAG, "Aspect ratio is too extreme, use max size");
+ if (DEBUG) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: Aspect ratio is too extreme, use max size", TAG);
+ }
expandedSize = new Size(maxWidth, mFixedExpandedHeightInPx);
}
}
}
- if (expandedSize == null) {
- return getTvNormalBounds();
- }
-
+ mTvPipBoundsState.setTvExpandedSize(expandedSize);
if (DEBUG) {
- Log.d(TAG, "expanded size, width: " + expandedSize.getWidth()
- + ", height: " + expandedSize.getHeight());
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: updateExpandedPipSize(): expanded size, width: %d, height: %d",
+ TAG, expandedSize.getWidth(), expandedSize.getHeight());
}
-
- Rect insetBounds = new Rect();
- getInsetBounds(insetBounds);
-
- Rect expandedBounds = new Rect();
- Gravity.apply(mTvPipBoundsState.getTvPipGravity(), expandedSize.getWidth(),
- expandedSize.getHeight(), insetBounds, expandedBounds);
- if (DEBUG) Log.d(TAG, "expanded bounds: " + expandedBounds.toShortString());
-
- mTvPipBoundsState.setTvExpandedSize(expandedSize);
- mTvPipBoundsState.setTvPipExpanded(true);
- return expandedBounds;
}
+ void keepUnstashedForCurrentKeepClearAreas() {
+ mKeepClearAlgorithm.keepUnstashedForCurrentKeepClearAreas();
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsState.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsState.java
index 9370e33fce65..986554853034 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsState.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsState.java
@@ -53,10 +53,10 @@ public class TvPipBoundsState extends PipBoundsState {
public static final int DEFAULT_TV_GRAVITY = Gravity.BOTTOM | Gravity.RIGHT;
- private boolean mIsTvExpandedPipEnabled;
+ private final boolean mIsTvExpandedPipSupported;
private boolean mIsTvPipExpanded;
private boolean mTvPipManuallyCollapsed;
- private float mTvExpandedAspectRatio;
+ private float mDesiredTvExpandedAspectRatio;
private @Orientation int mTvFixedPipOrientation;
private int mTvPipGravity;
private @Nullable Size mTvExpandedSize;
@@ -64,8 +64,8 @@ public class TvPipBoundsState extends PipBoundsState {
public TvPipBoundsState(@NonNull Context context) {
super(context);
- setIsTvExpandedPipEnabled(context.getPackageManager().hasSystemFeature(
- PackageManager.FEATURE_EXPANDED_PICTURE_IN_PICTURE));
+ mIsTvExpandedPipSupported = context.getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_EXPANDED_PICTURE_IN_PICTURE);
}
/**
@@ -75,7 +75,7 @@ public class TvPipBoundsState extends PipBoundsState {
public void setBoundsStateForEntry(ComponentName componentName, ActivityInfo activityInfo,
PictureInPictureParams params, PipBoundsAlgorithm pipBoundsAlgorithm) {
super.setBoundsStateForEntry(componentName, activityInfo, params, pipBoundsAlgorithm);
- setTvExpandedAspectRatio(params.getExpandedAspectRatio(), true);
+ setDesiredTvExpandedAspectRatio(params.getExpandedAspectRatioFloat(), true);
}
/** Resets the TV PiP state for a new activity. */
@@ -85,32 +85,32 @@ public class TvPipBoundsState extends PipBoundsState {
}
/** Set the tv expanded bounds of PIP */
- public void setTvExpandedSize(@Nullable Size bounds) {
- mTvExpandedSize = bounds;
+ public void setTvExpandedSize(@Nullable Size size) {
+ mTvExpandedSize = size;
}
- /** Get the PIP tv expanded bounds. */
+ /** Get the expanded size of the PiP. */
@Nullable
public Size getTvExpandedSize() {
return mTvExpandedSize;
}
/** Set the PIP aspect ratio for the expanded PIP (TV) that is desired by the app. */
- public void setTvExpandedAspectRatio(float aspectRatio, boolean override) {
+ public void setDesiredTvExpandedAspectRatio(float aspectRatio, boolean override) {
if (override || mTvFixedPipOrientation == ORIENTATION_UNDETERMINED || aspectRatio == 0) {
- mTvExpandedAspectRatio = aspectRatio;
+ mDesiredTvExpandedAspectRatio = aspectRatio;
resetTvPipState();
return;
}
if ((aspectRatio > 1 && mTvFixedPipOrientation == ORIENTATION_HORIZONTAL)
|| (aspectRatio <= 1 && mTvFixedPipOrientation == ORIENTATION_VERTICAL)) {
- mTvExpandedAspectRatio = aspectRatio;
+ mDesiredTvExpandedAspectRatio = aspectRatio;
}
}
/** Get the PIP aspect ratio for the expanded PIP (TV) that is desired by the app. */
- public float getTvExpandedAspectRatio() {
- return mTvExpandedAspectRatio;
+ public float getDesiredTvExpandedAspectRatio() {
+ return mDesiredTvExpandedAspectRatio;
}
/** Sets the orientation the expanded TV PiP activity has been fixed to. */
@@ -154,13 +154,9 @@ public class TvPipBoundsState extends PipBoundsState {
return mTvPipManuallyCollapsed;
}
- /** Sets whether expanded PiP is supported by the device. */
- public void setIsTvExpandedPipEnabled(boolean enabled) {
- mIsTvExpandedPipEnabled = enabled;
- }
-
/** Returns whether expanded PiP is supported by the device. */
- public boolean isTvExpandedPipEnabled() {
- return mIsTvExpandedPipEnabled;
+ public boolean isTvExpandedPipSupported() {
+ return mIsTvExpandedPipSupported;
}
+
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java
index 3c830e0a0d62..917eaa061d1b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java
@@ -22,6 +22,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import android.annotation.IntDef;
import android.app.ActivityManager;
import android.app.ActivityTaskManager;
+import android.app.PendingIntent;
import android.app.RemoteAction;
import android.app.TaskInfo;
import android.content.ComponentName;
@@ -30,11 +31,11 @@ import android.content.pm.ParceledListSlice;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Rect;
+import android.os.Handler;
import android.os.RemoteException;
-import android.util.Log;
-import android.view.DisplayInfo;
import android.view.Gravity;
+import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.R;
import com.android.wm.shell.WindowManagerShellWrapper;
import com.android.wm.shell.common.DisplayController;
@@ -45,9 +46,12 @@ import com.android.wm.shell.common.TaskStackListenerImpl;
import com.android.wm.shell.pip.PinnedStackListenerForwarder;
import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.pip.PipAnimationController;
+import com.android.wm.shell.pip.PipBoundsState;
import com.android.wm.shell.pip.PipMediaController;
import com.android.wm.shell.pip.PipTaskOrganizer;
import com.android.wm.shell.pip.PipTransitionController;
+import com.android.wm.shell.pip.tv.TvPipKeepClearAlgorithm.Placement;
+import com.android.wm.shell.protolog.ShellProtoLogGroup;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -62,10 +66,11 @@ public class TvPipController implements PipTransitionController.PipTransitionCal
private static final String TAG = "TvPipController";
static final boolean DEBUG = false;
+ private static final double EPS = 1e-7;
private static final int NONEXISTENT_TASK_ID = -1;
@Retention(RetentionPolicy.SOURCE)
- @IntDef(prefix = { "STATE_" }, value = {
+ @IntDef(prefix = {"STATE_"}, value = {
STATE_NO_PIP,
STATE_PIP,
STATE_PIP_MENU,
@@ -97,11 +102,17 @@ public class TvPipController implements PipTransitionController.PipTransitionCal
private final TvPipNotificationController mPipNotificationController;
private final TvPipMenuController mTvPipMenuController;
private final ShellExecutor mMainExecutor;
+ private final Handler mMainHandler;
private final TvPipImpl mImpl = new TvPipImpl();
private @State int mState = STATE_NO_PIP;
private int mPreviousGravity = TvPipBoundsState.DEFAULT_TV_GRAVITY;
private int mPinnedTaskId = NONEXISTENT_TASK_ID;
+ private Runnable mUnstashRunnable;
+
+ private RemoteAction mCloseAction;
+ // How long the shell will wait for the app to close the PiP if a custom action is set.
+ private int mPipForceCloseDelay;
private int mResizeAnimationDuration;
@@ -117,7 +128,8 @@ public class TvPipController implements PipTransitionController.PipTransitionCal
TaskStackListenerImpl taskStackListener,
DisplayController displayController,
WindowManagerShellWrapper wmShell,
- ShellExecutor mainExecutor) {
+ ShellExecutor mainExecutor,
+ Handler mainHandler) {
return new TvPipController(
context,
tvPipBoundsState,
@@ -130,7 +142,8 @@ public class TvPipController implements PipTransitionController.PipTransitionCal
taskStackListener,
displayController,
wmShell,
- mainExecutor).mImpl;
+ mainExecutor,
+ mainHandler).mImpl;
}
private TvPipController(
@@ -145,9 +158,11 @@ public class TvPipController implements PipTransitionController.PipTransitionCal
TaskStackListenerImpl taskStackListener,
DisplayController displayController,
WindowManagerShellWrapper wmShell,
- ShellExecutor mainExecutor) {
+ ShellExecutor mainExecutor,
+ Handler mainHandler) {
mContext = context;
mMainExecutor = mainExecutor;
+ mMainHandler = mainHandler;
mTvPipBoundsState = tvPipBoundsState;
mTvPipBoundsState.setDisplayId(context.getDisplayId());
@@ -173,15 +188,22 @@ public class TvPipController implements PipTransitionController.PipTransitionCal
}
private void onConfigurationChanged(Configuration newConfig) {
- if (DEBUG) Log.d(TAG, "onConfigurationChanged(), state=" + stateToName(mState));
+ if (DEBUG) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: onConfigurationChanged(), state=%s", TAG, stateToName(mState));
+ }
if (isPipShown()) {
- if (DEBUG) Log.d(TAG, " > closing Pip.");
+ if (DEBUG) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: > closing Pip.", TAG);
+ }
closePip();
}
loadConfigurations();
mPipNotificationController.onConfigurationChanged(mContext);
+ mTvPipBoundsAlgorithm.onConfigurationChanged(mContext);
}
/**
@@ -198,21 +220,37 @@ public class TvPipController implements PipTransitionController.PipTransitionCal
*/
@Override
public void showPictureInPictureMenu() {
- if (DEBUG) Log.d(TAG, "showPictureInPictureMenu(), state=" + stateToName(mState));
+ if (DEBUG) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: showPictureInPictureMenu(), state=%s", TAG, stateToName(mState));
+ }
if (mState == STATE_NO_PIP) {
- if (DEBUG) Log.d(TAG, " > cannot open Menu from the current state.");
+ if (DEBUG) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: > cannot open Menu from the current state.", TAG);
+ }
return;
}
setState(STATE_PIP_MENU);
- movePinnedStack();
+ updatePinnedStackBounds();
}
@Override
public void closeMenu() {
- if (DEBUG) Log.d(TAG, "closeMenu(), state before=" + stateToName(mState));
+ if (DEBUG) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: closeMenu(), state before=%s", TAG, stateToName(mState));
+ }
setState(STATE_PIP);
+ mTvPipBoundsAlgorithm.keepUnstashedForCurrentKeepClearAreas();
+ updatePinnedStackBounds();
+ }
+
+ @Override
+ public void onInMoveModeChanged() {
+ updatePinnedStackBounds();
}
/**
@@ -220,7 +258,10 @@ public class TvPipController implements PipTransitionController.PipTransitionCal
*/
@Override
public void movePipToFullscreen() {
- if (DEBUG) Log.d(TAG, "movePipToFullscreen(), state=" + stateToName(mState));
+ if (DEBUG) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: movePipToFullscreen(), state=%s", TAG, stateToName(mState));
+ }
mPipTaskOrganizer.exitPip(mResizeAnimationDuration, false /* requestEnterSplit */);
onPipDisappeared();
@@ -228,26 +269,32 @@ public class TvPipController implements PipTransitionController.PipTransitionCal
@Override
public void togglePipExpansion() {
- if (DEBUG) Log.d(TAG, "togglePipExpansion()");
+ if (DEBUG) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: togglePipExpansion()", TAG);
+ }
boolean expanding = !mTvPipBoundsState.isTvPipExpanded();
int saveGravity = mTvPipBoundsAlgorithm
- .updatePositionOnExpandToggled(mPreviousGravity, expanding);
+ .updateGravityOnExpandToggled(mPreviousGravity, expanding);
if (saveGravity != Gravity.NO_GRAVITY) {
mPreviousGravity = saveGravity;
}
mTvPipBoundsState.setTvPipManuallyCollapsed(!expanding);
mTvPipBoundsState.setTvPipExpanded(expanding);
- movePinnedStack();
+ updatePinnedStackBounds();
}
@Override
public void movePip(int keycode) {
- if (mTvPipBoundsAlgorithm.updatePosition(keycode)) {
+ if (mTvPipBoundsAlgorithm.updateGravity(keycode)) {
mTvPipMenuController.updateGravity(mTvPipBoundsState.getTvPipGravity());
mPreviousGravity = Gravity.NO_GRAVITY;
- movePinnedStack();
+ updatePinnedStackBounds();
} else {
- if (DEBUG) Log.d(TAG, "Position hasn't changed");
+ if (DEBUG) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: Position hasn't changed", TAG);
+ }
}
}
@@ -265,23 +312,57 @@ public class TvPipController implements PipTransitionController.PipTransitionCal
Set<Rect> unrestricted) {
if (mTvPipBoundsState.getDisplayId() == displayId) {
mTvPipBoundsState.setKeepClearAreas(restricted, unrestricted);
- movePinnedStack();
+ updatePinnedStackBounds();
}
}
/**
- * Animate to the updated position of the PiP based on the state and position of the PiP.
+ * Update the PiP bounds based on the state of the PiP and keep clear areas.
+ * Animates to the current PiP bounds, and schedules unstashing the PiP if necessary.
*/
- private void movePinnedStack() {
+ private void updatePinnedStackBounds() {
if (mState == STATE_NO_PIP) {
return;
}
- Rect bounds = mTvPipBoundsAlgorithm.getTvPipBounds(mTvPipBoundsState.isTvPipExpanded());
- if (DEBUG) Log.d(TAG, "movePinnedStack() - new pip bounds: " + bounds.toShortString());
+ final boolean stayAtAnchorPosition = mTvPipMenuController.isInMoveMode();
+ final boolean disallowStashing = mState == STATE_PIP_MENU || stayAtAnchorPosition;
+ final Placement placement = mTvPipBoundsAlgorithm.getTvPipBounds();
+
+ int stashType =
+ disallowStashing ? PipBoundsState.STASH_TYPE_NONE : placement.getStashType();
+ mTvPipBoundsState.setStashed(stashType);
+
+ if (stayAtAnchorPosition) {
+ movePinnedStackTo(placement.getAnchorBounds());
+ } else if (disallowStashing) {
+ movePinnedStackTo(placement.getUnstashedBounds());
+ } else {
+ movePinnedStackTo(placement.getBounds());
+ }
+
+ if (mUnstashRunnable != null) {
+ mMainHandler.removeCallbacks(mUnstashRunnable);
+ mUnstashRunnable = null;
+ }
+ if (!disallowStashing && placement.getUnstashDestinationBounds() != null) {
+ mUnstashRunnable = () -> movePinnedStackTo(placement.getUnstashDestinationBounds());
+ mMainHandler.postAtTime(mUnstashRunnable, placement.getUnstashTime());
+ }
+ }
+
+ /** Animates the PiP to the given bounds. */
+ private void movePinnedStackTo(Rect bounds) {
+ if (DEBUG) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: movePinnedStack() - new pip bounds: %s", TAG, bounds.toShortString());
+ }
mPipTaskOrganizer.scheduleAnimateResizePip(bounds,
mResizeAnimationDuration, rect -> {
- if (DEBUG) Log.d(TAG, "movePinnedStack() animation done");
+ if (DEBUG) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: movePinnedStack() animation done", TAG);
+ }
mTvPipMenuController.updateExpansionState();
});
}
@@ -291,8 +372,31 @@ public class TvPipController implements PipTransitionController.PipTransitionCal
*/
@Override
public void closePip() {
- if (DEBUG) Log.d(TAG, "closePip(), state=" + stateToName(mState));
+ if (DEBUG) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: closePip(), state=%s, loseAction=%s", TAG, stateToName(mState),
+ mCloseAction);
+ }
+ if (mCloseAction != null) {
+ try {
+ mCloseAction.getActionIntent().send();
+ } catch (PendingIntent.CanceledException e) {
+ ProtoLog.w(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: Failed to send close action, %s", TAG, e);
+ }
+ mMainExecutor.executeDelayed(() -> closeCurrentPiP(mPinnedTaskId), mPipForceCloseDelay);
+ } else {
+ closeCurrentPiP(mPinnedTaskId);
+ }
+ }
+
+ private void closeCurrentPiP(int pinnedTaskId) {
+ if (mPinnedTaskId != pinnedTaskId) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: PiP has already been closed by custom close action", TAG);
+ return;
+ }
removeTask(mPinnedTaskId);
onPipDisappeared();
}
@@ -303,7 +407,10 @@ public class TvPipController implements PipTransitionController.PipTransitionCal
private void checkIfPinnedTaskAppeared() {
final TaskInfo pinnedTask = getPinnedTaskInfo();
- if (DEBUG) Log.d(TAG, "checkIfPinnedTaskAppeared(), task=" + pinnedTask);
+ if (DEBUG) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: checkIfPinnedTaskAppeared(), task=%s", TAG, pinnedTask);
+ }
if (pinnedTask == null || pinnedTask.topActivity == null) return;
mPinnedTaskId = pinnedTask.taskId;
@@ -312,16 +419,23 @@ public class TvPipController implements PipTransitionController.PipTransitionCal
}
private void checkIfPinnedTaskIsGone() {
- if (DEBUG) Log.d(TAG, "onTaskStackChanged()");
+ if (DEBUG) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: onTaskStackChanged()", TAG);
+ }
if (isPipShown() && getPinnedTaskInfo() == null) {
- Log.w(TAG, "Pinned task is gone.");
+ ProtoLog.w(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: Pinned task is gone.", TAG);
onPipDisappeared();
}
}
private void onPipDisappeared() {
- if (DEBUG) Log.d(TAG, "onPipDisappeared() state=" + stateToName(mState));
+ if (DEBUG) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: onPipDisappeared() state=%s", TAG, stateToName(mState));
+ }
mPipNotificationController.dismiss();
mTvPipMenuController.hideMenu();
@@ -332,12 +446,18 @@ public class TvPipController implements PipTransitionController.PipTransitionCal
@Override
public void onPipTransitionStarted(int direction, Rect pipBounds) {
- if (DEBUG) Log.d(TAG, "onPipTransition_Started(), state=" + stateToName(mState));
+ if (DEBUG) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: onPipTransition_Started(), state=%s", TAG, stateToName(mState));
+ }
}
@Override
public void onPipTransitionCanceled(int direction) {
- if (DEBUG) Log.d(TAG, "onPipTransition_Canceled(), state=" + stateToName(mState));
+ if (DEBUG) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: onPipTransition_Canceled(), state=%s", TAG, stateToName(mState));
+ }
}
@Override
@@ -345,31 +465,35 @@ public class TvPipController implements PipTransitionController.PipTransitionCal
if (PipAnimationController.isInPipDirection(direction) && mState == STATE_NO_PIP) {
setState(STATE_PIP);
}
- if (DEBUG) Log.d(TAG, "onPipTransition_Finished(), state=" + stateToName(mState));
+ if (DEBUG) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: onPipTransition_Finished(), state=%s", TAG, stateToName(mState));
+ }
}
private void setState(@State int state) {
if (DEBUG) {
- Log.d(TAG, "setState(), state=" + stateToName(state) + ", prev="
- + stateToName(mState));
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: setState(), state=%s, prev=%s",
+ TAG, stateToName(state), stateToName(mState));
}
mState = state;
if (mState == STATE_PIP_MENU) {
- if (DEBUG) Log.d(TAG, " > show menu");
+ if (DEBUG) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: > show menu", TAG);
+ }
mTvPipMenuController.showMenu();
}
+
+ updatePinnedStackBounds();
}
private void loadConfigurations() {
final Resources res = mContext.getResources();
mResizeAnimationDuration = res.getInteger(R.integer.config_pipResizeAnimationDuration);
- }
-
- private DisplayInfo getDisplayInfo() {
- final DisplayInfo displayInfo = new DisplayInfo();
- mContext.getDisplay().getDisplayInfo(displayInfo);
- return displayInfo;
+ mPipForceCloseDelay = res.getInteger(R.integer.config_pipForceCloseDelay);
}
private void registerTaskStackListenerCallback(TaskStackListenerImpl taskStackListener) {
@@ -388,7 +512,10 @@ public class TvPipController implements PipTransitionController.PipTransitionCal
public void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task,
boolean homeTaskVisible, boolean clearedTask, boolean wasVisible) {
if (task.getWindowingMode() == WINDOWING_MODE_PINNED) {
- if (DEBUG) Log.d(TAG, "onPinnedActivityRestartAttempt()");
+ if (DEBUG) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: onPinnedActivityRestartAttempt()", TAG);
+ }
// If the "Pip-ed" Activity is launched again by Launcher or intent, make it
// fullscreen.
@@ -404,8 +531,9 @@ public class TvPipController implements PipTransitionController.PipTransitionCal
@Override
public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) {
if (DEBUG) {
- Log.d(TAG, "onImeVisibilityChanged(), visible=" + imeVisible
- + ", height=" + imeHeight);
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: onImeVisibilityChanged(), visible=%b, height=%d",
+ TAG, imeVisible, imeHeight);
}
if (imeVisible == mTvPipBoundsState.isImeShowing()
@@ -417,62 +545,72 @@ public class TvPipController implements PipTransitionController.PipTransitionCal
mTvPipBoundsState.setImeVisibility(imeVisible, imeHeight);
if (mState != STATE_NO_PIP) {
- movePinnedStack();
+ updatePinnedStackBounds();
}
}
@Override
public void onAspectRatioChanged(float ratio) {
- if (DEBUG) Log.d(TAG, "onAspectRatioChanged: " + ratio);
+ if (DEBUG) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: onAspectRatioChanged: %f", TAG, ratio);
+ }
boolean ratioChanged = mTvPipBoundsState.getAspectRatio() != ratio;
mTvPipBoundsState.setAspectRatio(ratio);
if (!mTvPipBoundsState.isTvPipExpanded() && ratioChanged) {
- movePinnedStack();
+ updatePinnedStackBounds();
}
}
@Override
public void onExpandedAspectRatioChanged(float ratio) {
- if (DEBUG) Log.d(TAG, "onExpandedAspectRatioChanged: " + ratio);
+ if (DEBUG) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: onExpandedAspectRatioChanged: %f", TAG, ratio);
+ }
// 0) No update to the ratio --> don't do anything
- if (mTvPipBoundsState.getTvExpandedAspectRatio() == ratio) {
+
+ if (Math.abs(mTvPipBoundsState.getDesiredTvExpandedAspectRatio() - ratio)
+ < EPS) {
return;
}
- mTvPipBoundsState.setTvExpandedAspectRatio(ratio, false);
+ mTvPipBoundsState.setDesiredTvExpandedAspectRatio(ratio, false);
// 1) PiP is expanded and only aspect ratio changed, but wasn't disabled
// --> update bounds, but don't toggle
if (mTvPipBoundsState.isTvPipExpanded() && ratio != 0) {
- movePinnedStack();
+ mTvPipBoundsAlgorithm.updateExpandedPipSize();
+ updatePinnedStackBounds();
}
// 2) PiP is expanded, but expanded PiP was disabled
// --> collapse PiP
if (mTvPipBoundsState.isTvPipExpanded() && ratio == 0) {
int saveGravity = mTvPipBoundsAlgorithm
- .updatePositionOnExpandToggled(mPreviousGravity, false);
+ .updateGravityOnExpandToggled(mPreviousGravity, false);
if (saveGravity != Gravity.NO_GRAVITY) {
mPreviousGravity = saveGravity;
}
mTvPipBoundsState.setTvPipExpanded(false);
- movePinnedStack();
+ updatePinnedStackBounds();
}
// 3) PiP not expanded and not manually collapsed and expand was enabled
// --> expand to new ratio
if (!mTvPipBoundsState.isTvPipExpanded() && ratio != 0
&& !mTvPipBoundsState.isTvPipManuallyCollapsed()) {
+ mTvPipBoundsAlgorithm.updateExpandedPipSize();
int saveGravity = mTvPipBoundsAlgorithm
- .updatePositionOnExpandToggled(mPreviousGravity, true);
+ .updateGravityOnExpandToggled(mPreviousGravity, true);
if (saveGravity != Gravity.NO_GRAVITY) {
mPreviousGravity = saveGravity;
}
mTvPipBoundsState.setTvPipExpanded(true);
- movePinnedStack();
+ updatePinnedStackBounds();
}
}
@@ -480,36 +618,53 @@ public class TvPipController implements PipTransitionController.PipTransitionCal
public void onMovementBoundsChanged(boolean fromImeAdjustment) {}
@Override
- public void onActionsChanged(ParceledListSlice<RemoteAction> actions) {
- if (DEBUG) Log.d(TAG, "onActionsChanged()");
+ public void onActionsChanged(ParceledListSlice<RemoteAction> actions,
+ RemoteAction closeAction) {
+ if (DEBUG) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: onActionsChanged()", TAG);
+ }
- mTvPipMenuController.setAppActions(actions);
+ mTvPipMenuController.setAppActions(actions, closeAction);
+ mCloseAction = closeAction;
}
});
} catch (RemoteException e) {
- Log.e(TAG, "Failed to register pinned stack listener", e);
+ ProtoLog.e(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: Failed to register pinned stack listener, %s", TAG, e);
}
}
private static TaskInfo getPinnedTaskInfo() {
- if (DEBUG) Log.d(TAG, "getPinnedTaskInfo()");
+ if (DEBUG) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: getPinnedTaskInfo()", TAG);
+ }
try {
final TaskInfo taskInfo = ActivityTaskManager.getService().getRootTaskInfo(
WINDOWING_MODE_PINNED, ACTIVITY_TYPE_UNDEFINED);
- if (DEBUG) Log.d(TAG, " > taskInfo=" + taskInfo);
+ if (DEBUG) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: taskInfo=%s", TAG, taskInfo);
+ }
return taskInfo;
} catch (RemoteException e) {
- Log.e(TAG, "getRootTaskInfo() failed", e);
+ ProtoLog.e(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: getRootTaskInfo() failed, %s", TAG, e);
return null;
}
}
private static void removeTask(int taskId) {
- if (DEBUG) Log.d(TAG, "removeTask(), taskId=" + taskId);
+ if (DEBUG) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: removeTask(), taskId=%d", TAG, taskId);
+ }
try {
ActivityTaskManager.getService().removeTask(taskId);
} catch (Exception e) {
- Log.e(TAG, "Atm.removeTask() failed", e);
+ ProtoLog.e(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: Atm.removeTask() failed, %s", TAG, e);
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipKeepClearAlgorithm.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipKeepClearAlgorithm.kt
new file mode 100644
index 000000000000..5ac7a7200494
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipKeepClearAlgorithm.kt
@@ -0,0 +1,741 @@
+/*
+ * 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.pip.tv
+
+import android.graphics.Point
+import android.graphics.Rect
+import android.util.Size
+import android.view.Gravity
+import com.android.wm.shell.pip.PipBoundsState
+import com.android.wm.shell.pip.PipBoundsState.STASH_TYPE_BOTTOM
+import com.android.wm.shell.pip.PipBoundsState.STASH_TYPE_LEFT
+import com.android.wm.shell.pip.PipBoundsState.STASH_TYPE_NONE
+import com.android.wm.shell.pip.PipBoundsState.STASH_TYPE_RIGHT
+import com.android.wm.shell.pip.PipBoundsState.STASH_TYPE_TOP
+import kotlin.math.abs
+import kotlin.math.max
+import kotlin.math.min
+import kotlin.math.roundToInt
+
+private const val DEFAULT_PIP_MARGINS = 48
+private const val DEFAULT_STASH_DURATION = 5000L
+private const val RELAX_DEPTH = 1
+private const val DEFAULT_MAX_RESTRICTED_DISTANCE_FRACTION = 0.15
+
+/**
+ * This class calculates an appropriate position for a Picture-In-Picture (PiP) window, taking
+ * into account app defined keep clear areas.
+ *
+ * @param clock A function returning a current timestamp (in milliseconds)
+ */
+class TvPipKeepClearAlgorithm(private val clock: () -> Long) {
+ /**
+ * Result of the positioning algorithm.
+ *
+ * @param bounds The bounds the PiP should be placed at
+ * @param anchorBounds The bounds of the PiP anchor position
+ * (where the PiP would be placed if there were no keep clear areas)
+ * @param stashType Where the PiP has been stashed, if at all
+ * @param unstashDestinationBounds If stashed, the PiP should move to this position after
+ * [stashDuration] has passed.
+ * @param unstashTime If stashed, the time at which the PiP should move
+ * to [unstashDestinationBounds]
+ */
+ data class Placement(
+ val bounds: Rect,
+ val anchorBounds: Rect,
+ @PipBoundsState.StashType val stashType: Int = STASH_TYPE_NONE,
+ val unstashDestinationBounds: Rect? = null,
+ val unstashTime: Long = 0L
+ ) {
+ /** Bounds to use if the PiP should not be stashed. */
+ fun getUnstashedBounds() = unstashDestinationBounds ?: bounds
+ }
+
+ /** The size of the screen */
+ private var screenSize = Size(0, 0)
+
+ /** The bounds the PiP is allowed to move in */
+ private var movementBounds = Rect()
+
+ /** Padding to add between a keep clear area that caused the PiP to move and the PiP */
+ var pipAreaPadding = DEFAULT_PIP_MARGINS
+
+ /** The distance the PiP peeks into the screen when stashed */
+ var stashOffset = DEFAULT_PIP_MARGINS
+
+ /**
+ * How long (in milliseconds) the PiP should stay stashed for after the last time the
+ * keep clear areas causing the PiP to stash have changed.
+ */
+ var stashDuration = DEFAULT_STASH_DURATION
+
+ /** The fraction of screen width/height restricted keep clear areas can move the PiP */
+ var maxRestrictedDistanceFraction = DEFAULT_MAX_RESTRICTED_DISTANCE_FRACTION
+
+ private var pipGravity = Gravity.BOTTOM or Gravity.RIGHT
+ private var transformedScreenBounds = Rect()
+ private var transformedMovementBounds = Rect()
+
+ private var lastAreasOverlappingUnstashPosition: Set<Rect> = emptySet()
+ private var lastStashTime: Long = Long.MIN_VALUE
+
+ /**
+ * Calculates the position the PiP should be placed at, taking into consideration the
+ * given keep clear areas.
+ *
+ * Restricted keep clear areas can move the PiP only by a limited amount, and may be ignored
+ * if there is no space for the PiP to move to.
+ * Apps holding the permission [android.Manifest.permission.USE_UNRESTRICTED_KEEP_CLEAR_AREAS]
+ * can declare unrestricted keep clear areas, which can move the PiP farther and placement will
+ * always try to respect these areas.
+ *
+ * If no free space the PiP is allowed to move to can be found, a stashed position is returned
+ * as [Placement.bounds], along with a position to move to once [Placement.unstashTime] has
+ * passed as [Placement.unstashDestinationBounds].
+ *
+ * @param pipSize The size of the PiP window
+ * @param restrictedAreas The restricted keep clear areas
+ * @param unrestrictedAreas The unrestricted keep clear areas
+ *
+ */
+ fun calculatePipPosition(
+ pipSize: Size,
+ restrictedAreas: Set<Rect>,
+ unrestrictedAreas: Set<Rect>
+ ): Placement {
+ val transformedRestrictedAreas = transformAndFilterAreas(restrictedAreas)
+ val transformedUnrestrictedAreas = transformAndFilterAreas(unrestrictedAreas)
+ val pipAnchorBounds = getNormalPipAnchorBounds(pipSize, transformedMovementBounds)
+
+ val result = calculatePipPositionTransformed(
+ pipAnchorBounds,
+ transformedRestrictedAreas,
+ transformedUnrestrictedAreas
+ )
+
+ val screenSpaceBounds = fromTransformedSpace(result.bounds)
+ return Placement(
+ screenSpaceBounds,
+ fromTransformedSpace(result.anchorBounds),
+ getStashType(screenSpaceBounds, movementBounds),
+ result.unstashDestinationBounds?.let { fromTransformedSpace(it) },
+ result.unstashTime
+ )
+ }
+
+ /**
+ * Filters out areas that encompass the entire movement bounds and returns them mapped to
+ * the base case space.
+ *
+ * Areas encompassing the entire movement bounds can occur when a full-screen View gets focused,
+ * but we don't want this to cause the PiP to get stashed.
+ */
+ private fun transformAndFilterAreas(areas: Set<Rect>): Set<Rect> {
+ return areas.mapNotNullTo(mutableSetOf()) {
+ when {
+ it.contains(movementBounds) -> null
+ else -> toTransformedSpace(it)
+ }
+ }
+ }
+
+ /**
+ * Calculates the position the PiP should be placed at, taking into consideration the
+ * given keep clear areas.
+ * All parameters are transformed from screen space to the base case space, where the PiP
+ * anchor is in the bottom right corner / on the right side.
+ *
+ * @see [calculatePipPosition]
+ */
+ private fun calculatePipPositionTransformed(
+ pipAnchorBounds: Rect,
+ restrictedAreas: Set<Rect>,
+ unrestrictedAreas: Set<Rect>
+ ): Placement {
+ if (restrictedAreas.isEmpty() && unrestrictedAreas.isEmpty()) {
+ return Placement(pipAnchorBounds, pipAnchorBounds)
+ }
+
+ // First try to find a free position to move to
+ val freeMovePos = findFreeMovePosition(pipAnchorBounds, restrictedAreas, unrestrictedAreas)
+ if (freeMovePos != null) {
+ lastAreasOverlappingUnstashPosition = emptySet()
+ return Placement(freeMovePos, pipAnchorBounds)
+ }
+
+ // If no free position is found, we have to stash the PiP.
+ // Find the position the PiP should return to once it unstashes by doing a relaxed
+ // search, or ignoring restricted areas, or returning to the anchor position
+ val unstashBounds =
+ findRelaxedMovePosition(pipAnchorBounds, restrictedAreas, unrestrictedAreas)
+ ?: findFreeMovePosition(pipAnchorBounds, emptySet(), unrestrictedAreas)
+ ?: pipAnchorBounds
+
+ val keepClearAreas = restrictedAreas + unrestrictedAreas
+ val areasOverlappingUnstashPosition =
+ keepClearAreas.filter { Rect.intersects(it, unstashBounds) }.toSet()
+ val areasOverlappingUnstashPositionChanged =
+ !lastAreasOverlappingUnstashPosition.containsAll(areasOverlappingUnstashPosition)
+ lastAreasOverlappingUnstashPosition = areasOverlappingUnstashPosition
+
+ val now = clock()
+ if (areasOverlappingUnstashPositionChanged) {
+ lastStashTime = now
+ }
+
+ // If overlapping areas haven't changed and the stash duration has passed, we can
+ // place the PiP at the unstash position
+ val unstashTime = lastStashTime + stashDuration
+ if (now >= unstashTime) {
+ return Placement(unstashBounds, pipAnchorBounds)
+ }
+
+ // Otherwise, we'll stash it close to the unstash position
+ val stashedBounds = getNearbyStashedPosition(unstashBounds, keepClearAreas)
+ return Placement(
+ stashedBounds,
+ pipAnchorBounds,
+ getStashType(stashedBounds, transformedMovementBounds),
+ unstashBounds,
+ unstashTime
+ )
+ }
+
+ @PipBoundsState.StashType
+ private fun getStashType(stashedBounds: Rect, movementBounds: Rect): Int {
+ return when {
+ stashedBounds.left < movementBounds.left -> STASH_TYPE_LEFT
+ stashedBounds.right > movementBounds.right -> STASH_TYPE_RIGHT
+ stashedBounds.top < movementBounds.top -> STASH_TYPE_TOP
+ stashedBounds.bottom > movementBounds.bottom -> STASH_TYPE_BOTTOM
+ else -> STASH_TYPE_NONE
+ }
+ }
+
+ private fun findRelaxedMovePosition(
+ pipAnchorBounds: Rect,
+ restrictedAreas: Set<Rect>,
+ unrestrictedAreas: Set<Rect>
+ ): Rect? {
+ if (RELAX_DEPTH <= 0) {
+ // relaxed search disabled
+ return null
+ }
+
+ return findRelaxedMovePosition(
+ RELAX_DEPTH,
+ pipAnchorBounds,
+ restrictedAreas.toMutableSet(),
+ unrestrictedAreas
+ )
+ }
+
+ private fun findRelaxedMovePosition(
+ depth: Int,
+ pipAnchorBounds: Rect,
+ restrictedAreas: MutableSet<Rect>,
+ unrestrictedAreas: Set<Rect>
+ ): Rect? {
+ if (depth == 0) {
+ return findFreeMovePosition(pipAnchorBounds, restrictedAreas, unrestrictedAreas)
+ }
+
+ val candidates = mutableListOf<Rect>()
+ val areasToExclude = restrictedAreas.toList()
+ for (area in areasToExclude) {
+ restrictedAreas.remove(area)
+ val candidate = findRelaxedMovePosition(
+ depth - 1,
+ pipAnchorBounds,
+ restrictedAreas,
+ unrestrictedAreas
+ )
+ restrictedAreas.add(area)
+
+ if (candidate != null) {
+ candidates.add(candidate)
+ }
+ }
+ return candidates.minByOrNull { candidateCost(it, pipAnchorBounds) }
+ }
+
+ /** Cost function to evaluate candidate bounds */
+ private fun candidateCost(candidateBounds: Rect, pipAnchorBounds: Rect): Int {
+ // squared euclidean distance of corresponding rect corners
+ val dx = candidateBounds.left - pipAnchorBounds.left
+ val dy = candidateBounds.top - pipAnchorBounds.top
+ return dx * dx + dy * dy
+ }
+
+ private fun findFreeMovePosition(
+ pipAnchorBounds: Rect,
+ restrictedAreas: Set<Rect>,
+ unrestrictedAreas: Set<Rect>
+ ): Rect? {
+ val movementBounds = transformedMovementBounds
+ val candidateEdgeRects = mutableListOf<Rect>()
+ val minRestrictedLeft =
+ pipAnchorBounds.right - screenSize.width * maxRestrictedDistanceFraction
+
+ candidateEdgeRects.add(
+ movementBounds.offsetCopy(movementBounds.width() + pipAreaPadding, 0)
+ )
+ candidateEdgeRects.addAll(unrestrictedAreas)
+ candidateEdgeRects.addAll(restrictedAreas.filter { it.left >= minRestrictedLeft })
+
+ // throw out edges that are too close to the left screen edge to fit the PiP
+ val minLeft = movementBounds.left + pipAnchorBounds.width()
+ candidateEdgeRects.retainAll { it.left - pipAreaPadding > minLeft }
+ candidateEdgeRects.sortBy { -it.left }
+
+ val maxRestrictedDY = (screenSize.height * maxRestrictedDistanceFraction).roundToInt()
+
+ val candidateBounds = mutableListOf<Rect>()
+ for (edgeRect in candidateEdgeRects) {
+ val edge = edgeRect.left - pipAreaPadding
+ val dx = (edge - pipAnchorBounds.width()) - pipAnchorBounds.left
+ val candidatePipBounds = pipAnchorBounds.offsetCopy(dx, 0)
+ val searchUp = true
+ val searchDown = !isPipAnchoredToCorner()
+
+ if (searchUp) {
+ val event = findMinMoveUp(candidatePipBounds, restrictedAreas, unrestrictedAreas)
+ val padding = if (event.start) 0 else pipAreaPadding
+ val dy = event.pos - pipAnchorBounds.bottom - padding
+ val maxDY = if (event.unrestricted) movementBounds.height() else maxRestrictedDY
+ val candidate = pipAnchorBounds.offsetCopy(dx, dy)
+ val isOnScreen = candidate.top > movementBounds.top
+ val hangingMidAir = !candidate.intersectsY(edgeRect)
+ if (isOnScreen && abs(dy) <= maxDY && !hangingMidAir) {
+ candidateBounds.add(candidate)
+ }
+ }
+
+ if (searchDown) {
+ val event = findMinMoveDown(candidatePipBounds, restrictedAreas, unrestrictedAreas)
+ val padding = if (event.start) 0 else pipAreaPadding
+ val dy = event.pos - pipAnchorBounds.top + padding
+ val maxDY = if (event.unrestricted) movementBounds.height() else maxRestrictedDY
+ val candidate = pipAnchorBounds.offsetCopy(dx, dy)
+ val isOnScreen = candidate.bottom < movementBounds.bottom
+ val hangingMidAir = !candidate.intersectsY(edgeRect)
+ if (isOnScreen && abs(dy) <= maxDY && !hangingMidAir) {
+ candidateBounds.add(candidate)
+ }
+ }
+ }
+
+ candidateBounds.sortBy { candidateCost(it, pipAnchorBounds) }
+ return candidateBounds.firstOrNull()
+ }
+
+ private fun getNearbyStashedPosition(bounds: Rect, keepClearAreas: Set<Rect>): Rect {
+ val screenBounds = transformedScreenBounds
+ val stashCandidates = Array(2) { Rect(bounds) }
+ val areasOverlappingPipX = keepClearAreas.filter { it.intersectsX(bounds) }
+ val areasOverlappingPipY = keepClearAreas.filter { it.intersectsY(bounds) }
+
+ if (screenBounds.bottom - bounds.bottom <= bounds.top - screenBounds.top) {
+ // bottom is closer than top, stash downwards
+ val fullStashTop = screenBounds.bottom - stashOffset
+
+ val maxBottom = areasOverlappingPipX.maxByOrNull { it.bottom }!!.bottom
+ val partialStashTop = maxBottom + pipAreaPadding
+
+ val downPosition = stashCandidates[0]
+ downPosition.offsetTo(bounds.left, min(fullStashTop, partialStashTop))
+ } else {
+ // top is closer than bottom, stash upwards
+ val fullStashY = screenBounds.top - bounds.height() + stashOffset
+
+ val minTop = areasOverlappingPipX.minByOrNull { it.top }!!.top
+ val partialStashY = minTop - bounds.height() - pipAreaPadding
+
+ val upPosition = stashCandidates[0]
+ upPosition.offsetTo(bounds.left, max(fullStashY, partialStashY))
+ }
+
+ if (screenBounds.right - bounds.right <= bounds.left - screenBounds.left) {
+ // right is closer than left, stash rightwards
+ val fullStashLeft = screenBounds.right - stashOffset
+
+ val maxRight = areasOverlappingPipY.maxByOrNull { it.right }!!.right
+ val partialStashLeft = maxRight + pipAreaPadding
+
+ val rightPosition = stashCandidates[1]
+ rightPosition.offsetTo(min(fullStashLeft, partialStashLeft), bounds.top)
+ } else {
+ // left is closer than right, stash leftwards
+ val fullStashLeft = screenBounds.left - bounds.width() + stashOffset
+
+ val minLeft = areasOverlappingPipY.minByOrNull { it.left }!!.left
+ val partialStashLeft = minLeft - bounds.width() - pipAreaPadding
+
+ val rightPosition = stashCandidates[1]
+ rightPosition.offsetTo(max(fullStashLeft, partialStashLeft), bounds.top)
+ }
+
+ return stashCandidates.minByOrNull {
+ val dx = abs(it.left - bounds.left)
+ val dy = abs(it.top - bounds.top)
+ dx * bounds.height() + dy * bounds.width()
+ }!!
+ }
+
+ /**
+ * Prevents the PiP from being stashed for the current set of keep clear areas.
+ * The PiP may stash again if keep clear areas change.
+ */
+ fun keepUnstashedForCurrentKeepClearAreas() {
+ lastStashTime = Long.MIN_VALUE
+ }
+
+ /**
+ * Updates the size of the screen.
+ *
+ * @param size The new size of the screen
+ */
+ fun setScreenSize(size: Size) {
+ if (screenSize == size) {
+ return
+ }
+
+ screenSize = size
+ transformedScreenBounds =
+ toTransformedSpace(Rect(0, 0, screenSize.width, screenSize.height))
+ transformedMovementBounds = toTransformedSpace(transformedMovementBounds)
+ }
+
+ /**
+ * Updates the bounds within which the PiP is allowed to move.
+ *
+ * @param bounds The new movement bounds
+ */
+ fun setMovementBounds(bounds: Rect) {
+ if (movementBounds == bounds) {
+ return
+ }
+
+ movementBounds.set(bounds)
+ transformedMovementBounds = toTransformedSpace(movementBounds)
+ }
+
+ /**
+ * Sets the corner/side of the PiP's home position.
+ */
+ fun setGravity(gravity: Int) {
+ if (pipGravity == gravity) return
+
+ pipGravity = gravity
+ transformedScreenBounds =
+ toTransformedSpace(Rect(0, 0, screenSize.width, screenSize.height))
+ transformedMovementBounds = toTransformedSpace(movementBounds)
+ }
+
+ /**
+ * @param open Whether this event marks the opening of an occupied segment
+ * @param pos The coordinate of this event
+ * @param unrestricted Whether this event was generated by an unrestricted keep clear area
+ * @param start Marks the special start event. Earlier events are skipped when sweeping
+ */
+ data class SweepLineEvent(
+ val open: Boolean,
+ val pos: Int,
+ val unrestricted: Boolean,
+ val start: Boolean = false
+ )
+
+ /**
+ * Returns a [SweepLineEvent] representing the minimal move up from [pipBounds] that clears
+ * the given keep clear areas.
+ */
+ private fun findMinMoveUp(
+ pipBounds: Rect,
+ restrictedAreas: Set<Rect>,
+ unrestrictedAreas: Set<Rect>
+ ): SweepLineEvent {
+ val events = mutableListOf<SweepLineEvent>()
+ val generateEvents: (Boolean) -> (Rect) -> Unit = { unrestricted ->
+ { area ->
+ if (pipBounds.intersectsX(area)) {
+ events.add(SweepLineEvent(true, area.bottom, unrestricted))
+ events.add(SweepLineEvent(false, area.top, unrestricted))
+ }
+ }
+ }
+
+ restrictedAreas.forEach(generateEvents(false))
+ unrestrictedAreas.forEach(generateEvents(true))
+
+ return sweepLineFindEarliestGap(
+ events,
+ pipBounds.height() + pipAreaPadding,
+ pipBounds.bottom,
+ pipBounds.height()
+ )
+ }
+
+ /**
+ * Returns a [SweepLineEvent] representing the minimal move down from [pipBounds] that clears
+ * the given keep clear areas.
+ */
+ private fun findMinMoveDown(
+ pipBounds: Rect,
+ restrictedAreas: Set<Rect>,
+ unrestrictedAreas: Set<Rect>
+ ): SweepLineEvent {
+ val events = mutableListOf<SweepLineEvent>()
+ val generateEvents: (Boolean) -> (Rect) -> Unit = { unrestricted ->
+ { area ->
+ if (pipBounds.intersectsX(area)) {
+ events.add(SweepLineEvent(true, -area.top, unrestricted))
+ events.add(SweepLineEvent(false, -area.bottom, unrestricted))
+ }
+ }
+ }
+
+ restrictedAreas.forEach(generateEvents(false))
+ unrestrictedAreas.forEach(generateEvents(true))
+
+ val earliestEvent = sweepLineFindEarliestGap(
+ events,
+ pipBounds.height() + pipAreaPadding,
+ -pipBounds.top,
+ pipBounds.height()
+ )
+
+ return earliestEvent.copy(pos = -earliestEvent.pos)
+ }
+
+ /**
+ * Takes a list of events representing the starts & ends of occupied segments, and
+ * returns the earliest event whose position is unoccupied and has [gapSize] distance to the
+ * next event.
+ *
+ * @param events List of [SweepLineEvent] representing occupied segments
+ * @param gapSize Size of the gap to search for
+ * @param startPos The position to start the search on.
+ * Inserts a special event marked with [SweepLineEvent.start].
+ * @param startGapSize Used instead of [gapSize] for the start event
+ */
+ private fun sweepLineFindEarliestGap(
+ events: MutableList<SweepLineEvent>,
+ gapSize: Int,
+ startPos: Int,
+ startGapSize: Int
+ ): SweepLineEvent {
+ events.add(
+ SweepLineEvent(
+ open = false,
+ pos = startPos,
+ unrestricted = true,
+ start = true
+ )
+ )
+ events.sortBy { -it.pos }
+
+ // sweep
+ var openCount = 0
+ var i = 0
+ while (i < events.size) {
+ val event = events[i]
+ if (!event.start) {
+ if (event.open) {
+ openCount++
+ } else {
+ openCount--
+ }
+ }
+
+ if (openCount == 0) {
+ // check if placement is possible
+ val candidate = event.pos
+ if (candidate > startPos) {
+ i++
+ continue
+ }
+
+ val eventGapSize = if (event.start) startGapSize else gapSize
+ val nextEvent = events.getOrNull(i + 1)
+ if (nextEvent == null || nextEvent.pos < candidate - eventGapSize) {
+ return event
+ }
+ }
+ i++
+ }
+
+ return events.last()
+ }
+
+ private fun shouldTransformFlipX(): Boolean {
+ return when (pipGravity) {
+ (Gravity.TOP), (Gravity.TOP or Gravity.CENTER_HORIZONTAL) -> true
+ (Gravity.TOP or Gravity.LEFT) -> true
+ (Gravity.LEFT), (Gravity.LEFT or Gravity.CENTER_VERTICAL) -> true
+ (Gravity.BOTTOM or Gravity.LEFT) -> true
+ else -> false
+ }
+ }
+
+ private fun shouldTransformFlipY(): Boolean {
+ return when (pipGravity) {
+ (Gravity.TOP or Gravity.LEFT) -> true
+ (Gravity.TOP or Gravity.RIGHT) -> true
+ else -> false
+ }
+ }
+
+ private fun shouldTransformRotate(): Boolean {
+ val horizontalGravity = pipGravity and Gravity.HORIZONTAL_GRAVITY_MASK
+ val leftOrRight = horizontalGravity == Gravity.LEFT || horizontalGravity == Gravity.RIGHT
+
+ if (leftOrRight) return false
+ return when (pipGravity and Gravity.VERTICAL_GRAVITY_MASK) {
+ (Gravity.TOP) -> true
+ (Gravity.BOTTOM) -> true
+ else -> false
+ }
+ }
+
+ /**
+ * Transforms the given rect from screen space into the base case space, where the PiP
+ * anchor is positioned in the bottom right corner or on the right side (for expanded PiP).
+ *
+ * @see [fromTransformedSpace]
+ */
+ private fun toTransformedSpace(r: Rect): Rect {
+ var screenWidth = screenSize.width
+ var screenHeight = screenSize.height
+
+ val tl = Point(r.left, r.top)
+ val tr = Point(r.right, r.top)
+ val br = Point(r.right, r.bottom)
+ val bl = Point(r.left, r.bottom)
+ val corners = arrayOf(tl, tr, br, bl)
+
+ // rotate first (CW)
+ if (shouldTransformRotate()) {
+ corners.forEach { p ->
+ val px = p.x
+ val py = p.y
+ p.x = py
+ p.y = -px
+ p.y += screenWidth // shift back screen into positive quadrant
+ }
+ screenWidth = screenSize.height
+ screenHeight = screenSize.width
+ }
+
+ // flip second
+ corners.forEach {
+ if (shouldTransformFlipX()) it.x = screenWidth - it.x
+ if (shouldTransformFlipY()) it.y = screenHeight - it.y
+ }
+
+ val top = corners.minByOrNull { it.y }!!.y
+ val right = corners.maxByOrNull { it.x }!!.x
+ val bottom = corners.maxByOrNull { it.y }!!.y
+ val left = corners.minByOrNull { it.x }!!.x
+
+ return Rect(left, top, right, bottom)
+ }
+
+ /**
+ * Transforms the given rect from the base case space, where the PiP anchor is positioned in
+ * the bottom right corner or on the right side, back into screen space.
+ *
+ * @see [toTransformedSpace]
+ */
+ private fun fromTransformedSpace(r: Rect): Rect {
+ val rotate = shouldTransformRotate()
+ val transformedScreenWidth = if (rotate) screenSize.height else screenSize.width
+ val transformedScreenHeight = if (rotate) screenSize.width else screenSize.height
+
+ val tl = Point(r.left, r.top)
+ val tr = Point(r.right, r.top)
+ val br = Point(r.right, r.bottom)
+ val bl = Point(r.left, r.bottom)
+ val corners = arrayOf(tl, tr, br, bl)
+
+ // flip first
+ corners.forEach {
+ if (shouldTransformFlipX()) it.x = transformedScreenWidth - it.x
+ if (shouldTransformFlipY()) it.y = transformedScreenHeight - it.y
+ }
+
+ // rotate second (CCW)
+ if (rotate) {
+ corners.forEach { p ->
+ p.y -= screenSize.width // undo shift back screen into positive quadrant
+ val px = p.x
+ val py = p.y
+ p.x = -py
+ p.y = px
+ }
+ }
+
+ val top = corners.minByOrNull { it.y }!!.y
+ val right = corners.maxByOrNull { it.x }!!.x
+ val bottom = corners.maxByOrNull { it.y }!!.y
+ val left = corners.minByOrNull { it.x }!!.x
+
+ return Rect(left, top, right, bottom)
+ }
+
+ /** PiP anchor bounds in base case for given gravity */
+ private fun getNormalPipAnchorBounds(pipSize: Size, movementBounds: Rect): Rect {
+ var size = pipSize
+ val rotateCW = shouldTransformRotate()
+ if (rotateCW) {
+ size = Size(pipSize.height, pipSize.width)
+ }
+
+ val pipBounds = Rect()
+ if (isPipAnchoredToCorner()) {
+ // bottom right
+ Gravity.apply(
+ Gravity.BOTTOM or Gravity.RIGHT,
+ size.width,
+ size.height,
+ movementBounds,
+ pipBounds
+ )
+ return pipBounds
+ } else {
+ // expanded, right side
+ Gravity.apply(Gravity.RIGHT, size.width, size.height, movementBounds, pipBounds)
+ return pipBounds
+ }
+ }
+
+ private fun isPipAnchoredToCorner(): Boolean {
+ val left = (pipGravity and Gravity.HORIZONTAL_GRAVITY_MASK) == Gravity.LEFT
+ val right = (pipGravity and Gravity.HORIZONTAL_GRAVITY_MASK) == Gravity.RIGHT
+ val top = (pipGravity and Gravity.VERTICAL_GRAVITY_MASK) == Gravity.TOP
+ val bottom = (pipGravity and Gravity.VERTICAL_GRAVITY_MASK) == Gravity.BOTTOM
+
+ val horizontal = left || right
+ val vertical = top || bottom
+
+ return horizontal && vertical
+ }
+
+ private fun Rect.offsetCopy(dx: Int, dy: Int) = Rect(this).apply { offset(dx, dy) }
+ private fun Rect.intersectsY(other: Rect) = bottom >= other.top && top <= other.bottom
+ private fun Rect.intersectsX(other: Rect) = right >= other.left && left <= other.right
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuActionButton.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuActionButton.java
index 4eb46d93c887..abbc614b4b4f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuActionButton.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuActionButton.java
@@ -126,4 +126,15 @@ public class TvPipMenuActionButton extends RelativeLayout implements View.OnClic
public boolean isEnabled() {
return mButtonView.isEnabled();
}
+
+ void setIsCustomCloseAction(boolean isCustomCloseAction) {
+ mIconImageView.setImageTintList(
+ getResources().getColorStateList(
+ isCustomCloseAction ? R.color.tv_pip_menu_close_icon
+ : R.color.tv_pip_menu_icon));
+ mButtonView.setBackgroundTintList(getResources()
+ .getColorStateList(isCustomCloseAction ? R.color.tv_pip_menu_close_icon_bg
+ : R.color.tv_pip_menu_icon_bg));
+ }
+
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java
index 32ebe2d6aecf..b6ae398c1eb9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java
@@ -30,20 +30,22 @@ import android.graphics.Rect;
import android.graphics.RectF;
import android.os.Handler;
import android.os.RemoteException;
-import android.util.Log;
import android.view.SurfaceControl;
import android.view.SyncRtSurfaceTransactionApplier;
import android.view.WindowManagerGlobal;
import androidx.annotation.Nullable;
+import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.R;
import com.android.wm.shell.common.SystemWindows;
import com.android.wm.shell.pip.PipMediaController;
import com.android.wm.shell.pip.PipMenuController;
+import com.android.wm.shell.protolog.ShellProtoLogGroup;
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
/**
* Manages the visibility of the PiP Menu as user interacts with PiP.
@@ -66,6 +68,7 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis
private final List<RemoteAction> mMediaActions = new ArrayList<>();
private final List<RemoteAction> mAppActions = new ArrayList<>();
+ private RemoteAction mCloseAction;
private SyncRtSurfaceTransactionApplier mApplier;
RectF mTmpSourceRectF = new RectF();
@@ -110,7 +113,10 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis
}
void setDelegate(Delegate delegate) {
- if (DEBUG) Log.d(TAG, "setDelegate(), delegate=" + delegate);
+ if (DEBUG) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: setDelegate(), delegate=%s", TAG, delegate);
+ }
if (mDelegate != null) {
throw new IllegalStateException(
"The delegate has already been set and should not change.");
@@ -133,7 +139,10 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis
}
private void attachPipMenuView() {
- if (DEBUG) Log.d(TAG, "attachPipMenuView()");
+ if (DEBUG) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: attachPipMenuView()", TAG);
+ }
if (mPipMenuView != null) {
detachPipMenuView();
@@ -148,7 +157,10 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis
@Override
public void showMenu() {
- if (DEBUG) Log.d(TAG, "showMenu()");
+ if (DEBUG) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: showMenu()", TAG);
+ }
if (mPipMenuView != null) {
Rect menuBounds = getMenuBounds(mTvPipBoundsState.getBounds());
@@ -174,8 +186,8 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis
}
void updateExpansionState() {
- mPipMenuView.setExpandedModeEnabled(mTvPipBoundsState.isTvExpandedPipEnabled()
- && mTvPipBoundsState.getTvExpandedAspectRatio() != 0);
+ mPipMenuView.setExpandedModeEnabled(mTvPipBoundsState.isTvExpandedPipSupported()
+ && mTvPipBoundsState.getDesiredTvExpandedAspectRatio() != 0);
mPipMenuView.setIsExpanded(mTvPipBoundsState.isTvPipExpanded());
}
@@ -189,10 +201,16 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis
void hideMenu() {
if (!isMenuVisible()) {
- if (DEBUG) Log.d(TAG, "hideMenu() - Menu isn't visible, so don't hide");
+ if (DEBUG) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: hideMenu() - Menu isn't visible, so don't hide", TAG);
+ }
return;
} else {
- if (DEBUG) Log.d(TAG, "hideMenu()");
+ if (DEBUG) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: hideMenu()", TAG);
+ }
}
mPipMenuView.hide();
@@ -202,21 +220,33 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis
}
}
+ boolean isInMoveMode() {
+ return mInMoveMode;
+ }
+
@Override
public void onEnterMoveMode() {
- if (DEBUG) Log.d(TAG, "onEnterMoveMode - " + mInMoveMode);
+ if (DEBUG) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: onEnterMoveMode - %b", TAG, mInMoveMode);
+ }
mInMoveMode = true;
mPipMenuView.showMenuButtons(false);
mPipMenuView.showMovementHints(mDelegate.getPipGravity());
+ mDelegate.onInMoveModeChanged();
}
@Override
public boolean onExitMoveMode() {
- if (DEBUG) Log.d(TAG, "onExitMoveMode - " + mInMoveMode);
+ if (DEBUG) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: onExitMoveMode - %b", TAG, mInMoveMode);
+ }
if (mInMoveMode) {
mInMoveMode = false;
mPipMenuView.showMenuButtons(true);
mPipMenuView.hideMovementHints();
+ mDelegate.onInMoveModeChanged();
return true;
}
return false;
@@ -224,7 +254,10 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis
@Override
public boolean onPipMovement(int keycode) {
- if (DEBUG) Log.d(TAG, "onPipMovement - " + mInMoveMode);
+ if (DEBUG) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: onPipMovement - %b", TAG, mInMoveMode);
+ }
if (mInMoveMode) {
mDelegate.movePip(keycode);
}
@@ -239,13 +272,19 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis
}
@Override
- public void setAppActions(ParceledListSlice<RemoteAction> actions) {
- if (DEBUG) Log.d(TAG, "setAppActions()");
- updateAdditionalActionsList(mAppActions, actions.getList());
+ public void setAppActions(ParceledListSlice<RemoteAction> actions, RemoteAction closeAction) {
+ if (DEBUG) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: setAppActions()", TAG);
+ }
+ updateAdditionalActionsList(mAppActions, actions.getList(), closeAction);
}
private void onMediaActionsChanged(List<RemoteAction> actions) {
- if (DEBUG) Log.d(TAG, "onMediaActionsChanged()");
+ if (DEBUG) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: onMediaActionsChanged()", TAG);
+ }
// Hide disabled actions.
List<RemoteAction> enabledActions = new ArrayList<>();
@@ -254,17 +293,19 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis
enabledActions.add(remoteAction);
}
}
- updateAdditionalActionsList(mMediaActions, enabledActions);
+ updateAdditionalActionsList(mMediaActions, enabledActions, mCloseAction);
}
- private void updateAdditionalActionsList(
- List<RemoteAction> destination, @Nullable List<RemoteAction> source) {
+ private void updateAdditionalActionsList(List<RemoteAction> destination,
+ @Nullable List<RemoteAction> source, RemoteAction closeAction) {
final int number = source != null ? source.size() : 0;
- if (number == 0 && destination.isEmpty()) {
+ if (number == 0 && destination.isEmpty() && Objects.equals(closeAction, mCloseAction)) {
// Nothing changed.
return;
}
+ mCloseAction = closeAction;
+
destination.clear();
if (number > 0) {
destination.addAll(source);
@@ -277,16 +318,19 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis
return;
}
if (!mAppActions.isEmpty()) {
- mPipMenuView.setAdditionalActions(mAppActions, mMainHandler);
+ mPipMenuView.setAdditionalActions(mAppActions, mCloseAction, mMainHandler);
} else {
- mPipMenuView.setAdditionalActions(mMediaActions, mMainHandler);
+ mPipMenuView.setAdditionalActions(mMediaActions, mCloseAction, mMainHandler);
}
}
@Override
public boolean isMenuVisible() {
boolean isVisible = mPipMenuView != null && mPipMenuView.isVisible();
- if (DEBUG) Log.d(TAG, "isMenuVisible: " + isVisible);
+ if (DEBUG) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: isMenuVisible: %b", TAG, isVisible);
+ }
return isVisible;
}
@@ -297,7 +341,10 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis
public void resizePipMenu(@android.annotation.Nullable SurfaceControl pipLeash,
@android.annotation.Nullable SurfaceControl.Transaction t,
Rect destinationBounds) {
- if (DEBUG) Log.d(TAG, "resizePipMenu: " + destinationBounds.toShortString());
+ if (DEBUG) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: resizePipMenu: %s", TAG, destinationBounds.toShortString());
+ }
if (destinationBounds.isEmpty()) {
return;
}
@@ -329,10 +376,16 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis
@Override
public void movePipMenu(SurfaceControl pipLeash, SurfaceControl.Transaction transaction,
Rect pipDestBounds) {
- if (DEBUG) Log.d(TAG, "movePipMenu: " + pipDestBounds.toShortString());
+ if (DEBUG) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: movePipMenu: %s", TAG, pipDestBounds.toShortString());
+ }
if (pipDestBounds.isEmpty()) {
- if (transaction == null && DEBUG) Log.d(TAG, "no transaction given");
+ if (transaction == null && DEBUG) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: no transaction given", TAG);
+ }
return;
}
if (!maybeCreateSyncApplier()) {
@@ -345,10 +398,16 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis
// resizing and the PiP menu is also resized. We then want to do a scale from the current
// new menu bounds.
if (pipLeash != null && transaction != null) {
- if (DEBUG) Log.d(TAG, "mTmpSourceBounds based on mPipMenuView.getBoundsOnScreen()");
+ if (DEBUG) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: mTmpSourceBounds based on mPipMenuView.getBoundsOnScreen()", TAG);
+ }
mPipMenuView.getBoundsOnScreen(mTmpSourceBounds);
} else {
- if (DEBUG) Log.d(TAG, "mTmpSourceBounds based on menu width and height");
+ if (DEBUG) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: mTmpSourceBounds based on menu width and height", TAG);
+ }
mTmpSourceBounds.set(0, 0, menuDestBounds.width(), menuDestBounds.height());
}
@@ -383,7 +442,8 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis
private boolean maybeCreateSyncApplier() {
if (mPipMenuView == null || mPipMenuView.getViewRootImpl() == null) {
- Log.v(TAG, "Not going to move PiP, either menu or its parent is not created.");
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: Not going to move PiP, either menu or its parent is not created.", TAG);
return false;
}
@@ -406,7 +466,10 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis
@Override
public void updateMenuBounds(Rect destinationBounds) {
Rect menuBounds = getMenuBounds(destinationBounds);
- if (DEBUG) Log.d(TAG, "updateMenuBounds: " + menuBounds.toShortString());
+ if (DEBUG) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: updateMenuBounds: %s", TAG, menuBounds.toShortString());
+ }
mSystemWindows.updateViewLayout(mPipMenuView,
getPipMenuLayoutParams(MENU_WINDOW_TITLE, menuBounds.width(),
menuBounds.height()));
@@ -417,7 +480,7 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis
@Override
public void onFocusTaskChanged(ActivityManager.RunningTaskInfo taskInfo) {
- Log.d(TAG, "onFocusTaskChanged");
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, "%s: onFocusTaskChanged", TAG);
}
@Override
@@ -447,6 +510,8 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis
void movePip(int keycode);
+ void onInMoveModeChanged();
+
int getPipGravity();
void togglePipExpansion();
@@ -457,13 +522,17 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis
}
private void grantPipMenuFocus(boolean grantFocus) {
- if (DEBUG) Log.d(TAG, "grantWindowFocus(" + grantFocus + ")");
+ if (DEBUG) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: grantWindowFocus(%b)", TAG, grantFocus);
+ }
try {
WindowManagerGlobal.getWindowSession().grantEmbeddedWindowFocus(null /* window */,
mSystemWindows.getFocusGrantToken(mPipMenuView), grantFocus);
} catch (Exception e) {
- Log.e(TAG, "Unable to update focus", e);
+ ProtoLog.e(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: Unable to update focus, %s", TAG, e);
}
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuView.java
index 3090139f6db9..7fdb9ed90875 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuView.java
@@ -31,7 +31,6 @@ import android.content.Context;
import android.graphics.Rect;
import android.os.Handler;
import android.util.AttributeSet;
-import android.util.Log;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.SurfaceControl;
@@ -45,10 +44,13 @@ import android.widget.LinearLayout;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.R;
+import com.android.wm.shell.protolog.ShellProtoLogGroup;
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
/**
* A View that represents Pip Menu on TV. It's responsible for displaying 3 ever-present Pip Menu
@@ -77,6 +79,7 @@ public class TvPipMenuView extends FrameLayout implements View.OnClickListener {
private Rect mCurrentBounds;
private final TvPipMenuActionButton mExpandButton;
+ private final TvPipMenuActionButton mCloseButton;
public TvPipMenuView(@NonNull Context context) {
this(context, null);
@@ -99,8 +102,11 @@ public class TvPipMenuView extends FrameLayout implements View.OnClickListener {
mActionButtonsContainer = findViewById(R.id.tv_pip_menu_action_buttons);
mActionButtonsContainer.findViewById(R.id.tv_pip_menu_fullscreen_button)
.setOnClickListener(this);
- mActionButtonsContainer.findViewById(R.id.tv_pip_menu_close_button)
- .setOnClickListener(this);
+
+ mCloseButton = mActionButtonsContainer.findViewById(R.id.tv_pip_menu_close_button);
+ mCloseButton.setOnClickListener(this);
+ mCloseButton.setIsCustomCloseAction(true);
+
mActionButtonsContainer.findViewById(R.id.tv_pip_menu_move_button)
.setOnClickListener(this);
mExpandButton = findViewById(R.id.tv_pip_menu_expand_button);
@@ -118,17 +124,24 @@ public class TvPipMenuView extends FrameLayout implements View.OnClickListener {
}
void updateLayout(Rect updatedBounds) {
- Log.d(TAG, "update menu layout: " + updatedBounds.toShortString());
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: update menu layout: %s", TAG, updatedBounds.toShortString());
boolean previouslyVertical =
mCurrentBounds != null && mCurrentBounds.height() > mCurrentBounds.width();
boolean vertical = updatedBounds.height() > updatedBounds.width();
mCurrentBounds = updatedBounds;
if (previouslyVertical == vertical) {
- if (DEBUG) Log.d(TAG, "no update for menu layout");
+ if (DEBUG) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: no update for menu layout", TAG);
+ }
return;
} else {
- if (DEBUG) Log.d(TAG, "change menu layout to vertical: " + vertical);
+ if (DEBUG) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: change menu layout to vertical: %b", TAG, vertical);
+ }
}
if (vertical) {
@@ -154,7 +167,10 @@ public class TvPipMenuView extends FrameLayout implements View.OnClickListener {
}
void setIsExpanded(boolean expanded) {
- if (DEBUG) Log.d(TAG, "setIsExpanded, expanded: " + expanded);
+ if (DEBUG) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: setIsExpanded, expanded: %b", TAG, expanded);
+ }
mExpandButton.setImageResource(
expanded ? R.drawable.pip_ic_collapse : R.drawable.pip_ic_expand);
mExpandButton.setTextAndDescription(
@@ -162,7 +178,10 @@ public class TvPipMenuView extends FrameLayout implements View.OnClickListener {
}
void show(boolean inMoveMode, int gravity) {
- if (DEBUG) Log.d(TAG, "show(), inMoveMode: " + inMoveMode);
+ if (DEBUG) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: show(), inMoveMode: %b", TAG, inMoveMode);
+ }
if (inMoveMode) {
showMovementHints(gravity);
} else {
@@ -172,7 +191,9 @@ public class TvPipMenuView extends FrameLayout implements View.OnClickListener {
}
void hide() {
- if (DEBUG) Log.d(TAG, "hide()");
+ if (DEBUG) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, "%s: hide()", TAG);
+ }
animateAlphaTo(0, mActionButtonsContainer);
animateAlphaTo(0, mMenuFrameView);
hideMovementHints();
@@ -204,8 +225,23 @@ public class TvPipMenuView extends FrameLayout implements View.OnClickListener {
|| mArrowLeft.getAlpha() != 0f;
}
- void setAdditionalActions(List<RemoteAction> actions, Handler mainHandler) {
- if (DEBUG) Log.d(TAG, "setAdditionalActions()");
+ void setAdditionalActions(List<RemoteAction> actions, RemoteAction closeAction,
+ Handler mainHandler) {
+ if (DEBUG) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: setAdditionalActions()", TAG);
+ }
+
+ // Replace system close action with custom close action if available
+ if (closeAction != null) {
+ setActionForButton(closeAction, mCloseButton, mainHandler);
+ } else {
+ mCloseButton.setTextAndDescription(R.string.pip_close);
+ mCloseButton.setImageResource(R.drawable.pip_ic_close_white);
+ }
+ mCloseButton.setIsCustomCloseAction(closeAction != null);
+ // Make sure the close action is always enabled
+ mCloseButton.setEnabled(true);
// Make sure we exactly as many additional buttons as we have actions to display.
final int actionsNumber = actions.size();
@@ -237,14 +273,37 @@ public class TvPipMenuView extends FrameLayout implements View.OnClickListener {
for (int index = 0; index < actionsNumber; index++) {
final RemoteAction action = actions.get(index);
final TvPipMenuActionButton button = mAdditionalButtons.get(index);
- button.setVisibility(View.VISIBLE); // Ensure the button is visible.
- button.setTextAndDescription(action.getContentDescription());
- button.setEnabled(action.isEnabled());
- button.setTag(action);
- action.getIcon().loadDrawableAsync(mContext, button::setImageDrawable, mainHandler);
+
+ // Remove action if it matches the custom close action.
+ if (actionsMatch(action, closeAction)) {
+ button.setVisibility(GONE);
+ continue;
+ }
+ setActionForButton(action, button, mainHandler);
}
}
+ /**
+ * Checks whether title, description and intent match.
+ * Comparing icons would be good, but using equals causes false negatives
+ */
+ private boolean actionsMatch(RemoteAction action1, RemoteAction action2) {
+ if (action1 == action2) return true;
+ if (action1 == null) return false;
+ return Objects.equals(action1.getTitle(), action2.getTitle())
+ && Objects.equals(action1.getContentDescription(), action2.getContentDescription())
+ && Objects.equals(action1.getActionIntent(), action2.getActionIntent());
+ }
+
+ private void setActionForButton(RemoteAction action, TvPipMenuActionButton button,
+ Handler mainHandler) {
+ button.setVisibility(View.VISIBLE); // Ensure the button is visible.
+ button.setTextAndDescription(action.getContentDescription());
+ button.setEnabled(action.isEnabled());
+ button.setTag(action);
+ action.getIcon().loadDrawableAsync(mContext, button::setImageDrawable, mainHandler);
+ }
+
@Nullable
SurfaceControl getWindowSurfaceControl() {
final ViewRootImpl root = getViewRootImpl();
@@ -278,10 +337,12 @@ public class TvPipMenuView extends FrameLayout implements View.OnClickListener {
try {
action.getActionIntent().send();
} catch (PendingIntent.CanceledException e) {
- Log.w(TAG, "Failed to send action", e);
+ ProtoLog.w(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: Failed to send action, %s", TAG, e);
}
} else {
- Log.w(TAG, "RemoteAction is null");
+ ProtoLog.w(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: RemoteAction is null", TAG);
}
}
}
@@ -289,8 +350,9 @@ public class TvPipMenuView extends FrameLayout implements View.OnClickListener {
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
if (DEBUG) {
- Log.d(TAG, "dispatchKeyEvent, action: " + event.getAction()
- + ", keycode: " + event.getKeyCode());
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: dispatchKeyEvent, action: %d, keycode: %d",
+ TAG, event.getAction(), event.getKeyCode());
}
if (mListener != null && event.getAction() == ACTION_UP) {
switch (event.getKeyCode()) {
@@ -317,7 +379,10 @@ public class TvPipMenuView extends FrameLayout implements View.OnClickListener {
* Shows user hints for moving the PiP, e.g. arrows.
*/
public void showMovementHints(int gravity) {
- if (DEBUG) Log.d(TAG, "showMovementHints(), position: " + Gravity.toString(gravity));
+ if (DEBUG) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: showMovementHints(), position: %s", TAG, Gravity.toString(gravity));
+ }
animateAlphaTo(checkGravity(gravity, Gravity.BOTTOM) ? 1f : 0f, mArrowUp);
animateAlphaTo(checkGravity(gravity, Gravity.TOP) ? 1f : 0f, mArrowDown);
@@ -333,7 +398,10 @@ public class TvPipMenuView extends FrameLayout implements View.OnClickListener {
* Hides user hints for moving the PiP, e.g. arrows.
*/
public void hideMovementHints() {
- if (DEBUG) Log.d(TAG, "hideMovementHints()");
+ if (DEBUG) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: hideMovementHints()", TAG);
+ }
animateAlphaTo(0, mArrowUp);
animateAlphaTo(0, mArrowRight);
animateAlphaTo(0, mArrowDown);
@@ -344,7 +412,10 @@ public class TvPipMenuView extends FrameLayout implements View.OnClickListener {
* Show or hide the pip user actions.
*/
public void showMenuButtons(boolean show) {
- if (DEBUG) Log.d(TAG, "showMenuButtons: " + show);
+ if (DEBUG) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: showMenuButtons: %b", TAG, show);
+ }
animateAlphaTo(show ? 1 : 0, mActionButtonsContainer);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipNotificationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipNotificationController.java
index dd7e29451ffc..7bd3ce9c45b2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipNotificationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipNotificationController.java
@@ -28,13 +28,13 @@ import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.media.MediaMetadata;
import android.os.Handler;
-import android.os.UserHandle;
import android.text.TextUtils;
-import android.util.Log;
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
+import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.R;
import com.android.wm.shell.pip.PipMediaController;
+import com.android.wm.shell.protolog.ShellProtoLogGroup;
import java.util.Objects;
@@ -98,7 +98,10 @@ public class TvPipNotificationController {
}
void setDelegate(Delegate delegate) {
- if (DEBUG) Log.d(TAG, "setDelegate(), delegate=" + delegate);
+ if (DEBUG) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: setDelegate(), delegate=%s", TAG, delegate);
+ }
if (mDelegate != null) {
throw new IllegalStateException(
"The delegate has already been set and should not change.");
@@ -240,7 +243,10 @@ public class TvPipNotificationController {
@Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
- if (DEBUG) Log.d(TAG, "on(Broadcast)Receive(), action=" + action);
+ if (DEBUG) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: on(Broadcast)Receive(), action=%s", TAG, action);
+ }
if (ACTION_SHOW_PIP_MENU.equals(action)) {
mDelegate.showPictureInPictureMenu();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java b/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java
index 1ddc0e7abeaf..64017e176fc3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java
@@ -38,6 +38,8 @@ public enum ShellProtoLogGroup implements IProtoLogGroup {
"ShellBackPreview"),
WM_SHELL_RECENT_TASKS(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
Consts.TAG_WM_SHELL),
+ WM_SHELL_PICTURE_IN_PICTURE(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG,
+ false, Consts.TAG_WM_SHELL),
TEST_GROUP(true, true, false, "WindowManagerShellProtoLogTest");
private final boolean mEnabled;
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 e88eef976e5c..2da5becae8f5 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
@@ -18,12 +18,14 @@ package com.android.wm.shell.splitscreen;
import static android.app.ActivityManager.START_SUCCESS;
import static android.app.ActivityManager.START_TASK_TO_FRONT;
+import static android.content.Intent.FLAG_ACTIVITY_NO_USER_ACTION;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.RemoteAnimationTarget.MODE_OPENING;
import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission;
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;
+import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED;
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_SIDE;
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_UNDEFINED;
import static com.android.wm.shell.transition.Transitions.ENABLE_SHELL_TRANSITIONS;
@@ -32,6 +34,7 @@ import android.app.ActivityManager;
import android.app.ActivityTaskManager;
import android.app.PendingIntent;
import android.content.ActivityNotFoundException;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.LauncherApps;
@@ -68,6 +71,7 @@ import com.android.wm.shell.common.SingleInstanceRemoteListener;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.common.annotations.ExternalThread;
+import com.android.wm.shell.common.split.SplitLayout;
import com.android.wm.shell.common.split.SplitScreenConstants.SplitPosition;
import com.android.wm.shell.draganddrop.DragAndDropPolicy;
import com.android.wm.shell.recents.RecentTasksController;
@@ -196,11 +200,12 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
@Nullable
public ActivityManager.RunningTaskInfo getTaskInfo(@SplitPosition int splitPosition) {
- if (isSplitScreenVisible()) {
- int taskId = mStageCoordinator.getTaskId(splitPosition);
- return mTaskOrganizer.getRunningTaskInfo(taskId);
+ if (!isSplitScreenVisible() || splitPosition == SPLIT_POSITION_UNDEFINED) {
+ return null;
}
- return null;
+
+ final int taskId = mStageCoordinator.getTaskId(splitPosition);
+ return mTaskOrganizer.getRunningTaskInfo(taskId);
}
public boolean isTaskInSplitScreen(int taskId) {
@@ -321,8 +326,8 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
}
}
- public void startIntent(PendingIntent intent, Intent fillInIntent, @SplitPosition int position,
- @Nullable Bundle options) {
+ public void startIntent(PendingIntent intent, @Nullable Intent fillInIntent,
+ @SplitPosition int position, @Nullable Bundle options) {
if (!ENABLE_SHELL_TRANSITIONS) {
startIntentLegacy(intent, fillInIntent, position, options);
return;
@@ -331,6 +336,15 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
try {
options = mStageCoordinator.resolveStartStage(STAGE_TYPE_UNDEFINED, position, options,
null /* wct */);
+
+ // Flag this as a no-user-action launch to prevent sending user leaving event to the
+ // current top activity since it's going to be put into another side of the split. This
+ // prevents the current top activity from going into pip mode due to user leaving event.
+ if (fillInIntent == null) {
+ fillInIntent = new Intent();
+ }
+ fillInIntent.addFlags(FLAG_ACTIVITY_NO_USER_ACTION);
+
intent.send(mContext, 0, fillInIntent, null /* onFinished */, null /* handler */,
null /* requiredPermission */, options);
} catch (PendingIntent.CanceledException e) {
@@ -338,7 +352,7 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
}
}
- private void startIntentLegacy(PendingIntent intent, Intent fillInIntent,
+ private void startIntentLegacy(PendingIntent intent, @Nullable Intent fillInIntent,
@SplitPosition int position, @Nullable Bundle options) {
final WindowContainerTransaction evictWct = new WindowContainerTransaction();
mStageCoordinator.prepareEvictChildTasks(position, evictWct);
@@ -350,6 +364,18 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
IRemoteAnimationFinishedCallback finishedCallback,
SurfaceControl.Transaction t) {
if (apps == null || apps.length == 0) {
+ final ActivityManager.RunningTaskInfo pairedTaskInfo =
+ getTaskInfo(SplitLayout.reversePosition(position));
+ final ComponentName pairedActivity =
+ pairedTaskInfo != null ? pairedTaskInfo.baseActivity : null;
+ final ComponentName intentActivity =
+ intent.getIntent() != null ? intent.getIntent().getComponent() : null;
+ if (pairedActivity != null && pairedActivity.equals(intentActivity)) {
+ // Switch split position if dragging the same activity to another side.
+ setSideStagePosition(SplitLayout.reversePosition(
+ mStageCoordinator.getSideStagePosition()));
+ }
+
// Do nothing when the animation was cancelled.
t.apply();
return;
@@ -377,6 +403,15 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
final WindowContainerTransaction wct = new WindowContainerTransaction();
options = mStageCoordinator.resolveStartStage(STAGE_TYPE_UNDEFINED, position, options, wct);
+
+ // Flag this as a no-user-action launch to prevent sending user leaving event to the current
+ // top activity since it's going to be put into another side of the split. This prevents the
+ // current top activity from going into pip mode due to user leaving event.
+ if (fillInIntent == null) {
+ fillInIntent = new Intent();
+ }
+ fillInIntent.addFlags(FLAG_ACTIVITY_NO_USER_ACTION);
+
wct.sendPendingIntent(intent, fillInIntent, options);
mSyncQueue.queue(transition, WindowManager.TRANSIT_OPEN, wct);
}
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 1a5e3f26ab37..ec1ddf077795 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
@@ -29,6 +29,7 @@ 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;
import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
@@ -1117,9 +1118,9 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
return SPLIT_POSITION_UNDEFINED;
}
- if (token.equals(mMainStage.mRootTaskInfo.getToken())) {
+ if (mMainStage.containsToken(token)) {
return getMainStagePosition();
- } else if (token.equals(mSideStage.mRootTaskInfo.getToken())) {
+ } else if (mSideStage.containsToken(token)) {
return getSideStagePosition();
}
@@ -1171,6 +1172,8 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
updateUnfoldBounds();
return;
}
+
+ mSplitLayout.update(null /* t */);
onLayoutSizeChanged(mSplitLayout);
}
}
@@ -1198,7 +1201,6 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
if (!ENABLE_SHELL_TRANSITIONS) return;
final SurfaceControl.Transaction t = mTransactionPool.acquire();
- setDividerVisibility(false, t);
mDisplayLayout.rotateTo(mContext.getResources(), toRotation);
mSplitLayout.rotateTo(toRotation, mDisplayLayout.stableInsets());
updateWindowBounds(mSplitLayout, wct);
@@ -1255,8 +1257,15 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
@Nullable TransitionRequestInfo request) {
final ActivityManager.RunningTaskInfo triggerTask = request.getTriggerTask();
if (triggerTask == null) {
- // Still want to monitor everything while in split-screen, so return non-null.
- return mMainStage.isActive() ? new WindowContainerTransaction() : null;
+ if (mMainStage.isActive()) {
+ if (request.getType() == TRANSIT_CHANGE && request.getDisplayChange() != null) {
+ mSplitLayout.setFreezeDividerWindow(true);
+ }
+ // Still want to monitor everything while in split-screen, so return non-null.
+ return new WindowContainerTransaction();
+ } else {
+ return null;
+ }
} else if (triggerTask.displayId != mDisplayId) {
// Skip handling task on the other display.
return null;
@@ -1329,8 +1338,11 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
// Once the pending enter transition got merged, make sure to bring divider bar visible and
// clear the pending transition from cache to prevent mess-up the following state.
if (transition == mSplitTransitions.mPendingEnter) {
- finishEnterSplitScreen(null);
+ final SurfaceControl.Transaction t = mTransactionPool.acquire();
+ finishEnterSplitScreen(t);
mSplitTransitions.mPendingEnter = null;
+ t.apply();
+ mTransactionPool.release(t);
}
}
@@ -1349,8 +1361,14 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
// If we're not in split-mode, just abort so something else can handle it.
if (!mMainStage.isActive()) return false;
+ mSplitLayout.setFreezeDividerWindow(false);
for (int iC = 0; iC < info.getChanges().size(); ++iC) {
final TransitionInfo.Change change = info.getChanges().get(iC);
+ if (change.getMode() == TRANSIT_CHANGE
+ && (change.getFlags() & FLAG_IS_DISPLAY) != 0) {
+ mSplitLayout.update(startTransaction);
+ }
+
final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo();
if (taskInfo == null || !taskInfo.hasParentTask()) continue;
final StageTaskListener stage = getStageOfTask(taskInfo);
@@ -1365,10 +1383,6 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
Log.w(TAG, "Expected onTaskVanished on " + stage + " to have been called"
+ " with " + taskInfo.taskId + " before startAnimation().");
}
- } else if (info.getType() == TRANSIT_CHANGE
- && change.getStartRotation() != change.getEndRotation()) {
- // Show the divider after transition finished.
- setDividerVisibility(true, finishTransaction);
}
}
if (mMainStage.getChildCount() == 0 || mSideStage.getChildCount() == 0) {
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 c5aab45f56fa..5f0cd01f5416 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
@@ -124,6 +124,20 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener {
return mChildrenTaskInfo.contains(taskId);
}
+ boolean containsToken(WindowContainerToken token) {
+ if (token.equals(mRootTaskInfo.token)) {
+ return true;
+ }
+
+ for (int i = mChildrenTaskInfo.size() - 1; i >= 0; --i) {
+ if (token.equals(mChildrenTaskInfo.valueAt(i).token)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
/**
* Returns the top visible child task's id.
*/
@@ -280,10 +294,20 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener {
@Override
public void attachChildSurfaceToTask(int taskId, SurfaceControl.Builder b) {
+ b.setParent(findTaskSurface(taskId));
+ }
+
+ @Override
+ public void reparentChildSurfaceToTask(int taskId, SurfaceControl sc,
+ SurfaceControl.Transaction t) {
+ t.reparent(sc, findTaskSurface(taskId));
+ }
+
+ private SurfaceControl findTaskSurface(int taskId) {
if (mRootTaskInfo.taskId == taskId) {
- b.setParent(mRootLeash);
+ return mRootLeash;
} else if (mChildrenLeashes.contains(taskId)) {
- b.setParent(mChildrenLeashes.get(taskId));
+ return mChildrenLeashes.get(taskId);
} else {
throw new IllegalArgumentException("There is no surface for taskId=" + taskId);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/StageTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/StageTaskListener.java
index 8b36c9406b15..7b679580fa87 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/StageTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/StageTaskListener.java
@@ -227,10 +227,20 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener {
@Override
public void attachChildSurfaceToTask(int taskId, SurfaceControl.Builder b) {
+ b.setParent(findTaskSurface(taskId));
+ }
+
+ @Override
+ public void reparentChildSurfaceToTask(int taskId, SurfaceControl sc,
+ SurfaceControl.Transaction t) {
+ t.reparent(sc, findTaskSurface(taskId));
+ }
+
+ private SurfaceControl findTaskSurface(int taskId) {
if (mRootTaskInfo.taskId == taskId) {
- b.setParent(mRootLeash);
+ return mRootLeash;
} else if (mChildrenLeashes.contains(taskId)) {
- b.setParent(mChildrenLeashes.get(taskId));
+ return mChildrenLeashes.get(taskId);
} else {
throw new IllegalArgumentException("There is no surface for taskId=" + 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 1bef552e57ca..0d46199bde77 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
@@ -62,6 +62,7 @@ import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.RectF;
import android.hardware.HardwareBuffer;
+import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.Trace;
@@ -243,7 +244,7 @@ public class TaskSnapshotWindow {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "TaskSnapshot#relayout");
session.relayout(window, layoutParams, -1, -1, View.VISIBLE, 0,
tmpFrames, tmpMergedConfiguration, surfaceControl, tmpInsetsState,
- tmpControls);
+ tmpControls, new Bundle());
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
} catch (RemoteException e) {
snapshotSurface.clearWindowSynced();
@@ -517,7 +518,7 @@ public class TaskSnapshotWindow {
private void reportDrawn() {
try {
- mSession.finishDrawing(mWindow, null /* postDrawTransaction */);
+ mSession.finishDrawing(mWindow, null /* postDrawTransaction */, Integer.MAX_VALUE);
} catch (RemoteException e) {
clearWindowSynced();
}
@@ -534,7 +535,7 @@ public class TaskSnapshotWindow {
@Override
public void resized(ClientWindowFrames frames, boolean reportDraw,
MergedConfiguration mergedConfiguration, boolean forceLayout,
- boolean alwaysConsumeSystemBars, int displayId) {
+ boolean alwaysConsumeSystemBars, int displayId, int seqId, int resizeMode) {
if (mOuter != null) {
mOuter.mSplashScreenExecutor.execute(() -> {
if (mergedConfiguration != null
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 56d51687603a..2aa63b3571ab 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
@@ -189,7 +189,7 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
}
private void updateEnterpriseThumbnailDrawable() {
- mEnterpriseThumbnailDrawable = mDevicePolicyManager.getDrawable(
+ mEnterpriseThumbnailDrawable = mDevicePolicyManager.getResources().getDrawable(
WORK_PROFILE_ICON, OUTLINE, PROFILE_SWITCH_ANIMATION,
() -> mContext.getDrawable(R.drawable.ic_corp_badge));
}
@@ -408,7 +408,8 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
|| type == TRANSIT_CLOSE
|| type == TRANSIT_TO_FRONT
|| type == TRANSIT_TO_BACK;
- if (isOpenOrCloseTransition) {
+ final boolean isTranslucent = (change.getFlags() & FLAG_TRANSLUCENT) != 0;
+ if (isOpenOrCloseTransition && !isTranslucent) {
// Use the overview background as the background for the animation
final Context uiContext = ActivityThread.currentActivityThread()
.getSystemUiContext();
@@ -729,14 +730,17 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
? R.styleable.WindowAnimation_wallpaperCloseEnterAnimation
: R.styleable.WindowAnimation_wallpaperCloseExitAnimation;
} else if (type == TRANSIT_OPEN) {
- if (isTask) {
+ // We will translucent open animation for translucent activities and tasks. Choose
+ // WindowAnimation_activityOpenEnterAnimation and set translucent here, then
+ // TransitionAnimation loads appropriate animation later.
+ if ((changeFlags & FLAG_TRANSLUCENT) != 0 && enter) {
+ translucent = true;
+ }
+ if (isTask && !translucent) {
animAttr = enter
? R.styleable.WindowAnimation_taskOpenEnterAnimation
: R.styleable.WindowAnimation_taskOpenExitAnimation;
} else {
- if ((changeFlags & FLAG_TRANSLUCENT) != 0 && enter) {
- translucent = true;
- }
animAttr = enter
? R.styleable.WindowAnimation_activityOpenEnterAnimation
: R.styleable.WindowAnimation_activityOpenExitAnimation;
@@ -770,7 +774,7 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
.loadAnimationAttr(options.getPackageName(), options.getAnimations(),
animAttr, translucent);
} else {
- a = mTransitionAnimation.loadDefaultAnimationAttr(animAttr);
+ a = mTransitionAnimation.loadDefaultAnimationAttr(animAttr, translucent);
}
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
index efb52a5b4644..435d67087f34 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
@@ -73,9 +73,9 @@ public class Transitions implements RemoteCallable<Transitions> {
/** Set to {@code true} to enable shell transitions. */
public static final boolean ENABLE_SHELL_TRANSITIONS =
- SystemProperties.getBoolean("persist.debug.shell_transit", false);
+ SystemProperties.getBoolean("persist.wm.debug.shell_transit", false);
public static final boolean SHELL_TRANSITIONS_ROTATION = ENABLE_SHELL_TRANSITIONS
- && SystemProperties.getBoolean("persist.debug.shell_transit_rotate", false);
+ && SystemProperties.getBoolean("persist.wm.debug.shell_transit_rotate", false);
/** Transition type for exiting PIP via the Shell, via pressing the expand button. */
public static final int TRANSIT_EXIT_PIP = TRANSIT_FIRST_CUSTOM + 1;
@@ -109,6 +109,9 @@ public class Transitions implements RemoteCallable<Transitions> {
/** List of possible handlers. Ordered by specificity (eg. tapped back to front). */
private final ArrayList<TransitionHandler> mHandlers = new ArrayList<>();
+ /** List of {@link Runnable} instances to run when the last active transition has finished. */
+ private final ArrayList<Runnable> mRunWhenIdleQueue = new ArrayList<>();
+
private float mTransitionAnimationScaleSetting = 1.0f;
private static final class ActiveTransition {
@@ -224,6 +227,21 @@ public class Transitions implements RemoteCallable<Transitions> {
mRemoteTransitionHandler.removeFiltered(remoteTransition);
}
+ /**
+ * Runs the given {@code runnable} when the last active transition has finished, or immediately
+ * if there are currently no active transitions.
+ *
+ * <p>This method should be called on the Shell main-thread, where the given {@code runnable}
+ * will be executed when the last active transition is finished.
+ */
+ public void runOnIdle(Runnable runnable) {
+ if (mActiveTransitions.isEmpty()) {
+ runnable.run();
+ } else {
+ mRunWhenIdleQueue.add(runnable);
+ }
+ }
+
/** @return true if the transition was triggered by opening something vs closing something */
public static boolean isOpeningType(@WindowManager.TransitionType int type) {
return type == TRANSIT_OPEN
@@ -363,7 +381,9 @@ public class Transitions implements RemoteCallable<Transitions> {
return;
}
- // apply transfer starting window directly if there is no other task change.
+ // apply transfer starting window directly if there is no other task change. Since this
+ // is an activity->activity situation, we can detect it by selecting transitions with only
+ // 2 changes where neither are tasks and one is a starting-window recipient.
final int changeSize = info.getChanges().size();
if (changeSize == 2) {
boolean nonTaskChange = true;
@@ -380,7 +400,9 @@ public class Transitions implements RemoteCallable<Transitions> {
}
if (nonTaskChange && transferStartingWindow) {
t.apply();
- onFinish(transitionToken, null /* wct */, null /* wctCB */);
+ // Treat this as an abort since we are bypassing any merge logic and effectively
+ // finishing immediately.
+ onAbort(transitionToken);
return;
}
}
@@ -516,6 +538,11 @@ public class Transitions implements RemoteCallable<Transitions> {
if (mActiveTransitions.size() <= activeIdx) {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "All active transition animations "
+ "finished");
+ // Run all runnables from the run-when-idle queue.
+ for (int i = 0; i < mRunWhenIdleQueue.size(); i++) {
+ mRunWhenIdleQueue.get(i).run();
+ }
+ mRunWhenIdleQueue.clear();
return;
}
// Start animating the next active transition
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/LaunchBubbleFromLockScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/LaunchBubbleFromLockScreen.kt
index 61e27f21aa0f..fb404b913465 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/LaunchBubbleFromLockScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/LaunchBubbleFromLockScreen.kt
@@ -16,6 +16,7 @@
package com.android.wm.shell.flicker.bubble
+import android.platform.test.annotations.Presubmit
import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import androidx.test.uiautomator.By
@@ -24,6 +25,8 @@ 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.runner.RunWith
import org.junit.Test
import org.junit.runners.Parameterized
@@ -69,9 +72,19 @@ class LaunchBubbleFromLockScreen(testSpec: FlickerTestParameter) : BaseBubbleScr
}
}
- @FlakyTest
+ @Presubmit
@Test
fun testAppIsVisibleAtEnd() {
+ Assume.assumeFalse(isShellTransitionsEnabled)
+ testSpec.assertLayersEnd {
+ this.isVisible(testApp.component)
+ }
+ }
+
+ @FlakyTest
+ @Test
+ fun testAppIsVisibleAtEnd_ShellTransit() {
+ Assume.assumeTrue(isShellTransitionsEnabled)
testSpec.assertLayersEnd {
this.isVisible(testApp.component)
}
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 a57d3e63b559..c43230e77683 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
@@ -16,6 +16,7 @@
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
@@ -57,9 +58,19 @@ open class LaunchBubbleScreen(testSpec: FlickerTestParameter) : BaseBubbleScreen
}
}
- @FlakyTest(bugId = 218642026)
+ @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/helpers/BaseAppHelper.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/BaseAppHelper.kt
index 57bc0d580d72..3dd9e0572947 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/BaseAppHelper.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/BaseAppHelper.kt
@@ -61,7 +61,7 @@ abstract class BaseAppHelper(
private const val APP_CLOSE_WAIT_TIME_MS = 3_000L
fun isShellTransitionsEnabled() =
- SystemProperties.getBoolean("persist.debug.shell_transit", false)
+ SystemProperties.getBoolean("persist.wm.debug.shell_transit", false)
fun executeShellCommand(instrumentation: Instrumentation, cmd: String) {
try {
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 905468514a65..3e7ee25da5f8 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
@@ -78,6 +78,7 @@ public class BackAnimationControllerTest {
MockitoAnnotations.initMocks(this);
mController = new BackAnimationController(
mShellExecutor, mTransaction, mActivityTaskManager, mContext);
+ mController.setEnableAnimations(true);
}
private void createNavigationInfo(RemoteAnimationTarget topAnimationTarget,
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitWindowManagerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitWindowManagerTests.java
index 9bb54a18063f..2e5078d86a8b 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitWindowManagerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitWindowManagerTests.java
@@ -61,7 +61,7 @@ public class SplitWindowManagerTests extends ShellTestCase {
public void testInitRelease() {
mSplitWindowManager.init(mSplitLayout, new InsetsState());
assertThat(mSplitWindowManager.getSurfaceControl()).isNotNull();
- mSplitWindowManager.release();
+ mSplitWindowManager.release(null /* t */);
assertThat(mSplitWindowManager.getSurfaceControl()).isNull();
}
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java
index 29e40be457d1..4607d8acc63e 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java
@@ -53,6 +53,7 @@ import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.compatui.letterboxedu.LetterboxEduWindowManager;
+import com.android.wm.shell.transition.Transitions;
import org.junit.Before;
import org.junit.Test;
@@ -62,6 +63,8 @@ import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import dagger.Lazy;
+
/**
* Tests for {@link CompatUIController}.
*
@@ -82,6 +85,7 @@ public class CompatUIControllerTest extends ShellTestCase {
private @Mock ShellTaskOrganizer.TaskListener mMockTaskListener;
private @Mock SyncTransactionQueue mMockSyncQueue;
private @Mock ShellExecutor mMockExecutor;
+ private @Mock Lazy<Transitions> mMockTransitionsLazy;
private @Mock CompatUIWindowManager mMockCompatLayout;
private @Mock LetterboxEduWindowManager mMockLetterboxEduLayout;
@@ -102,7 +106,8 @@ public class CompatUIControllerTest extends ShellTestCase {
doReturn(true).when(mMockLetterboxEduLayout).createLayout(anyBoolean());
doReturn(true).when(mMockLetterboxEduLayout).updateCompatInfo(any(), any(), anyBoolean());
mController = new CompatUIController(mContext, mMockDisplayController,
- mMockDisplayInsetsController, mMockImeController, mMockSyncQueue, mMockExecutor) {
+ mMockDisplayInsetsController, mMockImeController, mMockSyncQueue, mMockExecutor,
+ mMockTransitionsLazy) {
@Override
CompatUIWindowManager createCompatUiWindowManager(Context context, TaskInfo taskInfo,
ShellTaskOrganizer.TaskListener taskListener) {
@@ -325,17 +330,17 @@ public class CompatUIControllerTest extends ShellTestCase {
}
@Test
- public void testChangeLayoutsVisibilityOnKeyguardOccludedChanged() {
+ public void testChangeLayoutsVisibilityOnKeyguardShowingChanged() {
mController.onCompatInfoChanged(createTaskInfo(DISPLAY_ID, TASK_ID,
/* hasSizeCompat= */ true, CAMERA_COMPAT_CONTROL_HIDDEN), mMockTaskListener);
- // Verify that the restart button is hidden after keyguard becomes occluded.
- mController.onKeyguardOccludedChanged(true);
+ // Verify that the restart button is hidden after keyguard becomes showing.
+ mController.onKeyguardShowingChanged(true);
verify(mMockCompatLayout).updateVisibility(false);
verify(mMockLetterboxEduLayout).updateVisibility(false);
- // Verify button remains hidden while keyguard is occluded.
+ // Verify button remains hidden while keyguard is showing.
TaskInfo taskInfo = createTaskInfo(DISPLAY_ID, TASK_ID, /* hasSizeCompat= */ true,
CAMERA_COMPAT_CONTROL_HIDDEN);
mController.onCompatInfoChanged(taskInfo, mMockTaskListener);
@@ -345,20 +350,20 @@ public class CompatUIControllerTest extends ShellTestCase {
verify(mMockLetterboxEduLayout).updateCompatInfo(taskInfo, mMockTaskListener, /* canShow= */
false);
- // Verify button is shown after keyguard becomes not occluded.
- mController.onKeyguardOccludedChanged(false);
+ // Verify button is shown after keyguard becomes not showing.
+ mController.onKeyguardShowingChanged(false);
verify(mMockCompatLayout).updateVisibility(true);
verify(mMockLetterboxEduLayout).updateVisibility(true);
}
@Test
- public void testLayoutsRemainHiddenOnKeyguardOccludedFalseWhenImeIsShowing() {
+ public void testLayoutsRemainHiddenOnKeyguardShowingFalseWhenImeIsShowing() {
mController.onCompatInfoChanged(createTaskInfo(DISPLAY_ID, TASK_ID,
/* hasSizeCompat= */ true, CAMERA_COMPAT_CONTROL_HIDDEN), mMockTaskListener);
mController.onImeVisibilityChanged(DISPLAY_ID, /* isShowing= */ true);
- mController.onKeyguardOccludedChanged(true);
+ mController.onKeyguardShowingChanged(true);
verify(mMockCompatLayout, times(2)).updateVisibility(false);
verify(mMockLetterboxEduLayout, times(2)).updateVisibility(false);
@@ -366,8 +371,8 @@ public class CompatUIControllerTest extends ShellTestCase {
clearInvocations(mMockCompatLayout);
clearInvocations(mMockLetterboxEduLayout);
- // Verify button remains hidden after keyguard becomes not occluded since IME is showing.
- mController.onKeyguardOccludedChanged(false);
+ // Verify button remains hidden after keyguard becomes not showing since IME is showing.
+ mController.onKeyguardShowingChanged(false);
verify(mMockCompatLayout).updateVisibility(false);
verify(mMockLetterboxEduLayout).updateVisibility(false);
@@ -380,12 +385,12 @@ public class CompatUIControllerTest extends ShellTestCase {
}
@Test
- public void testLayoutsRemainHiddenOnImeHideWhenKeyguardIsOccluded() {
+ public void testLayoutsRemainHiddenOnImeHideWhenKeyguardIsShowing() {
mController.onCompatInfoChanged(createTaskInfo(DISPLAY_ID, TASK_ID,
/* hasSizeCompat= */ true, CAMERA_COMPAT_CONTROL_HIDDEN), mMockTaskListener);
mController.onImeVisibilityChanged(DISPLAY_ID, /* isShowing= */ true);
- mController.onKeyguardOccludedChanged(true);
+ mController.onKeyguardShowingChanged(true);
verify(mMockCompatLayout, times(2)).updateVisibility(false);
verify(mMockLetterboxEduLayout, times(2)).updateVisibility(false);
@@ -393,14 +398,14 @@ public class CompatUIControllerTest extends ShellTestCase {
clearInvocations(mMockCompatLayout);
clearInvocations(mMockLetterboxEduLayout);
- // Verify button remains hidden after IME is hidden since keyguard is occluded.
+ // Verify button remains hidden after IME is hidden since keyguard is showing.
mController.onImeVisibilityChanged(DISPLAY_ID, /* isShowing= */ false);
verify(mMockCompatLayout).updateVisibility(false);
verify(mMockLetterboxEduLayout).updateVisibility(false);
- // Verify button is shown after keyguard becomes not occluded.
- mController.onKeyguardOccludedChanged(false);
+ // Verify button is shown after keyguard becomes not showing.
+ mController.onKeyguardShowingChanged(false);
verify(mMockCompatLayout).updateVisibility(true);
verify(mMockLetterboxEduLayout).updateVisibility(true);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduDialogLayoutTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduDialogLayoutTest.java
index 00e4938d866c..1dee88c43806 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduDialogLayoutTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduDialogLayoutTest.java
@@ -70,6 +70,8 @@ public class LetterboxEduDialogLayoutTest extends ShellTestCase {
public void testOnFinishInflate() {
assertEquals(mLayout.getDialogContainer(),
mLayout.findViewById(R.id.letterbox_education_dialog_container));
+ assertEquals(mLayout.getDialogTitle(),
+ mLayout.findViewById(R.id.letterbox_education_dialog_title));
assertEquals(mLayout.getBackgroundDim(), mLayout.getBackground());
assertEquals(mLayout.getBackground().getAlpha(), 0);
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduWindowManagerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduWindowManagerTest.java
index 0509dd38abe0..7d51b521a9fb 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduWindowManagerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduWindowManagerTest.java
@@ -41,9 +41,11 @@ import android.testing.AndroidTestingRunner;
import android.view.DisplayCutout;
import android.view.DisplayInfo;
import android.view.SurfaceControlViewHost;
+import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.MarginLayoutParams;
import android.view.WindowManager;
+import android.view.accessibility.AccessibilityEvent;
import androidx.test.filters.SmallTest;
@@ -52,6 +54,7 @@ import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.common.SyncTransactionQueue;
+import com.android.wm.shell.transition.Transitions;
import org.junit.After;
import org.junit.Before;
@@ -84,11 +87,14 @@ public class LetterboxEduWindowManagerTest extends ShellTestCase {
private ArgumentCaptor<WindowManager.LayoutParams> mWindowAttrsCaptor;
@Captor
private ArgumentCaptor<Runnable> mEndCallbackCaptor;
+ @Captor
+ private ArgumentCaptor<Runnable> mRunOnIdleCaptor;
@Mock private LetterboxEduAnimationController mAnimationController;
@Mock private SyncTransactionQueue mSyncTransactionQueue;
@Mock private ShellTaskOrganizer.TaskListener mTaskListener;
@Mock private SurfaceControlViewHost mViewHost;
+ @Mock private Transitions mTransitions;
@Mock private Runnable mOnDismissCallback;
private SharedPreferences mSharedPreferences;
@@ -173,13 +179,19 @@ public class LetterboxEduWindowManagerTest extends ShellTestCase {
verifyLayout(layout, mWindowAttrsCaptor.getValue(), /* expectedWidth= */ TASK_WIDTH,
/* expectedHeight= */ TASK_HEIGHT, /* expectedExtraTopMargin= */ DISPLAY_CUTOUT_TOP,
/* expectedExtraBottomMargin= */ DISPLAY_CUTOUT_BOTTOM);
+ View dialogTitle = layout.getDialogTitle();
+ assertNotNull(dialogTitle);
+ spyOn(dialogTitle);
// Clicking the layout does nothing until enter animation is done.
layout.performClick();
verify(mAnimationController, never()).startExitAnimation(any(), any());
+ // The dialog title shouldn't be focused for Accessibility until enter animation is done.
+ verify(dialogTitle, never()).sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
verifyAndFinishEnterAnimation(layout);
+ verify(dialogTitle).sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
// Exit animation should start following a click on the layout.
layout.performClick();
@@ -196,6 +208,23 @@ public class LetterboxEduWindowManagerTest extends ShellTestCase {
}
@Test
+ public void testCreateLayout_windowManagerReleasedBeforeTransitionsIsIdle_doesNotStartAnim() {
+ LetterboxEduWindowManager windowManager = createWindowManager(/* eligible= */ true);
+
+ assertTrue(windowManager.createLayout(/* canShow= */ true));
+
+ assertTrue(mSharedPreferences.getBoolean(mPrefKey, /* default= */ false));
+
+ verify(mTransitions).runOnIdle(mRunOnIdleCaptor.capture());
+
+ windowManager.release();
+
+ mRunOnIdleCaptor.getValue().run();
+
+ verify(mAnimationController, never()).startEnterAnimation(any(), any());
+ }
+
+ @Test
public void testUpdateCompatInfo_updatesLayoutCorrectly() {
LetterboxEduWindowManager windowManager = createWindowManager(/* eligible= */ true);
@@ -295,6 +324,13 @@ public class LetterboxEduWindowManagerTest extends ShellTestCase {
}
private void verifyAndFinishEnterAnimation(LetterboxEduDialogLayout layout) {
+ verify(mTransitions).runOnIdle(mRunOnIdleCaptor.capture());
+
+ // startEnterAnimation isn't called until run-on-idle runnable is called.
+ verify(mAnimationController, never()).startEnterAnimation(any(), any());
+
+ mRunOnIdleCaptor.getValue().run();
+
verify(mAnimationController).startEnterAnimation(eq(layout), mEndCallbackCaptor.capture());
mEndCallbackCaptor.getValue().run();
}
@@ -312,7 +348,8 @@ public class LetterboxEduWindowManagerTest extends ShellTestCase {
boolean isTaskbarEduShowing) {
LetterboxEduWindowManager windowManager = new LetterboxEduWindowManager(mContext,
createTaskInfo(eligible), mSyncTransactionQueue, mTaskListener,
- createDisplayLayout(), mOnDismissCallback, mAnimationController);
+ createDisplayLayout(), mTransitions, mOnDismissCallback,
+ mAnimationController);
spyOn(windowManager);
doReturn(mViewHost).when(windowManager).createSurfaceViewHost();
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/fullscreen/FullscreenTaskListenerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/fullscreen/FullscreenTaskListenerTest.java
index 46fe201072c9..4523e2c9cba5 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/fullscreen/FullscreenTaskListenerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/fullscreen/FullscreenTaskListenerTest.java
@@ -50,7 +50,7 @@ import java.util.Optional;
@SmallTest
public class FullscreenTaskListenerTest {
private static final boolean ENABLE_SHELL_TRANSITIONS =
- SystemProperties.getBoolean("persist.debug.shell_transit", false);
+ SystemProperties.getBoolean("persist.wm.debug.shell_transit", false);
@Mock
private SyncTransactionQueue mSyncQueue;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/kidsmode/KidsModeTaskOrganizerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/kidsmode/KidsModeTaskOrganizerTest.java
new file mode 100644
index 000000000000..ff6dfdb748c4
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/kidsmode/KidsModeTaskOrganizerTest.java
@@ -0,0 +1,149 @@
+/*
+ * 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.kidsmode;
+
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.view.Display.DEFAULT_DISPLAY;
+
+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.doReturn;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.app.ActivityManager;
+import android.content.Context;
+import android.content.pm.ParceledListSlice;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.view.InsetsState;
+import android.view.SurfaceControl;
+import android.window.ITaskOrganizerController;
+import android.window.TaskAppearedInfo;
+import android.window.WindowContainerToken;
+import android.window.WindowContainerTransaction;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import com.android.internal.policy.ForceShowNavigationBarSettingsObserver;
+import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.common.DisplayInsetsController;
+import com.android.wm.shell.common.ShellExecutor;
+import com.android.wm.shell.common.SyncTransactionQueue;
+import com.android.wm.shell.startingsurface.StartingWindowController;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.ArrayList;
+import java.util.Optional;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class KidsModeTaskOrganizerTest {
+ @Mock private ITaskOrganizerController mTaskOrganizerController;
+ @Mock private Context mContext;
+ @Mock private Handler mHandler;
+ @Mock private SyncTransactionQueue mSyncTransactionQueue;
+ @Mock private ShellExecutor mTestExecutor;
+ @Mock private DisplayController mDisplayController;
+ @Mock private SurfaceControl mLeash;
+ @Mock private WindowContainerToken mToken;
+ @Mock private WindowContainerTransaction mTransaction;
+ @Mock private ForceShowNavigationBarSettingsObserver mObserver;
+ @Mock private StartingWindowController mStartingWindowController;
+ @Mock private DisplayInsetsController mDisplayInsetsController;
+
+ KidsModeTaskOrganizer mOrganizer;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ try {
+ doReturn(ParceledListSlice.<TaskAppearedInfo>emptyList())
+ .when(mTaskOrganizerController).registerTaskOrganizer(any());
+ } catch (RemoteException e) {
+ }
+ // NOTE: KidsModeTaskOrganizer should have a null CompatUIController.
+ mOrganizer = spy(new KidsModeTaskOrganizer(mTaskOrganizerController, mTestExecutor,
+ mHandler, mContext, mSyncTransactionQueue, mDisplayController,
+ mDisplayInsetsController, Optional.empty(), mObserver));
+ mOrganizer.initialize(mStartingWindowController);
+ doReturn(mTransaction).when(mOrganizer).getWindowContainerTransaction();
+ doReturn(new InsetsState()).when(mDisplayController).getInsetsState(DEFAULT_DISPLAY);
+ }
+
+ @Test
+ public void testKidsModeOn() {
+ doReturn(true).when(mObserver).isEnabled();
+
+ mOrganizer.updateKidsModeState();
+
+ verify(mOrganizer, times(1)).enable();
+ verify(mOrganizer, times(1)).registerOrganizer();
+ verify(mOrganizer, times(1)).createRootTask(
+ eq(DEFAULT_DISPLAY), eq(WINDOWING_MODE_FULLSCREEN), eq(mOrganizer.mCookie));
+
+ final ActivityManager.RunningTaskInfo rootTask = createTaskInfo(12,
+ WINDOWING_MODE_FULLSCREEN, mOrganizer.mCookie);
+ mOrganizer.onTaskAppeared(rootTask, mLeash);
+
+ assertThat(mOrganizer.mLaunchRootLeash).isEqualTo(mLeash);
+ assertThat(mOrganizer.mLaunchRootTask).isEqualTo(rootTask);
+ }
+
+ @Test
+ public void testKidsModeOff() {
+ doReturn(true).when(mObserver).isEnabled();
+ mOrganizer.updateKidsModeState();
+ final ActivityManager.RunningTaskInfo rootTask = createTaskInfo(12,
+ WINDOWING_MODE_FULLSCREEN, mOrganizer.mCookie);
+ mOrganizer.onTaskAppeared(rootTask, mLeash);
+
+ doReturn(false).when(mObserver).isEnabled();
+ mOrganizer.updateKidsModeState();
+
+
+ verify(mOrganizer, times(1)).disable();
+ verify(mOrganizer, times(1)).unregisterOrganizer();
+ verify(mOrganizer, times(1)).deleteRootTask(rootTask.token);
+ assertThat(mOrganizer.mLaunchRootLeash).isNull();
+ assertThat(mOrganizer.mLaunchRootTask).isNull();
+ }
+
+ private ActivityManager.RunningTaskInfo createTaskInfo(
+ int taskId, int windowingMode, IBinder cookies) {
+ ActivityManager.RunningTaskInfo taskInfo = new ActivityManager.RunningTaskInfo();
+ taskInfo.taskId = taskId;
+ taskInfo.token = mToken;
+ taskInfo.configuration.windowConfiguration.setWindowingMode(windowingMode);
+ final ArrayList<IBinder> launchCookies = new ArrayList<>();
+ if (cookies != null) {
+ launchCookies.add(cookies);
+ }
+ taskInfo.launchCookies = launchCookies;
+ return taskInfo;
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
index 0172cf324eea..14d9fb9babc4 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
@@ -48,7 +48,6 @@ import com.android.wm.shell.TestShellExecutor;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.common.SyncTransactionQueue;
-import com.android.wm.shell.legacysplitscreen.LegacySplitScreenController;
import com.android.wm.shell.pip.phone.PhonePipMenuController;
import com.android.wm.shell.splitscreen.SplitScreenController;
@@ -76,7 +75,6 @@ public class PipTaskOrganizerTest extends ShellTestCase {
@Mock private PipTransitionController mMockPipTransitionController;
@Mock private PipSurfaceTransactionHelper mMockPipSurfaceTransactionHelper;
@Mock private PipUiEventLogger mMockPipUiEventLogger;
- @Mock private Optional<LegacySplitScreenController> mMockOptionalLegacySplitScreen;
@Mock private Optional<SplitScreenController> mMockOptionalSplitScreen;
@Mock private ShellTaskOrganizer mMockShellTaskOrganizer;
private TestShellExecutor mMainExecutor;
@@ -101,8 +99,8 @@ public class PipTaskOrganizerTest extends ShellTestCase {
mMockSyncTransactionQueue, mPipTransitionState, mPipBoundsState,
mPipBoundsAlgorithm, mMockPhonePipMenuController,
mMockPipAnimationController, mMockPipSurfaceTransactionHelper,
- mMockPipTransitionController, mMockOptionalLegacySplitScreen,
- mMockOptionalSplitScreen, mMockDisplayController, mMockPipUiEventLogger,
+ mMockPipTransitionController, mMockOptionalSplitScreen,
+ mMockDisplayController, mMockPipUiEventLogger,
mMockShellTaskOrganizer, mMainExecutor));
mMainExecutor.flushAll();
preparePipTaskOrg();
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/tv/TvPipKeepClearAlgorithmTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/tv/TvPipKeepClearAlgorithmTest.kt
new file mode 100644
index 000000000000..e6ba70e1b60e
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/tv/TvPipKeepClearAlgorithmTest.kt
@@ -0,0 +1,469 @@
+/*
+ * 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.pip.tv
+
+import android.graphics.Rect
+import android.testing.AndroidTestingRunner
+import android.util.Size
+import android.view.Gravity
+import org.junit.runner.RunWith
+import com.android.wm.shell.pip.PipBoundsState.STASH_TYPE_NONE
+import com.android.wm.shell.pip.PipBoundsState.STASH_TYPE_BOTTOM
+import com.android.wm.shell.pip.PipBoundsState.STASH_TYPE_RIGHT
+import com.android.wm.shell.pip.tv.TvPipKeepClearAlgorithm.Placement
+import org.junit.Before
+import org.junit.Test
+import junit.framework.Assert.assertEquals
+import junit.framework.Assert.assertNull
+
+@RunWith(AndroidTestingRunner::class)
+class TvPipKeepClearAlgorithmTest {
+ private val DEFAULT_PIP_SIZE = Size(384, 216)
+ private val EXPANDED_WIDE_PIP_SIZE = Size(384*2, 216)
+ private val DASHBOARD_WIDTH = 484
+ private val BOTTOM_SHEET_HEIGHT = 524
+ private val STASH_OFFSET = 64
+ private val PADDING = 16
+ private val SCREEN_SIZE = Size(1920, 1080)
+ private val SCREEN_EDGE_INSET = 50
+
+ private lateinit var pipSize: Size
+ private lateinit var movementBounds: Rect
+ private lateinit var algorithm: TvPipKeepClearAlgorithm
+ private var currentTime = 0L
+ private var restrictedAreas = mutableSetOf<Rect>()
+ private var unrestrictedAreas = mutableSetOf<Rect>()
+ private var gravity: Int = 0
+
+ @Before
+ fun setup() {
+ movementBounds = Rect(0, 0, SCREEN_SIZE.width, SCREEN_SIZE.height)
+ movementBounds.inset(SCREEN_EDGE_INSET, SCREEN_EDGE_INSET)
+
+ restrictedAreas.clear()
+ unrestrictedAreas.clear()
+ currentTime = 0L
+ pipSize = DEFAULT_PIP_SIZE
+ gravity = Gravity.BOTTOM or Gravity.RIGHT
+
+ algorithm = TvPipKeepClearAlgorithm({ currentTime })
+ algorithm.setScreenSize(SCREEN_SIZE)
+ algorithm.setMovementBounds(movementBounds)
+ algorithm.pipAreaPadding = PADDING
+ algorithm.stashOffset = STASH_OFFSET
+ algorithm.stashDuration = 5000L
+ algorithm.setGravity(gravity)
+ algorithm.maxRestrictedDistanceFraction = 0.3
+ }
+
+ @Test
+ fun testAnchorPosition_BottomRight() {
+ gravity = Gravity.BOTTOM or Gravity.RIGHT
+ testAnchorPosition()
+ }
+
+ @Test
+ fun testAnchorPosition_TopRight() {
+ gravity = Gravity.TOP or Gravity.RIGHT
+ testAnchorPosition()
+ }
+
+ @Test
+ fun testAnchorPosition_TopLeft() {
+ gravity = Gravity.TOP or Gravity.LEFT
+ testAnchorPosition()
+ }
+
+ @Test
+ fun testAnchorPosition_BottomLeft() {
+ gravity = Gravity.BOTTOM or Gravity.LEFT
+ testAnchorPosition()
+ }
+
+ @Test
+ fun testAnchorPosition_Right() {
+ gravity = Gravity.RIGHT
+ testAnchorPosition()
+ }
+
+ @Test
+ fun testAnchorPosition_Left() {
+ gravity = Gravity.LEFT
+ testAnchorPosition()
+ }
+
+ @Test
+ fun testAnchorPosition_Top() {
+ gravity = Gravity.TOP
+ testAnchorPosition()
+ }
+
+ @Test
+ fun testAnchorPosition_Bottom() {
+ gravity = Gravity.BOTTOM
+ testAnchorPosition()
+ }
+
+ @Test
+ fun testAnchorPosition_TopCenterHorizontal() {
+ gravity = Gravity.TOP or Gravity.CENTER_HORIZONTAL
+ testAnchorPosition()
+ }
+
+ @Test
+ fun testAnchorPosition_BottomCenterHorizontal() {
+ gravity = Gravity.BOTTOM or Gravity.CENTER_HORIZONTAL
+ testAnchorPosition()
+ }
+
+ @Test
+ fun testAnchorPosition_RightCenterVertical() {
+ gravity = Gravity.RIGHT or Gravity.CENTER_VERTICAL
+ testAnchorPosition()
+ }
+
+ @Test
+ fun testAnchorPosition_LeftCenterVertical() {
+ gravity = Gravity.LEFT or Gravity.CENTER_VERTICAL
+ testAnchorPosition()
+ }
+
+ fun testAnchorPosition() {
+ val placement = getActualPlacement()
+
+ assertEquals(getExpectedAnchorBounds(), placement.bounds)
+ assertNotStashed(placement)
+ }
+
+ @Test
+ fun test_AnchorBottomRight_KeepClearNotObstructing_StayAtAnchor() {
+ gravity = Gravity.BOTTOM or Gravity.RIGHT
+
+ val sidebar = makeSideBar(DASHBOARD_WIDTH, Gravity.LEFT)
+ unrestrictedAreas.add(sidebar)
+
+ val expectedBounds = getExpectedAnchorBounds()
+
+ val placement = getActualPlacement()
+ assertEquals(expectedBounds, placement.bounds)
+ assertNotStashed(placement)
+ }
+
+ @Test
+ fun test_AnchorBottomRight_UnrestrictedRightSidebar_PushedLeft() {
+ gravity = Gravity.BOTTOM or Gravity.RIGHT
+
+ val sidebar = makeSideBar(DASHBOARD_WIDTH, Gravity.RIGHT)
+ unrestrictedAreas.add(sidebar)
+
+ val expectedBounds = anchorBoundsOffsetBy(SCREEN_EDGE_INSET - sidebar.width() - PADDING, 0)
+
+ val placement = getActualPlacement()
+ assertEquals(expectedBounds, placement.bounds)
+ assertNotStashed(placement)
+ }
+
+ @Test
+ fun test_AnchorTopRight_UnrestrictedRightSidebar_PushedLeft() {
+ gravity = Gravity.TOP or Gravity.RIGHT
+
+ val sidebar = makeSideBar(DASHBOARD_WIDTH, Gravity.RIGHT)
+ unrestrictedAreas.add(sidebar)
+
+ val expectedBounds = anchorBoundsOffsetBy(SCREEN_EDGE_INSET - sidebar.width() - PADDING, 0)
+
+ val placement = getActualPlacement()
+ assertEquals(expectedBounds, placement.bounds)
+ assertNotStashed(placement)
+ }
+
+ @Test
+ fun test_AnchorBottomLeft_UnrestrictedRightSidebar_StayAtAnchor() {
+ gravity = Gravity.BOTTOM or Gravity.LEFT
+
+ val sidebar = makeSideBar(DASHBOARD_WIDTH, Gravity.RIGHT)
+ unrestrictedAreas.add(sidebar)
+
+ val expectedBounds = anchorBoundsOffsetBy(0, 0)
+
+ val placement = getActualPlacement()
+ assertEquals(expectedBounds, placement.bounds)
+ assertNotStashed(placement)
+ }
+
+ @Test
+ fun test_AnchorBottom_UnrestrictedRightSidebar_StayAtAnchor() {
+ gravity = Gravity.BOTTOM
+
+ val sidebar = makeSideBar(DASHBOARD_WIDTH, Gravity.RIGHT)
+ unrestrictedAreas.add(sidebar)
+
+ val expectedBounds = anchorBoundsOffsetBy(0, 0)
+
+ val placement = getActualPlacement()
+ assertEquals(expectedBounds, placement.bounds)
+ assertNotStashed(placement)
+ }
+
+ @Test
+ fun testExpanded_AnchorBottom_UnrestrictedRightSidebar_StayAtAnchor() {
+ pipSize = EXPANDED_WIDE_PIP_SIZE
+ gravity = Gravity.BOTTOM
+
+ val sidebar = makeSideBar(DASHBOARD_WIDTH, Gravity.RIGHT)
+ unrestrictedAreas.add(sidebar)
+
+ val expectedBounds = anchorBoundsOffsetBy(0, 0)
+
+ val placement = getActualPlacement()
+ assertEquals(expectedBounds, placement.bounds)
+ assertNotStashed(placement)
+ }
+
+ @Test
+ fun test_AnchorBottomRight_RestrictedSmallBottomBar_PushedUp() {
+ gravity = Gravity.BOTTOM or Gravity.RIGHT
+
+ val bottomBar = makeBottomBar(96)
+ restrictedAreas.add(bottomBar)
+
+ val expectedBounds = anchorBoundsOffsetBy(0,
+ SCREEN_EDGE_INSET - bottomBar.height() - PADDING)
+
+ val placement = getActualPlacement()
+ assertEquals(expectedBounds, placement.bounds)
+ assertNotStashed(placement)
+ }
+
+ @Test
+ fun test_AnchorBottomRight_RestrictedBottomSheet_StashDownAtAnchor() {
+ gravity = Gravity.BOTTOM or Gravity.RIGHT
+
+ val bottomBar = makeBottomBar(BOTTOM_SHEET_HEIGHT)
+ restrictedAreas.add(bottomBar)
+
+ val expectedBounds = getExpectedAnchorBounds()
+ expectedBounds.offsetTo(expectedBounds.left, SCREEN_SIZE.height - STASH_OFFSET)
+
+ val placement = getActualPlacement()
+ assertEquals(expectedBounds, placement.bounds)
+ assertEquals(STASH_TYPE_BOTTOM, placement.stashType)
+ assertEquals(getExpectedAnchorBounds(), placement.unstashDestinationBounds)
+ assertEquals(algorithm.stashDuration, placement.unstashTime)
+ }
+
+ @Test
+ fun test_AnchorBottomRight_UnrestrictedBottomSheet_PushUp() {
+ gravity = Gravity.BOTTOM or Gravity.RIGHT
+
+ val bottomBar = makeBottomBar(BOTTOM_SHEET_HEIGHT)
+ unrestrictedAreas.add(bottomBar)
+
+ val expectedBounds = anchorBoundsOffsetBy(0,
+ SCREEN_EDGE_INSET - bottomBar.height() - PADDING)
+
+ val placement = getActualPlacement()
+ assertEquals(expectedBounds, placement.bounds)
+ assertNotStashed(placement)
+ }
+
+ @Test
+ fun test_AnchorBottomRight_UnrestrictedBottomSheet_RestrictedSidebar_StashAboveBottomSheet() {
+ gravity = Gravity.BOTTOM or Gravity.RIGHT
+
+ val bottomBar = makeBottomBar(BOTTOM_SHEET_HEIGHT)
+ unrestrictedAreas.add(bottomBar)
+
+ val maxRestrictedHorizontalPush =
+ (algorithm.maxRestrictedDistanceFraction * SCREEN_SIZE.width).toInt()
+ val sideBar = makeSideBar(maxRestrictedHorizontalPush + 100, Gravity.RIGHT)
+ restrictedAreas.add(sideBar)
+
+ val expectedUnstashBounds =
+ anchorBoundsOffsetBy(0, SCREEN_EDGE_INSET - bottomBar.height() - PADDING)
+
+ val expectedBounds = Rect(expectedUnstashBounds)
+ expectedBounds.offsetTo(SCREEN_SIZE.width - STASH_OFFSET, expectedBounds.top)
+
+ val placement = getActualPlacement()
+ assertEquals(expectedBounds, placement.bounds)
+ assertEquals(STASH_TYPE_RIGHT, placement.stashType)
+ assertEquals(expectedUnstashBounds, placement.unstashDestinationBounds)
+ assertEquals(algorithm.stashDuration, placement.unstashTime)
+ }
+
+ @Test
+ fun test_AnchorBottomRight_UnrestrictedBottomSheet_UnrestrictedSidebar_PushUpLeft() {
+ gravity = Gravity.BOTTOM or Gravity.RIGHT
+
+ val bottomBar = makeBottomBar(BOTTOM_SHEET_HEIGHT)
+ unrestrictedAreas.add(bottomBar)
+
+ val maxRestrictedHorizontalPush =
+ (algorithm.maxRestrictedDistanceFraction * SCREEN_SIZE.width).toInt()
+ val sideBar = makeSideBar(maxRestrictedHorizontalPush + 100, Gravity.RIGHT)
+ unrestrictedAreas.add(sideBar)
+
+ val expectedBounds = anchorBoundsOffsetBy(
+ SCREEN_EDGE_INSET - sideBar.width() - PADDING,
+ SCREEN_EDGE_INSET - bottomBar.height() - PADDING
+ )
+
+ val placement = getActualPlacement()
+ assertEquals(expectedBounds, placement.bounds)
+ assertNotStashed(placement)
+ }
+
+ @Test
+ fun test_Stashed_UnstashBoundsBecomeUnobstructed_Unstashes() {
+ gravity = Gravity.BOTTOM or Gravity.RIGHT
+
+ val bottomBar = makeBottomBar(BOTTOM_SHEET_HEIGHT)
+ unrestrictedAreas.add(bottomBar)
+
+ val maxRestrictedHorizontalPush =
+ (algorithm.maxRestrictedDistanceFraction * SCREEN_SIZE.width).toInt()
+ val sideBar = makeSideBar(maxRestrictedHorizontalPush + 100, Gravity.RIGHT)
+ restrictedAreas.add(sideBar)
+
+ val expectedUnstashBounds =
+ anchorBoundsOffsetBy(0, SCREEN_EDGE_INSET - bottomBar.height() - PADDING)
+
+ val expectedBounds = Rect(expectedUnstashBounds)
+ expectedBounds.offsetTo(SCREEN_SIZE.width - STASH_OFFSET, expectedBounds.top)
+
+ var placement = getActualPlacement()
+ assertEquals(expectedBounds, placement.bounds)
+ assertEquals(STASH_TYPE_RIGHT, placement.stashType)
+ assertEquals(expectedUnstashBounds, placement.unstashDestinationBounds)
+ assertEquals(algorithm.stashDuration, placement.unstashTime)
+
+ currentTime += 1000
+
+ restrictedAreas.remove(sideBar)
+ placement = getActualPlacement()
+ assertEquals(expectedUnstashBounds, placement.bounds)
+ assertNotStashed(placement)
+ }
+
+ @Test
+ fun test_Stashed_UnstashBoundsStaysObstructed_UnstashesAfterTimeout() {
+ gravity = Gravity.BOTTOM or Gravity.RIGHT
+
+ val bottomBar = makeBottomBar(BOTTOM_SHEET_HEIGHT)
+ unrestrictedAreas.add(bottomBar)
+
+ val maxRestrictedHorizontalPush =
+ (algorithm.maxRestrictedDistanceFraction * SCREEN_SIZE.width).toInt()
+ val sideBar = makeSideBar(maxRestrictedHorizontalPush + 100, Gravity.RIGHT)
+ restrictedAreas.add(sideBar)
+
+ val expectedUnstashBounds =
+ anchorBoundsOffsetBy(0, SCREEN_EDGE_INSET - bottomBar.height() - PADDING)
+
+ val expectedBounds = Rect(expectedUnstashBounds)
+ expectedBounds.offsetTo(SCREEN_SIZE.width - STASH_OFFSET, expectedBounds.top)
+
+ var placement = getActualPlacement()
+ assertEquals(expectedBounds, placement.bounds)
+ assertEquals(STASH_TYPE_RIGHT, placement.stashType)
+ assertEquals(expectedUnstashBounds, placement.unstashDestinationBounds)
+ assertEquals(algorithm.stashDuration, placement.unstashTime)
+
+ currentTime += algorithm.stashDuration
+
+ placement = getActualPlacement()
+ assertEquals(expectedUnstashBounds, placement.bounds)
+ assertNotStashed(placement)
+ }
+
+ @Test
+ fun test_Stashed_UnstashBoundsObstructionChanges_UnstashTimeExtended() {
+ gravity = Gravity.BOTTOM or Gravity.RIGHT
+
+ val bottomBar = makeBottomBar(BOTTOM_SHEET_HEIGHT)
+ unrestrictedAreas.add(bottomBar)
+
+ val maxRestrictedHorizontalPush =
+ (algorithm.maxRestrictedDistanceFraction * SCREEN_SIZE.width).toInt()
+ val sideBar = makeSideBar(maxRestrictedHorizontalPush + 100, Gravity.RIGHT)
+ restrictedAreas.add(sideBar)
+
+ val expectedUnstashBounds =
+ anchorBoundsOffsetBy(0, SCREEN_EDGE_INSET - bottomBar.height() - PADDING)
+
+ val expectedBounds = Rect(expectedUnstashBounds)
+ expectedBounds.offsetTo(SCREEN_SIZE.width - STASH_OFFSET, expectedBounds.top)
+
+ var placement = getActualPlacement()
+ assertEquals(expectedBounds, placement.bounds)
+ assertEquals(STASH_TYPE_RIGHT, placement.stashType)
+ assertEquals(expectedUnstashBounds, placement.unstashDestinationBounds)
+ assertEquals(algorithm.stashDuration, placement.unstashTime)
+
+ currentTime += 1000
+
+ val newObstruction = Rect(
+ 0,
+ expectedUnstashBounds.top,
+ expectedUnstashBounds.right,
+ expectedUnstashBounds.bottom
+ )
+ restrictedAreas.add(newObstruction)
+
+ placement = getActualPlacement()
+ assertEquals(expectedBounds, placement.bounds)
+ assertEquals(STASH_TYPE_RIGHT, placement.stashType)
+ assertEquals(expectedUnstashBounds, placement.unstashDestinationBounds)
+ assertEquals(currentTime + algorithm.stashDuration, placement.unstashTime)
+ }
+
+ private fun makeSideBar(width: Int, @Gravity.GravityFlags side: Int): Rect {
+ val sidebar = Rect(0, 0, width, SCREEN_SIZE.height)
+ if (side == Gravity.RIGHT) {
+ sidebar.offsetTo(SCREEN_SIZE.width - width, 0)
+ }
+ return sidebar
+ }
+
+ private fun makeBottomBar(height: Int): Rect {
+ return Rect(0, SCREEN_SIZE.height - height, SCREEN_SIZE.width, SCREEN_SIZE.height)
+ }
+
+ private fun getExpectedAnchorBounds(): Rect {
+ val expectedBounds = Rect()
+ Gravity.apply(gravity, pipSize.width, pipSize.height, movementBounds, expectedBounds)
+ return expectedBounds
+ }
+
+ private fun anchorBoundsOffsetBy(dx: Int, dy: Int): Rect {
+ val bounds = getExpectedAnchorBounds()
+ bounds.offset(dx, dy)
+ return bounds
+ }
+
+ private fun getActualPlacement(): Placement {
+ algorithm.setGravity(gravity)
+ return algorithm.calculatePipPosition(pipSize, restrictedAreas, unrestrictedAreas)
+ }
+
+ private fun assertNotStashed(actual: Placement) {
+ assertEquals(STASH_TYPE_NONE, actual.stashType)
+ assertNull(actual.unstashDestinationBounds)
+ assertEquals(0L, actual.unstashTime)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageTaskListenerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageTaskListenerTests.java
index 13b726efb046..157c30bcb6c7 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageTaskListenerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageTaskListenerTests.java
@@ -62,7 +62,7 @@ import org.mockito.MockitoAnnotations;
@RunWith(AndroidJUnit4.class)
public final class StageTaskListenerTests extends ShellTestCase {
private static final boolean ENABLE_SHELL_TRANSITIONS =
- SystemProperties.getBoolean("persist.debug.shell_transit", false);
+ SystemProperties.getBoolean("persist.wm.debug.shell_transit", false);
@Mock
private ShellTaskOrganizer mTaskOrganizer;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
index dbf93b4d7e0a..a0b12976b467 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
@@ -46,6 +46,7 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isNull;
+import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
@@ -93,7 +94,7 @@ import java.util.ArrayList;
* Tests for the shell transitions.
*
* Build/Install/Run:
- * atest WMShellUnitTests:ShellTransitionTests
+ * atest WMShellUnitTests:ShellTransitionTests
*/
@SmallTest
@RunWith(AndroidJUnit4.class)
@@ -600,6 +601,83 @@ public class ShellTransitionTests {
assertTrue(DefaultTransitionHandler.isRotationSeamless(seamlessDisplay, displays));
}
+ @Test
+ public void testRunWhenIdle() {
+ Transitions transitions = createTestTransitions();
+ transitions.replaceDefaultHandlerForTest(mDefaultHandler);
+
+ Runnable runnable1 = mock(Runnable.class);
+ Runnable runnable2 = mock(Runnable.class);
+ Runnable runnable3 = mock(Runnable.class);
+ Runnable runnable4 = mock(Runnable.class);
+
+ transitions.runOnIdle(runnable1);
+
+ // runnable1 is executed immediately because there are no active transitions.
+ verify(runnable1, times(1)).run();
+
+ clearInvocations(runnable1);
+
+ IBinder transitToken1 = new Binder();
+ transitions.requestStartTransition(transitToken1,
+ new TransitionRequestInfo(TRANSIT_OPEN, null /* trigger */, null /* remote */));
+ TransitionInfo info1 = new TransitionInfoBuilder(TRANSIT_OPEN)
+ .addChange(TRANSIT_OPEN).addChange(TRANSIT_CLOSE).build();
+ transitions.onTransitionReady(transitToken1, info1, mock(SurfaceControl.Transaction.class),
+ mock(SurfaceControl.Transaction.class));
+ assertEquals(1, mDefaultHandler.activeCount());
+
+ transitions.runOnIdle(runnable2);
+ transitions.runOnIdle(runnable3);
+
+ // runnable2 and runnable3 aren't executed immediately because there is an active
+ // transaction.
+
+ IBinder transitToken2 = new Binder();
+ transitions.requestStartTransition(transitToken2,
+ new TransitionRequestInfo(TRANSIT_CLOSE, null /* trigger */, null /* remote */));
+ TransitionInfo info2 = new TransitionInfoBuilder(TRANSIT_CLOSE)
+ .addChange(TRANSIT_OPEN).addChange(TRANSIT_CLOSE).build();
+ transitions.onTransitionReady(transitToken2, info2, mock(SurfaceControl.Transaction.class),
+ mock(SurfaceControl.Transaction.class));
+ assertEquals(1, mDefaultHandler.activeCount());
+
+ mDefaultHandler.finishAll();
+ mMainExecutor.flushAll();
+ // first transition finished
+ verify(mOrganizer, times(1)).finishTransition(eq(transitToken1), any(), any());
+ verify(mOrganizer, times(0)).finishTransition(eq(transitToken2), any(), any());
+ // But now the "queued" transition is running
+ assertEquals(1, mDefaultHandler.activeCount());
+
+ // runnable2 and runnable3 are still not executed because the second transition is still
+ // active.
+ verify(runnable2, times(0)).run();
+ verify(runnable3, times(0)).run();
+
+ mDefaultHandler.finishAll();
+ mMainExecutor.flushAll();
+ verify(mOrganizer, times(1)).finishTransition(eq(transitToken2), any(), any());
+
+ // runnable2 and runnable3 are executed after the second transition finishes because there
+ // are no other active transitions, runnable1 isn't executed again.
+ verify(runnable1, times(0)).run();
+ verify(runnable2, times(1)).run();
+ verify(runnable3, times(1)).run();
+
+ clearInvocations(runnable2);
+ clearInvocations(runnable3);
+
+ transitions.runOnIdle(runnable4);
+
+ // runnable4 is executed immediately because there are no active transitions, all other
+ // runnables aren't executed again.
+ verify(runnable1, times(0)).run();
+ verify(runnable2, times(0)).run();
+ verify(runnable3, times(0)).run();
+ verify(runnable4, times(1)).run();
+ }
+
class TransitionInfoBuilder {
final TransitionInfo mInfo;
@@ -749,7 +827,7 @@ public class ShellTransitionTests {
IWindowManager mockWM = mock(IWindowManager.class);
final IDisplayWindowListener[] displayListener = new IDisplayWindowListener[1];
try {
- doReturn(new int[] {DEFAULT_DISPLAY}).when(mockWM).registerDisplayWindowListener(any());
+ doReturn(new int[]{DEFAULT_DISPLAY}).when(mockWM).registerDisplayWindowListener(any());
} catch (RemoteException e) {
// No remote stuff happening, so this can't be hit
}
diff --git a/libs/androidfw/Android.bp b/libs/androidfw/Android.bp
index 63b831de5da1..c80fb188e70f 100644
--- a/libs/androidfw/Android.bp
+++ b/libs/androidfw/Android.bp
@@ -118,7 +118,7 @@ cc_library {
"libz",
],
},
- linux_glibc: {
+ host_linux: {
srcs: [
"CursorWindow.cpp",
],
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index f6ad4c2f3aa5..ece150a4bd45 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -535,7 +535,10 @@ cc_defaults {
target: {
android: {
- header_libs: ["libandroid_headers_private"],
+ header_libs: [
+ "libandroid_headers_private",
+ "libtonemap_headers",
+ ],
srcs: [
"hwui/AnimatedImageThread.cpp",
diff --git a/libs/hwui/HardwareBitmapUploader.cpp b/libs/hwui/HardwareBitmapUploader.cpp
index dd272cd5ff7d..c24cabb287de 100644
--- a/libs/hwui/HardwareBitmapUploader.cpp
+++ b/libs/hwui/HardwareBitmapUploader.cpp
@@ -310,6 +310,11 @@ bool HardwareBitmapUploader::has1010102Support() {
return has101012Support;
}
+bool HardwareBitmapUploader::hasAlpha8Support() {
+ static bool hasAlpha8Support = checkSupport(AHARDWAREBUFFER_FORMAT_R8_UNORM);
+ return hasAlpha8Support;
+}
+
static FormatInfo determineFormat(const SkBitmap& skBitmap, bool usingGL) {
FormatInfo formatInfo;
switch (skBitmap.info().colorType()) {
@@ -363,6 +368,13 @@ static FormatInfo determineFormat(const SkBitmap& skBitmap, bool usingGL) {
}
formatInfo.format = GL_RGBA;
break;
+ case kAlpha_8_SkColorType:
+ formatInfo.isSupported = HardwareBitmapUploader::hasAlpha8Support();
+ formatInfo.bufferFormat = AHARDWAREBUFFER_FORMAT_R8_UNORM;
+ formatInfo.format = GL_R8;
+ formatInfo.type = GL_UNSIGNED_BYTE;
+ formatInfo.vkFormat = VK_FORMAT_R8_UNORM;
+ break;
default:
ALOGW("unable to create hardware bitmap of colortype: %d", skBitmap.info().colorType());
formatInfo.valid = false;
diff --git a/libs/hwui/HardwareBitmapUploader.h b/libs/hwui/HardwareBitmapUploader.h
index 34f43cd8a198..81057a24c29c 100644
--- a/libs/hwui/HardwareBitmapUploader.h
+++ b/libs/hwui/HardwareBitmapUploader.h
@@ -30,11 +30,13 @@ public:
#ifdef __ANDROID__
static bool hasFP16Support();
static bool has1010102Support();
+ static bool hasAlpha8Support();
#else
static bool hasFP16Support() {
return true;
}
static bool has1010102Support() { return true; }
+ static bool hasAlpha8Support() { return true; }
#endif
};
diff --git a/libs/hwui/Properties.cpp b/libs/hwui/Properties.cpp
index bcfe9c3ecab4..30ca7d155c4c 100644
--- a/libs/hwui/Properties.cpp
+++ b/libs/hwui/Properties.cpp
@@ -135,7 +135,7 @@ bool Properties::load() {
skpCaptureEnabled = debuggingEnabled && base::GetBoolProperty(PROPERTY_CAPTURE_SKP_ENABLED, false);
SkAndroidFrameworkTraceUtil::setEnableTracing(
- base::GetBoolProperty(PROPERTY_SKIA_ATRACE_ENABLED, false));
+ base::GetBoolProperty(PROPERTY_SKIA_ATRACE_ENABLED, true));
runningInEmulator = base::GetBoolProperty(PROPERTY_IS_EMULATOR, false);
diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp
index 1a89cfd5d0ad..67f47580a70f 100644
--- a/libs/hwui/hwui/Bitmap.cpp
+++ b/libs/hwui/hwui/Bitmap.cpp
@@ -104,6 +104,10 @@ sk_sp<Bitmap> Bitmap::allocateAshmemBitmap(size_t size, const SkImageInfo& info,
sk_sp<Bitmap> Bitmap::allocateHardwareBitmap(const SkBitmap& bitmap) {
#ifdef __ANDROID__ // Layoutlib does not support hardware acceleration
+ if (bitmap.colorType() == kAlpha_8_SkColorType &&
+ !uirenderer::HardwareBitmapUploader::hasAlpha8Support()) {
+ return nullptr;
+ }
return uirenderer::HardwareBitmapUploader::allocateHardwareBitmap(bitmap);
#else
return Bitmap::allocateHeapBitmap(bitmap.info());
diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp
index 8c98c723dbb3..2357dfec72a6 100644
--- a/libs/hwui/renderthread/DrawFrameTask.cpp
+++ b/libs/hwui/renderthread/DrawFrameTask.cpp
@@ -133,6 +133,7 @@ int DrawFrameTask::drawFrame() {
}
void DrawFrameTask::postAndWait() {
+ ATRACE_CALL();
AutoMutex _lock(mLock);
mRenderThread->queue().post([this]() { run(); });
mSignal.wait(mLock);
diff --git a/libs/storage/IMountService.cpp b/libs/storage/IMountService.cpp
index fd6e6e932ebc..99508a2943ff 100644
--- a/libs/storage/IMountService.cpp
+++ b/libs/storage/IMountService.cpp
@@ -48,8 +48,6 @@ enum {
TRANSACTION_isObbMounted,
TRANSACTION_getMountedObbPath,
TRANSACTION_isExternalStorageEmulated,
- TRANSACTION_decryptStorage,
- TRANSACTION_encryptStorage,
};
class BpMountService: public BpInterface<IMountService>
@@ -442,14 +440,13 @@ public:
reply.readExceptionCode();
}
- void mountObb(const String16& rawPath, const String16& canonicalPath, const String16& key,
+ void mountObb(const String16& rawPath, const String16& canonicalPath,
const sp<IObbActionListener>& token, int32_t nonce, const sp<ObbInfo>& obbInfo)
{
Parcel data, reply;
data.writeInterfaceToken(IMountService::getInterfaceDescriptor());
data.writeString16(rawPath);
data.writeString16(canonicalPath);
- data.writeString16(key);
data.writeStrongBinder(IInterface::asBinder(token));
data.writeInt32(nonce);
obbInfo->writeToParcel(&data);
@@ -518,40 +515,6 @@ public:
path = reply.readString16();
return true;
}
-
- int32_t decryptStorage(const String16& password)
- {
- Parcel data, reply;
- data.writeInterfaceToken(IMountService::getInterfaceDescriptor());
- data.writeString16(password);
- if (remote()->transact(TRANSACTION_decryptStorage, data, &reply) != NO_ERROR) {
- ALOGD("decryptStorage could not contact remote\n");
- return -1;
- }
- int32_t err = reply.readExceptionCode();
- if (err < 0) {
- ALOGD("decryptStorage caught exception %d\n", err);
- return err;
- }
- return reply.readInt32();
- }
-
- int32_t encryptStorage(const String16& password)
- {
- Parcel data, reply;
- data.writeInterfaceToken(IMountService::getInterfaceDescriptor());
- data.writeString16(password);
- if (remote()->transact(TRANSACTION_encryptStorage, data, &reply) != NO_ERROR) {
- ALOGD("encryptStorage could not contact remote\n");
- return -1;
- }
- int32_t err = reply.readExceptionCode();
- if (err < 0) {
- ALOGD("encryptStorage caught exception %d\n", err);
- return err;
- }
- return reply.readInt32();
- }
};
IMPLEMENT_META_INTERFACE(MountService, "android.os.storage.IStorageManager")
diff --git a/libs/storage/include/storage/IMountService.h b/libs/storage/include/storage/IMountService.h
index 2463e023efc1..5a9c39bc021b 100644
--- a/libs/storage/include/storage/IMountService.h
+++ b/libs/storage/include/storage/IMountService.h
@@ -64,14 +64,12 @@ public:
virtual void shutdown(const sp<IMountShutdownObserver>& observer) = 0;
virtual void finishMediaUpdate() = 0;
virtual void mountObb(const String16& rawPath, const String16& canonicalPath,
- const String16& key, const sp<IObbActionListener>& token,
- const int32_t nonce, const sp<ObbInfo>& obbInfo) = 0;
+ const sp<IObbActionListener>& token, const int32_t nonce,
+ const sp<ObbInfo>& obbInfo) = 0;
virtual void unmountObb(const String16& filename, const bool force,
const sp<IObbActionListener>& token, const int32_t nonce) = 0;
virtual bool isObbMounted(const String16& filename) = 0;
virtual bool getMountedObbPath(const String16& filename, String16& path) = 0;
- virtual int32_t decryptStorage(const String16& password) = 0;
- virtual int32_t encryptStorage(const String16& password) = 0;
};
// ----------------------------------------------------------------------------
diff --git a/location/java/android/location/GnssExcessPathInfo.java b/location/java/android/location/GnssExcessPathInfo.java
new file mode 100644
index 000000000000..72b2374bad8f
--- /dev/null
+++ b/location/java/android/location/GnssExcessPathInfo.java
@@ -0,0 +1,375 @@
+/*
+ * 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.location;
+
+import static android.hardware.gnss.measurement_corrections.SingleSatCorrection.ExcessPathInfo.EXCESS_PATH_INFO_HAS_ATTENUATION;
+import static android.hardware.gnss.measurement_corrections.SingleSatCorrection.ExcessPathInfo.EXCESS_PATH_INFO_HAS_EXCESS_PATH_LENGTH;
+import static android.hardware.gnss.measurement_corrections.SingleSatCorrection.ExcessPathInfo.EXCESS_PATH_INFO_HAS_EXCESS_PATH_LENGTH_UNC;
+import static android.hardware.gnss.measurement_corrections.SingleSatCorrection.ExcessPathInfo.EXCESS_PATH_INFO_HAS_REFLECTING_PLANE;
+
+import android.annotation.FloatRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.Objects;
+
+/**
+ * Contains the info of an excess path signal caused by reflection
+ *
+ * @hide
+ */
+@SystemApi
+public final class GnssExcessPathInfo implements Parcelable {
+
+ private static final int HAS_EXCESS_PATH_LENGTH_MASK = EXCESS_PATH_INFO_HAS_EXCESS_PATH_LENGTH;
+ private static final int HAS_EXCESS_PATH_LENGTH_UNC_MASK =
+ EXCESS_PATH_INFO_HAS_EXCESS_PATH_LENGTH_UNC;
+ private static final int HAS_REFLECTING_PLANE_MASK = EXCESS_PATH_INFO_HAS_REFLECTING_PLANE;
+ private static final int HAS_ATTENUATION_MASK = EXCESS_PATH_INFO_HAS_ATTENUATION;
+
+ /* A bitmask of fields present in this object (see HAS_* constants defined above) */
+ private final int mFlags;
+ private final float mExcessPathLengthMeters;
+ private final float mExcessPathLengthUncertaintyMeters;
+ @Nullable
+ private final GnssReflectingPlane mReflectingPlane;
+ private final float mAttenuationDb;
+
+ private GnssExcessPathInfo(
+ int flags,
+ float excessPathLengthMeters,
+ float excessPathLengthUncertaintyMeters,
+ @Nullable GnssReflectingPlane reflectingPlane,
+ float attenuationDb) {
+ mFlags = flags;
+ mExcessPathLengthMeters = excessPathLengthMeters;
+ mExcessPathLengthUncertaintyMeters = excessPathLengthUncertaintyMeters;
+ mReflectingPlane = reflectingPlane;
+ mAttenuationDb = attenuationDb;
+ }
+
+ /**
+ * Gets a bitmask of fields present in this object.
+ *
+ * <p>This API exists for JNI since it is easier for JNI to get one integer flag than looking up
+ * several has* methods.
+ * @hide
+ */
+ public int getFlags() {
+ return mFlags;
+ }
+
+ /** Returns {@code true} if {@link #getExcessPathLengthMeters()} is valid. */
+ public boolean hasExcessPathLength() {
+ return (mFlags & HAS_EXCESS_PATH_LENGTH_MASK) != 0;
+ }
+
+ /**
+ * Returns the excess path length to be subtracted from pseudorange before using it in
+ * calculating location.
+ *
+ * <p>{@link #hasExcessPathLength()} must be true when calling this method. Otherwise, an
+ * {@link UnsupportedOperationException} will be thrown.
+ */
+ @FloatRange(from = 0.0f)
+ public float getExcessPathLengthMeters() {
+ if (!hasExcessPathLength()) {
+ throw new UnsupportedOperationException(
+ "getExcessPathLengthMeters() is not supported when hasExcessPathLength() is "
+ + "false");
+ }
+ return mExcessPathLengthMeters;
+ }
+
+ /** Returns {@code true} if {@link #getExcessPathLengthUncertaintyMeters()} is valid. */
+ public boolean hasExcessPathLengthUncertainty() {
+ return (mFlags & HAS_EXCESS_PATH_LENGTH_UNC_MASK) != 0;
+ }
+
+ /**
+ * Returns the error estimate (1-sigma) for the excess path length estimate.
+ *
+ * <p>{@link #hasExcessPathLengthUncertainty()} must be true when calling this method.
+ * Otherwise, an {@link UnsupportedOperationException} will be thrown.
+ */
+ @FloatRange(from = 0.0f)
+ public float getExcessPathLengthUncertaintyMeters() {
+ if (!hasExcessPathLengthUncertainty()) {
+ throw new UnsupportedOperationException(
+ "getExcessPathLengthUncertaintyMeters() is not supported when "
+ + "hasExcessPathLengthUncertainty() is false");
+ }
+ return mExcessPathLengthUncertaintyMeters;
+ }
+
+ /**
+ * Returns {@code true} if {@link #getReflectingPlane()} is valid.
+ *
+ * <p>Returns false if the satellite signal goes through multiple reflections or if reflection
+ * plane serving is not supported.
+ */
+ public boolean hasReflectingPlane() {
+ return (mFlags & HAS_REFLECTING_PLANE_MASK) != 0;
+ }
+
+ /**
+ * Returns the reflecting plane characteristics at which the signal has bounced.
+ *
+ * <p>{@link #hasReflectingPlane()} must be true when calling this method. Otherwise, an
+ * {@link UnsupportedOperationException} will be thrown.
+ */
+ @NonNull
+ public GnssReflectingPlane getReflectingPlane() {
+ if (!hasReflectingPlane()) {
+ throw new UnsupportedOperationException(
+ "getReflectingPlane() is not supported when hasReflectingPlane() is false");
+ }
+ return mReflectingPlane;
+ }
+
+ /** Returns {@code true} if {@link #getAttenuationDb()} is valid. */
+ public boolean hasAttenuation() {
+ return (mFlags & HAS_ATTENUATION_MASK) != 0;
+ }
+
+ /**
+ * Returns the expected reduction of signal strength of this path in non-negative dB.
+ *
+ * <p>{@link #hasAttenuation()} must be true when calling this method. Otherwise, an
+ * {@link UnsupportedOperationException} will be thrown.
+ */
+ @FloatRange(from = 0.0f)
+ public float getAttenuationDb() {
+ if (!hasAttenuation()) {
+ throw new UnsupportedOperationException(
+ "getAttenuationDb() is not supported when hasAttenuation() is false");
+ }
+ return mAttenuationDb;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel parcel, int parcelFlags) {
+ parcel.writeInt(mFlags);
+ if (hasExcessPathLength()) {
+ parcel.writeFloat(mExcessPathLengthMeters);
+ }
+ if (hasExcessPathLengthUncertainty()) {
+ parcel.writeFloat(mExcessPathLengthUncertaintyMeters);
+ }
+ if (hasReflectingPlane()) {
+ mReflectingPlane.writeToParcel(parcel, parcelFlags);
+ }
+ if (hasAttenuation()) {
+ parcel.writeFloat(mAttenuationDb);
+ }
+ }
+
+ public static final @NonNull Creator<GnssExcessPathInfo> CREATOR =
+ new Creator<GnssExcessPathInfo>() {
+ @Override
+ @NonNull
+ public GnssExcessPathInfo createFromParcel(@NonNull Parcel parcel) {
+ int flags = parcel.readInt();
+ float excessPathLengthMeters =
+ (flags & HAS_EXCESS_PATH_LENGTH_MASK) != 0
+ ? parcel.readFloat() : 0;
+ float excessPathLengthUncertaintyMeters =
+ (flags & HAS_EXCESS_PATH_LENGTH_UNC_MASK) != 0
+ ? parcel.readFloat() : 0;
+ GnssReflectingPlane reflectingPlane =
+ (flags & HAS_REFLECTING_PLANE_MASK) != 0
+ ? GnssReflectingPlane.CREATOR.createFromParcel(parcel) : null;
+ float attenuationDb =
+ (flags & HAS_ATTENUATION_MASK) != 0
+ ? parcel.readFloat() : 0;
+ return new GnssExcessPathInfo(flags, excessPathLengthMeters,
+ excessPathLengthUncertaintyMeters, reflectingPlane, attenuationDb);
+ }
+
+ @Override
+ public GnssExcessPathInfo[] newArray(int i) {
+ return new GnssExcessPathInfo[i];
+ }
+ };
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof GnssExcessPathInfo) {
+ GnssExcessPathInfo that = (GnssExcessPathInfo) obj;
+ return this.mFlags == that.mFlags
+ && (!hasExcessPathLength() || Float.compare(this.mExcessPathLengthMeters,
+ that.mExcessPathLengthMeters) == 0)
+ && (!hasExcessPathLengthUncertainty() || Float.compare(
+ this.mExcessPathLengthUncertaintyMeters,
+ that.mExcessPathLengthUncertaintyMeters) == 0)
+ && (!hasReflectingPlane() || Objects.equals(this.mReflectingPlane,
+ that.mReflectingPlane))
+ && (!hasAttenuation() || Float.compare(this.mAttenuationDb,
+ that.mAttenuationDb) == 0);
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mFlags,
+ mExcessPathLengthMeters,
+ mExcessPathLengthUncertaintyMeters,
+ mReflectingPlane,
+ mAttenuationDb);
+ }
+
+ @NonNull
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder("GnssExcessPathInfo[");
+ if (hasExcessPathLength()) {
+ builder.append(" ExcessPathLengthMeters=").append(mExcessPathLengthMeters);
+ }
+ if (hasExcessPathLengthUncertainty()) {
+ builder.append(" ExcessPathLengthUncertaintyMeters=").append(
+ mExcessPathLengthUncertaintyMeters);
+ }
+ if (hasReflectingPlane()) {
+ builder.append(" ReflectingPlane=").append(mReflectingPlane);
+ }
+ if (hasAttenuation()) {
+ builder.append(" AttenuationDb=").append(mAttenuationDb);
+ }
+ builder.append(']');
+ return builder.toString();
+ }
+
+ /** Builder for {@link GnssExcessPathInfo}. */
+ public static final class Builder {
+ private int mFlags;
+ private float mExcessPathLengthMeters;
+ private float mExcessPathLengthUncertaintyMeters;
+ @Nullable
+ private GnssReflectingPlane mReflectingPlane;
+ private float mAttenuationDb;
+
+ /** Constructor for {@link Builder}. */
+ public Builder() {}
+
+ /**
+ * Sets the excess path length to be subtracted from pseudorange before using it in
+ * calculating location.
+ */
+ @NonNull
+ public Builder setExcessPathLengthMeters(
+ @FloatRange(from = 0.0f) float excessPathLengthMeters) {
+ Preconditions.checkArgumentInRange(excessPathLengthMeters, 0, Float.MAX_VALUE,
+ "excessPathLengthMeters");
+ mExcessPathLengthMeters = excessPathLengthMeters;
+ mFlags |= HAS_EXCESS_PATH_LENGTH_MASK;
+ return this;
+ }
+
+ /**
+ * Clears the excess path length.
+ *
+ * <p>This is to negate {@link #setExcessPathLengthMeters} call.
+ */
+ @NonNull
+ public Builder clearExcessPathLengthMeters() {
+ mExcessPathLengthMeters = 0;
+ mFlags &= ~HAS_EXCESS_PATH_LENGTH_MASK;
+ return this;
+ }
+
+ /** Sets the error estimate (1-sigma) for the excess path length estimate */
+ @NonNull
+ public Builder setExcessPathLengthUncertaintyMeters(
+ @FloatRange(from = 0.0f) float excessPathLengthUncertaintyMeters) {
+ Preconditions.checkArgumentInRange(excessPathLengthUncertaintyMeters, 0,
+ Float.MAX_VALUE, "excessPathLengthUncertaintyMeters");
+ mExcessPathLengthUncertaintyMeters = excessPathLengthUncertaintyMeters;
+ mFlags |= HAS_EXCESS_PATH_LENGTH_UNC_MASK;
+ return this;
+ }
+
+ /**
+ * Clears the error estimate (1-sigma) for the excess path length estimate
+ *
+ * <p>This is to negate {@link #setExcessPathLengthUncertaintyMeters} call.
+ */
+ @NonNull
+ public Builder clearExcessPathLengthUncertaintyMeters() {
+ mExcessPathLengthUncertaintyMeters = 0;
+ mFlags &= ~HAS_EXCESS_PATH_LENGTH_UNC_MASK;
+ return this;
+ }
+
+ /** Sets the reflecting plane information */
+ @NonNull
+ public Builder setReflectingPlane(@Nullable GnssReflectingPlane reflectingPlane) {
+ mReflectingPlane = reflectingPlane;
+ if (reflectingPlane != null) {
+ mFlags |= HAS_REFLECTING_PLANE_MASK;
+ } else {
+ mFlags &= ~HAS_REFLECTING_PLANE_MASK;
+ }
+ return this;
+ }
+
+ /**
+ * Sets the attenuation value in dB.
+ */
+ @NonNull
+ public Builder setAttenuationDb(@FloatRange(from = 0.0f) float attenuationDb) {
+ Preconditions.checkArgumentInRange(attenuationDb, 0, Float.MAX_VALUE,
+ "attenuationDb");
+ mAttenuationDb = attenuationDb;
+ mFlags |= HAS_ATTENUATION_MASK;
+ return this;
+ }
+
+ /**
+ * Clears the attenuation value in dB.
+ *
+ * <p>This is to negate {@link #setAttenuationDb(float)} call.
+ */
+ @NonNull
+ public Builder clearAttenuationDb() {
+ mAttenuationDb = 0;
+ mFlags &= ~HAS_ATTENUATION_MASK;
+ return this;
+ }
+
+ /** Builds a {@link GnssExcessPathInfo} instance as specified by this builder. */
+ @NonNull
+ public GnssExcessPathInfo build() {
+ return new GnssExcessPathInfo(
+ mFlags,
+ mExcessPathLengthMeters,
+ mExcessPathLengthUncertaintyMeters,
+ mReflectingPlane,
+ mAttenuationDb);
+ }
+ }
+}
diff --git a/location/java/android/location/GnssReflectingPlane.java b/location/java/android/location/GnssReflectingPlane.java
index 1acdd1ecce0b..115cbec5e4de 100644
--- a/location/java/android/location/GnssReflectingPlane.java
+++ b/location/java/android/location/GnssReflectingPlane.java
@@ -22,9 +22,14 @@ import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
+import java.util.Objects;
+
/**
* Holds the characteristics of the reflecting plane that a satellite signal has bounced from.
*
+ * <p>Starting with Android T, this class supports {@link #equals} and {@link #hashCode}, which
+ * are not supported before that.
+ *
* @hide
*/
@SystemApi
@@ -107,24 +112,41 @@ public final class GnssReflectingPlane implements Parcelable {
}
};
+ @Override
+ public void writeToParcel(@NonNull Parcel parcel, int flags) {
+ parcel.writeDouble(mLatitudeDegrees);
+ parcel.writeDouble(mLongitudeDegrees);
+ parcel.writeDouble(mAltitudeMeters);
+ parcel.writeDouble(mAzimuthDegrees);
+ }
+
@NonNull
@Override
public String toString() {
- final String format = " %-29s = %s\n";
- StringBuilder builder = new StringBuilder("ReflectingPlane:\n");
- builder.append(String.format(format, "LatitudeDegrees = ", mLatitudeDegrees));
- builder.append(String.format(format, "LongitudeDegrees = ", mLongitudeDegrees));
- builder.append(String.format(format, "AltitudeMeters = ", mAltitudeMeters));
- builder.append(String.format(format, "AzimuthDegrees = ", mAzimuthDegrees));
+ StringBuilder builder = new StringBuilder("ReflectingPlane[");
+ builder.append(" LatitudeDegrees=").append(mLatitudeDegrees);
+ builder.append(" LongitudeDegrees=").append(mLongitudeDegrees);
+ builder.append(" AltitudeMeters=").append(mAltitudeMeters);
+ builder.append(" AzimuthDegrees=").append(mAzimuthDegrees);
+ builder.append(']');
return builder.toString();
}
@Override
- public void writeToParcel(@NonNull Parcel parcel, int flags) {
- parcel.writeDouble(mLatitudeDegrees);
- parcel.writeDouble(mLongitudeDegrees);
- parcel.writeDouble(mAltitudeMeters);
- parcel.writeDouble(mAzimuthDegrees);
+ public boolean equals(Object obj) {
+ if (obj instanceof GnssReflectingPlane) {
+ GnssReflectingPlane that = (GnssReflectingPlane) obj;
+ return Double.compare(this.mLatitudeDegrees, that.mLatitudeDegrees) == 0
+ && Double.compare(this.mLongitudeDegrees, that.mLongitudeDegrees) == 0
+ && Double.compare(this.mAltitudeMeters, that.mAltitudeMeters) == 0
+ && Double.compare(this.mAzimuthDegrees, that.mAzimuthDegrees) == 0;
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mLatitudeDegrees, mLatitudeDegrees, mAltitudeMeters, mAzimuthDegrees);
}
/** Builder for {@link GnssReflectingPlane} */
diff --git a/location/java/android/location/GnssSingleSatCorrection.java b/location/java/android/location/GnssSingleSatCorrection.java
index 262630b79cb0..a7fce0aaaf6c 100644
--- a/location/java/android/location/GnssSingleSatCorrection.java
+++ b/location/java/android/location/GnssSingleSatCorrection.java
@@ -16,6 +16,11 @@
package android.location;
+import static android.hardware.gnss.measurement_corrections.SingleSatCorrection.SINGLE_SAT_CORRECTION_HAS_COMBINED_ATTENUATION;
+import static android.hardware.gnss.measurement_corrections.SingleSatCorrection.SINGLE_SAT_CORRECTION_HAS_COMBINED_EXCESS_PATH_LENGTH;
+import static android.hardware.gnss.measurement_corrections.SingleSatCorrection.SINGLE_SAT_CORRECTION_HAS_COMBINED_EXCESS_PATH_LENGTH_UNC;
+import static android.hardware.gnss.measurement_corrections.SingleSatCorrection.SINGLE_SAT_CORRECTION_HAS_SAT_IS_LOS_PROBABILITY;
+
import android.annotation.FloatRange;
import android.annotation.IntRange;
import android.annotation.NonNull;
@@ -26,6 +31,8 @@ import android.os.Parcelable;
import com.android.internal.util.Preconditions;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Objects;
/**
@@ -36,106 +43,47 @@ import java.util.Objects;
@SystemApi
public final class GnssSingleSatCorrection implements Parcelable {
- /**
- * Bit mask for {@link #mSingleSatCorrectionFlags} indicating the presence of {@link
- * #mProbSatIsLos}.
- *
- * @hide
- */
- public static final int HAS_PROB_SAT_IS_LOS_MASK = 1 << 0;
-
- /**
- * Bit mask for {@link #mSingleSatCorrectionFlags} indicating the presence of {@link
- * #mExcessPathLengthMeters}.
- *
- * @hide
- */
- public static final int HAS_EXCESS_PATH_LENGTH_MASK = 1 << 1;
-
- /**
- * Bit mask for {@link #mSingleSatCorrectionFlags} indicating the presence of {@link
- * #mExcessPathLengthUncertaintyMeters}.
- *
- * @hide
- */
- public static final int HAS_EXCESS_PATH_LENGTH_UNC_MASK = 1 << 2;
-
- /**
- * Bit mask for {@link #mSingleSatCorrectionFlags} indicating the presence of {@link
- * #mReflectingPlane}.
- *
- * @hide
- */
- public static final int HAS_REFLECTING_PLANE_MASK = 1 << 3;
+ private static final int HAS_PROB_SAT_IS_LOS_MASK =
+ SINGLE_SAT_CORRECTION_HAS_SAT_IS_LOS_PROBABILITY;
+ private static final int HAS_COMBINED_EXCESS_PATH_LENGTH_MASK =
+ SINGLE_SAT_CORRECTION_HAS_COMBINED_EXCESS_PATH_LENGTH;
+ private static final int HAS_COMBINED_EXCESS_PATH_LENGTH_UNC_MASK =
+ SINGLE_SAT_CORRECTION_HAS_COMBINED_EXCESS_PATH_LENGTH_UNC;
+ private static final int HAS_COMBINED_ATTENUATION_MASK =
+ SINGLE_SAT_CORRECTION_HAS_COMBINED_ATTENUATION;
- /** A bitmask of fields present in this object (see HAS_* constants defined above) */
+ /* A bitmask of fields present in this object (see HAS_* constants defined above). */
private final int mSingleSatCorrectionFlags;
- /** Defines the constellation of the given satellite as defined in {@link GnssStatus}. */
- @GnssStatus.ConstellationType
private final int mConstellationType;
-
- /**
- * Satellite vehicle ID number
- *
- * <p>Interpretation depends on {@link GnssStatus#getSvid(int)}.
- */
- @IntRange(from = 0)
private final int mSatId;
-
- /**
- * Carrier frequency of the signal to be corrected, for example it can be the GPS center
- * frequency for L1 = 1,575,420,000 Hz, varying GLO channels, etc.
- *
- * <p>For an L1, L5 receiver tracking a satellite on L1 and L5 at the same time, two correction
- * objects will be reported for this same satellite, in one of the correction objects, all the
- * values related to L1 will be filled, and in the other all of the values related to L5 will be
- * filled.
- */
- @FloatRange(from = 0.0f, fromInclusive = false)
private final float mCarrierFrequencyHz;
-
- /**
- * The probability that the satellite is estimated to be in Line-of-Sight condition at the given
- * location.
- */
- @FloatRange(from = 0.0f, to = 1.0f)
private final float mProbSatIsLos;
+ private final float mCombinedExcessPathLengthMeters;
+ private final float mCombinedExcessPathLengthUncertaintyMeters;
+ private final float mCombinedAttenuationDb;
- /**
- * Excess path length to be subtracted from pseudorange before using it in calculating location.
- */
- @FloatRange(from = 0.0f)
- private final float mExcessPathLengthMeters;
-
- /** Error estimate (1-sigma) for the Excess path length estimate */
- @FloatRange(from = 0.0f)
- private final float mExcessPathLengthUncertaintyMeters;
-
- /**
- * Defines the reflecting plane location and azimuth information
- *
- * <p>The flag HAS_REFLECTING_PLANE will be used to set this value to invalid if the satellite
- * signal goes through multiple reflections or if reflection plane serving is not supported.
- */
- @Nullable
- private final GnssReflectingPlane mReflectingPlane;
+ @NonNull
+ private final List<GnssExcessPathInfo> mGnssExcessPathInfoList;
private GnssSingleSatCorrection(int singleSatCorrectionFlags, int constellationType, int satId,
float carrierFrequencyHz, float probSatIsLos, float excessPathLengthMeters,
- float excessPathLengthUncertaintyMeters, GnssReflectingPlane reflectingPlane) {
+ float excessPathLengthUncertaintyMeters,
+ float combinedAttenuationDb,
+ @NonNull List<GnssExcessPathInfo> gnssExcessPathInfoList) {
mSingleSatCorrectionFlags = singleSatCorrectionFlags;
mConstellationType = constellationType;
mSatId = satId;
mCarrierFrequencyHz = carrierFrequencyHz;
mProbSatIsLos = probSatIsLos;
- mExcessPathLengthMeters = excessPathLengthMeters;
- mExcessPathLengthUncertaintyMeters = excessPathLengthUncertaintyMeters;
- mReflectingPlane = reflectingPlane;
+ mCombinedExcessPathLengthMeters = excessPathLengthMeters;
+ mCombinedExcessPathLengthUncertaintyMeters = excessPathLengthUncertaintyMeters;
+ mCombinedAttenuationDb = combinedAttenuationDb;
+ mGnssExcessPathInfoList = gnssExcessPathInfoList;
}
/**
- * Gets a bitmask of fields present in this object
+ * Gets a bitmask of fields present in this object.
*
* @hide
*/
@@ -193,29 +141,46 @@ public final class GnssSingleSatCorrection implements Parcelable {
}
/**
- * Returns the Excess path length to be subtracted from pseudorange before using it in
+ * Returns the combined excess path length to be subtracted from pseudorange before using it in
* calculating location.
*/
@FloatRange(from = 0.0f)
public float getExcessPathLengthMeters() {
- return mExcessPathLengthMeters;
+ return mCombinedExcessPathLengthMeters;
}
- /** Returns the error estimate (1-sigma) for the Excess path length estimate */
+ /** Returns the error estimate (1-sigma) for the combined excess path length estimate. */
@FloatRange(from = 0.0f)
public float getExcessPathLengthUncertaintyMeters() {
- return mExcessPathLengthUncertaintyMeters;
+ return mCombinedExcessPathLengthUncertaintyMeters;
}
/**
- * Returns the reflecting plane characteristics at which the signal has bounced
+ * Returns the combined expected reduction of signal strength for this satellite in
+ * non-negative dB.
+ */
+ @FloatRange(from = 0.0f)
+ public float getCombinedAttenuationDb() {
+ return mCombinedAttenuationDb;
+ }
+
+ /**
+ * Returns the reflecting plane characteristics at which the signal has bounced.
*
- * <p>The flag HAS_REFLECTING_PLANE will be used to set this value to invalid if the satellite
- * signal goes through multiple reflections or if reflection plane serving is not supported
+ * @deprecated Combined excess path does not have a reflecting plane.
*/
@Nullable
+ @Deprecated
public GnssReflectingPlane getReflectingPlane() {
- return mReflectingPlane;
+ return null;
+ }
+
+ /**
+ * Returns the list of {@link GnssExcessPathInfo} associated with this satellite signal.
+ */
+ @NonNull
+ public List<GnssExcessPathInfo> getGnssExcessPathInfoList() {
+ return mGnssExcessPathInfoList;
}
/** Returns {@code true} if {@link #getProbabilityLineOfSight()} is valid. */
@@ -225,17 +190,27 @@ public final class GnssSingleSatCorrection implements Parcelable {
/** Returns {@code true} if {@link #getExcessPathLengthMeters()} is valid. */
public boolean hasExcessPathLength() {
- return (mSingleSatCorrectionFlags & HAS_EXCESS_PATH_LENGTH_MASK) != 0;
+ return (mSingleSatCorrectionFlags & HAS_COMBINED_EXCESS_PATH_LENGTH_MASK) != 0;
}
/** Returns {@code true} if {@link #getExcessPathLengthUncertaintyMeters()} is valid. */
public boolean hasExcessPathLengthUncertainty() {
- return (mSingleSatCorrectionFlags & HAS_EXCESS_PATH_LENGTH_UNC_MASK) != 0;
+ return (mSingleSatCorrectionFlags & HAS_COMBINED_EXCESS_PATH_LENGTH_UNC_MASK) != 0;
}
- /** Returns {@code true} if {@link #getReflectingPlane()} is valid. */
+ /**
+ * Returns {@code true} if {@link #getReflectingPlane()} is valid.
+ *
+ * @deprecated Combined excess path does not have a reflecting plane.
+ */
+ @Deprecated
public boolean hasReflectingPlane() {
- return (mSingleSatCorrectionFlags & HAS_REFLECTING_PLANE_MASK) != 0;
+ return false;
+ }
+
+ /** Returns {@code true} if {@link #getCombinedAttenuationDb()} is valid. */
+ public boolean hasCombinedAttenuation() {
+ return (mSingleSatCorrectionFlags & HAS_COMBINED_ATTENUATION_MASK) != 0;
}
@Override
@@ -253,14 +228,15 @@ public final class GnssSingleSatCorrection implements Parcelable {
parcel.writeFloat(mProbSatIsLos);
}
if (hasExcessPathLength()) {
- parcel.writeFloat(mExcessPathLengthMeters);
+ parcel.writeFloat(mCombinedExcessPathLengthMeters);
}
if (hasExcessPathLengthUncertainty()) {
- parcel.writeFloat(mExcessPathLengthUncertaintyMeters);
+ parcel.writeFloat(mCombinedExcessPathLengthUncertaintyMeters);
}
- if (hasReflectingPlane()) {
- mReflectingPlane.writeToParcel(parcel, flags);
+ if (hasCombinedAttenuation()) {
+ parcel.writeFloat(mCombinedAttenuationDb);
}
+ parcel.writeTypedList(mGnssExcessPathInfoList);
}
public static final Creator<GnssSingleSatCorrection> CREATOR =
@@ -274,18 +250,21 @@ public final class GnssSingleSatCorrection implements Parcelable {
float carrierFrequencyHz = parcel.readFloat();
float probSatIsLos = (singleSatCorrectionFlags & HAS_PROB_SAT_IS_LOS_MASK) != 0
? parcel.readFloat() : 0;
- float excessPathLengthMeters =
- (singleSatCorrectionFlags & HAS_EXCESS_PATH_LENGTH_MASK) != 0
+ float combinedExcessPathLengthMeters =
+ (singleSatCorrectionFlags & HAS_COMBINED_EXCESS_PATH_LENGTH_MASK) != 0
? parcel.readFloat() : 0;
- float excessPathLengthUncertaintyMeters =
- (singleSatCorrectionFlags & HAS_EXCESS_PATH_LENGTH_UNC_MASK) != 0
+ float combinedExcessPathLengthUncertaintyMeters =
+ (singleSatCorrectionFlags & HAS_COMBINED_EXCESS_PATH_LENGTH_UNC_MASK)
+ != 0 ? parcel.readFloat() : 0;
+ float combinedAttenuationDb =
+ (singleSatCorrectionFlags & HAS_COMBINED_ATTENUATION_MASK) != 0
? parcel.readFloat() : 0;
- GnssReflectingPlane reflectingPlane =
- (singleSatCorrectionFlags & HAS_REFLECTING_PLANE_MASK) != 0
- ? GnssReflectingPlane.CREATOR.createFromParcel(parcel) : null;
+ List<GnssExcessPathInfo> gnssExcessPathInfoList = parcel.createTypedArrayList(
+ GnssExcessPathInfo.CREATOR);
return new GnssSingleSatCorrection(singleSatCorrectionFlags, constellationType,
- satId, carrierFrequencyHz, probSatIsLos, excessPathLengthMeters,
- excessPathLengthUncertaintyMeters, reflectingPlane);
+ satId, carrierFrequencyHz, probSatIsLos, combinedExcessPathLengthMeters,
+ combinedExcessPathLengthUncertaintyMeters, combinedAttenuationDb,
+ gnssExcessPathInfoList);
}
@Override
@@ -296,56 +275,24 @@ public final class GnssSingleSatCorrection implements Parcelable {
@Override
public boolean equals(Object obj) {
- if (this == obj) {
- return true;
- }
- if (!(obj instanceof GnssSingleSatCorrection)) {
- return false;
- }
-
- GnssSingleSatCorrection other = (GnssSingleSatCorrection) obj;
- if (mConstellationType != other.mConstellationType) {
- return false;
- }
- if (mSatId != other.mSatId) {
- return false;
- }
- if (Float.compare(mCarrierFrequencyHz, other.mCarrierFrequencyHz) != 0) {
- return false;
- }
-
- if (hasValidSatelliteLineOfSight() != other.hasValidSatelliteLineOfSight()) {
- return false;
- }
- if (hasValidSatelliteLineOfSight()
- && Float.compare(mProbSatIsLos, other.mProbSatIsLos) != 0) {
- return false;
- }
-
- if (hasExcessPathLength() != other.hasExcessPathLength()) {
- return false;
- }
- if (hasExcessPathLength()
- && Float.compare(mExcessPathLengthMeters, other.mExcessPathLengthMeters) != 0) {
- return false;
- }
-
- if (hasExcessPathLengthUncertainty() != other.hasExcessPathLengthUncertainty()) {
- return false;
- }
- if (hasExcessPathLengthUncertainty() && Float.compare(mExcessPathLengthUncertaintyMeters,
- other.mExcessPathLengthUncertaintyMeters) != 0) {
- return false;
- }
-
- if (hasReflectingPlane() != other.hasReflectingPlane()) {
- return false;
- }
- if (hasReflectingPlane()
- && !mReflectingPlane.equals(other.mReflectingPlane)) {
- return false;
- }
- return true;
+ if (obj instanceof GnssSingleSatCorrection) {
+ GnssSingleSatCorrection that = (GnssSingleSatCorrection) obj;
+ return this.mSingleSatCorrectionFlags == that.mSingleSatCorrectionFlags
+ && this.mConstellationType == that.mConstellationType
+ && this.mSatId == that.mSatId
+ && Float.compare(mCarrierFrequencyHz, that.mCarrierFrequencyHz) == 0
+ && (!hasValidSatelliteLineOfSight() || Float.compare(mProbSatIsLos,
+ that.mProbSatIsLos) == 0)
+ && (!hasExcessPathLength() || Float.compare(mCombinedExcessPathLengthMeters,
+ that.mCombinedExcessPathLengthMeters) == 0)
+ && (!hasExcessPathLengthUncertainty() || Float.compare(
+ mCombinedExcessPathLengthUncertaintyMeters,
+ that.mCombinedExcessPathLengthUncertaintyMeters) == 0)
+ && (!hasCombinedAttenuation() || Float.compare(mCombinedAttenuationDb,
+ that.mCombinedAttenuationDb) == 0)
+ && mGnssExcessPathInfoList.equals(that.mGnssExcessPathInfoList);
+ }
+ return false;
}
@Override
@@ -355,9 +302,10 @@ public final class GnssSingleSatCorrection implements Parcelable {
mSatId,
mCarrierFrequencyHz,
mProbSatIsLos,
- mExcessPathLengthMeters,
- mExcessPathLengthUncertaintyMeters,
- mReflectingPlane);
+ mCombinedExcessPathLengthMeters,
+ mCombinedExcessPathLengthUncertaintyMeters,
+ mCombinedAttenuationDb,
+ mGnssExcessPathInfoList);
}
@NonNull
@@ -371,14 +319,19 @@ public final class GnssSingleSatCorrection implements Parcelable {
builder.append(" ProbSatIsLos=").append(mProbSatIsLos);
}
if (hasExcessPathLength()) {
- builder.append(" ExcessPathLengthMeters=").append(mExcessPathLengthMeters);
+ builder.append(" CombinedExcessPathLengthMeters=").append(
+ mCombinedExcessPathLengthMeters);
}
if (hasExcessPathLengthUncertainty()) {
- builder.append(" ExcessPathLengthUncertaintyMeters=").append(
- mExcessPathLengthUncertaintyMeters);
+ builder.append(" CombinedExcessPathLengthUncertaintyMeters=").append(
+ mCombinedExcessPathLengthUncertaintyMeters);
}
- if (hasReflectingPlane()) {
- builder.append(" ReflectingPlane=").append(mReflectingPlane);
+ if (hasCombinedAttenuation()) {
+ builder.append(" CombinedAttenuationDb=").append(
+ mCombinedAttenuationDb);
+ }
+ if (!mGnssExcessPathInfoList.isEmpty()) {
+ builder.append(' ').append(mGnssExcessPathInfoList.toString());
}
builder.append(']');
return builder.toString();
@@ -386,21 +339,16 @@ public final class GnssSingleSatCorrection implements Parcelable {
/** Builder for {@link GnssSingleSatCorrection} */
public static final class Builder {
-
- /**
- * For documentation of below fields, see corresponding fields in {@link
- * GnssSingleSatCorrection}.
- */
private int mSingleSatCorrectionFlags;
-
private int mConstellationType;
private int mSatId;
private float mCarrierFrequencyHz;
private float mProbSatIsLos;
- private float mExcessPathLengthMeters;
- private float mExcessPathLengthUncertaintyMeters;
- @Nullable
- private GnssReflectingPlane mReflectingPlane;
+ private float mCombinedExcessPathLengthMeters;
+ private float mCombinedExcessPathLengthUncertaintyMeters;
+ private float mCombinedAttenuationDb;
+ @NonNull
+ private List<GnssExcessPathInfo> mGnssExcessInfoList = new ArrayList<>();
/** Sets the constellation type. */
@NonNull public Builder setConstellationType(
@@ -409,18 +357,18 @@ public final class GnssSingleSatCorrection implements Parcelable {
return this;
}
- /** Sets the Satellite ID defined in the ICD of the given constellation. */
+ /** Sets the satellite ID defined in the ICD of the given constellation. */
@NonNull public Builder setSatelliteId(@IntRange(from = 0) int satId) {
Preconditions.checkArgumentNonnegative(satId, "satId should be non-negative.");
mSatId = satId;
return this;
}
- /** Sets the Carrier frequency in Hz. */
+ /** Sets the carrier frequency in Hz. */
@NonNull public Builder setCarrierFrequencyHz(
@FloatRange(from = 0.0f, fromInclusive = false) float carrierFrequencyHz) {
- Preconditions.checkArgument(
- carrierFrequencyHz >= 0, "carrierFrequencyHz should be non-negative.");
+ Preconditions.checkArgumentInRange(
+ carrierFrequencyHz, 0, Float.MAX_VALUE, "carrierFrequencyHz");
mCarrierFrequencyHz = carrierFrequencyHz;
return this;
}
@@ -450,58 +398,90 @@ public final class GnssSingleSatCorrection implements Parcelable {
}
/**
- * Sets the Excess path length to be subtracted from pseudorange before using it in
+ * Sets the combined excess path length to be subtracted from pseudorange before using it in
* calculating location.
*/
- @NonNull public Builder setExcessPathLengthMeters(
- @FloatRange(from = 0.0f) float excessPathLengthMeters) {
- Preconditions.checkArgument(excessPathLengthMeters >= 0,
- "excessPathLengthMeters should be non-negative.");
- mExcessPathLengthMeters = excessPathLengthMeters;
- mSingleSatCorrectionFlags |= HAS_EXCESS_PATH_LENGTH_MASK;
+ @NonNull
+ public Builder setExcessPathLengthMeters(
+ @FloatRange(from = 0.0f) float combinedExcessPathLengthMeters) {
+ Preconditions.checkArgumentInRange(combinedExcessPathLengthMeters, 0, Float.MAX_VALUE,
+ "excessPathLengthMeters");
+ mCombinedExcessPathLengthMeters = combinedExcessPathLengthMeters;
+ mSingleSatCorrectionFlags |= HAS_COMBINED_EXCESS_PATH_LENGTH_MASK;
return this;
}
/**
- * Clears the Excess path length.
+ * Clears the combined excess path length.
*
* <p>This is to negate {@link #setExcessPathLengthMeters} call.
*/
@NonNull public Builder clearExcessPathLengthMeters() {
- mExcessPathLengthMeters = 0;
- mSingleSatCorrectionFlags &= ~HAS_EXCESS_PATH_LENGTH_MASK;
+ mCombinedExcessPathLengthMeters = 0;
+ mSingleSatCorrectionFlags &= ~HAS_COMBINED_EXCESS_PATH_LENGTH_MASK;
return this;
}
- /** Sets the error estimate (1-sigma) for the Excess path length estimate */
+ /** Sets the error estimate (1-sigma) for the combined excess path length estimate. */
@NonNull public Builder setExcessPathLengthUncertaintyMeters(
- @FloatRange(from = 0.0f) float excessPathLengthUncertaintyMeters) {
- Preconditions.checkArgument(excessPathLengthUncertaintyMeters >= 0,
- "excessPathLengthUncertaintyMeters should be non-negative.");
- mExcessPathLengthUncertaintyMeters = excessPathLengthUncertaintyMeters;
- mSingleSatCorrectionFlags |= HAS_EXCESS_PATH_LENGTH_UNC_MASK;
+ @FloatRange(from = 0.0f) float combinedExcessPathLengthUncertaintyMeters) {
+ Preconditions.checkArgumentInRange(combinedExcessPathLengthUncertaintyMeters, 0,
+ Float.MAX_VALUE, "excessPathLengthUncertaintyMeters");
+ mCombinedExcessPathLengthUncertaintyMeters = combinedExcessPathLengthUncertaintyMeters;
+ mSingleSatCorrectionFlags |= HAS_COMBINED_EXCESS_PATH_LENGTH_UNC_MASK;
return this;
}
/**
- * Clears the error estimate (1-sigma) for the Excess path length estimate
+ * Clears the error estimate (1-sigma) for the combined excess path length estimate.
*
* <p>This is to negate {@link #setExcessPathLengthUncertaintyMeters} call.
*/
@NonNull public Builder clearExcessPathLengthUncertaintyMeters() {
- mExcessPathLengthUncertaintyMeters = 0;
- mSingleSatCorrectionFlags &= ~HAS_EXCESS_PATH_LENGTH_UNC_MASK;
+ mCombinedExcessPathLengthUncertaintyMeters = 0;
+ mSingleSatCorrectionFlags &= ~HAS_COMBINED_EXCESS_PATH_LENGTH_UNC_MASK;
return this;
}
- /** Sets the reflecting plane information */
+ /**
+ * Sets the combined attenuation in Db.
+ */
+ @NonNull public Builder setCombinedAttenuationDb(
+ @FloatRange(from = 0.0f) float combinedAttenuationDb) {
+ Preconditions.checkArgumentInRange(combinedAttenuationDb, 0, Float.MAX_VALUE,
+ "combinedAttenuationDb");
+ mCombinedAttenuationDb = combinedAttenuationDb;
+ mSingleSatCorrectionFlags |= HAS_COMBINED_ATTENUATION_MASK;
+ return this;
+ }
+
+ /**
+ * Clears the combined attenuation.
+ *
+ * <p>This is to negate {@link #setCombinedAttenuationDb} call.
+ */
+ @NonNull public Builder clearCombinedAttenuationDb() {
+ mCombinedAttenuationDb = 0;
+ mSingleSatCorrectionFlags &= ~HAS_COMBINED_ATTENUATION_MASK;
+ return this;
+ }
+
+ /**
+ * Sets the reflecting plane information.
+ *
+ * @deprecated Combined excess path does not have a reflecting plane.
+ */
+ @Deprecated
@NonNull public Builder setReflectingPlane(@Nullable GnssReflectingPlane reflectingPlane) {
- mReflectingPlane = reflectingPlane;
- if (reflectingPlane != null) {
- mSingleSatCorrectionFlags |= HAS_REFLECTING_PLANE_MASK;
- } else {
- mSingleSatCorrectionFlags &= ~HAS_REFLECTING_PLANE_MASK;
- }
+ return this;
+ }
+
+ /**
+ * Sets the collection of {@link GnssExcessPathInfo}.
+ */
+ @NonNull
+ public Builder setGnssExcessPathInfoList(@NonNull List<GnssExcessPathInfo> infoList) {
+ mGnssExcessInfoList = new ArrayList<>(infoList);
return this;
}
@@ -512,9 +492,10 @@ public final class GnssSingleSatCorrection implements Parcelable {
mSatId,
mCarrierFrequencyHz,
mProbSatIsLos,
- mExcessPathLengthMeters,
- mExcessPathLengthUncertaintyMeters,
- mReflectingPlane);
+ mCombinedExcessPathLengthMeters,
+ mCombinedExcessPathLengthUncertaintyMeters,
+ mCombinedAttenuationDb,
+ mGnssExcessInfoList);
}
}
}
diff --git a/location/java/android/location/LastLocationRequest.java b/location/java/android/location/LastLocationRequest.java
index fe0a14f37cb6..ec03a33d1c54 100644
--- a/location/java/android/location/LastLocationRequest.java
+++ b/location/java/android/location/LastLocationRequest.java
@@ -17,7 +17,6 @@
package android.location;
import static android.Manifest.permission.LOCATION_BYPASS;
-import static android.Manifest.permission.WRITE_SECURE_SETTINGS;
import android.Manifest;
import android.annotation.NonNull;
@@ -223,9 +222,8 @@ public final class LastLocationRequest implements Parcelable {
*
* @hide
*/
- // TODO: remove WRITE_SECURE_SETTINGS.
@SystemApi
- @RequiresPermission(anyOf = {WRITE_SECURE_SETTINGS, LOCATION_BYPASS})
+ @RequiresPermission(LOCATION_BYPASS)
public @NonNull LastLocationRequest.Builder setAdasGnssBypass(boolean adasGnssBypass) {
mAdasGnssBypass = adasGnssBypass;
return this;
@@ -242,9 +240,8 @@ public final class LastLocationRequest implements Parcelable {
*
* @hide
*/
- // TODO: remove WRITE_SECURE_SETTINGS.
@SystemApi
- @RequiresPermission(anyOf = {WRITE_SECURE_SETTINGS, LOCATION_BYPASS})
+ @RequiresPermission(LOCATION_BYPASS)
public @NonNull Builder setLocationSettingsIgnored(boolean locationSettingsIgnored) {
mLocationSettingsIgnored = locationSettingsIgnored;
return this;
diff --git a/location/java/android/location/Location.java b/location/java/android/location/Location.java
index f1605f1ffe5d..033056cb2a69 100644
--- a/location/java/android/location/Location.java
+++ b/location/java/android/location/Location.java
@@ -132,31 +132,31 @@ public class Location implements Parcelable {
}
/**
- * Construct a new Location object that is copied from an existing one.
+ * Constructs a new location copied from the given location.
*/
- public Location(@NonNull Location l) {
- set(l);
+ public Location(@NonNull Location location) {
+ set(location);
}
/**
* Turns this location into a copy of the given location.
*/
- public void set(@NonNull Location l) {
- mFieldsMask = l.mFieldsMask;
- mProvider = l.mProvider;
- mTimeMs = l.mTimeMs;
- mElapsedRealtimeNs = l.mElapsedRealtimeNs;
- mElapsedRealtimeUncertaintyNs = l.mElapsedRealtimeUncertaintyNs;
- mLatitudeDegrees = l.mLatitudeDegrees;
- mLongitudeDegrees = l.mLongitudeDegrees;
- mHorizontalAccuracyMeters = l.mHorizontalAccuracyMeters;
- mAltitudeMeters = l.mAltitudeMeters;
- mAltitudeAccuracyMeters = l.mAltitudeAccuracyMeters;
- mSpeedMetersPerSecond = l.mSpeedMetersPerSecond;
- mSpeedAccuracyMetersPerSecond = l.mSpeedAccuracyMetersPerSecond;
- mBearingDegrees = l.mBearingDegrees;
- mBearingAccuracyDegrees = l.mBearingAccuracyDegrees;
- mExtras = (l.mExtras == null) ? null : new Bundle(l.mExtras);
+ public void set(@NonNull Location location) {
+ mFieldsMask = location.mFieldsMask;
+ mProvider = location.mProvider;
+ mTimeMs = location.mTimeMs;
+ mElapsedRealtimeNs = location.mElapsedRealtimeNs;
+ mElapsedRealtimeUncertaintyNs = location.mElapsedRealtimeUncertaintyNs;
+ mLatitudeDegrees = location.mLatitudeDegrees;
+ mLongitudeDegrees = location.mLongitudeDegrees;
+ mHorizontalAccuracyMeters = location.mHorizontalAccuracyMeters;
+ mAltitudeMeters = location.mAltitudeMeters;
+ mAltitudeAccuracyMeters = location.mAltitudeAccuracyMeters;
+ mSpeedMetersPerSecond = location.mSpeedMetersPerSecond;
+ mSpeedAccuracyMetersPerSecond = location.mSpeedAccuracyMetersPerSecond;
+ mBearingDegrees = location.mBearingDegrees;
+ mBearingAccuracyDegrees = location.mBearingAccuracyDegrees;
+ mExtras = (location.mExtras == null) ? null : new Bundle(location.mExtras);
}
/**
@@ -182,14 +182,13 @@ public class Location implements Parcelable {
}
/**
- * Returns the approximate distance in meters between this
- * location and the given location. Distance is defined using
- * the WGS84 ellipsoid.
+ * Returns the approximate distance in meters between this location and the given location.
+ * Distance is defined using the WGS84 ellipsoid.
*
* @param dest the destination location
* @return the approximate distance in meters
*/
- public @FloatRange float distanceTo(@NonNull Location dest) {
+ public @FloatRange(from = 0.0) float distanceTo(@NonNull Location dest) {
BearingDistanceCache cache = sBearingDistanceCache.get();
// See if we already have the result
if (mLatitudeDegrees != cache.mLat1 || mLongitudeDegrees != cache.mLon1
@@ -201,11 +200,10 @@ public class Location implements Parcelable {
}
/**
- * Returns the approximate initial bearing in degrees East of true
- * North when traveling along the shortest path between this
- * location and the given location. The shortest path is defined
- * using the WGS84 ellipsoid. Locations that are (nearly)
- * antipodal may produce meaningless results.
+ * Returns the approximate initial bearing in degrees east of true north when traveling along
+ * the shortest path between this location and the given location. The shortest path is defined
+ * using the WGS84 ellipsoid. Locations that are (nearly) antipodal may produce meaningless
+ * results.
*
* @param dest the destination location
* @return the initial bearing in degrees
@@ -254,7 +252,7 @@ public class Location implements Parcelable {
* not be used to order or compare locations. Prefer {@link #getElapsedRealtimeNanos} for that
* purpose, as the elapsed realtime clock is guaranteed to be monotonic.
*
- * <p>On the other hand, this method may be useful for presenting a human readable time to the
+ * <p>On the other hand, this method may be useful for presenting a human-readable time to the
* user, or as a heuristic for comparing location fixes across reboot or across devices.
*
* <p>All locations generated by the {@link LocationManager} are guaranteed to have this time
@@ -263,25 +261,24 @@ public class Location implements Parcelable {
*
* @return the Unix epoch time of this location
*/
- public @IntRange long getTime() {
+ public @IntRange(from = 0) long getTime() {
return mTimeMs;
}
/**
* Sets the Unix epoch time of this location fix, in milliseconds since the start of the Unix
- * epoch (00:00:00 January 1, 1970 UTC).
+ * epoch (00:00:00 January 1 1970 UTC).
*
* @param timeMs the Unix epoch time of this location
- * @see #getTime for more information about times / clocks
*/
- public void setTime(@IntRange long timeMs) {
+ public void setTime(@IntRange(from = 0) long timeMs) {
mTimeMs = timeMs;
}
/**
* Return the time of this fix in nanoseconds of elapsed realtime since system boot.
*
- * <p>This value can be compared with {@link android.os.SystemClock#elapsedRealtimeNanos}, to
+ * <p>This value can be compared with {@link android.os.SystemClock#elapsedRealtimeNanos} to
* reliably order or compare locations. This is reliable because elapsed realtime is guaranteed
* to be monotonic and continues to increment even when the system is in deep sleep (unlike
* {@link #getTime}). However, since elapsed realtime is with reference to system boot, it does
@@ -292,7 +289,7 @@ public class Location implements Parcelable {
*
* @return elapsed realtime of this location in nanoseconds
*/
- public @IntRange long getElapsedRealtimeNanos() {
+ public @IntRange(from = 0) long getElapsedRealtimeNanos() {
return mElapsedRealtimeNs;
}
@@ -302,7 +299,7 @@ public class Location implements Parcelable {
* @return elapsed realtime of this location in milliseconds
* @see #getElapsedRealtimeNanos()
*/
- public @IntRange long getElapsedRealtimeMillis() {
+ public @IntRange(from = 0) long getElapsedRealtimeMillis() {
return NANOSECONDS.toMillis(mElapsedRealtimeNs);
}
@@ -312,7 +309,7 @@ public class Location implements Parcelable {
*
* @return age of this location in milliseconds
*/
- public @IntRange long getElapsedRealtimeAgeMillis() {
+ public @IntRange(from = 0) long getElapsedRealtimeAgeMillis() {
return getElapsedRealtimeAgeMillis(SystemClock.elapsedRealtime());
}
@@ -323,7 +320,8 @@ public class Location implements Parcelable {
* @param referenceRealtimeMs reference realtime in milliseconds
* @return age of this location in milliseconds
*/
- public @IntRange long getElapsedRealtimeAgeMillis(@IntRange long referenceRealtimeMs) {
+ public long getElapsedRealtimeAgeMillis(
+ @IntRange(from = 0) long referenceRealtimeMs) {
return referenceRealtimeMs - getElapsedRealtimeMillis();
}
@@ -332,7 +330,7 @@ public class Location implements Parcelable {
*
* @param elapsedRealtimeNs elapsed realtime in nanoseconds
*/
- public void setElapsedRealtimeNanos(@IntRange long elapsedRealtimeNs) {
+ public void setElapsedRealtimeNanos(@IntRange(from = 0) long elapsedRealtimeNs) {
mElapsedRealtimeNs = elapsedRealtimeNs;
}
@@ -346,7 +344,7 @@ public class Location implements Parcelable {
*
* @return uncertainty in nanoseconds of the elapsed realtime of this location
*/
- public @FloatRange double getElapsedRealtimeUncertaintyNanos() {
+ public @FloatRange(from = 0.0) double getElapsedRealtimeUncertaintyNanos() {
return mElapsedRealtimeUncertaintyNs;
}
@@ -358,20 +356,20 @@ public class Location implements Parcelable {
* this location
*/
public void setElapsedRealtimeUncertaintyNanos(
- @FloatRange double elapsedRealtimeUncertaintyNs) {
+ @FloatRange(from = 0.0) double elapsedRealtimeUncertaintyNs) {
mElapsedRealtimeUncertaintyNs = elapsedRealtimeUncertaintyNs;
mFieldsMask |= HAS_ELAPSED_REALTIME_UNCERTAINTY_MASK;
}
/**
- * True if this location has a elapsed realtime uncertainty, false otherwise.
+ * True if this location has an elapsed realtime uncertainty, false otherwise.
*/
public boolean hasElapsedRealtimeUncertaintyNanos() {
return (mFieldsMask & HAS_ELAPSED_REALTIME_UNCERTAINTY_MASK) != 0;
}
/**
- * Removes the elapsed realtime uncertainy from this location.
+ * Removes the elapsed realtime uncertainty from this location.
*/
public void removeElapsedRealtimeUncertaintyNanos() {
mFieldsMask &= ~HAS_ELAPSED_REALTIME_UNCERTAINTY_MASK;
@@ -383,7 +381,7 @@ public class Location implements Parcelable {
*
* @return latitude of this location
*/
- public @FloatRange double getLatitude() {
+ public @FloatRange(from = -90.0, to = 90.0) double getLatitude() {
return mLatitudeDegrees;
}
@@ -392,7 +390,7 @@ public class Location implements Parcelable {
*
* @param latitudeDegrees latitude in degrees
*/
- public void setLatitude(@FloatRange double latitudeDegrees) {
+ public void setLatitude(@FloatRange(from = -90.0, to = 90.0) double latitudeDegrees) {
mLatitudeDegrees = latitudeDegrees;
}
@@ -402,7 +400,7 @@ public class Location implements Parcelable {
*
* @return longitude of this location
*/
- public @FloatRange double getLongitude() {
+ public @FloatRange(from = -180.0, to = 180.0) double getLongitude() {
return mLongitudeDegrees;
}
@@ -411,7 +409,7 @@ public class Location implements Parcelable {
*
* @param longitudeDegrees longitude in degrees
*/
- public void setLongitude(@FloatRange double longitudeDegrees) {
+ public void setLongitude(@FloatRange(from = -180.0, to = 180.0) double longitudeDegrees) {
mLongitudeDegrees = longitudeDegrees;
}
@@ -423,12 +421,12 @@ public class Location implements Parcelable {
* reported location, there is a 68% chance that the true location falls within this circle.
* This accuracy value is only valid for horizontal positioning, and not vertical positioning.
*
- * <p>This is only valid if {@link #hasSpeed()} is true. All locations generated by the
+ * <p>This is only valid if {@link #hasAccuracy()} is true. All locations generated by the
* {@link LocationManager} include horizontal accuracy.
*
* @return horizontal accuracy of this location
*/
- public @FloatRange float getAccuracy() {
+ public @FloatRange(from = 0.0) float getAccuracy() {
return mHorizontalAccuracyMeters;
}
@@ -437,7 +435,7 @@ public class Location implements Parcelable {
*
* @param horizontalAccuracyMeters horizontal altitude in meters
*/
- public void setAccuracy(@FloatRange float horizontalAccuracyMeters) {
+ public void setAccuracy(@FloatRange(from = 0.0) float horizontalAccuracyMeters) {
mHorizontalAccuracyMeters = horizontalAccuracyMeters;
mFieldsMask |= HAS_HORIZONTAL_ACCURACY_MASK;
}
@@ -500,7 +498,7 @@ public class Location implements Parcelable {
*
* @return vertical accuracy of this location
*/
- public @FloatRange float getVerticalAccuracyMeters() {
+ public @FloatRange(from = 0.0) float getVerticalAccuracyMeters() {
return mAltitudeAccuracyMeters;
}
@@ -509,7 +507,7 @@ public class Location implements Parcelable {
*
* @param altitudeAccuracyMeters altitude accuracy in meters
*/
- public void setVerticalAccuracyMeters(@FloatRange float altitudeAccuracyMeters) {
+ public void setVerticalAccuracyMeters(@FloatRange(from = 0.0) float altitudeAccuracyMeters) {
mAltitudeAccuracyMeters = altitudeAccuracyMeters;
mFieldsMask |= HAS_ALTITUDE_ACCURACY_MASK;
}
@@ -538,17 +536,16 @@ public class Location implements Parcelable {
*
* @return speed at the time of this location
*/
- public @FloatRange float getSpeed() {
+ public @FloatRange(from = 0.0) float getSpeed() {
return mSpeedMetersPerSecond;
}
/**
- * Set the speed at the time of this location, in meters per second. Prefer not to set negative
- * speeds.
+ * Set the speed at the time of this location, in meters per second.
*
* @param speedMetersPerSecond speed in meters per second
*/
- public void setSpeed(@FloatRange float speedMetersPerSecond) {
+ public void setSpeed(@FloatRange(from = 0.0) float speedMetersPerSecond) {
mSpeedMetersPerSecond = speedMetersPerSecond;
mFieldsMask |= HAS_SPEED_MASK;
}
@@ -576,7 +573,7 @@ public class Location implements Parcelable {
*
* @return vertical accuracy of this location
*/
- public @FloatRange float getSpeedAccuracyMetersPerSecond() {
+ public @FloatRange(from = 0.0) float getSpeedAccuracyMetersPerSecond() {
return mSpeedAccuracyMetersPerSecond;
}
@@ -585,7 +582,8 @@ public class Location implements Parcelable {
*
* @param speedAccuracyMeterPerSecond speed accuracy in meters per second
*/
- public void setSpeedAccuracyMetersPerSecond(@FloatRange float speedAccuracyMeterPerSecond) {
+ public void setSpeedAccuracyMetersPerSecond(
+ @FloatRange(from = 0.0) float speedAccuracyMeterPerSecond) {
mSpeedAccuracyMetersPerSecond = speedAccuracyMeterPerSecond;
mFieldsMask |= HAS_SPEED_ACCURACY_MASK;
}
@@ -613,7 +611,7 @@ public class Location implements Parcelable {
*
* @return bearing at the time of this location
*/
- public @FloatRange(from = 0f, to = 360f, toInclusive = false) float getBearing() {
+ public @FloatRange(from = 0.0, to = 360.0, toInclusive = false) float getBearing() {
return mBearingDegrees;
}
@@ -663,7 +661,7 @@ public class Location implements Parcelable {
*
* @return bearing accuracy in degrees of this location
*/
- public @FloatRange float getBearingAccuracyDegrees() {
+ public @FloatRange(from = 0.0) float getBearingAccuracyDegrees() {
return mBearingAccuracyDegrees;
}
@@ -672,7 +670,7 @@ public class Location implements Parcelable {
*
* @param bearingAccuracyDegrees bearing accuracy in degrees
*/
- public void setBearingAccuracyDegrees(@FloatRange float bearingAccuracyDegrees) {
+ public void setBearingAccuracyDegrees(@FloatRange(from = 0.0) float bearingAccuracyDegrees) {
mBearingAccuracyDegrees = bearingAccuracyDegrees;
mFieldsMask |= HAS_BEARING_ACCURACY_MASK;
}
@@ -692,9 +690,11 @@ public class Location implements Parcelable {
}
/**
- * Returns true if the Location came from a mock provider.
+ * Returns true if this is a mock location. If this location comes from the Android framework,
+ * this indicates that the location was provided by a test location provider, and thus may not
+ * be related to the actual location of the device.
*
- * @return true if this Location came from a mock provider, false otherwise
+ * @return true if this location came from a mock provider, false otherwise
* @deprecated Prefer {@link #isMock()} instead.
*/
@Deprecated
@@ -703,9 +703,9 @@ public class Location implements Parcelable {
}
/**
- * Flag this Location as having come from a mock provider or not.
+ * Flag this location as having come from a mock provider or not.
*
- * @param isFromMockProvider true if this Location came from a mock provider, false otherwise
+ * @param isFromMockProvider true if this location came from a mock provider, false otherwise
* @deprecated Prefer {@link #setMock(boolean)} instead.
* @hide
*/
@@ -745,7 +745,7 @@ public class Location implements Parcelable {
* will be present for any location.
*
* <ul>
- * <li> satellites - the number of satellites used to derive the GNSS fix
+ * <li> satellites - the number of satellites used to derive a GNSS fix
* </ul>
*/
public @Nullable Bundle getExtras() {
@@ -899,7 +899,13 @@ public class Location implements Parcelable {
return s.toString();
}
- /** Dumps location. */
+ /**
+ * Dumps location information to the given Printer.
+ *
+ * @deprecated Prefer to use {@link #toString()} along with whatever custom formatting is
+ * required instead of this method. It is not this class's job to manage print representations.
+ */
+ @Deprecated
public void dump(@NonNull Printer pw, @Nullable String prefix) {
pw.println(prefix + this);
}
@@ -1209,10 +1215,10 @@ public class Location implements Parcelable {
* @throws IllegalArgumentException if results is null or has length < 1
*/
public static void distanceBetween(
- @FloatRange double startLatitude,
- @FloatRange double startLongitude,
- @FloatRange double endLatitude,
- @FloatRange double endLongitude,
+ @FloatRange(from = -90.0, to = 90.0) double startLatitude,
+ @FloatRange(from = -180.0, to = 180.0) double startLongitude,
+ @FloatRange(from = -90.0, to = 90.0) double endLatitude,
+ @FloatRange(from = -180.0, to = 180.0) double endLongitude,
float[] results) {
if (results == null || results.length < 1) {
throw new IllegalArgumentException("results is null or has length < 1");
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 59c989b7f01e..a504cfe9789d 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -679,9 +679,8 @@ public class LocationManager {
*
* @hide
*/
- // TODO: remove WRITE_SECURE_SETTINGS.
@SystemApi
- @RequiresPermission(anyOf = {WRITE_SECURE_SETTINGS, LOCATION_BYPASS})
+ @RequiresPermission(LOCATION_BYPASS)
public void setAdasGnssLocationEnabled(boolean enabled) {
try {
mService.setAdasGnssLocationEnabledForUser(enabled, mContext.getUser().getIdentifier());
diff --git a/location/java/android/location/LocationRequest.java b/location/java/android/location/LocationRequest.java
index 59f4f5e8c19e..09474b503fc0 100644
--- a/location/java/android/location/LocationRequest.java
+++ b/location/java/android/location/LocationRequest.java
@@ -17,7 +17,6 @@
package android.location;
import static android.Manifest.permission.LOCATION_BYPASS;
-import static android.Manifest.permission.WRITE_SECURE_SETTINGS;
import static java.lang.Math.max;
import static java.lang.Math.min;
@@ -665,10 +664,9 @@ public final class LocationRequest implements Parcelable {
* @hide
* @deprecated LocationRequests should be treated as immutable.
*/
- // TODO: remove WRITE_SECURE_SETTINGS.
@SystemApi
@Deprecated
- @RequiresPermission(anyOf = {WRITE_SECURE_SETTINGS, LOCATION_BYPASS})
+ @RequiresPermission(LOCATION_BYPASS)
public @NonNull LocationRequest setLocationSettingsIgnored(boolean locationSettingsIgnored) {
mBypass = locationSettingsIgnored;
return this;
@@ -1136,9 +1134,8 @@ public final class LocationRequest implements Parcelable {
*
* @hide
*/
- // TODO: remove WRITE_SECURE_SETTINGS
@SystemApi
- @RequiresPermission(anyOf = {WRITE_SECURE_SETTINGS, LOCATION_BYPASS})
+ @RequiresPermission(LOCATION_BYPASS)
public @NonNull Builder setAdasGnssBypass(boolean adasGnssBypass) {
mAdasGnssBypass = adasGnssBypass;
return this;
@@ -1155,9 +1152,8 @@ public final class LocationRequest implements Parcelable {
*
* @hide
*/
- // TODO: remove WRITE_SECURE_SETTINGS
@SystemApi
- @RequiresPermission(anyOf = {WRITE_SECURE_SETTINGS, LOCATION_BYPASS})
+ @RequiresPermission(LOCATION_BYPASS)
public @NonNull Builder setLocationSettingsIgnored(boolean locationSettingsIgnored) {
mBypass = locationSettingsIgnored;
return this;
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 3a2f0d9194f5..1a56b1542b07 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -6952,7 +6952,8 @@ public class AudioManager {
for (Integer format : formatsList) {
int btSourceCodec = AudioSystem.audioFormatToBluetoothSourceCodec(format);
if (btSourceCodec != BluetoothCodecConfig.SOURCE_CODEC_TYPE_INVALID) {
- codecConfigList.add(new BluetoothCodecConfig(btSourceCodec));
+ codecConfigList.add(
+ new BluetoothCodecConfig.Builder().setCodecType(btSourceCodec).build());
}
}
return codecConfigList;
@@ -8450,6 +8451,22 @@ public class AudioManager {
}
}
+ /**
+ * Returns the audio HAL version in the form MAJOR.MINOR. If there is no audio HAL found, null
+ * will be returned.
+ *
+ * @hide
+ */
+ @TestApi
+ public static @Nullable String getHalVersion() {
+ try {
+ return getService().getHalVersion();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error querying getHalVersion", e);
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
private final Object mMuteAwaitConnectionListenerLock = new Object();
@GuardedBy("mMuteAwaitConnectionListenerLock")
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index fa3057a4ead1..c186700a4326 100755
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -39,6 +39,7 @@ import android.media.IRecordingConfigDispatcher;
import android.media.IRingtonePlayer;
import android.media.IStrategyPreferredDevicesDispatcher;
import android.media.ISpatializerCallback;
+import android.media.ISpatializerHeadTrackerAvailableCallback;
import android.media.ISpatializerHeadTrackingModeCallback;
import android.media.ISpatializerHeadToSoundStagePoseCallback;
import android.media.ISpatializerOutputCallback;
@@ -414,6 +415,11 @@ interface IAudioService {
boolean isHeadTrackerEnabled(in AudioDeviceAttributes device);
+ boolean isHeadTrackerAvailable();
+
+ void registerSpatializerHeadTrackerAvailableCallback(
+ in ISpatializerHeadTrackerAvailableCallback cb, boolean register);
+
void setSpatializerEnabled(boolean enabled);
boolean canBeSpatialized(in AudioAttributes aa, in AudioFormat af);
@@ -480,7 +486,6 @@ interface IAudioService {
boolean sendFocusLoss(in AudioFocusInfo focusLoser, in IAudioPolicyCallback apcb);
-
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)")
void addAssistantServicesUids(in int[] assistantUID);
@@ -501,4 +506,6 @@ interface IAudioService {
in IAudioDeviceVolumeDispatcher cb,
in String packageName,
in AudioDeviceAttributes device, in List<VolumeInfo> volumes);
+
+ String getHalVersion();
}
diff --git a/media/java/android/media/ISpatializerHeadTrackerAvailableCallback.aidl b/media/java/android/media/ISpatializerHeadTrackerAvailableCallback.aidl
new file mode 100644
index 000000000000..dc5ee1d4e985
--- /dev/null
+++ b/media/java/android/media/ISpatializerHeadTrackerAvailableCallback.aidl
@@ -0,0 +1,27 @@
+/*
+ * 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.media;
+
+/**
+ * AIDL for the AudioService to signal whether audio device used by Spatializer has head tracker.
+ *
+ * {@hide}
+ */
+oneway interface ISpatializerHeadTrackerAvailableCallback {
+
+ void dispatchSpatializerHeadTrackerAvailable(boolean available);
+}
diff --git a/media/java/android/media/MediaActionSound.java b/media/java/android/media/MediaActionSound.java
index ec56d614f2b5..ad1405aa2356 100644
--- a/media/java/android/media/MediaActionSound.java
+++ b/media/java/android/media/MediaActionSound.java
@@ -25,7 +25,8 @@ import android.util.Log;
/**
* <p>A class for producing sounds that match those produced by various actions
- * taken by the media and camera APIs. </p>
+ * taken by the media and camera APIs. It is recommended to call methods in this class
+ * in a background thread since it relies on binder calls.</p>
*
* <p>This class is recommended for use with the {@link android.hardware.camera2} API, since the
* camera2 API does not play any sounds on its own for any capture or video recording actions.</p>
@@ -109,7 +110,7 @@ public class MediaActionSound {
/**
* <p>Returns true if the application must play the shutter sound in accordance
- * to certain regional restrictions. </p>
+ * to certain regional restrictions.</p>
*
* <p>If this method returns true, applications are strongly recommended to use
* MediaActionSound.play(SHUTTER_CLICK) or START_VIDEO_RECORDING whenever it captures
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index 4563259c31f2..e39914db4d0f 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -223,19 +223,19 @@ import java.util.concurrent.locks.ReentrantLock;
</thead>
<tbody>
<tr>
- <td>{@code "crop-left"}</td>
+ <td>{@link MediaFormat#KEY_CROP_LEFT}</td>
<td>Integer</td>
<td>The left-coordinate (x) of the crop rectangle</td>
</tr><tr>
- <td>{@code "crop-top"}</td>
+ <td>{@link MediaFormat#KEY_CROP_TOP}</td>
<td>Integer</td>
<td>The top-coordinate (y) of the crop rectangle</td>
</tr><tr>
- <td>{@code "crop-right"}</td>
+ <td>{@link MediaFormat#KEY_CROP_RIGHT}</td>
<td>Integer</td>
<td>The right-coordinate (x) <strong>MINUS 1</strong> of the crop rectangle</td>
</tr><tr>
- <td>{@code "crop-bottom"}</td>
+ <td>{@link MediaFormat#KEY_CROP_BOTTOM}</td>
<td>Integer</td>
<td>The bottom-coordinate (y) <strong>MINUS 1</strong> of the crop rectangle</td>
</tr><tr>
@@ -251,12 +251,16 @@ import java.util.concurrent.locks.ReentrantLock;
<pre class=prettyprint>
MediaFormat format = decoder.getOutputFormat(&hellip;);
int width = format.getInteger(MediaFormat.KEY_WIDTH);
- if (format.containsKey("crop-left") && format.containsKey("crop-right")) {
- width = format.getInteger("crop-right") + 1 - format.getInteger("crop-left");
+ if (format.containsKey(MediaFormat.KEY_CROP_LEFT)
+ && format.containsKey(MediaFormat.KEY_CROP_RIGHT)) {
+ width = format.getInteger(MediaFormat.KEY_CROP_RIGHT) + 1
+ - format.getInteger(MediaFormat.KEY_CROP_LEFT);
}
int height = format.getInteger(MediaFormat.KEY_HEIGHT);
- if (format.containsKey("crop-top") && format.containsKey("crop-bottom")) {
- height = format.getInteger("crop-bottom") + 1 - format.getInteger("crop-top");
+ if (format.containsKey(MediaFormat.KEY_CROP_TOP)
+ && format.containsKey(MediaFormat.KEY_CROP_BOTTOM)) {
+ height = format.getInteger(MediaFormat.KEY_CROP_BOTTOM) + 1
+ - format.getInteger(MediaFormat.KEY_CROP_TOP);
}
</pre>
<p class=note>
diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java
index 4956dbefa240..9dea5b9152b7 100644
--- a/media/java/android/media/MediaFormat.java
+++ b/media/java/android/media/MediaFormat.java
@@ -359,6 +359,42 @@ public final class MediaFormat {
public static final String KEY_HEIGHT = "height";
/**
+ * A key describing the bottom-coordinate (y) of the crop rectangle.
+ * This is the bottom-most row included in the crop frame,
+ * where row indices start at 0.
+ * Additional information on the crop rectangle semantics can be found at
+ * {@link android.media.MediaCodec}.
+ */
+ public static final String KEY_CROP_BOTTOM = "crop-bottom";
+
+ /**
+ * A key describing the left-coordinate (x) of the crop rectangle.
+ * This is the left-most column included in the crop frame,
+ * where column indices start at 0.
+ * Additional information on the crop rectangle semantics can be found at
+ * {@link android.media.MediaCodec}.
+ */
+ public static final String KEY_CROP_LEFT = "crop-left";
+
+ /**
+ * A key describing the right-coordinate (x) of the crop rectangle.
+ * This is the right-most column included in the crop frame,
+ * where column indices start at 0.
+ * Additional information on the crop rectangle semantics can be found at
+ * {@link android.media.MediaCodec}.
+ */
+ public static final String KEY_CROP_RIGHT = "crop-right";
+
+ /**
+ * A key describing the top-coordinate (y) of the crop rectangle.
+ * This is the top-most row included in the crop frame,
+ * where row indices start at 0.
+ * Additional information on the crop rectangle semantics can be found at
+ * {@link android.media.MediaCodec}.
+ */
+ public static final String KEY_CROP_TOP = "crop-top";
+
+ /**
* A key describing the maximum expected width of the content in a video
* decoder format, in case there are resolution changes in the video content.
* The associated value is an integer
@@ -793,8 +829,11 @@ public final class MediaFormat {
* By default, the decoder will output the same number of channels as present in the encoded
* stream, if supported. Set this value to limit the number of output channels, and use
* the downmix information in the stream, if available.
- * <p>Values larger than the number of channels in the content to decode are ignored.
+ * <p>Values larger than the number of channels in the content to decode behave just
+ * like the actual channel count of the content (e.g. passing 99 for the decoding of 5.1 content
+ * will behave like using 6).
* <p>This key is only used during decoding.
+ * @deprecated Use the non-AAC-specific key {@link #KEY_MAX_OUTPUT_CHANNEL_COUNT} instead
*/
public static final String KEY_AAC_MAX_OUTPUT_CHANNEL_COUNT = "aac-max-output-channel_count";
diff --git a/media/java/android/media/MediaRoute2Info.java b/media/java/android/media/MediaRoute2Info.java
index ee0293d629b1..283a41a81057 100644
--- a/media/java/android/media/MediaRoute2Info.java
+++ b/media/java/android/media/MediaRoute2Info.java
@@ -539,6 +539,7 @@ public final class MediaRoute2Info implements Parcelable {
/**
* Gets the Deduplication ID of the route if available.
* @see RouteDiscoveryPreference#shouldRemoveDuplicates()
+ * @hide
*/
@NonNull
public Set<String> getDeduplicationIds() {
@@ -968,6 +969,7 @@ public final class MediaRoute2Info implements Parcelable {
* <p>
* If it's {@code null}, the route will not be removed.
* @see RouteDiscoveryPreference#shouldRemoveDuplicates()
+ * @hide
*/
@NonNull
public Builder setDeduplicationIds(@NonNull Set<String> id) {
diff --git a/media/java/android/media/MediaRouter2.java b/media/java/android/media/MediaRouter2.java
index 311476cbd489..d8995b419f50 100644
--- a/media/java/android/media/MediaRouter2.java
+++ b/media/java/android/media/MediaRouter2.java
@@ -76,6 +76,7 @@ public final class MediaRouter2 {
@GuardedBy("sSystemRouterLock")
private static Map<String, MediaRouter2> sSystemMediaRouter2Map = new ArrayMap<>();
+
private static MediaRouter2Manager sManager;
@GuardedBy("sRouterLock")
@@ -119,14 +120,12 @@ public final class MediaRouter2 {
private final AtomicInteger mNextRequestId = new AtomicInteger(1);
final Handler mHandler;
- @GuardedBy("mLock")
- private boolean mShouldUpdateRoutes = true;
+
+ private volatile ArrayMap<String, MediaRoute2Info> mPreviousRoutes = new ArrayMap<>();
private volatile List<MediaRoute2Info> mFilteredRoutes = Collections.emptyList();
private volatile OnGetControllerHintsListener mOnGetControllerHintsListener;
- /**
- * Gets an instance of the media router associated with the context.
- */
+ /** Gets an instance of the media router associated with the context. */
@NonNull
public static MediaRouter2 getInstance(@NonNull Context context) {
Objects.requireNonNull(context, "context must not be null");
@@ -139,29 +138,31 @@ public final class MediaRouter2 {
}
/**
- * Gets an instance of the system media router which controls the app's media routing.
- * Returns {@code null} if the given package name is invalid.
- * There are several things to note when using the media routers created with this method.
- * <p>
- * First of all, the discovery preference passed to {@link #registerRouteCallback}
- * will have no effect. The callback will be called accordingly with the client app's
- * discovery preference. Therefore, it is recommended to pass
- * {@link RouteDiscoveryPreference#EMPTY} there.
- * <p>
- * Also, do not keep/compare the instances of the {@link RoutingController}, since they are
+ * Gets an instance of the system media router which controls the app's media routing. Returns
+ * {@code null} if the given package name is invalid. There are several things to note when
+ * using the media routers created with this method.
+ *
+ * <p>First of all, the discovery preference passed to {@link #registerRouteCallback} will have
+ * no effect. The callback will be called accordingly with the client app's discovery
+ * preference. Therefore, it is recommended to pass {@link RouteDiscoveryPreference#EMPTY}
+ * there.
+ *
+ * <p>Also, do not keep/compare the instances of the {@link RoutingController}, since they are
* always newly created with the latest session information whenever below methods are called:
+ *
* <ul>
- * <li> {@link #getControllers()} </li>
- * <li> {@link #getController(String)}} </li>
- * <li> {@link TransferCallback#onTransfer(RoutingController, RoutingController)} </li>
- * <li> {@link TransferCallback#onStop(RoutingController)} </li>
- * <li> {@link ControllerCallback#onControllerUpdated(RoutingController)} </li>
+ * <li>{@link #getControllers()}
+ * <li>{@link #getController(String)}}
+ * <li>{@link TransferCallback#onTransfer(RoutingController, RoutingController)}
+ * <li>{@link TransferCallback#onStop(RoutingController)}
+ * <li>{@link ControllerCallback#onControllerUpdated(RoutingController)}
* </ul>
+ *
* Therefore, in order to track the current routing status, keep the controller's ID instead,
- * and use {@link #getController(String)} and {@link #getSystemController()} for
- * getting controllers.
- * <p>
- * Finally, it will have no effect to call {@link #setOnGetControllerHintsListener}.
+ * and use {@link #getController(String)} and {@link #getSystemController()} for getting
+ * controllers.
+ *
+ * <p>Finally, it will have no effect to call {@link #setOnGetControllerHintsListener}.
*
* @param clientPackageName the package name of the app to control
* @throws SecurityException if the caller doesn't have MODIFY_AUDIO_ROUTING permission.
@@ -170,15 +171,16 @@ public final class MediaRouter2 {
@SystemApi
@RequiresPermission(Manifest.permission.MEDIA_CONTENT_CONTROL)
@Nullable
- public static MediaRouter2 getInstance(@NonNull Context context,
- @NonNull String clientPackageName) {
+ public static MediaRouter2 getInstance(
+ @NonNull Context context, @NonNull String clientPackageName) {
Objects.requireNonNull(context, "context must not be null");
Objects.requireNonNull(clientPackageName, "clientPackageName must not be null");
// Note: Even though this check could be somehow bypassed, the other permission checks
// in system server will not allow MediaRouter2Manager to be registered.
- IMediaRouterService serviceBinder = IMediaRouterService.Stub.asInterface(
- ServiceManager.getService(Context.MEDIA_ROUTER_SERVICE));
+ IMediaRouterService serviceBinder =
+ IMediaRouterService.Stub.asInterface(
+ ServiceManager.getService(Context.MEDIA_ROUTER_SERVICE));
try {
// SecurityException will be thrown if there's no permission.
serviceBinder.enforceMediaContentControlPermission();
@@ -212,17 +214,17 @@ public final class MediaRouter2 {
/**
* Starts scanning remote routes.
- * <p>
- * Route discovery can happen even when the {@link #startScan()} is not called.
- * This is because the scanning could be started before by other apps.
- * Therefore, calling this method after calling {@link #stopScan()} does not necessarily mean
- * that the routes found before are removed and added again.
- * <p>
- * Use {@link RouteCallback} to get the route related events.
- * <p>
- * Note that calling start/stopScan is applied to all system routers in the same process.
- * <p>
- * This will be no-op for non-system media routers.
+ *
+ * <p>Route discovery can happen even when the {@link #startScan()} is not called. This is
+ * because the scanning could be started before by other apps. Therefore, calling this method
+ * after calling {@link #stopScan()} does not necessarily mean that the routes found before are
+ * removed and added again.
+ *
+ * <p>Use {@link RouteCallback} to get the route related events.
+ *
+ * <p>Note that calling start/stopScan is applied to all system routers in the same process.
+ *
+ * <p>This will be no-op for non-system media routers.
*
* @see #stopScan()
* @see #getInstance(Context, String)
@@ -238,18 +240,17 @@ public final class MediaRouter2 {
/**
* Stops scanning remote routes to reduce resource consumption.
- * <p>
- * Route discovery can be continued even after this method is called.
- * This is because the scanning is only turned off when all the apps stop scanning.
- * Therefore, calling this method does not necessarily mean the routes are removed.
- * Also, for the same reason it does not mean that {@link RouteCallback#onRoutesAdded(List)}
- * is not called afterwards.
- * <p>
- * Use {@link RouteCallback} to get the route related events.
- * <p>
- * Note that calling start/stopScan is applied to all system routers in the same process.
- * <p>
- * This will be no-op for non-system media routers.
+ *
+ * <p>Route discovery can be continued even after this method is called. This is because the
+ * scanning is only turned off when all the apps stop scanning. Therefore, calling this method
+ * does not necessarily mean the routes are removed. Also, for the same reason it does not mean
+ * that {@link RouteCallback#onRoutesAdded(List)} is not called afterwards.
+ *
+ * <p>Use {@link RouteCallback} to get the route related events.
+ *
+ * <p>Note that calling start/stopScan is applied to all system routers in the same process.
+ *
+ * <p>This will be no-op for non-system media routers.
*
* @see #startScan()
* @see #getInstance(Context, String)
@@ -265,8 +266,9 @@ public final class MediaRouter2 {
private MediaRouter2(Context appContext) {
mContext = appContext;
- mMediaRouterService = IMediaRouterService.Stub.asInterface(
- ServiceManager.getService(Context.MEDIA_ROUTER_SERVICE));
+ mMediaRouterService =
+ IMediaRouterService.Stub.asInterface(
+ ServiceManager.getService(Context.MEDIA_ROUTER_SERVICE));
mPackageName = mContext.getPackageName();
mHandler = new Handler(Looper.getMainLooper());
@@ -302,9 +304,10 @@ public final class MediaRouter2 {
mClientPackageName = clientPackageName;
mManagerCallback = new ManagerCallback();
mHandler = new Handler(Looper.getMainLooper());
- mSystemController = new SystemRoutingController(
- ensureClientPackageNameForSystemSession(
- sManager.getSystemRoutingSession(clientPackageName)));
+ mSystemController =
+ new SystemRoutingController(
+ ensureClientPackageNameForSystemSession(
+ sManager.getSystemRoutingSession(clientPackageName)));
mDiscoveryPreference = sManager.getDiscoveryPreference(clientPackageName);
updateAllRoutesFromManager();
@@ -318,8 +321,8 @@ public final class MediaRouter2 {
*
* @hide
*/
- static boolean checkRouteListContainsRouteId(@NonNull List<MediaRoute2Info> routeList,
- @NonNull String routeId) {
+ static boolean checkRouteListContainsRouteId(
+ @NonNull List<MediaRoute2Info> routeList, @NonNull String routeId) {
for (MediaRoute2Info info : routeList) {
if (TextUtils.equals(routeId, info.getId())) {
return true;
@@ -330,8 +333,8 @@ public final class MediaRouter2 {
/**
* Gets the client package name of the app which this media router controls.
- * <p>
- * This will return null for non-system media routers.
+ *
+ * <p>This will return null for non-system media routers.
*
* @see #getInstance(Context, String)
* @hide
@@ -344,12 +347,12 @@ public final class MediaRouter2 {
/**
* Registers a callback to discover routes and to receive events when they change.
- * <p>
- * If the specified callback is already registered, its registration will be updated for the
+ *
+ * <p>If the specified callback is already registered, its registration will be updated for the
* given {@link Executor executor} and {@link RouteDiscoveryPreference discovery preference}.
- * </p>
*/
- public void registerRouteCallback(@NonNull @CallbackExecutor Executor executor,
+ public void registerRouteCallback(
+ @NonNull @CallbackExecutor Executor executor,
@NonNull RouteCallback routeCallback,
@NonNull RouteDiscoveryPreference preference) {
Objects.requireNonNull(executor, "executor must not be null");
@@ -391,8 +394,8 @@ public final class MediaRouter2 {
}
/**
- * Unregisters the given callback. The callback will no longer receive events.
- * If the callback has not been added or been removed already, it is ignored.
+ * Unregisters the given callback. The callback will no longer receive events. If the callback
+ * has not been added or been removed already, it is ignored.
*
* @param routeCallback the callback to unregister
* @see #registerRouteCallback
@@ -400,8 +403,7 @@ public final class MediaRouter2 {
public void unregisterRouteCallback(@NonNull RouteCallback routeCallback) {
Objects.requireNonNull(routeCallback, "callback must not be null");
- if (!mRouteCallbackRecords.remove(
- new RouteCallbackRecord(null, routeCallback, null))) {
+ if (!mRouteCallbackRecords.remove(new RouteCallbackRecord(null, routeCallback, null))) {
Log.w(TAG, "unregisterRouteCallback: Ignoring unknown callback");
return;
}
@@ -416,8 +418,7 @@ public final class MediaRouter2 {
}
if (updateDiscoveryPreferenceIfNeededLocked()) {
try {
- mMediaRouterService.setDiscoveryRequestWithRouter2(
- mStub, mDiscoveryPreference);
+ mMediaRouterService.setDiscoveryRequestWithRouter2(mStub, mDiscoveryPreference);
} catch (RemoteException ex) {
Log.e(TAG, "unregisterRouteCallback: Unable to set discovery request.", ex);
}
@@ -430,27 +431,28 @@ public final class MediaRouter2 {
}
mStub = null;
}
- mShouldUpdateRoutes = true;
}
}
+ @GuardedBy("mLock")
private boolean updateDiscoveryPreferenceIfNeededLocked() {
RouteDiscoveryPreference newDiscoveryPreference = new RouteDiscoveryPreference.Builder(
mRouteCallbackRecords.stream().map(record -> record.mPreference).collect(
Collectors.toList())).build();
+
if (Objects.equals(mDiscoveryPreference, newDiscoveryPreference)) {
return false;
}
mDiscoveryPreference = newDiscoveryPreference;
- mShouldUpdateRoutes = true;
+ updateFilteredRoutesLocked();
return true;
}
/**
- * Gets the list of all discovered routes.
- * This list includes the routes that are not related to the client app.
- * <p>
- * This will return an empty list for non-system media routers.
+ * Gets the list of all discovered routes. This list includes the routes that are not related to
+ * the client app.
+ *
+ * <p>This will return an empty list for non-system media routers.
*
* @hide
*/
@@ -464,25 +466,19 @@ public final class MediaRouter2 {
}
/**
- * Gets the unmodifiable list of {@link MediaRoute2Info routes} currently
- * known to the media router.
- * <p>
- * Please note that the list can be changed before callbacks are invoked.
- * </p>
+ * Gets the unmodifiable list of {@link MediaRoute2Info routes} currently known to the media
+ * router.
+ *
+ * <p>Please note that the list can be changed before callbacks are invoked.
+ *
* @return the list of routes that contains at least one of the route features in discovery
- * preferences registered by the application
+ * preferences registered by the application
*/
@NonNull
public List<MediaRoute2Info> getRoutes() {
synchronized (mLock) {
- if (mShouldUpdateRoutes) {
- mShouldUpdateRoutes = false;
-
- mFilteredRoutes = Collections.unmodifiableList(
- filterRoutes(List.copyOf(mRoutes.values()), mDiscoveryPreference));
- }
+ return mFilteredRoutes;
}
- return mFilteredRoutes;
}
/**
@@ -493,8 +489,8 @@ public final class MediaRouter2 {
* @param callback the callback to register
* @see #unregisterTransferCallback
*/
- public void registerTransferCallback(@NonNull @CallbackExecutor Executor executor,
- @NonNull TransferCallback callback) {
+ public void registerTransferCallback(
+ @NonNull @CallbackExecutor Executor executor, @NonNull TransferCallback callback) {
Objects.requireNonNull(executor, "executor must not be null");
Objects.requireNonNull(callback, "callback must not be null");
@@ -522,12 +518,13 @@ public final class MediaRouter2 {
}
/**
- * Registers a {@link ControllerCallback}.
- * If you register the same callback twice or more, it will be ignored.
+ * Registers a {@link ControllerCallback}. If you register the same callback twice or more, it
+ * will be ignored.
+ *
* @see #unregisterControllerCallback(ControllerCallback)
*/
- public void registerControllerCallback(@NonNull @CallbackExecutor Executor executor,
- @NonNull ControllerCallback callback) {
+ public void registerControllerCallback(
+ @NonNull @CallbackExecutor Executor executor, @NonNull ControllerCallback callback) {
Objects.requireNonNull(executor, "executor must not be null");
Objects.requireNonNull(callback, "callback must not be null");
@@ -539,12 +536,12 @@ public final class MediaRouter2 {
}
/**
- * Unregisters a {@link ControllerCallback}. The callback will no longer receive
- * events. If the callback has not been added or been removed already, it is ignored.
+ * Unregisters a {@link ControllerCallback}. The callback will no longer receive events.
+ * If the callback has not been added or been removed already, it is ignored.
+ *
* @see #registerControllerCallback(Executor, ControllerCallback)
*/
- public void unregisterControllerCallback(
- @NonNull ControllerCallback callback) {
+ public void unregisterControllerCallback(@NonNull ControllerCallback callback) {
Objects.requireNonNull(callback, "callback must not be null");
if (!mControllerCallbackRecords.remove(new ControllerCallbackRecord(null, callback))) {
@@ -559,7 +556,7 @@ public final class MediaRouter2 {
* {@link #transferTo(MediaRoute2Info)}.
*
* @param listener A listener to send optional app-specific hints when creating a controller.
- * {@code null} for unset.
+ * {@code null} for unset.
*/
public void setOnGetControllerHintsListener(@Nullable OnGetControllerHintsListener listener) {
if (isSystemRouter()) {
@@ -569,13 +566,11 @@ public final class MediaRouter2 {
}
/**
- * Transfers the current media to the given route.
- * If it's necessary a new {@link RoutingController} is created or it is handled within
- * the current routing controller.
+ * Transfers the current media to the given route. If it's necessary a new
+ * {@link RoutingController} is created or it is handled within the current routing controller.
*
* @param route the route you want to transfer the current media to. Pass {@code null} to
* stop routing of the current media.
- *
* @see TransferCallback#onTransfer
* @see TransferCallback#onTransferFailure
*/
@@ -622,8 +617,8 @@ public final class MediaRouter2 {
/**
* Transfers the media of a routing controller to the given route.
- * <p>
- * This will be no-op for non-system media routers.
+ *
+ * <p>This will be no-op for non-system media routers.
*
* @param controller a routing controller controlling media routing.
* @param route the route you want to transfer the media to.
@@ -638,13 +633,15 @@ public final class MediaRouter2 {
}
}
- void requestCreateController(@NonNull RoutingController controller,
- @NonNull MediaRoute2Info route, long managerRequestId) {
+ void requestCreateController(
+ @NonNull RoutingController controller,
+ @NonNull MediaRoute2Info route,
+ long managerRequestId) {
final int requestId = mNextRequestId.getAndIncrement();
- ControllerCreationRequest request = new ControllerCreationRequest(requestId,
- managerRequestId, route, controller);
+ ControllerCreationRequest request =
+ new ControllerCreationRequest(requestId, managerRequestId, route, controller);
mControllerCreationRequests.add(request);
OnGetControllerHintsListener listener = mOnGetControllerHintsListener;
@@ -663,11 +660,15 @@ public final class MediaRouter2 {
if (stub != null) {
try {
mMediaRouterService.requestCreateSessionWithRouter2(
- stub, requestId, managerRequestId,
- controller.getRoutingSessionInfo(), route, controllerHints);
+ stub,
+ requestId,
+ managerRequestId,
+ controller.getRoutingSessionInfo(),
+ route,
+ controllerHints);
} catch (RemoteException ex) {
Log.e(TAG, "createControllerForTransfer: "
- + "Failed to request for creating a controller.", ex);
+ + "Failed to request for creating a controller.", ex);
mControllerCreationRequests.remove(request);
if (managerRequestId == MANAGER_REQUEST_ID_NONE) {
notifyTransferFailure(route);
@@ -685,11 +686,11 @@ public final class MediaRouter2 {
/**
* Gets a {@link RoutingController} which can control the routes provided by system.
* e.g. Phone speaker, wired headset, Bluetooth, etc.
- * <p>
- * Note: The system controller can't be released. Calling {@link RoutingController#release()}
+ *
+ * <p>Note: The system controller can't be released. Calling {@link RoutingController#release()}
* will be ignored.
- * <p>
- * This method always returns the same instance.
+ *
+ * <p>This method always returns the same instance.
*/
@NonNull
public RoutingController getSystemController() {
@@ -714,8 +715,8 @@ public final class MediaRouter2 {
/**
* Gets the list of currently active {@link RoutingController routing controllers} on which
* media can be played.
- * <p>
- * Note: The list returned here will never be empty. The first element in the list is
+ *
+ * <p>Note: The list returned here will never be empty. The first element in the list is
* always the {@link #getSystemController() system controller}.
*/
@NonNull
@@ -750,8 +751,8 @@ public final class MediaRouter2 {
/**
* Requests a volume change for the route asynchronously.
* It may have no effect if the route is currently not selected.
- * <p>
- * This will be no-op for non-system media routers.
+ *
+ * <p>This will be no-op for non-system media routers.
*
* @param volume The new volume value between 0 and {@link MediaRoute2Info#getVolumeMax}.
* @see #getInstance(Context, String)
@@ -769,55 +770,61 @@ public final class MediaRouter2 {
// If this API needs to be public, use IMediaRouterService#setRouteVolumeWithRouter2()
}
- void syncRoutesOnHandler(List<MediaRoute2Info> currentRoutes,
- RoutingSessionInfo currentSystemSessionInfo) {
+ void syncRoutesOnHandler(
+ List<MediaRoute2Info> currentRoutes, RoutingSessionInfo currentSystemSessionInfo) {
if (currentRoutes == null || currentRoutes.isEmpty() || currentSystemSessionInfo == null) {
Log.e(TAG, "syncRoutesOnHandler: Received wrong data. currentRoutes=" + currentRoutes
+ ", currentSystemSessionInfo=" + currentSystemSessionInfo);
return;
}
+ synchronized (mLock) {
+ mRoutes.clear();
+ for (MediaRoute2Info route : currentRoutes) {
+ mRoutes.put(route.getId(), route);
+ }
+ updateFilteredRoutesLocked();
+ }
+
+ RoutingSessionInfo oldInfo = mSystemController.getRoutingSessionInfo();
+ mSystemController.setRoutingSessionInfo(currentSystemSessionInfo);
+ if (!oldInfo.equals(currentSystemSessionInfo)) {
+ notifyControllerUpdated(mSystemController);
+ }
+ }
+
+ void dispatchFilteredRoutesChangedLocked(List<MediaRoute2Info> newRoutes) {
List<MediaRoute2Info> addedRoutes = new ArrayList<>();
List<MediaRoute2Info> removedRoutes = new ArrayList<>();
List<MediaRoute2Info> changedRoutes = new ArrayList<>();
- synchronized (mLock) {
- List<String> currentRoutesIds = currentRoutes.stream().map(MediaRoute2Info::getId)
- .collect(Collectors.toList());
-
- for (String routeId : mRoutes.keySet()) {
- if (!currentRoutesIds.contains(routeId)) {
- // This route is removed while the callback is unregistered.
- MediaRoute2Info route = mRoutes.get(routeId);
- if (route.hasAnyFeatures(mDiscoveryPreference.getPreferredFeatures())) {
- removedRoutes.add(mRoutes.get(routeId));
- }
- }
- }
+ Set<String> newRouteIds =
+ newRoutes.stream().map(MediaRoute2Info::getId).collect(Collectors.toSet());
- for (MediaRoute2Info route : currentRoutes) {
- if (mRoutes.containsKey(route.getId())) {
- if (!route.equals(mRoutes.get(route.getId()))) {
- // This route is changed while the callback is unregistered.
- if (route.hasAnyFeatures(
- mDiscoveryPreference.getPreferredFeatures())) {
- changedRoutes.add(route);
- }
- }
- } else {
- // This route is added while the callback is unregistered.
- if (route.hasAnyFeatures(mDiscoveryPreference.getPreferredFeatures())) {
- addedRoutes.add(route);
- }
- }
+ for (MediaRoute2Info route : newRoutes) {
+ MediaRoute2Info prevRoute = mPreviousRoutes.get(route.getId());
+ if (prevRoute == null) {
+ addedRoutes.add(route);
+ } else if (!prevRoute.equals(route)) {
+ changedRoutes.add(route);
}
+ }
- mRoutes.clear();
- for (MediaRoute2Info route : currentRoutes) {
- mRoutes.put(route.getId(), route);
+ for (int i = 0; i < mPreviousRoutes.size(); i++) {
+ if (!newRouteIds.contains(mPreviousRoutes.keyAt(i))) {
+ removedRoutes.add(mPreviousRoutes.valueAt(i));
}
+ }
- mShouldUpdateRoutes = true;
+ // update previous routes
+ for (MediaRoute2Info route : removedRoutes) {
+ mPreviousRoutes.remove(route.getId());
+ }
+ for (MediaRoute2Info route : addedRoutes) {
+ mPreviousRoutes.put(route.getId(), route);
+ }
+ for (MediaRoute2Info route : changedRoutes) {
+ mPreviousRoutes.put(route.getId(), route);
}
if (!addedRoutes.isEmpty()) {
@@ -829,43 +836,23 @@ public final class MediaRouter2 {
if (!changedRoutes.isEmpty()) {
notifyRoutesChanged(changedRoutes);
}
-
- RoutingSessionInfo oldInfo = mSystemController.getRoutingSessionInfo();
- mSystemController.setRoutingSessionInfo(currentSystemSessionInfo);
- if (!oldInfo.equals(currentSystemSessionInfo)) {
- notifyControllerUpdated(mSystemController);
- }
}
void addRoutesOnHandler(List<MediaRoute2Info> routes) {
- List<MediaRoute2Info> addedRoutes = new ArrayList<>();
synchronized (mLock) {
for (MediaRoute2Info route : routes) {
mRoutes.put(route.getId(), route);
- if (route.hasAnyFeatures(mDiscoveryPreference.getPreferredFeatures())) {
- addedRoutes.add(route);
- }
}
- mShouldUpdateRoutes = true;
- }
- if (!addedRoutes.isEmpty()) {
- notifyRoutesAdded(addedRoutes);
+ updateFilteredRoutesLocked();
}
}
void removeRoutesOnHandler(List<MediaRoute2Info> routes) {
- List<MediaRoute2Info> removedRoutes = new ArrayList<>();
synchronized (mLock) {
for (MediaRoute2Info route : routes) {
mRoutes.remove(route.getId());
- if (route.hasAnyFeatures(mDiscoveryPreference.getPreferredFeatures())) {
- removedRoutes.add(route);
- }
}
- mShouldUpdateRoutes = true;
- }
- if (!removedRoutes.isEmpty()) {
- notifyRoutesRemoved(removedRoutes);
+ updateFilteredRoutesLocked();
}
}
@@ -874,23 +861,27 @@ public final class MediaRouter2 {
synchronized (mLock) {
for (MediaRoute2Info route : routes) {
mRoutes.put(route.getId(), route);
- if (route.hasAnyFeatures(mDiscoveryPreference.getPreferredFeatures())) {
- changedRoutes.add(route);
- }
}
- mShouldUpdateRoutes = true;
- }
- if (!changedRoutes.isEmpty()) {
- notifyRoutesChanged(changedRoutes);
+ updateFilteredRoutesLocked();
}
}
+ /** Updates filtered routes and dispatch callbacks */
+ @GuardedBy("mLock")
+ void updateFilteredRoutesLocked() {
+ mFilteredRoutes =
+ Collections.unmodifiableList(
+ filterRoutesWithCompositePreferenceLocked(List.copyOf(mRoutes.values())));
+ mHandler.sendMessage(
+ obtainMessage(MediaRouter2::dispatchFilteredRoutesChangedLocked,
+ this, mFilteredRoutes));
+ }
+
/**
- * Creates a controller and calls the {@link TransferCallback#onTransfer}.
- * If the controller creation has failed, then it calls
- * {@link TransferCallback#onTransferFailure}.
- * <p>
- * Pass {@code null} to sessionInfo for the failure case.
+ * Creates a controller and calls the {@link TransferCallback#onTransfer}. If the controller
+ * creation has failed, then it calls {@link TransferCallback#onTransferFailure}.
+ *
+ * <p>Pass {@code null} to sessionInfo for the failure case.
*/
void createControllerOnHandler(int requestId, @Nullable RoutingSessionInfo sessionInfo) {
ControllerCreationRequest matchingRequest = null;
@@ -913,12 +904,15 @@ public final class MediaRouter2 {
if (sessionInfo == null) {
notifyTransferFailure(requestedRoute);
return;
- } else if (!TextUtils.equals(requestedRoute.getProviderId(),
- sessionInfo.getProviderId())) {
- Log.w(TAG, "The session's provider ID does not match the requested route's. "
- + "(requested route's providerId=" + requestedRoute.getProviderId()
- + ", actual providerId=" + sessionInfo.getProviderId()
- + ")");
+ } else if (!TextUtils.equals(requestedRoute.getProviderId(), sessionInfo.getProviderId())) {
+ Log.w(
+ TAG,
+ "The session's provider ID does not match the requested route's. "
+ + "(requested route's providerId="
+ + requestedRoute.getProviderId()
+ + ", actual providerId="
+ + sessionInfo.getProviderId()
+ + ")");
notifyTransferFailure(requestedRoute);
return;
}
@@ -927,9 +921,12 @@ public final class MediaRouter2 {
// When the old controller is released before transferred, treat it as a failure.
// This could also happen when transfer is requested twice or more.
if (!oldController.scheduleRelease()) {
- Log.w(TAG, "createControllerOnHandler: "
- + "Ignoring controller creation for released old controller. "
- + "oldController=" + oldController);
+ Log.w(
+ TAG,
+ "createControllerOnHandler: "
+ + "Ignoring controller creation for released old controller. "
+ + "oldController="
+ + oldController);
if (!sessionInfo.isSystemSession()) {
new RoutingController(sessionInfo).release();
}
@@ -971,15 +968,21 @@ public final class MediaRouter2 {
}
if (matchingController == null) {
- Log.w(TAG, "updateControllerOnHandler: Matching controller not found. uniqueSessionId="
- + sessionInfo.getId());
+ Log.w(
+ TAG,
+ "updateControllerOnHandler: Matching controller not found. uniqueSessionId="
+ + sessionInfo.getId());
return;
}
RoutingSessionInfo oldInfo = matchingController.getRoutingSessionInfo();
if (!TextUtils.equals(oldInfo.getProviderId(), sessionInfo.getProviderId())) {
- Log.w(TAG, "updateControllerOnHandler: Provider IDs are not matched. old="
- + oldInfo.getProviderId() + ", new=" + sessionInfo.getProviderId());
+ Log.w(
+ TAG,
+ "updateControllerOnHandler: Provider IDs are not matched. old="
+ + oldInfo.getProviderId()
+ + ", new="
+ + sessionInfo.getProviderId());
return;
}
@@ -1000,24 +1003,31 @@ public final class MediaRouter2 {
if (matchingController == null) {
if (DEBUG) {
- Log.d(TAG, "releaseControllerOnHandler: Matching controller not found. "
- + "uniqueSessionId=" + sessionInfo.getId());
+ Log.d(
+ TAG,
+ "releaseControllerOnHandler: Matching controller not found. "
+ + "uniqueSessionId="
+ + sessionInfo.getId());
}
return;
}
RoutingSessionInfo oldInfo = matchingController.getRoutingSessionInfo();
if (!TextUtils.equals(oldInfo.getProviderId(), sessionInfo.getProviderId())) {
- Log.w(TAG, "releaseControllerOnHandler: Provider IDs are not matched. old="
- + oldInfo.getProviderId() + ", new=" + sessionInfo.getProviderId());
+ Log.w(
+ TAG,
+ "releaseControllerOnHandler: Provider IDs are not matched. old="
+ + oldInfo.getProviderId()
+ + ", new="
+ + sessionInfo.getProviderId());
return;
}
matchingController.releaseInternal(/* shouldReleaseSession= */ false);
}
- void onRequestCreateControllerByManagerOnHandler(RoutingSessionInfo oldSession,
- MediaRoute2Info route, long managerRequestId) {
+ void onRequestCreateControllerByManagerOnHandler(
+ RoutingSessionInfo oldSession, MediaRoute2Info route, long managerRequestId) {
RoutingController controller;
if (oldSession.isSystemSession()) {
controller = getSystemController();
@@ -1033,17 +1043,17 @@ public final class MediaRouter2 {
}
/**
- * Returns whether this router is created with {@link #getInstance(Context, String)}.
- * This kind of router can control the target app's media routing.
+ * Returns whether this router is created with {@link #getInstance(Context, String)}. This kind
+ * of router can control the target app's media routing.
*/
private boolean isSystemRouter() {
return mClientPackageName != null;
}
/**
- * Returns a {@link RoutingSessionInfo} which has the client package name.
- * The client package name is set only when the given sessionInfo doesn't have it.
- * Should only used for system media routers.
+ * Returns a {@link RoutingSessionInfo} which has the client package name. The client package
+ * name is set only when the given sessionInfo doesn't have it. Should only used for system
+ * media routers.
*/
private RoutingSessionInfo ensureClientPackageNameForSystemSession(
@NonNull RoutingSessionInfo sessionInfo) {
@@ -1057,41 +1067,44 @@ public final class MediaRouter2 {
.build();
}
- private List<MediaRoute2Info> getSortedRoutes(List<MediaRoute2Info> routes,
- RouteDiscoveryPreference preference) {
- if (!preference.shouldRemoveDuplicates()) {
+ private List<MediaRoute2Info> getSortedRoutes(
+ List<MediaRoute2Info> routes, List<String> packageOrder) {
+ if (packageOrder.isEmpty()) {
return routes;
}
Map<String, Integer> packagePriority = new ArrayMap<>();
- int count = preference.getDeduplicationPackageOrder().size();
+ int count = packageOrder.size();
for (int i = 0; i < count; i++) {
// the last package will have 1 as the priority
- packagePriority.put(preference.getDeduplicationPackageOrder().get(i), count - i);
+ packagePriority.put(packageOrder.get(i), count - i);
}
ArrayList<MediaRoute2Info> sortedRoutes = new ArrayList<>(routes);
// take the negative for descending order
- sortedRoutes.sort(Comparator.comparingInt(
- r -> -packagePriority.getOrDefault(r.getPackageName(), 0)));
+ sortedRoutes.sort(
+ Comparator.comparingInt(r -> -packagePriority.getOrDefault(r.getPackageName(), 0)));
return sortedRoutes;
}
- private List<MediaRoute2Info> filterRoutes(List<MediaRoute2Info> routes,
- RouteDiscoveryPreference discoveryPreference) {
+ @GuardedBy("mLock")
+ private List<MediaRoute2Info> filterRoutesWithCompositePreferenceLocked(
+ List<MediaRoute2Info> routes) {
Set<String> deduplicationIdSet = new ArraySet<>();
List<MediaRoute2Info> filteredRoutes = new ArrayList<>();
- for (MediaRoute2Info route : getSortedRoutes(routes, discoveryPreference)) {
- if (!route.hasAnyFeatures(discoveryPreference.getPreferredFeatures())) {
+ for (MediaRoute2Info route :
+ getSortedRoutes(routes, mDiscoveryPreference.getDeduplicationPackageOrder())) {
+ if (!route.hasAnyFeatures(mDiscoveryPreference.getPreferredFeatures())) {
continue;
}
- if (!discoveryPreference.getAllowedPackages().isEmpty()
+ if (!mDiscoveryPreference.getAllowedPackages().isEmpty()
&& (route.getPackageName() == null
- || !discoveryPreference.getAllowedPackages()
- .contains(route.getPackageName()))) {
+ || !mDiscoveryPreference
+ .getAllowedPackages()
+ .contains(route.getPackageName()))) {
continue;
}
- if (discoveryPreference.shouldRemoveDuplicates()) {
+ if (mDiscoveryPreference.shouldRemoveDuplicates()) {
if (!Collections.disjoint(deduplicationIdSet, route.getDeduplicationIds())) {
continue;
}
@@ -1102,6 +1115,30 @@ public final class MediaRouter2 {
return filteredRoutes;
}
+ private List<MediaRoute2Info> filterRoutesWithIndividualPreference(
+ List<MediaRoute2Info> routes, RouteDiscoveryPreference discoveryPreference) {
+ List<MediaRoute2Info> filteredRoutes = new ArrayList<>();
+ if (isSystemRouter()) {
+ // Individual discovery preferences do not apply for the system router.
+ filteredRoutes.addAll(routes);
+ return filteredRoutes;
+ }
+ for (MediaRoute2Info route : routes) {
+ if (!route.hasAnyFeatures(discoveryPreference.getPreferredFeatures())) {
+ continue;
+ }
+ if (!discoveryPreference.getAllowedPackages().isEmpty()
+ && (route.getPackageName() == null
+ || !discoveryPreference
+ .getAllowedPackages()
+ .contains(route.getPackageName()))) {
+ continue;
+ }
+ filteredRoutes.add(route);
+ }
+ return filteredRoutes;
+ }
+
private void updateAllRoutesFromManager() {
if (!isSystemRouter()) {
return;
@@ -1111,23 +1148,24 @@ public final class MediaRouter2 {
for (MediaRoute2Info route : sManager.getAllRoutes()) {
mRoutes.put(route.getId(), route);
}
- mShouldUpdateRoutes = true;
+ updateFilteredRoutesLocked();
}
}
private void notifyRoutesAdded(List<MediaRoute2Info> routes) {
- for (RouteCallbackRecord record: mRouteCallbackRecords) {
- List<MediaRoute2Info> filteredRoutes = filterRoutes(routes, record.mPreference);
+ for (RouteCallbackRecord record : mRouteCallbackRecords) {
+ List<MediaRoute2Info> filteredRoutes =
+ filterRoutesWithIndividualPreference(routes, record.mPreference);
if (!filteredRoutes.isEmpty()) {
- record.mExecutor.execute(
- () -> record.mRouteCallback.onRoutesAdded(filteredRoutes));
+ record.mExecutor.execute(() -> record.mRouteCallback.onRoutesAdded(filteredRoutes));
}
}
}
private void notifyRoutesRemoved(List<MediaRoute2Info> routes) {
- for (RouteCallbackRecord record: mRouteCallbackRecords) {
- List<MediaRoute2Info> filteredRoutes = filterRoutes(routes, record.mPreference);
+ for (RouteCallbackRecord record : mRouteCallbackRecords) {
+ List<MediaRoute2Info> filteredRoutes =
+ filterRoutesWithIndividualPreference(routes, record.mPreference);
if (!filteredRoutes.isEmpty()) {
record.mExecutor.execute(
() -> record.mRouteCallback.onRoutesRemoved(filteredRoutes));
@@ -1136,8 +1174,9 @@ public final class MediaRouter2 {
}
private void notifyRoutesChanged(List<MediaRoute2Info> routes) {
- for (RouteCallbackRecord record: mRouteCallbackRecords) {
- List<MediaRoute2Info> filteredRoutes = filterRoutes(routes, record.mPreference);
+ for (RouteCallbackRecord record : mRouteCallbackRecords) {
+ List<MediaRoute2Info> filteredRoutes =
+ filterRoutesWithIndividualPreference(routes, record.mPreference);
if (!filteredRoutes.isEmpty()) {
record.mExecutor.execute(
() -> record.mRouteCallback.onRoutesChanged(filteredRoutes));
@@ -1146,46 +1185,42 @@ public final class MediaRouter2 {
}
private void notifyPreferredFeaturesChanged(List<String> features) {
- for (RouteCallbackRecord record: mRouteCallbackRecords) {
+ for (RouteCallbackRecord record : mRouteCallbackRecords) {
record.mExecutor.execute(
() -> record.mRouteCallback.onPreferredFeaturesChanged(features));
}
}
private void notifyTransfer(RoutingController oldController, RoutingController newController) {
- for (TransferCallbackRecord record: mTransferCallbackRecords) {
+ for (TransferCallbackRecord record : mTransferCallbackRecords) {
record.mExecutor.execute(
() -> record.mTransferCallback.onTransfer(oldController, newController));
}
}
private void notifyTransferFailure(MediaRoute2Info route) {
- for (TransferCallbackRecord record: mTransferCallbackRecords) {
- record.mExecutor.execute(
- () -> record.mTransferCallback.onTransferFailure(route));
+ for (TransferCallbackRecord record : mTransferCallbackRecords) {
+ record.mExecutor.execute(() -> record.mTransferCallback.onTransferFailure(route));
}
}
private void notifyStop(RoutingController controller) {
- for (TransferCallbackRecord record: mTransferCallbackRecords) {
- record.mExecutor.execute(
- () -> record.mTransferCallback.onStop(controller));
+ for (TransferCallbackRecord record : mTransferCallbackRecords) {
+ record.mExecutor.execute(() -> record.mTransferCallback.onStop(controller));
}
}
private void notifyControllerUpdated(RoutingController controller) {
- for (ControllerCallbackRecord record: mControllerCallbackRecords) {
+ for (ControllerCallbackRecord record : mControllerCallbackRecords) {
record.mExecutor.execute(() -> record.mCallback.onControllerUpdated(controller));
}
}
- /**
- * Callback for receiving events about media route discovery.
- */
+ /** Callback for receiving events about media route discovery. */
public abstract static class RouteCallback {
/**
- * Called when routes are added. Whenever you registers a callback, this will
- * be invoked with known routes.
+ * Called when routes are added. Whenever you registers a callback, this will be invoked
+ * with known routes.
*
* @param routes the list of routes that have been added. It's never empty.
*/
@@ -1199,17 +1234,17 @@ public final class MediaRouter2 {
public void onRoutesRemoved(@NonNull List<MediaRoute2Info> routes) {}
/**
- * Called when routes are changed. For example, it is called when the route's name
- * or volume have been changed.
+ * Called when routes are changed. For example, it is called when the route's name or volume
+ * have been changed.
*
* @param routes the list of routes that have been changed. It's never empty.
*/
public void onRoutesChanged(@NonNull List<MediaRoute2Info> routes) {}
/**
- * Called when the client app's preferred features are changed.
- * When this is called, it is recommended to {@link #getRoutes()} to get the routes
- * that are currently available to the app.
+ * Called when the client app's preferred features are changed. When this is called, it is
+ * recommended to {@link #getRoutes()} to get the routes that are currently available to the
+ * app.
*
* @param preferredFeatures the new preferred features set by the application
* @hide
@@ -1218,26 +1253,25 @@ public final class MediaRouter2 {
public void onPreferredFeaturesChanged(@NonNull List<String> preferredFeatures) {}
}
- /**
- * Callback for receiving events on media transfer.
- */
+ /** Callback for receiving events on media transfer. */
public abstract static class TransferCallback {
/**
- * Called when a media is transferred between two different routing controllers.
- * This can happen by calling {@link #transferTo(MediaRoute2Info)}.
- * <p> Override this to start playback with {@code newController}. You may want to get
- * the status of the media that is being played with {@code oldController} and resume it
- * continuously with {@code newController}.
- * After this is called, any callbacks with {@code oldController} will not be invoked
- * unless {@code oldController} is the {@link #getSystemController() system controller}.
- * You need to {@link RoutingController#release() release} {@code oldController} before
- * playing the media with {@code newController}.
+ * Called when a media is transferred between two different routing controllers. This can
+ * happen by calling {@link #transferTo(MediaRoute2Info)}.
+ *
+ * <p>Override this to start playback with {@code newController}. You may want to get the
+ * status of the media that is being played with {@code oldController} and resume it
+ * continuously with {@code newController}. After this is called, any callbacks with {@code
+ * oldController} will not be invoked unless {@code oldController} is the {@link
+ * #getSystemController() system controller}. You need to {@link RoutingController#release()
+ * release} {@code oldController} before playing the media with {@code newController}.
*
* @param oldController the previous controller that controlled routing
* @param newController the new controller to control routing
* @see #transferTo(MediaRoute2Info)
*/
- public void onTransfer(@NonNull RoutingController oldController,
+ public void onTransfer(
+ @NonNull RoutingController oldController,
@NonNull RoutingController newController) {}
/**
@@ -1248,61 +1282,58 @@ public final class MediaRouter2 {
public void onTransferFailure(@NonNull MediaRoute2Info requestedRoute) {}
/**
- * Called when a media routing stops. It can be stopped by a user or a provider.
- * App should not continue playing media locally when this method is called.
- * The {@code controller} is released before this method is called.
+ * Called when a media routing stops. It can be stopped by a user or a provider. App should
+ * not continue playing media locally when this method is called. The {@code controller} is
+ * released before this method is called.
*
* @param controller the controller that controlled the stopped media routing
*/
- public void onStop(@NonNull RoutingController controller) { }
+ public void onStop(@NonNull RoutingController controller) {}
}
/**
- * A listener interface to send optional app-specific hints when creating a
- * {@link RoutingController}.
+ * A listener interface to send optional app-specific hints when creating a {@link
+ * RoutingController}.
*/
public interface OnGetControllerHintsListener {
/**
- * Called when the {@link MediaRouter2} or the system is about to request
- * a media route provider service to create a controller with the given route.
- * The {@link Bundle} returned here will be sent to media route provider service as a hint.
- * <p>
- * Since controller creation can be requested by the {@link MediaRouter2} and the system,
- * set the listener as soon as possible after acquiring {@link MediaRouter2} instance.
- * The method will be called on the same thread that calls
- * {@link #transferTo(MediaRoute2Info)} or the main thread if it is requested by the system.
+ * Called when the {@link MediaRouter2} or the system is about to request a media route
+ * provider service to create a controller with the given route. The {@link Bundle} returned
+ * here will be sent to media route provider service as a hint.
+ *
+ * <p>Since controller creation can be requested by the {@link MediaRouter2} and the system,
+ * set the listener as soon as possible after acquiring {@link MediaRouter2} instance. The
+ * method will be called on the same thread that calls {@link #transferTo(MediaRoute2Info)}
+ * or the main thread if it is requested by the system.
*
* @param route the route to create a controller with
- * @return An optional bundle of app-specific arguments to send to the provider,
- * or {@code null} if none. The contents of this bundle may affect the result of
- * controller creation.
+ * @return An optional bundle of app-specific arguments to send to the provider, or {@code
+ * null} if none. The contents of this bundle may affect the result of controller
+ * creation.
* @see MediaRoute2ProviderService#onCreateSession(long, String, String, Bundle)
*/
@Nullable
Bundle onGetControllerHints(@NonNull MediaRoute2Info route);
}
- /**
- * Callback for receiving {@link RoutingController} updates.
- */
+ /** Callback for receiving {@link RoutingController} updates. */
public abstract static class ControllerCallback {
/**
- * Called when a controller is updated. (e.g., when the selected routes of the
- * controller is changed or when the volume of the controller is changed.)
+ * Called when a controller is updated. (e.g., when the selected routes of the controller is
+ * changed or when the volume of the controller is changed.)
*
- * @param controller the updated controller. It may be the
- * {@link #getSystemController() system controller}.
+ * @param controller the updated controller. It may be the {@link #getSystemController()
+ * system controller}.
* @see #getSystemController()
*/
- public void onControllerUpdated(@NonNull RoutingController controller) { }
+ public void onControllerUpdated(@NonNull RoutingController controller) {}
}
/**
- * A class to control media routing session in media route provider.
- * For example, selecting/deselecting/transferring to routes of a session can be done through
- * this. Instances are created when
- * {@link TransferCallback#onTransfer(RoutingController, RoutingController)} is called,
- * which is invoked after {@link #transferTo(MediaRoute2Info)} is called.
+ * A class to control media routing session in media route provider. For example,
+ * selecting/deselecting/transferring to routes of a session can be done through this. Instances
+ * are created when {@link TransferCallback#onTransfer(RoutingController, RoutingController)} is
+ * called, which is invoked after {@link #transferTo(MediaRoute2Info)} is called.
*/
public class RoutingController {
private final Object mControllerLock = new Object();
@@ -1339,8 +1370,8 @@ public final class MediaRouter2 {
}
/**
- * Gets the original session ID set by
- * {@link RoutingSessionInfo.Builder#Builder(String, String)}.
+ * Gets the original session ID set by {@link RoutingSessionInfo.Builder#Builder(String,
+ * String)}.
*
* @hide
*/
@@ -1353,8 +1384,8 @@ public final class MediaRouter2 {
}
/**
- * Gets the control hints used to control routing session if available.
- * It is set by the media route provider.
+ * Gets the control hints used to control routing session if available. It is set by the
+ * media route provider.
*/
@Nullable
public Bundle getControlHints() {
@@ -1401,11 +1432,12 @@ public final class MediaRouter2 {
/**
* Gets the information about how volume is handled on the session.
- * <p>Please note that you may not control the volume of the session even when
- * you can control the volume of each selected route in the session.
*
- * @return {@link MediaRoute2Info#PLAYBACK_VOLUME_FIXED} or
- * {@link MediaRoute2Info#PLAYBACK_VOLUME_VARIABLE}
+ * <p>Please note that you may not control the volume of the session even when you can
+ * control the volume of each selected route in the session.
+ *
+ * @return {@link MediaRoute2Info#PLAYBACK_VOLUME_FIXED} or {@link
+ * MediaRoute2Info#PLAYBACK_VOLUME_VARIABLE}
*/
@MediaRoute2Info.PlaybackVolume
public int getVolumeHandling() {
@@ -1414,9 +1446,7 @@ public final class MediaRouter2 {
}
}
- /**
- * Gets the maximum volume of the session.
- */
+ /** Gets the maximum volume of the session. */
public int getVolumeMax() {
synchronized (mControllerLock) {
return mSessionInfo.getVolumeMax();
@@ -1425,11 +1455,10 @@ public final class MediaRouter2 {
/**
* Gets the current volume of the session.
- * <p>
- * When it's available, it represents the volume of routing session, which is a group
- * of selected routes. Use {@link MediaRoute2Info#getVolume()}
- * to get the volume of a route,
- * </p>
+ *
+ * <p>When it's available, it represents the volume of routing session, which is a group of
+ * selected routes. Use {@link MediaRoute2Info#getVolume()} to get the volume of a route,
+ *
* @see MediaRoute2Info#getVolume()
*/
public int getVolume() {
@@ -1439,9 +1468,9 @@ public final class MediaRouter2 {
}
/**
- * Returns true if this controller is released, false otherwise.
- * If it is released, then all other getters from this instance may return invalid values.
- * Also, any operations to this instance will be ignored once released.
+ * Returns true if this controller is released, false otherwise. If it is released, then all
+ * other getters from this instance may return invalid values. Also, any operations to this
+ * instance will be ignored once released.
*
* @see #release
*/
@@ -1454,14 +1483,16 @@ public final class MediaRouter2 {
/**
* Selects a route for the remote session. After a route is selected, the media is expected
* to be played to the all the selected routes. This is different from {@link
- * MediaRouter2#transferTo(MediaRoute2Info)} transferring to a route},
- * where the media is expected to 'move' from one route to another.
- * <p>
- * The given route must satisfy all of the following conditions:
+ * MediaRouter2#transferTo(MediaRoute2Info)} transferring to a route}, where the media is
+ * expected to 'move' from one route to another.
+ *
+ * <p>The given route must satisfy all of the following conditions:
+ *
* <ul>
- * <li>It should not be included in {@link #getSelectedRoutes()}</li>
- * <li>It should be included in {@link #getSelectableRoutes()}</li>
+ * <li>It should not be included in {@link #getSelectedRoutes()}
+ * <li>It should be included in {@link #getSelectableRoutes()}
* </ul>
+ *
* If the route doesn't meet any of above conditions, it will be ignored.
*
* @see #deselectRoute(MediaRoute2Info)
@@ -1509,12 +1540,14 @@ public final class MediaRouter2 {
/**
* Deselects a route from the remote session. After a route is deselected, the media is
* expected to be stopped on the deselected route.
- * <p>
- * The given route must satisfy all of the following conditions:
+ *
+ * <p>The given route must satisfy all of the following conditions:
+ *
* <ul>
- * <li>It should be included in {@link #getSelectedRoutes()}</li>
- * <li>It should be included in {@link #getDeselectableRoutes()}</li>
+ * <li>It should be included in {@link #getSelectedRoutes()}
+ * <li>It should be included in {@link #getDeselectableRoutes()}
* </ul>
+ *
* If the route doesn't meet any of above conditions, it will be ignored.
*
* @see #getSelectedRoutes()
@@ -1559,8 +1592,8 @@ public final class MediaRouter2 {
}
/**
- * Transfers to a given route for the remote session. The given route must be included
- * in {@link RoutingSessionInfo#getTransferableRoutes()}.
+ * Transfers to a given route for the remote session. The given route must be included in
+ * {@link RoutingSessionInfo#getTransferableRoutes()}.
*
* @see RoutingSessionInfo#getSelectedRoutes()
* @see RoutingSessionInfo#getTransferableRoutes()
@@ -1597,7 +1630,7 @@ public final class MediaRouter2 {
* Requests a volume change for the remote session asynchronously.
*
* @param volume The new volume value between 0 and {@link RoutingController#getVolumeMax}
- * (inclusive).
+ * (inclusive).
* @see #getVolume()
*/
public void setVolume(int volume) {
@@ -1634,9 +1667,9 @@ public final class MediaRouter2 {
}
/**
- * Releases this controller and the corresponding session.
- * Any operations on this controller after calling this method will be ignored.
- * The devices that are playing media will stop playing it.
+ * Releases this controller and the corresponding session. Any operations on this controller
+ * after calling this method will be ignored. The devices that are playing media will stop
+ * playing it.
*/
public void release() {
releaseInternal(/* shouldReleaseSession= */ true);
@@ -1644,8 +1677,9 @@ public final class MediaRouter2 {
/**
* Schedules release of the controller.
+ *
* @return {@code true} if it's successfully scheduled, {@code false} if it's already
- * scheduled to be released or released.
+ * scheduled to be released or released.
*/
boolean scheduleRelease() {
synchronized (mControllerLock) {
@@ -1701,11 +1735,15 @@ public final class MediaRouter2 {
}
if (shouldNotifyStop) {
- mHandler.sendMessage(obtainMessage(MediaRouter2::notifyStop, MediaRouter2.this,
- RoutingController.this));
+ mHandler.sendMessage(
+ obtainMessage(
+ MediaRouter2::notifyStop,
+ MediaRouter2.this,
+ RoutingController.this));
}
- if (mRouteCallbackRecords.isEmpty() && mNonSystemRoutingControllers.isEmpty()
+ if (mRouteCallbackRecords.isEmpty()
+ && mNonSystemRoutingControllers.isEmpty()
&& mStub != null) {
try {
mMediaRouterService.unregisterRouter2(mStub);
@@ -1720,26 +1758,34 @@ public final class MediaRouter2 {
@Override
public String toString() {
// To prevent logging spam, we only print the ID of each route.
- List<String> selectedRoutes = getSelectedRoutes().stream()
- .map(MediaRoute2Info::getId).collect(Collectors.toList());
- List<String> selectableRoutes = getSelectableRoutes().stream()
- .map(MediaRoute2Info::getId).collect(Collectors.toList());
- List<String> deselectableRoutes = getDeselectableRoutes().stream()
- .map(MediaRoute2Info::getId).collect(Collectors.toList());
-
- StringBuilder result = new StringBuilder()
- .append("RoutingController{ ")
- .append("id=").append(getId())
- .append(", selectedRoutes={")
- .append(selectedRoutes)
- .append("}")
- .append(", selectableRoutes={")
- .append(selectableRoutes)
- .append("}")
- .append(", deselectableRoutes={")
- .append(deselectableRoutes)
- .append("}")
- .append(" }");
+ List<String> selectedRoutes =
+ getSelectedRoutes().stream()
+ .map(MediaRoute2Info::getId)
+ .collect(Collectors.toList());
+ List<String> selectableRoutes =
+ getSelectableRoutes().stream()
+ .map(MediaRoute2Info::getId)
+ .collect(Collectors.toList());
+ List<String> deselectableRoutes =
+ getDeselectableRoutes().stream()
+ .map(MediaRoute2Info::getId)
+ .collect(Collectors.toList());
+
+ StringBuilder result =
+ new StringBuilder()
+ .append("RoutingController{ ")
+ .append("id=")
+ .append(getId())
+ .append(", selectedRoutes={")
+ .append(selectedRoutes)
+ .append("}")
+ .append(", selectableRoutes={")
+ .append(selectableRoutes)
+ .append("}")
+ .append(", deselectableRoutes={")
+ .append(deselectableRoutes)
+ .append("}")
+ .append(" }");
return result.toString();
}
@@ -1764,7 +1810,8 @@ public final class MediaRouter2 {
}
synchronized (mLock) {
- return routeIds.stream().map(mRoutes::get)
+ return routeIds.stream()
+ .map(mRoutes::get)
.filter(Objects::nonNull)
.collect(Collectors.toList());
}
@@ -1799,7 +1846,9 @@ public final class MediaRouter2 {
public final RouteCallback mRouteCallback;
public final RouteDiscoveryPreference mPreference;
- RouteCallbackRecord(@Nullable Executor executor, @NonNull RouteCallback routeCallback,
+ RouteCallbackRecord(
+ @Nullable Executor executor,
+ @NonNull RouteCallback routeCallback,
@Nullable RouteDiscoveryPreference preference) {
mRouteCallback = routeCallback;
mExecutor = executor;
@@ -1827,8 +1876,8 @@ public final class MediaRouter2 {
public final Executor mExecutor;
public final TransferCallback mTransferCallback;
- TransferCallbackRecord(@NonNull Executor executor,
- @NonNull TransferCallback transferCallback) {
+ TransferCallbackRecord(
+ @NonNull Executor executor, @NonNull TransferCallback transferCallback) {
mTransferCallback = transferCallback;
mExecutor = executor;
}
@@ -1854,8 +1903,8 @@ public final class MediaRouter2 {
public final Executor mExecutor;
public final ControllerCallback mCallback;
- ControllerCallbackRecord(@Nullable Executor executor,
- @NonNull ControllerCallback callback) {
+ ControllerCallbackRecord(
+ @Nullable Executor executor, @NonNull ControllerCallback callback) {
mCallback = callback;
mExecutor = executor;
}
@@ -1883,66 +1932,87 @@ public final class MediaRouter2 {
public final MediaRoute2Info mRoute;
public final RoutingController mOldController;
- ControllerCreationRequest(int requestId, long managerRequestId,
- @NonNull MediaRoute2Info route, @NonNull RoutingController oldController) {
+ ControllerCreationRequest(
+ int requestId,
+ long managerRequestId,
+ @NonNull MediaRoute2Info route,
+ @NonNull RoutingController oldController) {
mRequestId = requestId;
mManagerRequestId = managerRequestId;
mRoute = Objects.requireNonNull(route, "route must not be null");
- mOldController = Objects.requireNonNull(oldController,
- "oldController must not be null");
+ mOldController =
+ Objects.requireNonNull(oldController, "oldController must not be null");
}
}
class MediaRouter2Stub extends IMediaRouter2.Stub {
@Override
- public void notifyRouterRegistered(List<MediaRoute2Info> currentRoutes,
- RoutingSessionInfo currentSystemSessionInfo) {
- mHandler.sendMessage(obtainMessage(MediaRouter2::syncRoutesOnHandler,
- MediaRouter2.this, currentRoutes, currentSystemSessionInfo));
+ public void notifyRouterRegistered(
+ List<MediaRoute2Info> currentRoutes, RoutingSessionInfo currentSystemSessionInfo) {
+ mHandler.sendMessage(
+ obtainMessage(
+ MediaRouter2::syncRoutesOnHandler,
+ MediaRouter2.this,
+ currentRoutes,
+ currentSystemSessionInfo));
}
@Override
public void notifyRoutesAdded(List<MediaRoute2Info> routes) {
- mHandler.sendMessage(obtainMessage(MediaRouter2::addRoutesOnHandler,
- MediaRouter2.this, routes));
+ mHandler.sendMessage(
+ obtainMessage(MediaRouter2::addRoutesOnHandler, MediaRouter2.this, routes));
}
@Override
public void notifyRoutesRemoved(List<MediaRoute2Info> routes) {
- mHandler.sendMessage(obtainMessage(MediaRouter2::removeRoutesOnHandler,
- MediaRouter2.this, routes));
+ mHandler.sendMessage(
+ obtainMessage(MediaRouter2::removeRoutesOnHandler, MediaRouter2.this, routes));
}
@Override
public void notifyRoutesChanged(List<MediaRoute2Info> routes) {
- mHandler.sendMessage(obtainMessage(MediaRouter2::changeRoutesOnHandler,
- MediaRouter2.this, routes));
+ mHandler.sendMessage(
+ obtainMessage(MediaRouter2::changeRoutesOnHandler, MediaRouter2.this, routes));
}
@Override
public void notifySessionCreated(int requestId, @Nullable RoutingSessionInfo sessionInfo) {
- mHandler.sendMessage(obtainMessage(MediaRouter2::createControllerOnHandler,
- MediaRouter2.this, requestId, sessionInfo));
+ mHandler.sendMessage(
+ obtainMessage(
+ MediaRouter2::createControllerOnHandler,
+ MediaRouter2.this,
+ requestId,
+ sessionInfo));
}
@Override
public void notifySessionInfoChanged(@Nullable RoutingSessionInfo sessionInfo) {
- mHandler.sendMessage(obtainMessage(MediaRouter2::updateControllerOnHandler,
- MediaRouter2.this, sessionInfo));
+ mHandler.sendMessage(
+ obtainMessage(
+ MediaRouter2::updateControllerOnHandler,
+ MediaRouter2.this,
+ sessionInfo));
}
@Override
public void notifySessionReleased(RoutingSessionInfo sessionInfo) {
- mHandler.sendMessage(obtainMessage(MediaRouter2::releaseControllerOnHandler,
- MediaRouter2.this, sessionInfo));
+ mHandler.sendMessage(
+ obtainMessage(
+ MediaRouter2::releaseControllerOnHandler,
+ MediaRouter2.this,
+ sessionInfo));
}
@Override
- public void requestCreateSessionByManager(long managerRequestId,
- RoutingSessionInfo oldSession, MediaRoute2Info route) {
- mHandler.sendMessage(obtainMessage(
- MediaRouter2::onRequestCreateControllerByManagerOnHandler,
- MediaRouter2.this, oldSession, route, managerRequestId));
+ public void requestCreateSessionByManager(
+ long managerRequestId, RoutingSessionInfo oldSession, MediaRoute2Info route) {
+ mHandler.sendMessage(
+ obtainMessage(
+ MediaRouter2::onRequestCreateControllerByManagerOnHandler,
+ MediaRouter2.this,
+ oldSession,
+ route,
+ managerRequestId));
}
}
@@ -1952,57 +2022,21 @@ public final class MediaRouter2 {
@Override
public void onRoutesAdded(@NonNull List<MediaRoute2Info> routes) {
updateAllRoutesFromManager();
-
- List<MediaRoute2Info> filteredRoutes;
- synchronized (mLock) {
- filteredRoutes = filterRoutes(routes, mDiscoveryPreference);
- }
- if (filteredRoutes.isEmpty()) {
- return;
- }
- for (RouteCallbackRecord record: mRouteCallbackRecords) {
- record.mExecutor.execute(
- () -> record.mRouteCallback.onRoutesAdded(filteredRoutes));
- }
}
@Override
public void onRoutesRemoved(@NonNull List<MediaRoute2Info> routes) {
updateAllRoutesFromManager();
-
- List<MediaRoute2Info> filteredRoutes;
- synchronized (mLock) {
- filteredRoutes = filterRoutes(routes, mDiscoveryPreference);
- }
- if (filteredRoutes.isEmpty()) {
- return;
- }
- for (RouteCallbackRecord record: mRouteCallbackRecords) {
- record.mExecutor.execute(
- () -> record.mRouteCallback.onRoutesRemoved(filteredRoutes));
- }
}
@Override
public void onRoutesChanged(@NonNull List<MediaRoute2Info> routes) {
updateAllRoutesFromManager();
-
- List<MediaRoute2Info> filteredRoutes;
- synchronized (mLock) {
- filteredRoutes = filterRoutes(routes, mDiscoveryPreference);
- }
- if (filteredRoutes.isEmpty()) {
- return;
- }
- for (RouteCallbackRecord record: mRouteCallbackRecords) {
- record.mExecutor.execute(
- () -> record.mRouteCallback.onRoutesChanged(filteredRoutes));
- }
}
@Override
- public void onTransferred(@NonNull RoutingSessionInfo oldSession,
- @NonNull RoutingSessionInfo newSession) {
+ public void onTransferred(
+ @NonNull RoutingSessionInfo oldSession, @NonNull RoutingSessionInfo newSession) {
if (!oldSession.isSystemSession()
&& !TextUtils.equals(mClientPackageName, oldSession.getClientPackageName())) {
return;
@@ -2018,7 +2052,6 @@ public final class MediaRouter2 {
return;
}
-
RoutingController oldController;
if (oldSession.isSystemSession()) {
mSystemController.setRoutingSessionInfo(
@@ -2041,8 +2074,8 @@ public final class MediaRouter2 {
}
@Override
- public void onTransferFailed(@NonNull RoutingSessionInfo session,
- @NonNull MediaRoute2Info route) {
+ public void onTransferFailed(
+ @NonNull RoutingSessionInfo session, @NonNull MediaRoute2Info route) {
if (!session.isSystemSession()
&& !TextUtils.equals(mClientPackageName, session.getClientPackageName())) {
return;
@@ -2083,8 +2116,8 @@ public final class MediaRouter2 {
}
@Override
- public void onDiscoveryPreferenceChanged(@NonNull String packageName,
- @NonNull RouteDiscoveryPreference preference) {
+ public void onDiscoveryPreferenceChanged(
+ @NonNull String packageName, @NonNull RouteDiscoveryPreference preference) {
if (!TextUtils.equals(mClientPackageName, packageName)) {
return;
}
diff --git a/media/java/android/media/NearbyDevice.java b/media/java/android/media/NearbyDevice.java
index c203e7b2b88b..dbcc6b716c8f 100644
--- a/media/java/android/media/NearbyDevice.java
+++ b/media/java/android/media/NearbyDevice.java
@@ -22,9 +22,10 @@ import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
-
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.Arrays;
+import java.util.List;
/**
* A parcelable representing a nearby device that can be used for media transfer.
@@ -35,6 +36,7 @@ import java.lang.annotation.RetentionPolicy;
* <li>a range zone specifying how far away this device is from the device with the media route.
* </li>
* </ul>
+ *
* @hide
*/
@SystemApi
@@ -69,7 +71,7 @@ public final class NearbyDevice implements Parcelable {
*
* @hide
*/
- @IntDef(prefix = { "RANGE_" }, value = {
+ @IntDef(prefix = {"RANGE_"}, value = {
RANGE_UNKNOWN,
RANGE_FAR,
RANGE_LONG,
@@ -77,7 +79,8 @@ public final class NearbyDevice implements Parcelable {
RANGE_WITHIN_REACH
})
@Retention(RetentionPolicy.SOURCE)
- public @interface RangeZone {}
+ public @interface RangeZone {
+ }
/**
* Gets a human-readable string of the range zone.
@@ -102,8 +105,17 @@ public final class NearbyDevice implements Parcelable {
}
}
- @NonNull private final String mMediaRoute2Id;
- @RangeZone private final int mRangeZone;
+ /**
+ * A list stores all the range and list from far to close, used for range comparison.
+ */
+ private static final List<Integer> RANGE_WEIGHT_LIST =
+ Arrays.asList(RANGE_UNKNOWN,
+ RANGE_FAR, RANGE_LONG, RANGE_CLOSE, RANGE_WITHIN_REACH);
+
+ @NonNull
+ private final String mMediaRoute2Id;
+ @RangeZone
+ private final int mRangeZone;
/** Creates a device object with the given ID and range zone. */
public NearbyDevice(@NonNull String mediaRoute2Id, @RangeZone int rangeZone) {
@@ -129,6 +141,22 @@ public final class NearbyDevice implements Parcelable {
}
};
+ /**
+ * Compares two ranges and return result.
+ *
+ * @return 0 means two ranges are the same, -1 means first range is closer, 1 means farther
+ *
+ * @hide
+ */
+ public static int compareRangeZones(@RangeZone int rangeZone, @RangeZone int anotherRangeZone) {
+ if (rangeZone == anotherRangeZone) {
+ return 0;
+ } else {
+ return RANGE_WEIGHT_LIST.indexOf(rangeZone) > RANGE_WEIGHT_LIST.indexOf(
+ anotherRangeZone) ? -1 : 1;
+ }
+ }
+
@Override
public int describeContents() {
return 0;
diff --git a/media/java/android/media/RouteDiscoveryPreference.java b/media/java/android/media/RouteDiscoveryPreference.java
index 0ba36feb4ce9..207460af140c 100644
--- a/media/java/android/media/RouteDiscoveryPreference.java
+++ b/media/java/android/media/RouteDiscoveryPreference.java
@@ -119,6 +119,7 @@ public final class RouteDiscoveryPreference implements Parcelable {
* first in the provided list will remain.
*
* @see #shouldRemoveDuplicates()
+ * @hide
*/
@NonNull
public List<String> getDeduplicationPackageOrder() {
@@ -130,6 +131,7 @@ public final class RouteDiscoveryPreference implements Parcelable {
* <p>
* If it's not empty, it will only discover routes from the provider whose package name
* belongs to the list.
+ * @hide
*/
@NonNull
public List<String> getAllowedPackages() {
@@ -151,6 +153,7 @@ public final class RouteDiscoveryPreference implements Parcelable {
* Gets whether duplicate routes removal is enabled.
*
* @see #getDeduplicationPackageOrder()
+ * @hide
*/
public boolean shouldRemoveDuplicates() {
return !mPackageOrder.isEmpty();
@@ -293,6 +296,7 @@ public final class RouteDiscoveryPreference implements Parcelable {
* <p>
* If it's non-empty, media router only discovers route from the provider in the list.
* The default value is empty, which discovers routes from all providers.
+ * @hide
*/
@NonNull
public Builder setAllowedPackages(@NonNull List<String> allowedPackages) {
@@ -324,6 +328,7 @@ public final class RouteDiscoveryPreference implements Parcelable {
*
* @param packageOrder ordered list of package names used to remove duplicate routes, or an
* empty list if deduplication should not be enabled.
+ * @hide
*/
@NonNull
public Builder setDeduplicationPackageOrder(@NonNull List<String> packageOrder) {
diff --git a/media/java/android/media/Spatializer.java b/media/java/android/media/Spatializer.java
index be0ef37345ed..74ca4b858ff6 100644
--- a/media/java/android/media/Spatializer.java
+++ b/media/java/android/media/Spatializer.java
@@ -185,6 +185,45 @@ public class Spatializer {
return false;
}
+ /**
+ * Returns whether a head tracker is currently available for the audio device used by the
+ * spatializer effect.
+ * @return true if a head tracker is available and the effect is enabled, false otherwise.
+ * @see OnHeadTrackerAvailableListener
+ * @see #addOnHeadTrackerAvailableListener(Executor, OnHeadTrackerAvailableListener)
+ */
+ public boolean isHeadTrackerAvailable() {
+ try {
+ return mAm.getService().isHeadTrackerAvailable();
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ return false;
+ }
+
+ /**
+ * Adds a listener to be notified of changes to the availability of a head tracker.
+ * @param executor the {@code Executor} handling the callback
+ * @param listener the listener to receive availability updates
+ * @see #removeOnHeadTrackerAvailableListener(OnHeadTrackerAvailableListener)
+ */
+ public void addOnHeadTrackerAvailableListener(@NonNull @CallbackExecutor Executor executor,
+ @NonNull OnHeadTrackerAvailableListener listener) {
+ mHeadTrackerListenerMgr.addListener(executor, listener,
+ "addOnHeadTrackerAvailableListener",
+ () -> new SpatializerHeadTrackerAvailableDispatcherStub());
+ }
+
+ /**
+ * Removes a previously registered listener for the availability of a head tracker.
+ * @param listener the listener previously registered with
+ * {@link #addOnHeadTrackerAvailableListener(Executor, OnHeadTrackerAvailableListener)}
+ */
+ public void removeOnHeadTrackerAvailableListener(
+ @NonNull OnHeadTrackerAvailableListener listener) {
+ mHeadTrackerListenerMgr.removeListener(listener, "removeOnHeadTrackerAvailableListener");
+ }
+
/** @hide */
@IntDef(flag = false, value = {
SPATIALIZER_IMMERSIVE_LEVEL_OTHER,
@@ -401,6 +440,22 @@ public class Spatializer {
@HeadTrackingModeSet int mode);
}
+ /**
+ * Interface to be notified of changes to the availability of a head tracker on the audio
+ * device to be used by the spatializer effect.
+ */
+ public interface OnHeadTrackerAvailableListener {
+ /**
+ * Called when the availability of the head tracker changed.
+ * @param spatializer the {@code Spatializer} instance for which the head tracker
+ * availability was updated
+ * @param available true if the audio device that would output audio processed by
+ * the {@code Spatializer} has a head tracker associated with it, false
+ * otherwise.
+ */
+ void onHeadTrackerAvailableChanged(@NonNull Spatializer spatializer,
+ boolean available);
+ }
/**
* @hide
@@ -827,8 +882,12 @@ public class Spatializer {
/**
* @hide
- * Returns the id of the output stream used for the spatializer effect playback
+ * Returns the id of the output stream used for the spatializer effect playback.
+ * This getter or associated listener {@link OnSpatializerOutputChangedListener} can be used for
+ * handling spatializer output-specific configurations (e.g. disabling speaker post-processing
+ * to avoid double-processing of the spatialized path).
* @return id of the output stream, or 0 if no spatializer playback is active
+ * @see #setOnSpatializerOutputChangedListener(Executor, OnSpatializerOutputChangedListener)
*/
@SystemApi(client = SystemApi.Client.PRIVILEGED_APPS)
@RequiresPermission(android.Manifest.permission.MODIFY_DEFAULT_AUDIO_EFFECTS)
@@ -865,6 +924,8 @@ public class Spatializer {
mOutputDispatcher = new SpatializerOutputDispatcherStub();
try {
mAm.getService().registerSpatializerOutputCallback(mOutputDispatcher);
+ // immediately report the current output
+ mOutputDispatcher.dispatchSpatializerOutputChanged(getOutput());
} catch (RemoteException e) {
mOutputListener = null;
mOutputDispatcher = null;
@@ -935,6 +996,36 @@ public class Spatializer {
}
//-----------------------------------------------------------------------------
+ // head tracker availability callback management and stub
+ /**
+ * manages the OnHeadTrackerAvailableListener listeners and the
+ * SpatializerHeadTrackerAvailableDispatcherStub
+ */
+ private final CallbackUtil.LazyListenerManager<OnHeadTrackerAvailableListener>
+ mHeadTrackerListenerMgr = new CallbackUtil.LazyListenerManager();
+
+ private final class SpatializerHeadTrackerAvailableDispatcherStub
+ extends ISpatializerHeadTrackerAvailableCallback.Stub
+ implements CallbackUtil.DispatcherStub {
+ @Override
+ public void register(boolean register) {
+ try {
+ mAm.getService().registerSpatializerHeadTrackerAvailableCallback(this, register);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
+
+ @Override
+ @SuppressLint("GuardedBy") // lock applied inside callListeners method
+ public void dispatchSpatializerHeadTrackerAvailable(boolean available) {
+ mHeadTrackerListenerMgr.callListeners(
+ (listener) -> listener.onHeadTrackerAvailableChanged(
+ Spatializer.this, available));
+ }
+ }
+
+ //-----------------------------------------------------------------------------
// head pose callback management and stub
private final Object mPoseListenerLock = new Object();
/**
diff --git a/media/java/android/media/projection/IMediaProjection.aidl b/media/java/android/media/projection/IMediaProjection.aidl
index 19fc0521d7aa..b136d5bc4db3 100644
--- a/media/java/android/media/projection/IMediaProjection.aidl
+++ b/media/java/android/media/projection/IMediaProjection.aidl
@@ -17,6 +17,7 @@
package android.media.projection;
import android.media.projection.IMediaProjectionCallback;
+import android.window.WindowContainerToken;
/** {@hide} */
interface IMediaProjection {
@@ -28,4 +29,16 @@ interface IMediaProjection {
int applyVirtualDisplayFlags(int flags);
void registerCallback(IMediaProjectionCallback callback);
void unregisterCallback(IMediaProjectionCallback callback);
+
+ /**
+ * Returns the {@link android.window.WindowContainerToken} identifying the task to record, or
+ * {@code null} if there is none.
+ */
+ WindowContainerToken getTaskRecordingWindowContainerToken();
+
+ /**
+ * Updates the {@link android.window.WindowContainerToken} identifying the task to record, or
+ * {@code null} if there is none.
+ */
+ void setTaskRecordingWindowContainerToken(in WindowContainerToken token);
}
diff --git a/media/java/android/media/projection/MediaProjection.java b/media/java/android/media/projection/MediaProjection.java
index 4dde5e8d39a2..b5f95938f845 100644
--- a/media/java/android/media/projection/MediaProjection.java
+++ b/media/java/android/media/projection/MediaProjection.java
@@ -25,13 +25,14 @@ import android.hardware.display.DisplayManager;
import android.hardware.display.VirtualDisplay;
import android.hardware.display.VirtualDisplayConfig;
import android.os.Handler;
-import android.os.IBinder;
import android.os.RemoteException;
import android.util.ArrayMap;
import android.util.Log;
import android.view.ContentRecordingSession;
+import android.view.IWindowManager;
import android.view.Surface;
import android.view.WindowManagerGlobal;
+import android.window.WindowContainerToken;
import java.util.Map;
@@ -171,16 +172,34 @@ public final class MediaProjection {
@NonNull VirtualDisplayConfig.Builder virtualDisplayConfig,
@Nullable VirtualDisplay.Callback callback, @Nullable Handler handler) {
try {
- final Context windowContext = mContext.createWindowContext(
- mContext.getDisplayNoVerify(),
- TYPE_APPLICATION, null /* options */);
- final IBinder windowContextToken = windowContext.getWindowContextToken();
+ final IWindowManager wmService = WindowManagerGlobal.getWindowManagerService();
+ final WindowContainerToken taskWindowContainerToken =
+ mImpl.getTaskRecordingWindowContainerToken();
+ Context windowContext = null;
+ ContentRecordingSession session;
+ if (taskWindowContainerToken == null) {
+ windowContext = mContext.createWindowContext(mContext.getDisplayNoVerify(),
+ TYPE_APPLICATION, null /* options */);
+ session = ContentRecordingSession.createDisplaySession(
+ windowContext.getWindowContextToken());
+ } else {
+ session = ContentRecordingSession.createTaskSession(
+ taskWindowContainerToken.asBinder());
+ }
virtualDisplayConfig.setWindowManagerMirroring(true);
final DisplayManager dm = mContext.getSystemService(DisplayManager.class);
final VirtualDisplay virtualDisplay = dm.createVirtualDisplay(this,
- virtualDisplayConfig.build(),
- callback, handler, windowContext);
- setSession(windowContextToken, virtualDisplay);
+ virtualDisplayConfig.build(), callback, handler, windowContext);
+ if (virtualDisplay == null) {
+ // Since WM handling a new display and DM creating a new VirtualDisplay is async,
+ // WM may have tried to start task recording and encountered an error that required
+ // stopping recording entirely. The VirtualDisplay would then be null when the
+ // MediaProjection is no longer active.
+ return null;
+ }
+ session.setDisplayId(virtualDisplay.getDisplay().getDisplayId());
+ // Successfully set up, so save the current session details.
+ wmService.setContentRecordingSession(session);
return virtualDisplay;
} catch (RemoteException e) {
// Can not capture if WMS is not accessible, so bail out.
@@ -189,28 +208,6 @@ public final class MediaProjection {
}
/**
- * Updates the {@link ContentRecordingSession} describing the recording taking place on this
- * {@link VirtualDisplay}.
- *
- * @throws RemoteException if updating the session on the server failed.
- */
- private void setSession(@NonNull IBinder windowContextToken,
- @Nullable VirtualDisplay virtualDisplay)
- throws RemoteException {
- if (virtualDisplay == null) {
- // Not able to set up a new VirtualDisplay.
- return;
- }
- // Identify the VirtualDisplay that will be hosting the recording.
- ContentRecordingSession session = ContentRecordingSession.createDisplaySession(
- windowContextToken);
- session.setDisplayId(virtualDisplay.getDisplay().getDisplayId());
- // TODO(b/216625226) handle task recording.
- // Successfully set up, so save the current session details.
- WindowManagerGlobal.getWindowManagerService().setContentRecordingSession(session);
- }
-
- /**
* Stops projection.
*/
public void stop() {
diff --git a/media/java/android/media/tv/AdRequest.java b/media/java/android/media/tv/AdRequest.java
index 0542c5598c01..f2fb93d803a8 100644
--- a/media/java/android/media/tv/AdRequest.java
+++ b/media/java/android/media/tv/AdRequest.java
@@ -163,7 +163,11 @@ public final class AdRequest implements Parcelable {
/**
* Gets the metadata of the media file.
- * <p>This includes additional information the TV input needs to play the AD media.
+ *
+ * <p>This includes additional information the TV input needs to play the AD media. This may
+ * include fields in {@link android.media.MediaFormat} like
+ * {@link android.media.MediaFormat#KEY_SAMPLE_RATE}, or integrity information like SHA. What
+ * data is included depends on the format of the media file.
*
* @return The metadata of the media file. Can be an empty bundle for
* {@link #REQUEST_TYPE_STOP}.
diff --git a/media/java/android/media/tv/AitInfo.java b/media/java/android/media/tv/AitInfo.java
index 8e80a62be3de..c88a2b5048df 100644
--- a/media/java/android/media/tv/AitInfo.java
+++ b/media/java/android/media/tv/AitInfo.java
@@ -17,7 +17,7 @@
package android.media.tv;
import android.annotation.NonNull;
-import android.media.tv.interactive.TvInteractiveAppInfo;
+import android.media.tv.interactive.TvInteractiveAppServiceInfo;
import android.os.Parcel;
import android.os.Parcelable;
@@ -50,7 +50,7 @@ public final class AitInfo implements Parcelable {
/**
* Constructs AIT info.
*/
- public AitInfo(@TvInteractiveAppInfo.InteractiveAppType int type, int version) {
+ public AitInfo(@TvInteractiveAppServiceInfo.InteractiveAppType int type, int version) {
mType = type;
mVersion = version;
}
@@ -58,7 +58,7 @@ public final class AitInfo implements Parcelable {
/**
* Gets interactive app type.
*/
- @TvInteractiveAppInfo.InteractiveAppType
+ @TvInteractiveAppServiceInfo.InteractiveAppType
public int getType() {
return mType;
}
diff --git a/media/java/android/media/tv/CommandRequest.java b/media/java/android/media/tv/CommandRequest.java
index ffb6e07bc485..3245fb504f85 100644
--- a/media/java/android/media/tv/CommandRequest.java
+++ b/media/java/android/media/tv/CommandRequest.java
@@ -24,6 +24,8 @@ import android.os.Parcelable;
* A request for command from broadcast signal.
*/
public final class CommandRequest extends BroadcastInfoRequest implements Parcelable {
+ public static final String ARGUMENT_TYPE_XML = "xml";
+ public static final String ARGUMENT_TYPE_JSON = "json";
private static final @TvInputManager.BroadcastInfoType int REQUEST_TYPE =
TvInputManager.BROADCAST_INFO_TYPE_COMMAND;
@@ -41,35 +43,38 @@ public final class CommandRequest extends BroadcastInfoRequest implements Parcel
}
};
- private final String mNameSpace;
+ private final String mNamespace;
private final String mName;
private final String mArguments;
+ private final String mArgumentType;
static CommandRequest createFromParcelBody(Parcel in) {
return new CommandRequest(in);
}
- public CommandRequest(int requestId, @RequestOption int option, @NonNull String nameSpace,
- @NonNull String name, @NonNull String arguments) {
+ public CommandRequest(int requestId, @RequestOption int option, @NonNull String namespace,
+ @NonNull String name, @NonNull String arguments, @NonNull String argumentType) {
super(REQUEST_TYPE, requestId, option);
- mNameSpace = nameSpace;
+ mNamespace = namespace;
mName = name;
mArguments = arguments;
+ mArgumentType = argumentType;
}
CommandRequest(Parcel source) {
super(REQUEST_TYPE, source);
- mNameSpace = source.readString();
+ mNamespace = source.readString();
mName = source.readString();
mArguments = source.readString();
+ mArgumentType = source.readString();
}
/**
* Gets the namespace of the command.
*/
@NonNull
- public String getNameSpace() {
- return mNameSpace;
+ public String getNamespace() {
+ return mNamespace;
}
/**
@@ -89,6 +94,15 @@ public final class CommandRequest extends BroadcastInfoRequest implements Parcel
return mArguments;
}
+ /**
+ * Gets the argument type of the command.
+ * It could be either JSON or XML.
+ */
+ @NonNull
+ public String getArgumentType() {
+ return mArgumentType;
+ }
+
@Override
public int describeContents() {
return 0;
@@ -97,8 +111,9 @@ public final class CommandRequest extends BroadcastInfoRequest implements Parcel
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
super.writeToParcel(dest, flags);
- dest.writeString(mNameSpace);
+ dest.writeString(mNamespace);
dest.writeString(mName);
dest.writeString(mArguments);
+ dest.writeString(mArgumentType);
}
}
diff --git a/media/java/android/media/tv/CommandResponse.java b/media/java/android/media/tv/CommandResponse.java
index c8853f1d8373..8e448cdbd707 100644
--- a/media/java/android/media/tv/CommandResponse.java
+++ b/media/java/android/media/tv/CommandResponse.java
@@ -25,6 +25,8 @@ import android.os.Parcelable;
* A response for command from broadcast signal.
*/
public final class CommandResponse extends BroadcastInfoResponse implements Parcelable {
+ public static final String RESPONSE_TYPE_XML = "xml";
+ public static final String RESPONSE_TYPE_JSON = "json";
private static final @TvInputManager.BroadcastInfoType int RESPONSE_TYPE =
TvInputManager.BROADCAST_INFO_TYPE_COMMAND;
@@ -43,20 +45,23 @@ public final class CommandResponse extends BroadcastInfoResponse implements Parc
};
private final String mResponse;
+ private final String mResponseType;
static CommandResponse createFromParcelBody(Parcel in) {
return new CommandResponse(in);
}
- public CommandResponse(int requestId, int sequence,
- @ResponseResult int responseResult, @Nullable String response) {
+ public CommandResponse(int requestId, int sequence, @ResponseResult int responseResult,
+ @Nullable String response, @NonNull String responseType) {
super(RESPONSE_TYPE, requestId, sequence, responseResult);
mResponse = response;
+ mResponseType = responseType;
}
CommandResponse(Parcel source) {
super(RESPONSE_TYPE, source);
mResponse = source.readString();
+ mResponseType = source.readString();
}
/**
@@ -68,6 +73,15 @@ public final class CommandResponse extends BroadcastInfoResponse implements Parc
return mResponse;
}
+ /**
+ * Gets the type of the command response.
+ * It could be either JSON or XML.
+ */
+ @NonNull
+ public String getResponseType() {
+ return mResponseType;
+ }
+
@Override
public int describeContents() {
return 0;
@@ -77,5 +91,6 @@ public final class CommandResponse extends BroadcastInfoResponse implements Parc
public void writeToParcel(@NonNull Parcel dest, int flags) {
super.writeToParcel(dest, flags);
dest.writeString(mResponse);
+ dest.writeString(mResponseType);
}
}
diff --git a/media/java/android/media/tv/SectionRequest.java b/media/java/android/media/tv/SectionRequest.java
index 5957528554dc..078e83222e4e 100644
--- a/media/java/android/media/tv/SectionRequest.java
+++ b/media/java/android/media/tv/SectionRequest.java
@@ -80,6 +80,11 @@ public final class SectionRequest extends BroadcastInfoRequest implements Parcel
/**
* Gets the version number of requested session. If it is null, value will be -1.
+ * <p>The consistency of version numbers between request and response depends on
+ * {@link BroadcastInfoRequest.RequestOption}. If the request has RequestOption value
+ * REQUEST_OPTION_AUTO_UPDATE, then the response may be set to the latest version which may be
+ * different from the version of the request. Otherwise, response with a different version from
+ * its request will be considered invalid.
*/
public int getVersion() {
return mVersion;
diff --git a/media/java/android/media/tv/SectionResponse.java b/media/java/android/media/tv/SectionResponse.java
index 35836bed385f..f38ea9dfac99 100644
--- a/media/java/android/media/tv/SectionResponse.java
+++ b/media/java/android/media/tv/SectionResponse.java
@@ -74,14 +74,20 @@ public final class SectionResponse extends BroadcastInfoResponse implements Parc
}
/**
- * Gets the Version number of requested session.
+ * Gets the Version number of requested session. If it is null, value will be -1.
+ * <p>The consistency of version numbers between request and response depends on
+ * {@link BroadcastInfoRequest.RequestOption}. If the request has RequestOption value
+ * REQUEST_OPTION_AUTO_UPDATE, then the response may be set to the latest version which may be
+ * different from the version of the request. Otherwise, response with a different version from
+ * its request will be considered invalid.
*/
public int getVersion() {
return mVersion;
}
/**
- * Gets the raw data of session.
+ * Gets the raw data of session. The sessionData field represents payload data of the session
+ * after session header, which includes version and sessionId.
*/
@NonNull
public Bundle getSessionData() {
diff --git a/media/java/android/media/tv/StreamEventResponse.java b/media/java/android/media/tv/StreamEventResponse.java
index f952ce929842..28dff374d539 100644
--- a/media/java/android/media/tv/StreamEventResponse.java
+++ b/media/java/android/media/tv/StreamEventResponse.java
@@ -43,7 +43,7 @@ public final class StreamEventResponse extends BroadcastInfoResponse implements
};
private final int mEventId;
- private final long mNpt;
+ private final long mNptMillis;
private final byte[] mData;
static StreamEventResponse createFromParcelBody(Parcel in) {
@@ -51,17 +51,17 @@ public final class StreamEventResponse extends BroadcastInfoResponse implements
}
public StreamEventResponse(int requestId, int sequence, @ResponseResult int responseResult,
- int eventId, long npt, @Nullable byte[] data) {
+ int eventId, long nptMillis, @Nullable byte[] data) {
super(RESPONSE_TYPE, requestId, sequence, responseResult);
mEventId = eventId;
- mNpt = npt;
+ mNptMillis = nptMillis;
mData = data;
}
private StreamEventResponse(@NonNull Parcel source) {
super(RESPONSE_TYPE, source);
mEventId = source.readInt();
- mNpt = source.readLong();
+ mNptMillis = source.readLong();
int dataLength = source.readInt();
mData = new byte[dataLength];
source.readByteArray(mData);
@@ -76,9 +76,10 @@ public final class StreamEventResponse extends BroadcastInfoResponse implements
/**
* Returns the NPT(Normal Play Time) value when the event occurred or will occur.
+ * <p>The time unit of NPT is millisecond.
*/
- public long getNpt() {
- return mNpt;
+ public long getNptMillis() {
+ return mNptMillis;
}
/**
@@ -98,7 +99,7 @@ public final class StreamEventResponse extends BroadcastInfoResponse implements
public void writeToParcel(@NonNull Parcel dest, int flags) {
super.writeToParcel(dest, flags);
dest.writeInt(mEventId);
- dest.writeLong(mNpt);
+ dest.writeLong(mNptMillis);
dest.writeInt(mData.length);
dest.writeByteArray(mData);
}
diff --git a/media/java/android/media/tv/TableRequest.java b/media/java/android/media/tv/TableRequest.java
index 37df4eaf1ed0..a1a6b516859c 100644
--- a/media/java/android/media/tv/TableRequest.java
+++ b/media/java/android/media/tv/TableRequest.java
@@ -91,7 +91,12 @@ public final class TableRequest extends BroadcastInfoRequest implements Parcelab
}
/**
- * Gets the version number of requested table.
+ * Gets the version number of requested table. If it is null, value will be -1.
+ * <p>The consistency of version numbers between request and response depends on
+ * {@link BroadcastInfoRequest.RequestOption}. If the request has RequestOption value
+ * REQUEST_OPTION_AUTO_UPDATE, then the response may be set to the latest version which may be
+ * different from the version of the request. Otherwise, response with a different version from
+ * its request will be considered invalid.
*/
public int getVersion() {
return mVersion;
diff --git a/media/java/android/media/tv/TableResponse.java b/media/java/android/media/tv/TableResponse.java
index e9f1136875f5..afc9bee5fb85 100644
--- a/media/java/android/media/tv/TableResponse.java
+++ b/media/java/android/media/tv/TableResponse.java
@@ -76,7 +76,12 @@ public final class TableResponse extends BroadcastInfoResponse implements Parcel
}
/**
- * Gets the Version number of table.
+ * Gets the version number of requested table. If it is null, value will be -1.
+ * <p>The consistency of version numbers between request and response depends on
+ * {@link BroadcastInfoRequest.RequestOption}. If the request has RequestOption value
+ * REQUEST_OPTION_AUTO_UPDATE, then the response may be set to the latest version which may be
+ * different from the version of the request. Otherwise, response with a different version from
+ * its request will be considered invalid.
*/
public int getVersion() {
return mVersion;
diff --git a/media/java/android/media/tv/TimelineResponse.java b/media/java/android/media/tv/TimelineResponse.java
index fbeb0c4bf268..7de30f579a35 100644
--- a/media/java/android/media/tv/TimelineResponse.java
+++ b/media/java/android/media/tv/TimelineResponse.java
@@ -18,6 +18,7 @@ package android.media.tv;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.net.Uri;
import android.os.Parcel;
import android.os.Parcelable;
@@ -79,8 +80,8 @@ public final class TimelineResponse extends BroadcastInfoResponse implements Par
* that conveys Time Values on it.
*/
@Nullable
- public String getSelector() {
- return mSelector;
+ public Uri getSelector() {
+ return Uri.parse(mSelector);
}
/**
diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java
index 69fe5ee49872..149c2f471a4c 100644
--- a/media/java/android/media/tv/TvInputManager.java
+++ b/media/java/android/media/tv/TvInputManager.java
@@ -680,7 +680,7 @@ public final class TvInputManager {
* @param session A {@link TvInputManager.Session} associated with this callback.
* @param strength The current signal strength.
*/
- public void onSignalStrength(Session session, @SignalStrength int strength) {
+ public void onSignalStrengthUpdated(Session session, @SignalStrength int strength) {
}
/**
@@ -898,7 +898,7 @@ public final class TvInputManager {
mHandler.post(new Runnable() {
@Override
public void run() {
- mSessionCallback.onSignalStrength(mSession, strength);
+ mSessionCallback.onSignalStrengthUpdated(mSession, strength);
if (mSession.mIAppNotificationEnabled
&& mSession.getInteractiveAppSession() != null) {
mSession.getInteractiveAppSession().notifySignalStrength(strength);
diff --git a/media/java/android/media/tv/TvView.java b/media/java/android/media/tv/TvView.java
index 4d63af7be474..ff3d06c5bd69 100644
--- a/media/java/android/media/tv/TvView.java
+++ b/media/java/android/media/tv/TvView.java
@@ -1083,7 +1083,7 @@ public class TvView extends ViewGroup {
* @param inputId The ID of the TV input bound to this view.
* @param strength The current signal strength.
*/
- public void onSignalStrength(
+ public void onSignalStrengthUpdated(
@NonNull String inputId, @TvInputManager.SignalStrength int strength) {
}
@@ -1406,16 +1406,16 @@ public class TvView extends ViewGroup {
}
@Override
- public void onSignalStrength(Session session, int strength) {
+ public void onSignalStrengthUpdated(Session session, int strength) {
if (DEBUG) {
- Log.d(TAG, "onSignalStrength(strength=" + strength + ")");
+ Log.d(TAG, "onSignalStrengthUpdated(strength=" + strength + ")");
}
if (this != mSessionCallback) {
- Log.w(TAG, "onSignalStrength - session not created");
+ Log.w(TAG, "onSignalStrengthUpdated - session not created");
return;
}
if (mCallback != null) {
- mCallback.onSignalStrength(mInputId, strength);
+ mCallback.onSignalStrengthUpdated(mInputId, strength);
}
}
diff --git a/media/java/android/media/tv/interactive/AppLinkInfo.aidl b/media/java/android/media/tv/interactive/AppLinkInfo.aidl
index 6759fc499e1c..f551c9fcf6c7 100644
--- a/media/java/android/media/tv/interactive/AppLinkInfo.aidl
+++ b/media/java/android/media/tv/interactive/AppLinkInfo.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/media/java/android/media/tv/interactive/AppLinkInfo.java b/media/java/android/media/tv/interactive/AppLinkInfo.java
index cd201f79ed41..d5e995cbcfab 100644
--- a/media/java/android/media/tv/interactive/AppLinkInfo.java
+++ b/media/java/android/media/tv/interactive/AppLinkInfo.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,7 +17,8 @@
package android.media.tv.interactive;
import android.annotation.NonNull;
-import android.annotation.Nullable;
+import android.content.ComponentName;
+import android.net.Uri;
import android.os.Parcel;
import android.os.Parcelable;
@@ -25,91 +26,58 @@ import android.os.Parcelable;
* App link information used by TV interactive app to launch Android apps.
*/
public final class AppLinkInfo implements Parcelable {
- private @NonNull String mPackageName;
- private @NonNull String mClassName;
- private @Nullable String mUriScheme;
- private @Nullable String mUriHost;
- private @Nullable String mUriPrefix;
-
+ private @NonNull ComponentName mComponentName;
+ private @NonNull Uri mUri;
/**
* Creates a new AppLinkInfo.
+ *
+ * @param packageName Package Name of AppLinkInfo.
+ * @param className Class Name of AppLinkInfo.
+ * @param uriString Uri of AppLinkInfo.
*/
- private AppLinkInfo(
+ public AppLinkInfo(
@NonNull String packageName,
@NonNull String className,
- @Nullable String uriScheme,
- @Nullable String uriHost,
- @Nullable String uriPrefix) {
- this.mPackageName = packageName;
+ @NonNull String uriString) {
com.android.internal.util.AnnotationValidations.validate(
- NonNull.class, null, mPackageName);
- this.mClassName = className;
+ NonNull.class, null, packageName);
com.android.internal.util.AnnotationValidations.validate(
- NonNull.class, null, mClassName);
- this.mUriScheme = uriScheme;
- this.mUriHost = uriHost;
- this.mUriPrefix = uriPrefix;
+ NonNull.class, null, className);
+ this.mComponentName = new ComponentName(packageName, className);
+ this.mUri = Uri.parse(uriString);
}
/**
- * Gets package name of the App link.
+ * Gets component name of the App link, which contains package name and class name.
*/
@NonNull
- public String getPackageName() {
- return mPackageName;
+ public ComponentName getComponentName() {
+ return mComponentName;
}
/**
- * Gets package class of the App link.
+ * Gets URI of the App link.
*/
@NonNull
- public String getClassName() {
- return mClassName;
- }
-
- /**
- * Gets URI scheme of the App link.
- */
- @Nullable
- public String getUriScheme() {
- return mUriScheme;
- }
-
- /**
- * Gets URI host of the App link.
- */
- @Nullable
- public String getUriHost() {
- return mUriHost;
- }
-
- /**
- * Gets URI prefix of the App link.
- */
- @Nullable
- public String getUriPrefix() {
- return mUriPrefix;
+ public Uri getUri() {
+ return mUri;
}
@Override
public String toString() {
return "AppLinkInfo { "
- + "packageName = " + mPackageName + ", "
- + "className = " + mClassName + ", "
- + "uriScheme = " + mUriScheme + ", "
- + "uriHost = " + mUriHost + ", "
- + "uriPrefix = " + mUriPrefix
+ + "packageName = " + mComponentName.getPackageName() + ", "
+ + "className = " + mComponentName.getClassName() + ", "
+ + "uri = " + mUri.toString()
+ " }";
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
- dest.writeString(mPackageName);
- dest.writeString(mClassName);
- dest.writeString(mUriScheme);
- dest.writeString(mUriHost);
- dest.writeString(mUriPrefix);
+ mComponentName.writeToParcel(dest, flags);
+ String uriString = mUri == null ? null : mUri.toString();
+ dest.writeString(uriString);
}
@Override
@@ -118,21 +86,13 @@ public final class AppLinkInfo implements Parcelable {
}
/* package-private */ AppLinkInfo(@NonNull Parcel in) {
- String packageName = in.readString();
- String className = in.readString();
- String uriScheme = in.readString();
- String uriHost = in.readString();
- String uriPrefix = in.readString();
-
- this.mPackageName = packageName;
+ mComponentName = ComponentName.readFromParcel(in);
com.android.internal.util.AnnotationValidations.validate(
- NonNull.class, null, mPackageName);
- this.mClassName = className;
+ NonNull.class, null, mComponentName.getPackageName());
com.android.internal.util.AnnotationValidations.validate(
- NonNull.class, null, mClassName);
- this.mUriScheme = uriScheme;
- this.mUriHost = uriHost;
- this.mUriPrefix = uriPrefix;
+ NonNull.class, null, mComponentName.getClassName());
+ String uriString = in.readString();
+ mUri = uriString == null ? null : Uri.parse(uriString);
}
@NonNull
@@ -148,86 +108,4 @@ public final class AppLinkInfo implements Parcelable {
return new AppLinkInfo(in);
}
};
-
- /**
- * A builder for {@link AppLinkInfo}
- */
- public static final class Builder {
- private @NonNull String mPackageName;
- private @NonNull String mClassName;
- private @Nullable String mUriScheme;
- private @Nullable String mUriHost;
- private @Nullable String mUriPrefix;
-
- /**
- * Creates a new Builder.
- */
- public Builder(
- @NonNull String packageName,
- @NonNull String className) {
- mPackageName = packageName;
- com.android.internal.util.AnnotationValidations.validate(
- NonNull.class, null, mPackageName);
- mClassName = className;
- com.android.internal.util.AnnotationValidations.validate(
- NonNull.class, null, mClassName);
- }
-
- /**
- * Sets package name of the App link.
- */
- @NonNull
- public Builder setPackageName(@NonNull String value) {
- mPackageName = value;
- return this;
- }
-
- /**
- * Sets app name of the App link.
- */
- @NonNull
- public Builder setClassName(@NonNull String value) {
- mClassName = value;
- return this;
- }
-
- /**
- * Sets URI scheme of the App link.
- */
- @NonNull
- public Builder setUriScheme(@Nullable String value) {
- mUriScheme = value;
- return this;
- }
-
- /**
- * Sets URI host of the App link.
- */
- @NonNull
- public Builder setUriHost(@Nullable String value) {
- mUriHost = value;
- return this;
- }
-
- /**
- * Sets URI prefix of the App link.
- */
- @NonNull
- public Builder setUriPrefix(@Nullable String value) {
- mUriPrefix = value;
- return this;
- }
-
- /** Builds the instance. This builder should not be touched after calling this! */
- @NonNull
- public AppLinkInfo build() {
- AppLinkInfo o = new AppLinkInfo(
- mPackageName,
- mClassName,
- mUriScheme,
- mUriHost,
- mUriPrefix);
- return o;
- }
- }
}
diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppClient.aidl b/media/java/android/media/tv/interactive/ITvInteractiveAppClient.aidl
index a3e58d16f655..50aa6febacf7 100644
--- a/media/java/android/media/tv/interactive/ITvInteractiveAppClient.aidl
+++ b/media/java/android/media/tv/interactive/ITvInteractiveAppClient.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -44,5 +44,7 @@ oneway interface ITvInteractiveAppClient {
void onRequestStreamVolume(int seq);
void onRequestTrackInfoList(int seq);
void onRequestCurrentTvInputId(int seq);
+ void onRequestSigning(
+ in String id, in String algorithm, in String alias, in byte[] data, int seq);
void onAdRequest(in AdRequest request, int Seq);
}
diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppManager.aidl b/media/java/android/media/tv/interactive/ITvInteractiveAppManager.aidl
index aaabe342d9f1..9ff564ea3737 100644
--- a/media/java/android/media/tv/interactive/ITvInteractiveAppManager.aidl
+++ b/media/java/android/media/tv/interactive/ITvInteractiveAppManager.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -23,7 +23,7 @@ import android.media.tv.TvTrackInfo;
import android.media.tv.interactive.AppLinkInfo;
import android.media.tv.interactive.ITvInteractiveAppClient;
import android.media.tv.interactive.ITvInteractiveAppManagerCallback;
-import android.media.tv.interactive.TvInteractiveAppInfo;
+import android.media.tv.interactive.TvInteractiveAppServiceInfo;
import android.net.Uri;
import android.os.Bundle;
import android.view.Surface;
@@ -33,8 +33,7 @@ import android.view.Surface;
* @hide
*/
interface ITvInteractiveAppManager {
- List<TvInteractiveAppInfo> getTvInteractiveAppServiceList(int userId);
- void prepare(String tiasId, int type, int userId);
+ List<TvInteractiveAppServiceInfo> getTvInteractiveAppServiceList(int userId);
void registerAppLinkInfo(String tiasId, in AppLinkInfo info, int userId);
void unregisterAppLinkInfo(String tiasId, in AppLinkInfo info, int userId);
void sendAppLinkCommand(String tiasId, in Bundle command, int userId);
@@ -50,6 +49,8 @@ interface ITvInteractiveAppManager {
void sendStreamVolume(in IBinder sessionToken, float volume, int userId);
void sendTrackInfoList(in IBinder sessionToken, in List<TvTrackInfo> tracks, int userId);
void sendCurrentTvInputId(in IBinder sessionToken, in String inputId, int userId);
+ void sendSigningResult(in IBinder sessionToken, in String signingId, in byte[] result,
+ int userId);
void createSession(in ITvInteractiveAppClient client, in String iAppServiceId, int type,
int seq, int userId);
void releaseSession(in IBinder sessionToken, int userId);
diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppManagerCallback.aidl b/media/java/android/media/tv/interactive/ITvInteractiveAppManagerCallback.aidl
index 23be4c64fcc4..fed86dc9e0a8 100644
--- a/media/java/android/media/tv/interactive/ITvInteractiveAppManagerCallback.aidl
+++ b/media/java/android/media/tv/interactive/ITvInteractiveAppManagerCallback.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,7 +16,7 @@
package android.media.tv.interactive;
-import android.media.tv.interactive.TvInteractiveAppInfo;
+import android.media.tv.interactive.TvInteractiveAppServiceInfo;
/**
* Interface to receive callbacks from ITvInteractiveAppManager regardless of sessions.
@@ -26,6 +26,6 @@ interface ITvInteractiveAppManagerCallback {
void onInteractiveAppServiceAdded(in String iAppServiceId);
void onInteractiveAppServiceRemoved(in String iAppServiceId);
void onInteractiveAppServiceUpdated(in String iAppServiceId);
- void onTvInteractiveAppInfoUpdated(in TvInteractiveAppInfo tvIAppInfo);
+ void onTvInteractiveAppServiceInfoUpdated(in TvInteractiveAppServiceInfo tvIAppInfo);
void onStateChanged(in String iAppServiceId, int type, int state, int err);
} \ No newline at end of file
diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppService.aidl b/media/java/android/media/tv/interactive/ITvInteractiveAppService.aidl
index b6d518ff7242..fb58ca7843ef 100644
--- a/media/java/android/media/tv/interactive/ITvInteractiveAppService.aidl
+++ b/media/java/android/media/tv/interactive/ITvInteractiveAppService.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -32,7 +32,6 @@ oneway interface ITvInteractiveAppService {
void unregisterCallback(in ITvInteractiveAppServiceCallback callback);
void createSession(in InputChannel channel, in ITvInteractiveAppSessionCallback callback,
in String iAppServiceId, int type);
- void prepare(int type);
void registerAppLinkInfo(in AppLinkInfo info);
void unregisterAppLinkInfo(in AppLinkInfo info);
void sendAppLinkCommand(in Bundle command);
diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppServiceCallback.aidl b/media/java/android/media/tv/interactive/ITvInteractiveAppServiceCallback.aidl
index 970b94327572..87b3c1df6197 100644
--- a/media/java/android/media/tv/interactive/ITvInteractiveAppServiceCallback.aidl
+++ b/media/java/android/media/tv/interactive/ITvInteractiveAppServiceCallback.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppSession.aidl b/media/java/android/media/tv/interactive/ITvInteractiveAppSession.aidl
index c449d2475428..e14b2bb18ea6 100644
--- a/media/java/android/media/tv/interactive/ITvInteractiveAppSession.aidl
+++ b/media/java/android/media/tv/interactive/ITvInteractiveAppSession.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -42,6 +42,7 @@ oneway interface ITvInteractiveAppSession {
void sendStreamVolume(float volume);
void sendTrackInfoList(in List<TvTrackInfo> tracks);
void sendCurrentTvInputId(in String inputId);
+ void sendSigningResult(in String signingId, in byte[] result);
void release();
void notifyTuned(in Uri channelUri);
void notifyTrackSelected(int type, in String trackId);
diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppSessionCallback.aidl b/media/java/android/media/tv/interactive/ITvInteractiveAppSessionCallback.aidl
index 385f0d4f766a..32b08b7042fe 100644
--- a/media/java/android/media/tv/interactive/ITvInteractiveAppSessionCallback.aidl
+++ b/media/java/android/media/tv/interactive/ITvInteractiveAppSessionCallback.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -43,5 +43,6 @@ oneway interface ITvInteractiveAppSessionCallback {
void onRequestStreamVolume();
void onRequestTrackInfoList();
void onRequestCurrentTvInputId();
+ void onRequestSigning(in String id, in String algorithm, in String alias, in byte[] data);
void onAdRequest(in AdRequest request);
}
diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppManager.java b/media/java/android/media/tv/interactive/TvInteractiveAppManager.java
index f75aa56813ab..d3cbcdc9a255 100755
--- a/media/java/android/media/tv/interactive/TvInteractiveAppManager.java
+++ b/media/java/android/media/tv/interactive/TvInteractiveAppManager.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -28,7 +28,6 @@ import android.media.tv.AdResponse;
import android.media.tv.BroadcastInfoRequest;
import android.media.tv.BroadcastInfoResponse;
import android.media.tv.TvContentRating;
-import android.media.tv.TvInputInfo;
import android.media.tv.TvInputManager;
import android.media.tv.TvTrackInfo;
import android.net.Uri;
@@ -249,7 +248,7 @@ public final class TvInteractiveAppManager {
*
* @see #sendAppLinkCommand(String, Bundle)
* @see #ACTION_APP_LINK_COMMAND
- * @see android.media.tv.interactive.TvInteractiveAppInfo#getId()
+ * @see TvInteractiveAppServiceInfo#getId()
*/
public static final String INTENT_KEY_INTERACTIVE_APP_SERVICE_ID = "interactive_app_id";
@@ -269,7 +268,7 @@ public final class TvInteractiveAppManager {
*
* @see #sendAppLinkCommand(String, Bundle)
* @see #ACTION_APP_LINK_COMMAND
- * @see android.media.tv.interactive.TvInteractiveAppInfo#getSupportedTypes()
+ * @see android.media.tv.interactive.TvInteractiveAppServiceInfo#getSupportedTypes()
* @see android.media.tv.interactive.TvInteractiveAppView#createBiInteractiveApp(Uri, Bundle)
*/
public static final String INTENT_KEY_BI_INTERACTIVE_APP_TYPE = "bi_interactive_app_type";
@@ -285,6 +284,16 @@ public final class TvInteractiveAppManager {
*/
public static final String INTENT_KEY_BI_INTERACTIVE_APP_URI = "bi_interactive_app_uri";
+ /**
+ * Intent key for command type. It's used to send app command to TV app. The value of this key
+ * could vary according to TV apps.
+ * <p>Type: String
+ *
+ * @see #sendAppLinkCommand(String, Bundle)
+ * @see #ACTION_APP_LINK_COMMAND
+ */
+ public static final String INTENT_KEY_COMMAND_TYPE = "command_type";
+
private final ITvInteractiveAppManager mService;
private final int mUserId;
@@ -478,6 +487,19 @@ public final class TvInteractiveAppManager {
}
@Override
+ public void onRequestSigning(
+ String id, String algorithm, String alias, byte[] data, int seq) {
+ synchronized (mSessionCallbackRecordMap) {
+ SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
+ if (record == null) {
+ Log.e(TAG, "Callback not found for seq " + seq);
+ return;
+ }
+ record.postRequestSigning(id, algorithm, alias, data);
+ }
+ }
+
+ @Override
public void onSessionStateChanged(int state, int err, int seq) {
synchronized (mSessionCallbackRecordMap) {
SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
@@ -543,11 +565,11 @@ public final class TvInteractiveAppManager {
}
@Override
- public void onTvInteractiveAppInfoUpdated(TvInteractiveAppInfo iAppInfo) {
+ public void onTvInteractiveAppServiceInfoUpdated(TvInteractiveAppServiceInfo iAppInfo) {
// TODO: add public API updateInteractiveAppInfo()
synchronized (mLock) {
for (TvInteractiveAppCallbackRecord record : mCallbackRecords) {
- record.postTvInteractiveAppInfoUpdated(iAppInfo);
+ record.postTvInteractiveAppServiceInfoUpdated(iAppInfo);
}
}
}
@@ -611,21 +633,23 @@ public final class TvInteractiveAppManager {
* This is called when the information about an existing TV Interactive App service has been
* updated.
*
- * <p>Because the system automatically creates a <code>TvInteractiveAppInfo</code> object
- * for each TV Interactive App service based on the information collected from the
+ * <p>Because the system automatically creates a <code>TvInteractiveAppServiceInfo</code>
+ * object for each TV Interactive App service based on the information collected from the
* <code>AndroidManifest.xml</code>, this method is only called back when such information
* has changed dynamically.
*
- * @param iAppInfo The <code>TvInteractiveAppInfo</code> object that contains new
+ * @param iAppInfo The <code>TvInteractiveAppServiceInfo</code> object that contains new
* information.
* @hide
*/
- public void onTvInteractiveAppInfoUpdated(@NonNull TvInteractiveAppInfo iAppInfo) {
+ public void onTvInteractiveAppServiceInfoUpdated(
+ @NonNull TvInteractiveAppServiceInfo iAppInfo) {
}
/**
* This is called when the state of the interactive app service is changed.
*
+ * @param iAppServiceId The ID of the TV Interactive App service.
* @param type the interactive app type
* @param state the current state of the service of the given type
* @param err the error code for error state. {@link #ERROR_NONE} is used when the state is
@@ -633,7 +657,7 @@ public final class TvInteractiveAppManager {
*/
public void onTvInteractiveAppServiceStateChanged(
@NonNull String iAppServiceId,
- @TvInteractiveAppInfo.InteractiveAppType int type,
+ @TvInteractiveAppServiceInfo.InteractiveAppType int type,
@ServiceState int state,
@ErrorCode int err) {
}
@@ -679,11 +703,12 @@ public final class TvInteractiveAppManager {
});
}
- public void postTvInteractiveAppInfoUpdated(final TvInteractiveAppInfo iAppInfo) {
+ public void postTvInteractiveAppServiceInfoUpdated(
+ final TvInteractiveAppServiceInfo iAppInfo) {
mExecutor.execute(new Runnable() {
@Override
public void run() {
- mCallback.onTvInteractiveAppInfoUpdated(iAppInfo);
+ mCallback.onTvInteractiveAppServiceInfoUpdated(iAppInfo);
}
});
}
@@ -736,11 +761,11 @@ public final class TvInteractiveAppManager {
/**
* Returns the complete list of TV Interactive App service on the system.
*
- * @return List of {@link TvInteractiveAppInfo} for each TV Interactive App service that
+ * @return List of {@link TvInteractiveAppServiceInfo} for each TV Interactive App service that
* describes its meta information.
*/
@NonNull
- public List<TvInteractiveAppInfo> getTvInteractiveAppServiceList() {
+ public List<TvInteractiveAppServiceInfo> getTvInteractiveAppServiceList() {
try {
return mService.getTvInteractiveAppServiceList(mUserId);
} catch (RemoteException e) {
@@ -749,18 +774,12 @@ public final class TvInteractiveAppManager {
}
/**
- * Prepares TV Interactive App service environment for the given type.
- */
- public void prepare(@NonNull String tvIAppServiceId, int type) {
- try {
- mService.prepare(tvIAppServiceId, type, mUserId);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Registers app link info.
+ * Registers an Android application link info record which can be used to launch the specific
+ * Android application by TV interactive App RTE.
+ *
+ * @param tvIAppServiceId The ID of TV interactive service which the command to be sent to. The
+ * ID can be found in {@link TvInteractiveAppServiceInfo#getId()}.
+ * @param appLinkInfo The Android application link info record to be registered.
*/
public void registerAppLinkInfo(
@NonNull String tvIAppServiceId, @NonNull AppLinkInfo appLinkInfo) {
@@ -772,7 +791,12 @@ public final class TvInteractiveAppManager {
}
/**
- * Unregisters app link info.
+ * Unregisters an Android application link info record which can be used to launch the specific
+ * Android application by TV interactive App RTE.
+ *
+ * @param tvIAppServiceId The ID of TV interactive service which the command to be sent to. The
+ * ID can be found in {@link TvInteractiveAppServiceInfo#getId()}.
+ * @param appLinkInfo The Android application link info record to be unregistered.
*/
public void unregisterAppLinkInfo(
@NonNull String tvIAppServiceId, @NonNull AppLinkInfo appLinkInfo) {
@@ -787,7 +811,7 @@ public final class TvInteractiveAppManager {
* Sends app link command.
*
* @param tvIAppServiceId The ID of TV interactive service which the command to be sent to. The
- * ID can be found in {@link TvInputInfo#getId()}.
+ * ID can be found in {@link TvInteractiveAppServiceInfo#getId()}.
* @param command The command to be sent.
*/
public void sendAppLinkCommand(@NonNull String tvIAppServiceId, @NonNull Bundle command) {
@@ -805,8 +829,8 @@ public final class TvInteractiveAppManager {
* @param executor A {@link Executor} that the status change will be delivered to.
*/
public void registerCallback(
- @NonNull TvInteractiveAppCallback callback,
- @CallbackExecutor @NonNull Executor executor) {
+ @CallbackExecutor @NonNull Executor executor,
+ @NonNull TvInteractiveAppCallback callback) {
Preconditions.checkNotNull(callback);
Preconditions.checkNotNull(executor);
synchronized (mLock) {
@@ -1011,6 +1035,18 @@ public final class TvInteractiveAppManager {
}
}
+ void sendSigningResult(@NonNull String signingId, @NonNull byte[] result) {
+ if (mToken == null) {
+ Log.w(TAG, "The session has been already released");
+ return;
+ }
+ try {
+ mService.sendSigningResult(mToken, signingId, result, mUserId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
/**
* Sets the {@link android.view.Surface} for this session.
*
@@ -1644,6 +1680,15 @@ public final class TvInteractiveAppManager {
});
}
+ void postRequestSigning(String id, String algorithm, String alias, byte[] data) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mSessionCallback.onRequestSigning(mSession, id, algorithm, alias, data);
+ }
+ });
+ }
+
void postAdRequest(final AdRequest request) {
mHandler.post(new Runnable() {
@Override
@@ -1781,12 +1826,27 @@ public final class TvInteractiveAppManager {
* called.
*
* @param session A {@link TvInteractiveAppService.Session} associated with this callback.
- * @hide
*/
public void onRequestCurrentTvInputId(Session session) {
}
/**
+ * This is called when
+ * {@link TvInteractiveAppService.Session#requestSigning(String, String, String, byte[])} is
+ * called.
+ *
+ * @param session A {@link TvInteractiveAppService.Session} associated with this callback.
+ * @param signingId the ID to identify the request.
+ * @param algorithm the standard name of the signature algorithm requested, such as
+ * MD5withRSA, SHA256withDSA, etc.
+ * @param alias the alias of the corresponding {@link java.security.KeyStore}.
+ * @param data the original bytes to be signed.
+ */
+ public void onRequestSigning(
+ Session session, String signingId, String algorithm, String alias, byte[] data) {
+ }
+
+ /**
* This is called when {@link TvInteractiveAppService.Session#notifySessionStateChanged} is
* called.
*
@@ -1813,8 +1873,8 @@ public final class TvInteractiveAppManager {
}
/**
- * This is called when {@link TvIAppService.Session#notifyTeletextAppStateChanged} is
- * called.
+ * This is called when {@link TvInteractiveAppService.Session#notifyTeletextAppStateChanged}
+ * is called.
*
* @param session A {@link TvInteractiveAppManager.Session} associated with this callback.
* @param state the current state.
diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppService.java b/media/java/android/media/tv/interactive/TvInteractiveAppService.java
index 57730aca125f..b103b1036303 100755
--- a/media/java/android/media/tv/interactive/TvInteractiveAppService.java
+++ b/media/java/android/media/tv/interactive/TvInteractiveAppService.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,9 +16,12 @@
package android.media.tv.interactive;
+import android.annotation.CallSuper;
import android.annotation.MainThread;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.Px;
+import android.annotation.SdkConstant;
import android.annotation.StringDef;
import android.annotation.SuppressLint;
import android.app.ActivityManager;
@@ -76,15 +79,14 @@ public abstract class TvInteractiveAppService extends Service {
private static final int DETACH_MEDIA_VIEW_TIMEOUT_MS = 5000;
- // TODO: cleanup and unhide APIs.
-
/**
* This is the interface name that a service implementing a TV Interactive App service should
* say that it supports -- that is, this is the action it uses for its intent filter. To be
* supported, the service must also require the
- * android.Manifest.permission#BIND_TV_INTERACTIVE_APP permission so that other applications
- * cannot abuse it.
+ * {@link android.Manifest.permission#BIND_TV_INTERACTIVE_APP} permission so that other
+ * applications cannot abuse it.
*/
+ @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
public static final String SERVICE_INTERFACE =
"android.media.tv.interactive.TvInteractiveAppService";
@@ -216,11 +218,6 @@ public abstract class TvInteractiveAppService extends Service {
}
@Override
- public void prepare(int type) {
- onPrepare(type);
- }
-
- @Override
public void registerAppLinkInfo(AppLinkInfo appLinkInfo) {
onRegisterAppLinkInfo(appLinkInfo);
}
@@ -239,18 +236,13 @@ public abstract class TvInteractiveAppService extends Service {
}
/**
- * Prepares TV Interactive App service for the given type.
- */
- public abstract void onPrepare(@TvInteractiveAppInfo.InteractiveAppType int type);
-
- /**
- * Registers App link info.
+ * Called when a request to register an Android application link info record is received.
*/
public void onRegisterAppLinkInfo(@NonNull AppLinkInfo appLinkInfo) {
}
/**
- * Unregisters App link info.
+ * Called when a request to unregister an Android application link info record is received.
*/
public void onUnregisterAppLinkInfo(@NonNull AppLinkInfo appLinkInfo) {
}
@@ -276,7 +268,7 @@ public abstract class TvInteractiveAppService extends Service {
@Nullable
public abstract Session onCreateSession(
@NonNull String iAppServiceId,
- @TvInteractiveAppInfo.InteractiveAppType int type);
+ @TvInteractiveAppServiceInfo.InteractiveAppType int type);
/**
* Notifies the system when the state of the interactive app RTE has been changed.
@@ -288,7 +280,7 @@ public abstract class TvInteractiveAppService extends Service {
* {@link TvInteractiveAppManager#SERVICE_STATE_ERROR}.
*/
public final void notifyStateChanged(
- @TvInteractiveAppInfo.InteractiveAppType int type,
+ @TvInteractiveAppServiceInfo.InteractiveAppType int type,
@TvInteractiveAppManager.ServiceState int state,
@TvInteractiveAppManager.ErrorCode int error) {
SomeArgs args = SomeArgs.obtain();
@@ -351,6 +343,7 @@ public abstract class TvInteractiveAppService extends Service {
* @param enable {@code true} if you want to enable the media view. {@code false}
* otherwise.
*/
+ @CallSuper
public void setMediaViewEnabled(final boolean enable) {
mHandler.post(new Runnable() {
@Override
@@ -371,6 +364,15 @@ public abstract class TvInteractiveAppService extends Service {
}
/**
+ * Returns {@code true} if media view is enabled, {@code false} otherwise.
+ *
+ * @see #setMediaViewEnabled(boolean)
+ */
+ public boolean isMediaViewEnabled() {
+ return mMediaViewEnabled;
+ }
+
+ /**
* Starts TvInteractiveAppService session.
*/
public void onStartInteractiveApp() {
@@ -383,7 +385,7 @@ public abstract class TvInteractiveAppService extends Service {
}
/**
- * Resets TvIAppService session.
+ * Resets TvInteractiveAppService session.
*/
public void onResetInteractiveApp() {
}
@@ -395,9 +397,10 @@ public abstract class TvInteractiveAppService extends Service {
* no matter if it's created successfully or not.
*
* @see #notifyBiInteractiveAppCreated(Uri, String)
- * @see #onDestroyBiInteractiveApp(String)
+ * @see #onDestroyBiInteractiveAppRequest(String)
*/
- public void onCreateBiInteractiveApp(@NonNull Uri biIAppUri, @Nullable Bundle params) {
+ public void onCreateBiInteractiveAppRequest(
+ @NonNull Uri biIAppUri, @Nullable Bundle params) {
}
@@ -405,11 +408,11 @@ public abstract class TvInteractiveAppService extends Service {
* Destroys broadcast-independent(BI) interactive application.
*
* @param biIAppId the BI interactive app ID from
- * {@link #onCreateBiInteractiveApp(Uri, Bundle)}}
+ * {@link #onCreateBiInteractiveAppRequest(Uri, Bundle)}
*
- * @see #onCreateBiInteractiveApp(Uri, Bundle)
+ * @see #onCreateBiInteractiveAppRequest(Uri, Bundle)
*/
- public void onDestroyBiInteractiveApp(@NonNull String biIAppId) {
+ public void onDestroyBiInteractiveAppRequest(@NonNull String biIAppId) {
}
/**
@@ -433,6 +436,8 @@ public abstract class TvInteractiveAppService extends Service {
/**
* Receives current stream volume.
+ *
+ * @param volume a volume value between {@code 0.0f} and {@code 1.0f}, inclusive.
*/
public void onStreamVolume(float volume) {
}
@@ -450,6 +455,17 @@ public abstract class TvInteractiveAppService extends Service {
}
/**
+ * Receives signing result.
+ * @param signingId the ID to identify the request. It's the same as the corresponding ID in
+ * {@link Session#requestSigning(String, String, String, byte[])}
+ * @param result the signed result.
+ *
+ * @see #requestSigning(String, String, String, byte[])
+ */
+ public void onSigningResult(@NonNull String signingId, @NonNull byte[] result) {
+ }
+
+ /**
* Called when the application sets the surface.
*
* <p>The TV Interactive App service should render interactive app UI onto the given
@@ -467,11 +483,11 @@ public abstract class TvInteractiveAppService extends Service {
* in {@link #onSetSurface}. This method is always called at least once, after
* {@link #onSetSurface} is called with non-null surface.
*
- * @param format The new PixelFormat of the surface.
+ * @param format The new {@link PixelFormat} of the surface.
* @param width The new width of the surface.
* @param height The new height of the surface.
*/
- public void onSurfaceChanged(int format, int width, int height) {
+ public void onSurfaceChanged(@PixelFormat.Format int format, int width, int height) {
}
/**
@@ -482,10 +498,10 @@ public abstract class TvInteractiveAppService extends Service {
* containing {@link TvInteractiveAppView}. Note that the size of the underlying surface can
* be different if the surface was changed by calling {@link #layoutSurface}.
*
- * @param width The width of the media view.
- * @param height The height of the media view.
+ * @param width The width of the media view, in pixels.
+ * @param height The height of the media view, in pixels.
*/
- public void onMediaViewSizeChanged(int width, int height) {
+ public void onMediaViewSizeChanged(@Px int width, @Px int height) {
}
/**
@@ -631,6 +647,7 @@ public abstract class TvInteractiveAppService extends Service {
* @param right Right position in pixels, relative to the overlay view.
* @param bottom Bottom position in pixels, relative to the overlay view.
*/
+ @CallSuper
public void layoutSurface(final int left, final int top, final int right,
final int bottom) {
if (left > right || top > bottom) {
@@ -659,6 +676,7 @@ public abstract class TvInteractiveAppService extends Service {
* Requests broadcast related information from the related TV input.
* @param request the request for broadcast info
*/
+ @CallSuper
public void requestBroadcastInfo(@NonNull final BroadcastInfoRequest request) {
executeOrPostRunnableOnMainThread(new Runnable() {
@MainThread
@@ -683,6 +701,7 @@ public abstract class TvInteractiveAppService extends Service {
* Remove broadcast information request from the related TV input.
* @param requestId the ID of the request
*/
+ @CallSuper
public void removeBroadcastInfo(final int requestId) {
executeOrPostRunnableOnMainThread(new Runnable() {
@MainThread
@@ -709,6 +728,7 @@ public abstract class TvInteractiveAppService extends Service {
* @param cmdType type of the specific command
* @param parameters parameters of the specific command
*/
+ @CallSuper
public void sendPlaybackCommandRequest(
@PlaybackCommandType @NonNull String cmdType, @Nullable Bundle parameters) {
executeOrPostRunnableOnMainThread(new Runnable() {
@@ -733,6 +753,7 @@ public abstract class TvInteractiveAppService extends Service {
/**
* Sets broadcast video bounds.
*/
+ @CallSuper
public void setVideoBounds(@NonNull Rect rect) {
executeOrPostRunnableOnMainThread(new Runnable() {
@MainThread
@@ -755,6 +776,7 @@ public abstract class TvInteractiveAppService extends Service {
/**
* Requests the URI of the current channel.
*/
+ @CallSuper
public void requestCurrentChannelUri() {
executeOrPostRunnableOnMainThread(new Runnable() {
@MainThread
@@ -777,6 +799,7 @@ public abstract class TvInteractiveAppService extends Service {
/**
* Requests the logic channel number (LCN) of the current channel.
*/
+ @CallSuper
public void requestCurrentChannelLcn() {
executeOrPostRunnableOnMainThread(new Runnable() {
@MainThread
@@ -799,6 +822,7 @@ public abstract class TvInteractiveAppService extends Service {
/**
* Requests stream volume.
*/
+ @CallSuper
public void requestStreamVolume() {
executeOrPostRunnableOnMainThread(new Runnable() {
@MainThread
@@ -821,6 +845,7 @@ public abstract class TvInteractiveAppService extends Service {
/**
* Requests the list of {@link TvTrackInfo}.
*/
+ @CallSuper
public void requestTrackInfoList() {
executeOrPostRunnableOnMainThread(new Runnable() {
@MainThread
@@ -845,6 +870,7 @@ public abstract class TvInteractiveAppService extends Service {
*
* @see android.media.tv.TvInputInfo
*/
+ @CallSuper
public void requestCurrentTvInputId() {
executeOrPostRunnableOnMainThread(new Runnable() {
@MainThread
@@ -865,10 +891,52 @@ public abstract class TvInteractiveAppService extends Service {
}
/**
+ * Requests signing of the given data.
+ *
+ * <p>This is used when the corresponding server of the broadcast-independent interactive
+ * app requires signing during handshaking, and the interactive app service doesn't have
+ * the built-in private key. The private key is provided by the content providers and
+ * pre-built in the related app, such as TV app.
+ *
+ * @param signingId the ID to identify the request. When a result is received, this ID can
+ * be used to correlate the result with the request.
+ * @param algorithm the standard name of the signature algorithm requested, such as
+ * MD5withRSA, SHA256withDSA, etc. The name is from standards like
+ * FIPS PUB 186-4 and PKCS #1.
+ * @param alias the alias of the corresponding {@link java.security.KeyStore}.
+ * @param data the original bytes to be signed.
+ *
+ * @see #onSigningResult(String, byte[])
+ * @see TvInteractiveAppView#createBiInteractiveApp(Uri, Bundle)
+ * @see TvInteractiveAppView#BI_INTERACTIVE_APP_KEY_ALIAS
+ */
+ @CallSuper
+ public void requestSigning(@NonNull String signingId, @NonNull String algorithm,
+ @NonNull String alias, @NonNull byte[] data) {
+ executeOrPostRunnableOnMainThread(new Runnable() {
+ @MainThread
+ @Override
+ public void run() {
+ try {
+ if (DEBUG) {
+ Log.d(TAG, "requestSigning");
+ }
+ if (mSessionCallback != null) {
+ mSessionCallback.onRequestSigning(signingId, algorithm, alias, data);
+ }
+ } catch (RemoteException e) {
+ Log.w(TAG, "error in requestSigning", e);
+ }
+ }
+ });
+ }
+
+ /**
* Sends an advertisement request to be processed by the related TV input.
*
* @param request The advertisement request
*/
+ @CallSuper
public void requestAd(@NonNull final AdRequest request) {
executeOrPostRunnableOnMainThread(new Runnable() {
@MainThread
@@ -901,11 +969,11 @@ public abstract class TvInteractiveAppService extends Service {
}
void createBiInteractiveApp(@NonNull Uri biIAppUri, @Nullable Bundle params) {
- onCreateBiInteractiveApp(biIAppUri, params);
+ onCreateBiInteractiveAppRequest(biIAppUri, params);
}
void destroyBiInteractiveApp(@NonNull String biIAppId) {
- onDestroyBiInteractiveApp(biIAppId);
+ onDestroyBiInteractiveAppRequest(biIAppId);
}
void setTeletextAppEnabled(boolean enable) {
@@ -932,6 +1000,10 @@ public abstract class TvInteractiveAppService extends Service {
onCurrentTvInputId(inputId);
}
+ void sendSigningResult(String signingId, byte[] result) {
+ onSigningResult(signingId, result);
+ }
+
void release() {
onRelease();
if (mSurface != null) {
@@ -986,7 +1058,7 @@ public abstract class TvInteractiveAppService extends Service {
if (DEBUG) {
Log.d(TAG, "notifyContentAllowed");
}
- notifyContentAllowed();
+ onContentAllowed();
}
void notifyContentBlocked(TvContentRating rating) {
@@ -1032,6 +1104,7 @@ public abstract class TvInteractiveAppService extends Service {
* used when the state is not
* {@link TvInteractiveAppManager#INTERACTIVE_APP_STATE_ERROR}.
*/
+ @CallSuper
public void notifySessionStateChanged(
@TvInteractiveAppManager.InteractiveAppState int state,
@TvInteractiveAppManager.ErrorCode int err) {
@@ -1060,8 +1133,9 @@ public abstract class TvInteractiveAppService extends Service {
* @param biIAppId BI interactive app ID, which can be used to destroy the BI interactive
* app. {@code null} if it's not created successfully.
*
- * @see #onCreateBiInteractiveApp(Uri, Bundle)
+ * @see #onCreateBiInteractiveAppRequest(Uri, Bundle)
*/
+ @CallSuper
public final void notifyBiInteractiveAppCreated(
@NonNull Uri biIAppUri, @Nullable String biIAppId) {
executeOrPostRunnableOnMainThread(new Runnable() {
@@ -1087,6 +1161,7 @@ public abstract class TvInteractiveAppService extends Service {
* Notifies when the digital teletext app state is changed.
* @param state the current state.
*/
+ @CallSuper
public final void notifyTeletextAppStateChanged(
@TvInteractiveAppManager.TeletextAppState int state) {
executeOrPostRunnableOnMainThread(new Runnable() {
@@ -1397,6 +1472,11 @@ public abstract class TvInteractiveAppService extends Service {
}
@Override
+ public void sendSigningResult(@NonNull String signingId, @NonNull byte[] result) {
+ mSessionImpl.sendSigningResult(signingId, result);
+ }
+
+ @Override
public void release() {
mSessionImpl.scheduleMediaViewCleanup();
mSessionImpl.release();
diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppInfo.aidl b/media/java/android/media/tv/interactive/TvInteractiveAppServiceInfo.aidl
index 5e1501677b3b..4b6127c01d1e 100644
--- a/media/java/android/media/tv/interactive/TvInteractiveAppInfo.aidl
+++ b/media/java/android/media/tv/interactive/TvInteractiveAppServiceInfo.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,4 +16,4 @@
package android.media.tv.interactive;
-parcelable TvInteractiveAppInfo; \ No newline at end of file
+parcelable TvInteractiveAppServiceInfo; \ No newline at end of file
diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppInfo.java b/media/java/android/media/tv/interactive/TvInteractiveAppServiceInfo.java
index e1f535c93d19..3e0885214dcd 100644
--- a/media/java/android/media/tv/interactive/TvInteractiveAppInfo.java
+++ b/media/java/android/media/tv/interactive/TvInteractiveAppServiceInfo.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -45,9 +45,9 @@ import java.util.List;
/**
* This class is used to specify meta information of a TV interactive app.
*/
-public final class TvInteractiveAppInfo implements Parcelable {
+public final class TvInteractiveAppServiceInfo implements Parcelable {
private static final boolean DEBUG = false;
- private static final String TAG = "TvInteractiveAppInfo";
+ private static final String TAG = "TvInteractiveAppServiceInfo";
private static final String XML_START_TAG_NAME = "tv-interactive-app";
@@ -71,7 +71,13 @@ public final class TvInteractiveAppInfo implements Parcelable {
private final String mId;
private int mTypes;
- public TvInteractiveAppInfo(@NonNull Context context, @NonNull ComponentName component) {
+ /**
+ * Constructs a TvInteractiveAppServiceInfo object.
+ *
+ * @param context the application context
+ * @param component the component name of the TvInteractiveAppService
+ */
+ public TvInteractiveAppServiceInfo(@NonNull Context context, @NonNull ComponentName component) {
if (context == null) {
throw new IllegalArgumentException("context cannot be null.");
}
@@ -94,28 +100,28 @@ public final class TvInteractiveAppInfo implements Parcelable {
mId = id;
mTypes = toTypesFlag(types);
}
- private TvInteractiveAppInfo(ResolveInfo service, String id, int types) {
+ private TvInteractiveAppServiceInfo(ResolveInfo service, String id, int types) {
mService = service;
mId = id;
mTypes = types;
}
- private TvInteractiveAppInfo(@NonNull Parcel in) {
+ private TvInteractiveAppServiceInfo(@NonNull Parcel in) {
mService = ResolveInfo.CREATOR.createFromParcel(in);
mId = in.readString();
mTypes = in.readInt();
}
- public static final @NonNull Creator<TvInteractiveAppInfo> CREATOR =
- new Creator<TvInteractiveAppInfo>() {
+ public static final @NonNull Creator<TvInteractiveAppServiceInfo> CREATOR =
+ new Creator<TvInteractiveAppServiceInfo>() {
@Override
- public TvInteractiveAppInfo createFromParcel(Parcel in) {
- return new TvInteractiveAppInfo(in);
+ public TvInteractiveAppServiceInfo createFromParcel(Parcel in) {
+ return new TvInteractiveAppServiceInfo(in);
}
@Override
- public TvInteractiveAppInfo[] newArray(int size) {
- return new TvInteractiveAppInfo[size];
+ public TvInteractiveAppServiceInfo[] newArray(int size) {
+ return new TvInteractiveAppServiceInfo[size];
}
};
@@ -131,6 +137,10 @@ public final class TvInteractiveAppInfo implements Parcelable {
dest.writeInt(mTypes);
}
+ /**
+ * Returns a unique ID for this TV interactive app service. The ID is generated from the package
+ * and class name implementing the TV interactive app service.
+ */
@NonNull
public String getId() {
return mId;
diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppView.java b/media/java/android/media/tv/interactive/TvInteractiveAppView.java
index 773e54f30744..1df757b2d9d7 100755
--- a/media/java/android/media/tv/interactive/TvInteractiveAppView.java
+++ b/media/java/android/media/tv/interactive/TvInteractiveAppView.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -46,6 +46,7 @@ import android.view.View;
import android.view.ViewGroup;
import android.view.ViewRootImpl;
+import java.security.KeyStore;
import java.util.List;
import java.util.concurrent.Executor;
@@ -61,6 +62,41 @@ public class TvInteractiveAppView extends ViewGroup {
private static final int UNSET_TVVIEW_SUCCESS = 3;
private static final int UNSET_TVVIEW_FAIL = 4;
+ /**
+ * Used to share client {@link java.security.cert.Certificate} with
+ * {@link TvInteractiveAppService}.
+ * @see #createBiInteractiveApp(Uri, Bundle)
+ * @see java.security.cert.Certificate
+ */
+ public static final String BI_INTERACTIVE_APP_KEY_CERTIFICATE = "certificate";
+ /**
+ * Used to share the {@link KeyStore} alias with {@link TvInteractiveAppService}.
+ * @see #createBiInteractiveApp(Uri, Bundle)
+ * @see KeyStore#aliases()
+ */
+ public static final String BI_INTERACTIVE_APP_KEY_ALIAS = "alias";
+ /**
+ * Used to share the {@link java.security.PrivateKey} with {@link TvInteractiveAppService}.
+ * <p>The private key is optional. It is used to encrypt data when necessary.
+ *
+ * @see #createBiInteractiveApp(Uri, Bundle)
+ * @see java.security.PrivateKey
+ */
+ public static final String BI_INTERACTIVE_APP_KEY_PRIVATE_KEY = "private_key";
+ /**
+ * Additional HTTP headers to be used by {@link TvInteractiveAppService} to load the
+ * broadcast-independent interactive application.
+ * @see #createBiInteractiveApp(Uri, Bundle)
+ */
+ public static final String BI_INTERACTIVE_APP_KEY_HTTP_ADDITIONAL_HEADERS =
+ "http_additional_headers";
+ /**
+ * HTTP user agent to be used by {@link TvInteractiveAppService} for broadcast-independent
+ * interactive application.
+ * @see #createBiInteractiveApp(Uri, Bundle)
+ */
+ public static final String BI_INTERACTIVE_APP_KEY_HTTP_USER_AGENT = "http_user_agent";
+
private final TvInteractiveAppManager mTvInteractiveAppManager;
private final Handler mHandler = new Handler();
private final Object mCallbackLock = new Object();
@@ -148,12 +184,14 @@ public class TvInteractiveAppView extends ViewGroup {
/**
* Sets the callback to be invoked when an event is dispatched to this TvInteractiveAppView.
*
- * @param callback The callback to receive events. A value of {@code null} removes the existing
- * callback.
+ * @param callback the callback to receive events. MUST NOT be {@code null}.
+ *
+ * @see #clearCallback()
*/
public void setCallback(
@NonNull @CallbackExecutor Executor executor,
@NonNull TvInteractiveAppCallback callback) {
+ com.android.internal.util.AnnotationValidations.validate(NonNull.class, null, callback);
synchronized (mCallbackLock) {
mCallbackExecutor = executor;
mCallback = callback;
@@ -162,6 +200,8 @@ public class TvInteractiveAppView extends ViewGroup {
/**
* Clears the callback.
+ *
+ * @see #setCallback(Executor, TvInteractiveAppCallback)
*/
public void clearCallback() {
synchronized (mCallbackLock) {
@@ -238,7 +278,9 @@ public class TvInteractiveAppView extends ViewGroup {
}
/**
- * Resets this TvInteractiveAppView.
+ * Resets this TvInteractiveAppView to release its resources.
+ *
+ * <p>It can be reused by call {@link #prepareInteractiveApp(String, int)}.
*/
public void reset() {
if (DEBUG) Log.d(TAG, "reset()");
@@ -364,6 +406,19 @@ public class TvInteractiveAppView extends ViewGroup {
mOnUnhandledInputEventListener = listener;
// TODO: handle CallbackExecutor
}
+
+ /**
+ * Gets the {@link OnUnhandledInputEventListener}.
+ * <p>Returns {@code null} if the listener is not set or is cleared.
+ *
+ * @see #setOnUnhandledInputEventListener(Executor, OnUnhandledInputEventListener)
+ * @see #clearOnUnhandledInputEventListener()
+ */
+ @Nullable
+ public OnUnhandledInputEventListener getOnUnhandledInputEventListener() {
+ return mOnUnhandledInputEventListener;
+ }
+
/**
* Clears the {@link OnUnhandledInputEventListener}.
*/
@@ -386,16 +441,17 @@ public class TvInteractiveAppView extends ViewGroup {
}
/**
- * Prepares the interactive application.
+ * Prepares the interactive application runtime environment of corresponding
+ * {@link TvInteractiveAppService}.
*
* @param iAppServiceId the interactive app service ID, which can be found in
- * {@link TvInteractiveAppInfo#getId()}.
+ * {@link TvInteractiveAppServiceInfo#getId()}.
*
* @see android.media.tv.interactive.TvInteractiveAppManager#getTvInteractiveAppServiceList()
*/
public void prepareInteractiveApp(
@NonNull String iAppServiceId,
- @TvInteractiveAppInfo.InteractiveAppType int type) {
+ @TvInteractiveAppServiceInfo.InteractiveAppType int type) {
// TODO: document and handle the cases that this method is called multiple times.
if (DEBUG) {
Log.d(TAG, "prepareInteractiveApp");
@@ -432,6 +488,8 @@ public class TvInteractiveAppView extends ViewGroup {
/**
* Resets the interactive application.
+ *
+ * <p>This releases the resources of the corresponding {@link TvInteractiveAppService.Session}.
*/
public void resetInteractiveApp() {
if (DEBUG) {
@@ -471,6 +529,8 @@ public class TvInteractiveAppView extends ViewGroup {
/**
* Sends stream volume to related TV interactive app.
+ *
+ * @param volume a volume value between {@code 0.0f} and {@code 1.0f}, inclusive.
*/
public void sendStreamVolume(float volume) {
if (DEBUG) {
@@ -509,6 +569,27 @@ public class TvInteractiveAppView extends ViewGroup {
}
}
+ /**
+ * Sends signing result to related TV interactive app.
+ *
+ * <p>This is used when the corresponding server of the broadcast-independent interactive
+ * app requires signing during handshaking, and the interactive app service doesn't have
+ * the built-in private key. The private key is provided by the content providers and
+ * pre-built in the related app, such as TV app.
+ *
+ * @param signingId the ID to identify the request. It's the same as the corresponding ID in
+ * {@link TvInteractiveAppService.Session#requestSigning(String, String, String, byte[])}
+ * @param result the signed result.
+ */
+ public void sendSigningResult(@NonNull String signingId, @NonNull byte[] result) {
+ if (DEBUG) {
+ Log.d(TAG, "sendSigningResult");
+ }
+ if (mSession != null) {
+ mSession.sendSigningResult(signingId, result);
+ }
+ }
+
private void resetInternal() {
mSessionCallback = null;
if (mSession != null) {
@@ -527,7 +608,14 @@ public class TvInteractiveAppView extends ViewGroup {
* <p>{@link TvInteractiveAppCallback#onBiInteractiveAppCreated(String, Uri, String)} will be
* called for the result.
*
+ * @param biIAppUri URI associated this BI interactive app.
+ * @param params optional parameters for broadcast-independent interactive application, such as
+ * {@link #BI_INTERACTIVE_APP_KEY_CERTIFICATE}.
+ *
* @see TvInteractiveAppCallback#onBiInteractiveAppCreated(String, Uri, String)
+ * @see #BI_INTERACTIVE_APP_KEY_CERTIFICATE
+ * @see #BI_INTERACTIVE_APP_KEY_HTTP_ADDITIONAL_HEADERS
+ * @see #BI_INTERACTIVE_APP_KEY_HTTP_USER_AGENT
*/
public void createBiInteractiveApp(@NonNull Uri biIAppUri, @Nullable Bundle params) {
if (DEBUG) {
@@ -721,6 +809,22 @@ public class TvInteractiveAppView extends ViewGroup {
public void onRequestCurrentTvInputId(@NonNull String iAppServiceId) {
}
+ /**
+ * This is called when
+ * {@link TvInteractiveAppService.Session#requestSigning(String, String, String, byte[])} is
+ * called.
+ *
+ * @param iAppServiceId The ID of the TV interactive app service bound to this view.
+ * @param signingId the ID to identify the request.
+ * @param algorithm the standard name of the signature algorithm requested, such as
+ * MD5withRSA, SHA256withDSA, etc.
+ * @param alias the alias of the corresponding {@link java.security.KeyStore}.
+ * @param data the original bytes to be signed.
+ */
+ public void onRequestSigning(@NonNull String iAppServiceId, @NonNull String signingId,
+ @NonNull String algorithm, @NonNull String alias, @NonNull byte[] data) {
+ }
+
}
/**
@@ -1027,5 +1131,20 @@ public class TvInteractiveAppView extends ViewGroup {
mCallback.onRequestCurrentTvInputId(mIAppServiceId);
}
}
+
+ @Override
+ public void onRequestSigning(
+ Session session, String id, String algorithm, String alias, byte[] data) {
+ if (DEBUG) {
+ Log.d(TAG, "onRequestSigning");
+ }
+ if (this != mSessionCallback) {
+ Log.w(TAG, "onRequestSigning - session not created");
+ return;
+ }
+ if (mCallback != null) {
+ mCallback.onRequestSigning(mIAppServiceId, id, algorithm, alias, data);
+ }
+ }
}
}
diff --git a/media/java/android/media/tv/tuner/Lnb.java b/media/java/android/media/tv/tuner/Lnb.java
index 50a208344c3a..3b7089030255 100644
--- a/media/java/android/media/tv/tuner/Lnb.java
+++ b/media/java/android/media/tv/tuner/Lnb.java
@@ -167,10 +167,10 @@ public class Lnb implements AutoCloseable {
private Lnb() {}
- void setCallbackAndOwner(Executor executor, @Nullable LnbCallback callback, Tuner tuner) {
+ void setCallbackAndOwner(Tuner tuner, Executor executor, @Nullable LnbCallback callback) {
synchronized (mCallbackLock) {
if (callback != null && executor != null) {
- addCallback(callback, executor);
+ addCallback(executor, callback);
}
}
setOwner(tuner);
@@ -179,12 +179,12 @@ public class Lnb implements AutoCloseable {
/**
* Adds LnbCallback
*
- * @param callback the callback to receive notifications from LNB.
* @param executor the executor on which callback will be invoked. Cannot be null.
+ * @param callback the callback to receive notifications from LNB.
*/
- public void addCallback(@NonNull LnbCallback callback, @NonNull Executor executor) {
- Objects.requireNonNull(callback, "callback must not be null");
+ public void addCallback(@NonNull Executor executor, @NonNull LnbCallback callback) {
Objects.requireNonNull(executor, "executor must not be null");
+ Objects.requireNonNull(callback, "callback must not be null");
synchronized (mCallbackLock) {
mCallbackMap.put(callback, executor);
}
diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java
index 1e32cadc2748..ef0270b5414c 100644
--- a/media/java/android/media/tv/tuner/Tuner.java
+++ b/media/java/android/media/tv/tuner/Tuner.java
@@ -62,7 +62,9 @@ import android.os.Looper;
import android.os.Message;
import android.os.Process;
import android.util.Log;
+
import com.android.internal.util.FrameworkStatsLog;
+
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.ref.WeakReference;
@@ -2147,12 +2149,12 @@ public class Tuner implements AutoCloseable {
Objects.requireNonNull(executor, "executor must not be null");
Objects.requireNonNull(cb, "LnbCallback must not be null");
if (mLnb != null) {
- mLnb.setCallbackAndOwner(executor, cb, this);
+ mLnb.setCallbackAndOwner(this, executor, cb);
return mLnb;
}
if (checkResource(TunerResourceManager.TUNER_RESOURCE_TYPE_LNB, mLnbLock)
&& mLnb != null) {
- mLnb.setCallbackAndOwner(executor, cb, this);
+ mLnb.setCallbackAndOwner(this, executor, cb);
setLnb(mLnb);
return mLnb;
}
@@ -2186,7 +2188,7 @@ public class Tuner implements AutoCloseable {
mLnbHandle = null;
}
mLnb = newLnb;
- mLnb.setCallbackAndOwner(executor, cb, this);
+ mLnb.setCallbackAndOwner(this, executor, cb);
setLnb(mLnb);
}
return mLnb;
diff --git a/media/jni/android_media_MediaDrm.cpp b/media/jni/android_media_MediaDrm.cpp
index 4f7b7115fe26..2f4dd8fad8bb 100644
--- a/media/jni/android_media_MediaDrm.cpp
+++ b/media/jni/android_media_MediaDrm.cpp
@@ -1003,19 +1003,9 @@ DrmPlugin::SecurityLevel jintToSecurityLevel(jint jlevel) {
}
static jbyteArray android_media_MediaDrm_getSupportedCryptoSchemesNative(JNIEnv *env) {
+ sp<IDrm> drm = android::DrmUtils::MakeDrm();
std::vector<uint8_t> bv;
- for (auto &factory : DrmUtils::MakeDrmFactories()) {
- sp<drm::V1_3::IDrmFactory> factoryV1_3 = drm::V1_3::IDrmFactory::castFrom(factory);
- if (factoryV1_3 == nullptr) {
- continue;
- }
- factoryV1_3->getSupportedCryptoSchemes(
- [&](const hardware::hidl_vec<hardware::hidl_array<uint8_t, 16>>& schemes) {
- for (const auto &scheme : schemes) {
- bv.insert(bv.end(), scheme.data(), scheme.data() + scheme.size());
- }
- });
- }
+ drm->getSupportedSchemes(bv);
jbyteArray jUuidBytes = env->NewByteArray(bv.size());
env->SetByteArrayRegion(jUuidBytes, 0, bv.size(), reinterpret_cast<const jbyte *>(bv.data()));
diff --git a/native/android/storage_manager.cpp b/native/android/storage_manager.cpp
index 22725254fef6..9e0a6eb476d3 100644
--- a/native/android/storage_manager.cpp
+++ b/native/android/storage_manager.cpp
@@ -140,8 +140,7 @@ public:
}
}
- void mountObb(const char* rawPath, const char* key, AStorageManager_obbCallbackFunc func,
- void* data) {
+ void mountObb(const char* rawPath, AStorageManager_obbCallbackFunc func, void* data) {
// Resolve path before sending to MountService
char canonicalPath[PATH_MAX];
if (realpath(rawPath, canonicalPath) == NULL) {
@@ -158,9 +157,7 @@ public:
ObbCallback* cb = registerObbCallback(func, data);
String16 rawPath16(rawPath);
String16 canonicalPath16(canonicalPath);
- String16 key16(key);
- mMountService->mountObb(rawPath16, canonicalPath16, key16, mObbActionListener,
- cb->nonce, obbInfo);
+ mMountService->mountObb(rawPath16, canonicalPath16, mObbActionListener, cb->nonce, obbInfo);
}
void unmountObb(const char* filename, const bool force, AStorageManager_obbCallbackFunc func, void* data) {
@@ -207,7 +204,11 @@ void AStorageManager_delete(AStorageManager* mgr) {
void AStorageManager_mountObb(AStorageManager* mgr, const char* filename, const char* key,
AStorageManager_obbCallbackFunc cb, void* data) {
- mgr->mountObb(filename, key, cb, data);
+ if (key != nullptr && key[0] != '\0') {
+ ALOGE("mounting encrypted OBBs is no longer supported");
+ return;
+ }
+ mgr->mountObb(filename, cb, data);
}
void AStorageManager_unmountObb(AStorageManager* mgr, const char* filename, const int force,
diff --git a/packages/BackupRestoreConfirmation/res/values/strings.xml b/packages/BackupRestoreConfirmation/res/values/strings.xml
index 3fb3fd475ab3..5c90fd019cd8 100644
--- a/packages/BackupRestoreConfirmation/res/values/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values/strings.xml
@@ -44,8 +44,6 @@
<string name="backup_enc_password_text">Please enter a password to use for encrypting the full backup data. If this is left blank, your current backup password will be used:</string>
<!-- Text for message to user that they may optionally supply an encryption password to use for a full backup operation. -->
<string name="backup_enc_password_optional">If you wish to encrypt the full backup data, enter a password below:</string>
- <!-- Text for message to user that they must supply an encryption password to use for a full backup operation because their phone is locked. -->
- <string name="backup_enc_password_required">Since your device is encrypted, you are required to encrypt your backup. Please enter a password below:</string>
<!-- Text for message to user when performing a full restore operation, explaining that they must enter the password originally used to encrypt the full backup data. -->
<string name="restore_enc_password_text">If the restore data is encrypted, please enter the password below:</string>
diff --git a/packages/BackupRestoreConfirmation/src/com/android/backupconfirm/BackupRestoreConfirmation.java b/packages/BackupRestoreConfirmation/src/com/android/backupconfirm/BackupRestoreConfirmation.java
index d6b6bf8d1e56..3c790f0e24ee 100644
--- a/packages/BackupRestoreConfirmation/src/com/android/backupconfirm/BackupRestoreConfirmation.java
+++ b/packages/BackupRestoreConfirmation/src/com/android/backupconfirm/BackupRestoreConfirmation.java
@@ -27,8 +27,6 @@ import android.os.Handler;
import android.os.Message;
import android.os.RemoteException;
import android.os.ServiceManager;
-import android.os.storage.IStorageManager;
-import android.os.storage.StorageManager;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Slog;
@@ -66,10 +64,8 @@ public class BackupRestoreConfirmation extends Activity {
Handler mHandler;
IBackupManager mBackupManager;
- IStorageManager mStorageManager;
FullObserver mObserver;
int mToken;
- boolean mIsEncrypted;
boolean mDidAcknowledge;
String mAction;
@@ -144,7 +140,6 @@ public class BackupRestoreConfirmation extends Activity {
}
mBackupManager = IBackupManager.Stub.asInterface(ServiceManager.getService(Context.BACKUP_SERVICE));
- mStorageManager = IStorageManager.Stub.asInterface(ServiceManager.getService("mount"));
mHandler = new ObserverHandler(getApplicationContext());
final Object oldObserver = getLastNonConfigurationInstance();
@@ -248,20 +243,13 @@ public class BackupRestoreConfirmation extends Activity {
mDenyButton.setEnabled(!mDidAcknowledge);
}
- // We vary the password prompt depending on whether one is predefined, and whether
- // the device is encrypted.
- mIsEncrypted = deviceIsEncrypted();
+ // We vary the password prompt depending on whether one is predefined.
if (!haveBackupPassword()) {
curPwDesc.setVisibility(View.GONE);
mCurPassword.setVisibility(View.GONE);
if (layoutId == R.layout.confirm_backup) {
TextView encPwDesc = findViewById(R.id.enc_password_desc);
- if (mIsEncrypted) {
- encPwDesc.setText(R.string.backup_enc_password_required);
- monitorEncryptionPassword();
- } else {
- encPwDesc.setText(R.string.backup_enc_password_optional);
- }
+ encPwDesc.setText(R.string.backup_enc_password_optional);
}
}
}
@@ -312,20 +300,6 @@ public class BackupRestoreConfirmation extends Activity {
}
}
- boolean deviceIsEncrypted() {
- try {
- return mStorageManager.getEncryptionState()
- != StorageManager.ENCRYPTION_STATE_NONE
- && mStorageManager.getPasswordType()
- != StorageManager.CRYPT_TYPE_DEFAULT;
- } catch (Exception e) {
- // If we can't talk to the storagemanager service we have a serious problem; fail
- // "secure" i.e. assuming that the device is encrypted.
- Slog.e(TAG, "Unable to communicate with storagemanager service: " + e.getMessage());
- return true;
- }
- }
-
boolean haveBackupPassword() {
try {
return mBackupManager.hasBackupPassword();
diff --git a/packages/CompanionDeviceManager/res/color/selector.xml b/packages/CompanionDeviceManager/res/color/selector.xml
index 56e5dca0f72f..aebc5d5adf6e 100644
--- a/packages/CompanionDeviceManager/res/color/selector.xml
+++ b/packages/CompanionDeviceManager/res/color/selector.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2022 The Android Open Source Project
~
diff --git a/packages/CompanionDeviceManager/res/drawable/btn_negative_multiple_devices.xml b/packages/CompanionDeviceManager/res/drawable/btn_negative_multiple_devices.xml
new file mode 100644
index 000000000000..ebe16a7a14e5
--- /dev/null
+++ b/packages/CompanionDeviceManager/res/drawable/btn_negative_multiple_devices.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.
+ -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <solid android:color="@android:color/transparent" />
+ <corners android:topLeftRadius="16dp" android:topRightRadius="16dp"
+ android:bottomLeftRadius="16dp" android:bottomRightRadius="16dp"/>
+ <stroke
+ android:width="1dp"
+ android:color="@android:color/system_accent1_600" />
+</shape> \ No newline at end of file
diff --git a/packages/CompanionDeviceManager/res/drawable/btn_negative_top.xml b/packages/CompanionDeviceManager/res/drawable/btn_negative_top.xml
new file mode 100644
index 000000000000..3cd7929bdd83
--- /dev/null
+++ b/packages/CompanionDeviceManager/res/drawable/btn_negative_top.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.
+ -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <solid android:color="@android:color/system_accent1_100"/>
+ <corners android:topLeftRadius="4dp" android:topRightRadius="4dp"
+ android:bottomLeftRadius="12dp" android:bottomRightRadius="12dp"/>
+</shape>
diff --git a/packages/CompanionDeviceManager/res/drawable/btn_positive_bottom.xml b/packages/CompanionDeviceManager/res/drawable/btn_positive_bottom.xml
new file mode 100644
index 000000000000..2cff4737cabf
--- /dev/null
+++ b/packages/CompanionDeviceManager/res/drawable/btn_positive_bottom.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.
+ -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <solid android:color="@android:color/system_accent1_100"/>
+ <corners android:topLeftRadius="12dp" android:topRightRadius="12dp"
+ android:bottomLeftRadius="4dp" android:bottomRightRadius="4dp"/>
+</shape>
diff --git a/packages/CompanionDeviceManager/res/drawable/helper_ok_button.xml b/packages/CompanionDeviceManager/res/drawable/helper_ok_button.xml
index f9ec5d0dce55..8e92051faf6c 100644
--- a/packages/CompanionDeviceManager/res/drawable/helper_ok_button.xml
+++ b/packages/CompanionDeviceManager/res/drawable/helper_ok_button.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2022 The Android Open Source Project
~
diff --git a/packages/CompanionDeviceManager/res/drawable/ic_apps.xml b/packages/CompanionDeviceManager/res/drawable/ic_apps.xml
new file mode 100644
index 000000000000..d1ec8637775c
--- /dev/null
+++ b/packages/CompanionDeviceManager/res/drawable/ic_apps.xml
@@ -0,0 +1,27 @@
+<?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">
+ <path
+ android:pathData="M6.2529,18.5H16.2529V17.5H18.2529V21.5C18.2529,22.6 17.3529,23.5 16.2529,23.5H6.2529C5.1529,23.5 4.2529,22.6 4.2529,21.5V3.5C4.2529,2.4 5.1529,1.51 6.2529,1.51L16.2529,1.5C17.3529,1.5 18.2529,2.4 18.2529,3.5V7.5H16.2529V6.5H6.2529V18.5ZM16.2529,3.5H6.2529V4.5H16.2529V3.5ZM6.2529,21.5V20.5H16.2529V21.5H6.2529ZM12.6553,9.4049C12.6553,8.8526 13.103,8.4049 13.6553,8.4049H20.5254C21.0776,8.4049 21.5254,8.8526 21.5254,9.4049V14.6055C21.5254,15.1578 21.0776,15.6055 20.5254,15.6055H14.355L12.6553,17.0871V9.4049Z"
+ android:fillColor="#3C4043"
+ android:fillType="evenOdd"/>
+</vector> \ No newline at end of file
diff --git a/packages/CompanionDeviceManager/res/drawable/ic_device_other.xml b/packages/CompanionDeviceManager/res/drawable/ic_device_other.xml
new file mode 100644
index 000000000000..2a8eb24bcf1f
--- /dev/null
+++ b/packages/CompanionDeviceManager/res/drawable/ic_device_other.xml
@@ -0,0 +1,24 @@
+<?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="M7,20H4Q3.175,20 2.588,19.413Q2,18.825 2,18V6Q2,5.175 2.588,4.588Q3.175,4 4,4H20V6H4Q4,6 4,6Q4,6 4,6V18Q4,18 4,18Q4,18 4,18H7ZM9,20V18.2Q8.55,17.775 8.275,17.225Q8,16.675 8,16Q8,15.325 8.275,14.775Q8.55,14.225 9,13.8V12H13V13.8Q13.45,14.225 13.725,14.775Q14,15.325 14,16Q14,16.675 13.725,17.225Q13.45,17.775 13,18.2V20ZM11,17.5Q11.65,17.5 12.075,17.075Q12.5,16.65 12.5,16Q12.5,15.35 12.075,14.925Q11.65,14.5 11,14.5Q10.35,14.5 9.925,14.925Q9.5,15.35 9.5,16Q9.5,16.65 9.925,17.075Q10.35,17.5 11,17.5ZM21,20H16Q15.575,20 15.288,19.712Q15,19.425 15,19V10Q15,9.575 15.288,9.287Q15.575,9 16,9H21Q21.425,9 21.712,9.287Q22,9.575 22,10V19Q22,19.425 21.712,19.712Q21.425,20 21,20ZM17,18H20V11H17Z"/>
+</vector> \ No newline at end of file
diff --git a/packages/CompanionDeviceManager/res/drawable/ic_notifications.xml b/packages/CompanionDeviceManager/res/drawable/ic_notifications.xml
new file mode 100644
index 000000000000..e5825bcbf70c
--- /dev/null
+++ b/packages/CompanionDeviceManager/res/drawable/ic_notifications.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.
+ -->
+
+<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="M4,19V17H6V10Q6,7.925 7.25,6.312Q8.5,4.7 10.5,4.2V3.5Q10.5,2.875 10.938,2.438Q11.375,2 12,2Q12.625,2 13.062,2.438Q13.5,2.875 13.5,3.5V4.2Q15.5,4.7 16.75,6.312Q18,7.925 18,10V17H20V19ZM12,11.5Q12,11.5 12,11.5Q12,11.5 12,11.5Q12,11.5 12,11.5Q12,11.5 12,11.5ZM12,22Q11.175,22 10.588,21.413Q10,20.825 10,20H14Q14,20.825 13.413,21.413Q12.825,22 12,22ZM8,17H16V10Q16,8.35 14.825,7.175Q13.65,6 12,6Q10.35,6 9.175,7.175Q8,8.35 8,10Z"/>
+</vector> \ No newline at end of file
diff --git a/packages/CompanionDeviceManager/res/drawable/ic_storage.xml b/packages/CompanionDeviceManager/res/drawable/ic_storage.xml
new file mode 100644
index 000000000000..406a3b5dada5
--- /dev/null
+++ b/packages/CompanionDeviceManager/res/drawable/ic_storage.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.
+ -->
+
+<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="M6,17H18L14.25,12L11.25,16L9,13ZM5,21Q4.175,21 3.587,20.413Q3,19.825 3,19V5Q3,4.175 3.587,3.587Q4.175,3 5,3H19Q19.825,3 20.413,3.587Q21,4.175 21,5V19Q21,19.825 20.413,20.413Q19.825,21 19,21ZM5,19H19Q19,19 19,19Q19,19 19,19V5Q19,5 19,5Q19,5 19,5H5Q5,5 5,5Q5,5 5,5V19Q5,19 5,19Q5,19 5,19ZM5,5Q5,5 5,5Q5,5 5,5V19Q5,19 5,19Q5,19 5,19Q5,19 5,19Q5,19 5,19V5Q5,5 5,5Q5,5 5,5Z"/>
+</vector> \ No newline at end of file
diff --git a/packages/CompanionDeviceManager/res/drawable/ic_watch.xml b/packages/CompanionDeviceManager/res/drawable/ic_watch.xml
new file mode 100644
index 000000000000..d7a28d949997
--- /dev/null
+++ b/packages/CompanionDeviceManager/res/drawable/ic_watch.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.
+ -->
+
+<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="M9,22 L7.65,17.45Q6.45,16.5 5.725,15.075Q5,13.65 5,12Q5,10.35 5.725,8.925Q6.45,7.5 7.65,6.55L9,2H15L16.35,6.55Q17.55,7.5 18.275,8.925Q19,10.35 19,12Q19,13.65 18.275,15.075Q17.55,16.5 16.35,17.45L15,22ZM12,17Q14.075,17 15.538,15.537Q17,14.075 17,12Q17,9.925 15.538,8.462Q14.075,7 12,7Q9.925,7 8.463,8.462Q7,9.925 7,12Q7,14.075 8.463,15.537Q9.925,17 12,17ZM10.1,5.25Q11.075,4.975 12,4.975Q12.925,4.975 13.9,5.25L13.5,4H10.5ZM10.5,20H13.5L13.9,18.75Q12.925,19.025 12,19.025Q11.075,19.025 10.1,18.75ZM10.1,4H10.5H13.5H13.9Q12.925,4 12,4Q11.075,4 10.1,4ZM10.5,20H10.1Q11.075,20 12,20Q12.925,20 13.9,20H13.5Z"/>
+</vector> \ No newline at end of file
diff --git a/packages/CompanionDeviceManager/res/layout/activity_confirmation.xml b/packages/CompanionDeviceManager/res/layout/activity_confirmation.xml
index f30dadffa788..c37054e9e98d 100644
--- a/packages/CompanionDeviceManager/res/layout/activity_confirmation.xml
+++ b/packages/CompanionDeviceManager/res/layout/activity_confirmation.xml
@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2021 The Android Open Source Project
-
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
@@ -22,60 +21,111 @@
<!-- Do NOT change the ID of the root LinearLayout above: it's referenced in CTS tests. -->
- <TextView
+ <ImageView
+ android:id="@+id/profile_icon"
+ android:layout_width="match_parent"
+ android:layout_height="32dp"
+ android:gravity="center"
+ android:layout_marginTop="18dp"
+ android:tint="@android:color/system_accent1_600"/>
+
+ <LinearLayout style="@style/Description">
+ <TextView
android:id="@+id/title"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity="center"
- android:paddingHorizontal="12dp"
- style="@*android:style/TextAppearance.Widget.Toolbar.Title"/>
+ style="@style/DescriptionTitle" />
- <TextView
+ <TextView
android:id="@+id/summary"
+ style="@style/DescriptionSummary" />
+
+ </LinearLayout>
+
+ <RelativeLayout
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1">
+
+ <LinearLayout
+ android:id="@+id/multiple_device_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:layout_marginBottom="12dp"
- android:gravity="center"
- android:textColor="?android:attr/textColorSecondary"
- android:textSize="14sp" />
+ android:orientation="vertical"
+ android:visibility="gone">
- <RelativeLayout
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_weight="1">
+ <View
+ android:id="@+id/border_top"
+ style="@style/DeviceListBorder" />
+
+ <androidx.recyclerview.widget.RecyclerView
+ android:id="@+id/device_list"
+ android:layout_width="match_parent"
+ android:scrollbars="vertical"
+ android:layout_marginBottom="12dp"
+ android:layout_height="200dp" />
+
+ <View
+ android:id="@+id/border_bottom"
+ style="@style/DeviceListBorder" />
+
+ </LinearLayout>
<androidx.recyclerview.widget.RecyclerView
- android:id="@+id/device_list"
+ android:id="@+id/permission_list"
android:layout_width="match_parent"
- android:scrollbars="vertical"
- android:layout_height="200dp" />
+ android:layout_height="wrap_content" />
+
+ <ProgressBar
+ android:id="@+id/spinner"
+ android:layout_width="56dp"
+ android:layout_height="56dp"
+ android:layout_centerInParent="true"
+ android:indeterminate="true"
+ android:tint="@android:color/system_accent1_600"
+ android:visibility="gone"
+ style="?android:attr/progressBarStyleLarge" />
</RelativeLayout>
<LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:gravity="end">
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:orientation="vertical"
+ android:layout_marginTop="16dp">
<!-- Do NOT change the IDs of the buttons: they are referenced in CTS tests. -->
<Button
- android:id="@+id/btn_negative"
- style="@android:style/Widget.Material.Button.Borderless.Colored"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/consent_no"
- android:textColor="?android:attr/textColorSecondary" />
+ android:id="@+id/btn_positive"
+ style="@style/PositiveButton"
+ android:text="@string/consent_yes" />
<Button
- android:id="@+id/btn_positive"
- style="@android:style/Widget.Material.Button.Borderless.Colored"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/consent_yes" />
+ android:id="@+id/btn_negative"
+ android:layout_marginBottom="12dp"
+ style="@style/NegativeButton"
+ android:text="@string/consent_no" />
+
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="bottom|right"
+ android:orientation="vertical"
+ android:layout_marginRight="16dp"
+ android:layout_marginBottom="16dp">
+ <!-- Do NOT change the IDs of the buttons: they are referenced in CTS tests. -->
+
+ <Button
+ android:id="@+id/btn_negative_multiple_devices"
+ style="@style/NegativeButtonMultipleDevices"
+ android:textColor="?android:textColorPrimary"
+ android:visibility="gone"
+ android:text="@string/consent_no" />
</LinearLayout>
</LinearLayout> \ No newline at end of file
diff --git a/packages/CompanionDeviceManager/res/layout/data_transfer_confirmation.xml b/packages/CompanionDeviceManager/res/layout/data_transfer_confirmation.xml
index a1855fdda78d..3d0849356281 100644
--- a/packages/CompanionDeviceManager/res/layout/data_transfer_confirmation.xml
+++ b/packages/CompanionDeviceManager/res/layout/data_transfer_confirmation.xml
@@ -15,58 +15,41 @@
~ limitations under the License.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/activity_confirmation"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:background="@drawable/dialog_background"
- android:elevation="16dp"
- android:maxHeight="400dp"
- android:orientation="vertical"
- android:padding="18dp"
- android:layout_gravity="center">
+ android:id="@+id/data_transfer_confirmation"
+ style="@style/ContainerLayout">
<!-- Do NOT change the ID of the root LinearLayout above: it's referenced in CTS tests. -->
- <TextView
+ <LinearLayout style="@style/Description">
+ <TextView
android:id="@+id/title"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity="center"
- android:paddingHorizontal="12dp"
- style="@*android:style/TextAppearance.Widget.Toolbar.Title"/>
+ style="@style/DescriptionTitle" />
- <TextView
+ <TextView
android:id="@+id/summary"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="12dp"
- android:layout_marginBottom="12dp"
- android:gravity="center"
- android:textColor="?android:attr/textColorSecondary"
- android:textSize="14sp" />
+ style="@style/DescriptionSummary" />
+
+ </LinearLayout>
<LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:gravity="end">
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:orientation="vertical"
+ android:layout_marginTop="16dp">
<!-- Do NOT change the IDs of the buttons: they are referenced in CTS tests. -->
<Button
- android:id="@+id/btn_negative"
- style="@android:style/Widget.Material.Button.Borderless.Colored"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/consent_no"
- android:textColor="?android:attr/textColorSecondary" />
+ android:id="@+id/btn_positive"
+ style="@style/PositiveButton"
+ android:text="@string/consent_yes" />
<Button
- android:id="@+id/btn_positive"
- style="@android:style/Widget.Material.Button.Borderless.Colored"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/consent_yes" />
+ android:id="@+id/btn_negative"
+ android:layout_marginBottom="12dp"
+ style="@style/NegativeButton"
+ android:text="@string/consent_no" />
</LinearLayout>
diff --git a/packages/CompanionDeviceManager/res/layout/helper_confirmation.xml b/packages/CompanionDeviceManager/res/layout/helper_confirmation.xml
index 8fd1fb0de891..a22ca941c5eb 100644
--- a/packages/CompanionDeviceManager/res/layout/helper_confirmation.xml
+++ b/packages/CompanionDeviceManager/res/layout/helper_confirmation.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2022 The Android Open Source Project
~
@@ -17,6 +18,7 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/helper_confirmation"
android:theme="@style/ChooserActivity"
+ android:padding="12dp"
style="@style/ContainerLayout">
<ImageView
@@ -24,8 +26,8 @@
android:layout_width="match_parent"
android:layout_height="32dp"
android:gravity="center"
- android:layout_marginBottom="12dp"
- android:layout_marginTop="1dp"/>
+ android:layout_marginTop="12dp"
+ android:layout_marginBottom="12dp"/>
<TextView
android:id="@+id/helper_title"
@@ -33,17 +35,18 @@
android:layout_height="wrap_content"
android:gravity="center"
android:paddingHorizontal="12dp"
- style="@*android:style/TextAppearance.Widget.Toolbar.Title"
- android:textSize="20sp" />
+ android:textColor="?android:attr/textColorPrimary"
+ android:textSize="22sp" />
<TextView
android:id="@+id/helper_summary"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:layout_marginLeft="24dp"
+ android:layout_marginRight="24dp"
android:layout_marginTop="12dp"
- android:layout_marginLeft="20dp"
android:layout_marginBottom="24dp"
- android:gravity="start"
+ android:gravity="center"
android:textColor="?android:attr/textColorSecondary"
android:textSize="14sp" />
@@ -51,6 +54,8 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
+ android:layout_marginRight="12dp"
+ android:layout_marginBottom="12dp"
android:gravity="end">
<Button
@@ -60,4 +65,4 @@
</LinearLayout>
-</LinearLayout>
+</LinearLayout> \ No newline at end of file
diff --git a/packages/CompanionDeviceManager/res/layout/list_item_device.xml b/packages/CompanionDeviceManager/res/layout/list_item_device.xml
index 153fc1f35abe..eeb988f364b2 100644
--- a/packages/CompanionDeviceManager/res/layout/list_item_device.xml
+++ b/packages/CompanionDeviceManager/res/layout/list_item_device.xml
@@ -25,16 +25,18 @@
<!-- Do NOT change the ID of the root LinearLayout above: it's referenced in CTS tests. -->
<ImageView
- android:id="@android:id/icon"
- android:layout_width="24dp"
- android:layout_height="24dp"
- android:layout_marginRight="12dp"/>
+ android:id="@android:id/icon"
+ android:layout_width="24dp"
+ android:layout_height="24dp"
+ android:layout_marginLeft="24dp"
+ android:layout_marginRight="12dp"
+ android:tint="@android:color/system_accent1_600"/>
<TextView
- android:id="@android:id/text1"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:singleLine="true"
- android:textAppearance="?android:attr/textAppearanceListItemSmall"/>
+ android:id="@android:id/text1"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:textAppearance="?android:attr/textAppearanceListItemSmall"/>
</LinearLayout> \ No newline at end of file
diff --git a/packages/CompanionDeviceManager/res/layout/list_item_permission.xml b/packages/CompanionDeviceManager/res/layout/list_item_permission.xml
new file mode 100644
index 000000000000..3dce38d0dc20
--- /dev/null
+++ b/packages/CompanionDeviceManager/res/layout/list_item_permission.xml
@@ -0,0 +1,60 @@
+<?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/list_item_permission"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:paddingLeft="32dp"
+ android:paddingRight="32dp"
+ android:paddingBottom="14dp">
+
+ <ImageView
+ android:id="@+id/permission_icon"
+ android:layout_width="24dp"
+ android:layout_height="24dp"
+ android:layout_marginTop="8dp"
+ android:layout_marginEnd="12dp"
+ android:tint="@android:color/system_accent1_600"
+ android:contentDescription="Permission Icon"/>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:gravity="center_vertical"
+ android:padding="6dp">
+
+ <TextView
+ android:id="@+id/permission_name"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:textSize="16sp"
+ android:textAppearance="?android:attr/textAppearanceListItemSmall"/>
+
+ <TextView
+ android:id="@+id/permission_summary"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingRight="24dp"
+ android:textSize="14sp"
+ android:textColor="?android:attr/textColorSecondary"/>
+
+ </LinearLayout>
+
+</LinearLayout> \ No newline at end of file
diff --git a/packages/CompanionDeviceManager/res/layout/vendor_header.xml b/packages/CompanionDeviceManager/res/layout/vendor_header.xml
index d04eadfb62f4..5f6aa9419c6e 100644
--- a/packages/CompanionDeviceManager/res/layout/vendor_header.xml
+++ b/packages/CompanionDeviceManager/res/layout/vendor_header.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2022 The Android Open Source Project
~
@@ -21,7 +22,10 @@
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_gravity="center"
- android:layout_marginBottom="16dp"
+ android:paddingTop="24dp"
+ android:paddingBottom="4dp"
+ android:paddingLeft="24dp"
+ android:paddingRight="24dp"
android:visibility="gone" >
<ImageView
@@ -42,7 +46,6 @@
style="?android:attr/actionOverflowButtonStyle"
android:layout_width="31dp"
android:layout_height="32dp"
- android:layout_marginLeft="100dp"
android:layout_alignParentRight="true" />
</RelativeLayout> \ No newline at end of file
diff --git a/packages/CompanionDeviceManager/res/values-af/strings.xml b/packages/CompanionDeviceManager/res/values-af/strings.xml
index 2d8ef7348dfd..eec09d20eec1 100644
--- a/packages/CompanionDeviceManager/res/values-af/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-af/strings.xml
@@ -22,18 +22,30 @@
<string name="chooser_title" msgid="2262294130493605839">"Kies \'n <xliff:g id="PROFILE_NAME">%1$s</xliff:g> om deur &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; bestuur te word"</string>
<string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> sal interaksie met jou kennisgewings mag hê en toegang kry tot jou Foon-, SMS-, Kontakte- en Kalender-toestemmings."</string>
<string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> sal interaksie met jou kennisgewings mag hê en toegang kry tot jou Foon-, SMS-, Kontakte- en Kalender-toestemmings."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Laat &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; toe om programme te stroom?"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Programme"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"Stroom jou foon se programme"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"Gee &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; toegang tot hierdie inligting op jou foon"</string>
<string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Gee &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; afstandtoegang tot programme wat op &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; geïnstalleer is wanneer hierdie foon aan die internet gekoppel is."</string>
<string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Gee &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; afstandtoegang tot programme wat op &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; geïnstalleer is wanneer hierdie tablet aan die internet gekoppel is."</string>
<string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Gee &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; afstandtoegang tot programme wat op &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; geïnstalleer is wanneer hierdie toestel aan die internet gekoppel is."</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Oorkruistoestel-dienste"</string>
+ <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Hierdie diens word gebruik om programme tussen jou toestelle te stroom"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Gee &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; toegang tot hierdie inligting op jou foon"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Kennisgewings"</string>
+ <string name="permission_notification_summary" msgid="4398672775023193663">"Kan alle kennisgewings lees, insluitend inligting soos kontakte, boodskappe en foto\'s"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"Foto\'s en media"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Google Play Dienste"</string>
+ <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Hierdie diens deel foto\'s, media en kennisgewings van jou foon af na ander dienste"</string>
+ <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Hierdie diens deel foto\'s, media en kennisgewings van jou foon af na ander dienste"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"toestel"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Laat toe"</string>
<string name="consent_no" msgid="2640796915611404382">"Moenie toelaat nie"</string>
+ <string name="consent_ok" msgid="3662376764371001106">"OK"</string>
<string name="permission_sync_confirmation_title" msgid="667074294393493186">"Dra programtoestemmings na jou horlosie toe oor"</string>
<string name="permission_sync_summary" msgid="8873391306499120778">"Om dit makliker te maak om jou horlosie op te stel, sal programme wat gedurende opstelling op jou horlosie geïnstalleer word, dieselfde toestemmings as jou foon gebruik.\n\n Hierdie toestemmings kan toegang tot jou horlosie se mikrofoon en ligging insluit."</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-am/strings.xml b/packages/CompanionDeviceManager/res/values-am/strings.xml
index 5cb306f14380..0411f3aa3f4d 100644
--- a/packages/CompanionDeviceManager/res/values-am/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-am/strings.xml
@@ -22,18 +22,30 @@
<string name="chooser_title" msgid="2262294130493605839">"በ&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; የሚተዳደር <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ይምረጡ"</string>
<string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ከማሳወቂያዎችዎ ጋር መስተጋብር እንዲፈጥር እና የእርስዎን ስልክ፣ ኤስኤምኤስ፣ እውቂያዎች እና የቀን መቁጠሪያ ፈቃዶች እንዲደርስ ይፈቀድለታል።"</string>
<string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ከማሳወቂያዎችዎ ጋር መስተጋብር እንዲፈጥር እና የእርስዎን ስልክ፣ ኤስኤምኤስ፣ እውቂያዎች እና የቀን መቁጠሪያ ፈቃዶች እንዲደርስ ይፈቀድለታል።"</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; መተግበሪያዎችን እንዲለቅቅ ይፈቀድለት?"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"መተግበሪያዎች"</string>
+ <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="summary_app_streaming" product="default" msgid="6105916810614498138">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ሲገናኙ በዚህ ስልክ ላይ የተጫኑ መተግበሪያዎችን እንዲደርስ ለ&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; የርቀት መዳረሻ እንዲያቀርብ ይፍቀዱለት።"</string>
<string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ሲገናኙ በዚህ ጡባዊ ላይ የተጫኑ መተግበሪያዎችን እንዲደርስ ለ&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; የርቀት መዳረሻ እንዲያቀርብ ይፍቀዱለት።"</string>
<string name="summary_app_streaming" product="device" msgid="7614171699434639963">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ሲገናኙ በዚህ መሳሪያ ላይ የተጫኑ መተግበሪያዎችን እንዲደርስ ለ&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; የርቀት መዳረሻ እንዲያቀርብ ይፍቀዱለት።"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"መሣሪያ ተሻጋሪ አገልግሎቶች"</string>
+ <string name="helper_summary_app_streaming" msgid="5344341720432827388">"ይህ አገልግሎት በእርስዎ መሣሪያዎች መካከል መተግበሪያዎችን ለመልቀቅ ስራ ላይ ይውላል"</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>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"ማሳወቂያዎች"</string>
+ <string name="permission_notification_summary" msgid="4398672775023193663">"እንደ ውሎች፣ መልዕክቶች እና ፎቶዎች ያሉ መረጃዎችን ጨምሮ ሁሉንም ማሳወቂያዎች ማንበብ ይችላል"</string>
+ <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>
+ <string name="helper_summary_computer" product="default" msgid="467996390095403648">"ይህ አገልግሎት ፎቶዎችን፣ ሚዲያዎችን እና ማሳወቂያዎችን ከስልክዎ ለሌሎች መሣሪያዎች ያጋራል"</string>
+ <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"ይህ አገልግሎት ፎቶዎችን፣ ሚዲያዎችን እና ማሳወቂያዎችን ከስልክዎ ለሌሎች መሣሪያዎች ያጋራል"</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>
+ <string name="consent_ok" msgid="3662376764371001106">"እሺ"</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-ar/strings.xml b/packages/CompanionDeviceManager/res/values-ar/strings.xml
index b4c74ad07e40..5c00999d6a31 100644
--- a/packages/CompanionDeviceManager/res/values-ar/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ar/strings.xml
@@ -22,18 +22,30 @@
<string name="chooser_title" msgid="2262294130493605839">"‏اختَر <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ليديره تطبيق &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="summary_watch" product="default" msgid="7113724443198337683">"سيتم السماح لتطبيق <xliff:g id="APP_NAME">%1$s</xliff:g> بالتفاعل مع الإشعارات والوصول إلى أذونات الهاتف والرسائل القصيرة وجهات الاتصال والتقويم."</string>
<string name="summary_watch" product="tablet" msgid="7113724443198337683">"سيتم السماح لتطبيق <xliff:g id="APP_NAME">%1$s</xliff:g> بالتفاعل مع الإشعارات والوصول إلى أذونات الهاتف والرسائل القصيرة وجهات الاتصال والتقويم."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"‏هل تريد السماح لتطبيق &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ببث التطبيقات؟"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"التطبيقات"</string>
+ <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="summary_app_streaming" product="default" msgid="6105916810614498138">"‏السماح لتطبيق &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; بمنح الإذن بالوصول عن بُعد إلى التطبيقات المثبَّتة &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; الإذن بالوصول عن بُعد إلى التطبيقات المثبَّتة على هذا الهاتف عندما يكون متصلاً بالإنترنت."</string>
<string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"‏السماح لتطبيق &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; بمنح &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; الإذن بالوصول عن بُعد إلى التطبيقات المثبَّتة على هذا الجهاز اللوحي عندما يكون متصلاً بالإنترنت."</string>
<string name="summary_app_streaming" product="device" msgid="7614171699434639963">"‏السماح لتطبيق &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; بمنح &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; الإذن بالوصول عن بُعد إلى التطبيقات المثبَّتة على هذا الجهاز عندما يكون متصلاً بالإنترنت."</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"الخدمات التي تعمل بين الأجهزة"</string>
+ <string name="helper_summary_app_streaming" msgid="5344341720432827388">"تُستخدَم هذه الخدمة لبث التطبيقات بين الأجهزة."</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>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"الإشعارات"</string>
+ <string name="permission_notification_summary" msgid="4398672775023193663">"يمكن لهذا الملف الشخصي قراءة جميع الإشعارات، بما في ذلك المعلومات، مثل جهات الاتصال والرسائل والصور."</string>
+ <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>
+ <string name="helper_summary_computer" product="default" msgid="467996390095403648">"تشارك هذه الخدمة الصور والوسائط والإشعارات من هاتفك إلى أجهزة أخرى."</string>
+ <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"تشارك هذه الخدمة الصور والوسائط والإشعارات من هاتفك إلى أجهزة أخرى."</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>
+ <string name="consent_ok" msgid="3662376764371001106">"حسنًا"</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-as/strings.xml b/packages/CompanionDeviceManager/res/values-as/strings.xml
index b2865dc79ad5..dbb5c3b000a8 100644
--- a/packages/CompanionDeviceManager/res/values-as/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-as/strings.xml
@@ -22,18 +22,30 @@
<string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;এ পৰিচালনা কৰিব লগা এটা <xliff:g id="PROFILE_NAME">%1$s</xliff:g> বাছনি কৰক"</string>
<string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g>ক আপোনাৰ জাননী ব্যৱহাৰ কৰিবলৈ আৰু আপোনাৰ ফ’ন, এছএমএছ, সম্পৰ্ক আৰু কেলেণ্ডাৰৰ অনুমতি এক্সেছ কৰিবলৈ দিয়া হ’ব।"</string>
<string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g>ক আপোনাৰ জাননী ব্যৱহাৰ কৰিবলৈ আৰু আপোনাৰ ফ’ন, এছএমএছ, সম্পৰ্ক আৰু কেলেণ্ডাৰৰ অনুমতি এক্সেছ কৰিবলৈ দিয়া হ’ব।"</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;ক এপ্লিকেশ্বন ষ্ট্ৰীম কৰিবলৈ অনুমতি দিবনে?"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"এপ্‌"</string>
+ <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="summary_app_streaming" product="default" msgid="6105916810614498138">"সংযোগ কৰিলে &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;ক এই ফ’নটোত ইনষ্টল কৰি থোৱা এপ্লিকেশ্বনসমূহ এক্সেছ কৰিবলৈ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;ক ৰিম’ট এক্সেছ দিবলৈ দিয়ক।"</string>
<string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"সংযোগ কৰিলে &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;ক এই টেবলেটটোত ইনষ্টল কৰি থোৱা এপ্লিকেশ্বনসমূহ এক্সেছ কৰিবলৈ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;ক ৰিম’ট এক্সেছ দিবলৈ দিয়ক।"</string>
<string name="summary_app_streaming" product="device" msgid="7614171699434639963">"সংযোগ কৰিলে &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;ক এই ডিভাইচটোত ইনষ্টল কৰি থোৱা এপ্লিকেশ্বনসমূহ এক্সেছ কৰিবলৈ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;ক ৰিম’ট এক্সেছ দিবলৈ দিয়ক।"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"ক্ৰছ-ডিভাইচ সেৱাসমূহ"</string>
+ <string name="helper_summary_app_streaming" msgid="5344341720432827388">"এই সেৱাটো আপোনাৰ ডিভাইচবোৰৰ মাজত এপ্‌ ষ্ট্ৰীম কৰিবলৈ ব্যৱহাৰ কৰা হয়"</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>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"জাননী"</string>
+ <string name="permission_notification_summary" msgid="4398672775023193663">"চুক্তি, বাৰ্তা আৰু ফট’ৰ দৰে তথ্যকে ধৰি আটাইবোৰ জাননী পঢ়িব পাৰে"</string>
+ <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>
+ <string name="helper_summary_computer" product="default" msgid="467996390095403648">"এই সেৱাটোৱে আপোনাৰ ফ\'নৰ পৰা অন্য ডিভাইচলৈ ফট’, মিডিয়া আৰু জাননী শ্বেয়াৰ কৰে"</string>
+ <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"এই সেৱাটোৱে আপোনাৰ ফ\'নৰ পৰা অন্য ডিভাইচলৈ ফট’, মিডিয়া আৰু জাননী শ্বেয়াৰ কৰে"</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>
+ <string name="consent_ok" msgid="3662376764371001106">"ঠিক আছে"</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 e8e4e7631481..a0b5b8c0c3fd 100644
--- a/packages/CompanionDeviceManager/res/values-az/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-az/strings.xml
@@ -22,18 +22,30 @@
<string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; tərəfindən idarə ediləcək <xliff:g id="PROFILE_NAME">%1$s</xliff:g> seçin"</string>
<string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> bildirişlərinizə, Telefon, SMS, Kontaktlar və Təqvimə giriş əldə edəcək."</string>
<string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> bildirişlərinizə, Telefon, SMS, Kontaktlar və Təqvimə giriş əldə edəcək."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; tətbiqinin tətbiqlərdə yayım etməsinə icazə verilsin?"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Tətbiqlər"</string>
+ <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="summary_app_streaming" product="default" msgid="6105916810614498138">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; tətbiqinə &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; cihazının qoşulduqda bu telefonda quraşdırılmış tətbiqlərə uzaqdan giriş icazəsi verməsinə imkan verin."</string>
<string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; tətbiqinə &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; cihazının qoşulduqda bu planşetdə quraşdırılmış tətbiqlərə uzaqdan giriş icazəsi verməsinə imkan verin."</string>
<string name="summary_app_streaming" product="device" msgid="7614171699434639963">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; tətbiqinə &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; cihazının qoşulduqda bu cihazda quraşdırılmış tətbiqlərə uzaqdan giriş icazəsi verməsinə imkan verin."</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Cihazlararası xidmətlər"</string>
+ <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Bu xidmət cihazlarınız arasında tətbiqləri yayımlamaq üçün istifadə olunur"</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>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Bildirişlər"</string>
+ <string name="permission_notification_summary" msgid="4398672775023193663">"Bütün bildirişləri, o cümlədən müqavilələr, mesajlar və fotolar kimi məlumatları oxuya bilər"</string>
+ <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>
+ <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Bu xidmət telefonunuzdakı foto, media və bildirişləri digər cihazlarla paylaşır"</string>
+ <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Bu xidmət telefonunuzdakı foto, media və bildirişləri digər cihazlarla paylaşır"</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>
+ <string name="consent_ok" msgid="3662376764371001106">"OK"</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 5d98a13e660e..78cac0a8c092 100644
--- a/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml
@@ -22,18 +22,30 @@
<string name="chooser_title" msgid="2262294130493605839">"Odaberite profil <xliff:g id="PROFILE_NAME">%1$s</xliff:g> kojim će upravljati aplikacija &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> će dobiti dozvolu za interakciju sa obaveštenjima i pristup dozvolama za telefon, SMS poruke, kontakte i kalendar."</string>
<string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> će dobiti dozvolu za interakciju sa obaveštenjima i pristup dozvolama za telefon, SMS poruke, kontakte i kalendar."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Želite da dozvolite aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; da strimuje aplikacije?"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Aplikacije"</string>
+ <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="summary_app_streaming" product="default" msgid="6105916810614498138">"Dozvolite aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; da daljinski pristupa aplikacijama instaliranim na telefonu &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; kada je povezan."</string>
<string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Dozvolite aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; da daljinski pristupa aplikacijama instaliranim na tabletu &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; kada je povezan."</string>
<string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Dozvolite aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; da daljinski pristupa aplikacijama instaliranim na uređaju &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; kada je povezan."</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Usluge na više uređaja"</string>
+ <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Ova usluga se koristi za strimovanje aplikacija između uređaja"</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>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Obaveštenja"</string>
+ <string name="permission_notification_summary" msgid="4398672775023193663">"Može da čita sva obaveštenja, uključujući informacije poput ugovora, poruka i slika"</string>
+ <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>
+ <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Ova usluga deli slike, medijski sadržaj i obaveštenja sa telefona na druge uređaje"</string>
+ <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Ova usluga deli slike, medijski sadržaj i obaveštenja sa telefona na druge uređaje"</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>
+ <string name="consent_ok" msgid="3662376764371001106">"Potvrdi"</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-be/strings.xml b/packages/CompanionDeviceManager/res/values-be/strings.xml
index 3a57bcc34fb6..ed521b1bf6fa 100644
--- a/packages/CompanionDeviceManager/res/values-be/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-be/strings.xml
@@ -22,18 +22,30 @@
<string name="chooser_title" msgid="2262294130493605839">"Выберыце прыладу (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>), якой будзе кіраваць праграма &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> атрымае доступ да вашых апавяшчэнняў, тэлефона, SMS, кантактаў і календара."</string>
<string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> атрымае доступ да вашых апавяшчэнняў, тэлефона, SMS, кантактаў і календара."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Дазволіць праграме &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; перадаваць праграмы плынню?"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Праграмы"</string>
+ <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="summary_app_streaming" product="default" msgid="6105916810614498138">"Дазвольце праграме &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; атрымліваць аддалены доступ да праграм, усталяваных на тэлефоне &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; (калі тэлефон падключаны)."</string>
<string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Дазвольце праграме &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; атрымліваць аддалены доступ да праграм, усталяваных на планшэце &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; (калі планшэт падключаны)."</string>
<string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Дазвольце праграме &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; атрымліваць аддалены доступ да праграм, усталяваных на прыладзе &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; (калі прылада падключана)."</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Сэрвісы для некалькіх прылад"</string>
+ <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Гэты сэрвіс выкарыстоўваецца для перадачы праграм плынню паміж прыладамі"</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>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Апавяшчэнні"</string>
+ <string name="permission_notification_summary" msgid="4398672775023193663">"Можа счытваць усе апавяшчэнні, уключаючы паведамленні, фота і інфармацыю пра кантакты"</string>
+ <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>
+ <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Гэты сэрвіс абагульвае з іншымі прыладамі фота, медыяфайлы і апавяшчэнні, якія захоўваюцца на вашым тэлефоне"</string>
+ <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Гэты сэрвіс абагульвае з іншымі прыладамі фота, медыяфайлы і апавяшчэнні, якія захоўваюцца на вашым тэлефоне"</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>
+ <string name="consent_ok" msgid="3662376764371001106">"ОК"</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-bg/strings.xml b/packages/CompanionDeviceManager/res/values-bg/strings.xml
index d29a9081afc0..fe65bda4b434 100644
--- a/packages/CompanionDeviceManager/res/values-bg/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-bg/strings.xml
@@ -22,18 +22,30 @@
<string name="chooser_title" msgid="2262294130493605839">"Изберете устройство (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>), което да се управлява от &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ще получи разрешение да взаимодейства с известията ви и да осъществява достъп до разрешенията за телефона, SMS съобщенията, контактите и календара."</string>
<string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ще получи разрешение да взаимодейства с известията ви и да осъществява достъп до разрешенията за телефона, SMS съобщенията, контактите и календара."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Разрешавате ли на &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да предава поточно приложения?"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Приложения"</string>
+ <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="summary_app_streaming" product="default" msgid="6105916810614498138">"Разрешете на &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да предоставя на &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; отдалечен достъп до приложенията, инсталирани на този телефон, когато има установена връзка."</string>
<string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Разрешете на &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да предоставя на &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; отдалечен достъп до приложенията, инсталирани на този таблет, когато има установена връзка."</string>
<string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Разрешете на &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да предоставя на &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; отдалечен достъп до приложенията, инсталирани на това устройство, когато има установена връзка."</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Услуги за различни устройства"</string>
+ <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Тази услуга служи за поточно предаване на приложения между устройствата ви"</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>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Известия"</string>
+ <string name="permission_notification_summary" msgid="4398672775023193663">"Може да чете всички известия, включително различна информация, като например договори, съобщения и снимки"</string>
+ <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>
+ <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Тази услуга споделя с други устройства снимки, мултимедия и известия от телефона ви"</string>
+ <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Тази услуга споделя с други устройства снимки, мултимедия и известия от телефона ви"</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>
+ <string name="consent_ok" msgid="3662376764371001106">"OK"</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-bn/strings.xml b/packages/CompanionDeviceManager/res/values-bn/strings.xml
index 7d0b097f2a99..58c6c265aa96 100644
--- a/packages/CompanionDeviceManager/res/values-bn/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-bn/strings.xml
@@ -22,18 +22,30 @@
<string name="chooser_title" msgid="2262294130493605839">"<xliff:g id="PROFILE_NAME">%1$s</xliff:g> বেছে নিন যেটি &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; ম্যানেজ করবে"</string>
<string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> আপনার বিজ্ঞপ্তির সাথে ইন্টার‌্যাক্ট করতে পারবে, তার সাথে আপনার ফোন, এমএসএস, পরিচিতি এবং ক্যালেন্ডারের অনুমতিও অ্যাক্সেস করতে পারবে।"</string>
<string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> আপনার বিজ্ঞপ্তির সাথে ইন্টার‌্যাক্ট করতে পারবে, তার সাথে আপনার ফোন, এমএসএস, পরিচিতি এবং ক্যালেন্ডারের অনুমতিও অ্যাক্সেস করতে পারবে।"</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"অ্যাপ্লিকেশন স্ট্রিম করার জন্য &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; কে অনুমতি দেবেন?"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"অ্যাপ"</string>
+ <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="summary_app_streaming" product="default" msgid="6105916810614498138">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; কে &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;এ দূরবর্তী অ্যাক্সেস প্রদান করতে দিন যাতে কানেক্ট থাকাকালীন এই ফোনে ইনস্টল করা অ্যাপ্লিকেশনগুলিতে অ্যাক্সেস করা যায়।"</string>
<string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; কে &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;এ দূরবর্তী অ্যাক্সেস প্রদান করতে দিন যাতে কানেক্ট থাকাকালীন এই ট্যাবলেটে ইনস্টল করা অ্যাপ্লিকেশনগুলিতে অ্যাক্সেস করা যায়।"</string>
<string name="summary_app_streaming" product="device" msgid="7614171699434639963">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; কে &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;এ দূরবর্তী অ্যাক্সেস প্রদান করতে দিন যাতে কানেক্ট থাকাকালীন এই ডিভাইসে ইনস্টল করা অ্যাপ্লিকেশনগুলিতে অ্যাক্সেস করা যায়।"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"ক্রস-ডিভাইস পরিষেবা"</string>
+ <string name="helper_summary_app_streaming" msgid="5344341720432827388">"আপনার ডিভাইসের মধ্যে অ্যাপ স্ট্রিম করার জন্য এই পরিষেবা ব্যবহার করা হয়"</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>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"বিজ্ঞপ্তি"</string>
+ <string name="permission_notification_summary" msgid="4398672775023193663">"চুক্তি, মেসেজ ও ফটোর সহ সব বিজ্ঞপ্তি পড়তে পারে"</string>
+ <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>
+ <string name="helper_summary_computer" product="default" msgid="467996390095403648">"এই পরিষেবা আপনার ফোন থেকে অন্যান্য ডিভাইসে ফটো, মিডিয়া ও বিজ্ঞপ্তি শেয়ার করে"</string>
+ <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"এই পরিষেবা আপনার ফোন থেকে অন্যান্য ডিভাইসে ফটো, মিডিয়া ও বিজ্ঞপ্তি শেয়ার করে"</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>
+ <string name="consent_ok" msgid="3662376764371001106">"ঠিক আছে"</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-bs/strings.xml b/packages/CompanionDeviceManager/res/values-bs/strings.xml
index a723da8f59a4..1ce89443afff 100644
--- a/packages/CompanionDeviceManager/res/values-bs/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-bs/strings.xml
@@ -22,18 +22,30 @@
<string name="chooser_title" msgid="2262294130493605839">"Odaberite uređaj <xliff:g id="PROFILE_NAME">%1$s</xliff:g> kojim će upravljati aplikacija &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="summary_watch" product="default" msgid="7113724443198337683">"Aplikaciji <xliff:g id="APP_NAME">%1$s</xliff:g> će se dozvoliti da ostvari interakciju s vašim obavještenjima i da pristupi odobrenjima za Telefon, SMS, Kontakte i Kalendar."</string>
<string name="summary_watch" product="tablet" msgid="7113724443198337683">"Aplikaciji <xliff:g id="APP_NAME">%1$s</xliff:g> će se dozvoliti da ostvari interakciju s vašim obavještenjima i da pristupi odobrenjima za Telefon, SMS, Kontakte i Kalendar."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Dozvoliti da &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; prenosi aplikacije?"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Aplikacije"</string>
+ <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="summary_app_streaming" product="default" msgid="6105916810614498138">"Dozvolite da &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; omogući daljinski pristup uređaju &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; radi pristupanja aplikacijama instaliranim na ovom telefonu kada je povezan s mrežom."</string>
<string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Dozvolite da &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; omogući daljinski pristup uređaju &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; radi pristupanja aplikacijama instaliranim na ovom tabletu kada je povezan s mrežom."</string>
<string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Dozvolite da &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; omogući daljinski pristup uređaju &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; radi pristupanja aplikacijama instaliranim na njemu kada je povezan s mrežom."</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Usluga na više uređaja"</string>
+ <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Ova usluga se koristi za prijenos aplikacija između vaših uređaja"</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 aplikacija &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; pristupa ovim informacijama s vašeg telefona"</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>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Obavještenja"</string>
+ <string name="permission_notification_summary" msgid="4398672775023193663">"Može čitati sva obavještenja, uključujući informacije kao što su kontakti, poruke i fotografije"</string>
+ <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>
+ <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Ova usluga dijeli fotografije, medijski sadržaj i obavještenja s vašeg telefona na druge uređaje"</string>
+ <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Ova usluga dijeli fotografije, medijski sadržaj i obavještenja s vašeg telefona na druge uređaje"</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>
+ <string name="consent_ok" msgid="3662376764371001106">"Uredu"</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-ca/strings.xml b/packages/CompanionDeviceManager/res/values-ca/strings.xml
index de7e2256ede8..0b1847692faf 100644
--- a/packages/CompanionDeviceManager/res/values-ca/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ca/strings.xml
@@ -22,18 +22,30 @@
<string name="chooser_title" msgid="2262294130493605839">"Tria un <xliff:g id="PROFILE_NAME">%1$s</xliff:g> perquè el gestioni &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> tindrà permís per interaccionar amb les teves notificacions i accedir al telèfon, als SMS, als contactes i al calendari."</string>
<string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> tindrà permís per interaccionar amb les teves notificacions i accedir al telèfon, als SMS, als contactes i al calendari."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Vols permetre que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; reprodueixi aplicacions en continu?"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Aplicacions"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"Reprodueix en continu aplicacions del telèfon"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"Permet que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; accedeixi a aquesta informació del telèfon"</string>
<string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Permet que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; proporcioni accés remot a &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; per accedir a les aplicacions instal·lades en aquest telèfon quan estigui connectat."</string>
<string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Permet que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; proporcioni accés remot a &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; per accedir a les aplicacions instal·lades en aquesta tauleta quan estigui connectada."</string>
<string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Permet que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; proporcioni accés remot a &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; per accedir a les aplicacions instal·lades en aquest dispositiu quan estigui connectat."</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Serveis multidispositiu"</string>
+ <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Aquest servei s\'utilitza per reproduir en continu aplicacions entre dispositius"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Permet que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; accedeixi a aquesta informació del telèfon"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Notificacions"</string>
+ <string name="permission_notification_summary" msgid="4398672775023193663">"Pot llegir totes les notificacions, inclosa informació com ara els contactes, els missatges i les fotos"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"Fotos i contingut multimèdia"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Serveis de Google Play"</string>
+ <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Aquest servei comparteix fotos, contingut multimèdia i notificacions amb altres dispositius des del teu telèfon"</string>
+ <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Aquest servei comparteix fotos, contingut multimèdia i notificacions amb altres dispositius des del teu telèfon"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"dispositiu"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Permet"</string>
<string name="consent_no" msgid="2640796915611404382">"No permetis"</string>
+ <string name="consent_ok" msgid="3662376764371001106">"D\'acord"</string>
<string name="permission_sync_confirmation_title" msgid="667074294393493186">"Transfereix els permisos de les aplicacions al teu rellotge"</string>
<string name="permission_sync_summary" msgid="8873391306499120778">"Per facilitar la configuració del rellotge, les aplicacions instal·lades al rellotge durant la configuració utilitzaran els mateixos permisos que al teu telèfon.\n\n Aquests permisos poden incloure l\'accés al micròfon i a la ubicació del rellotge."</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-cs/strings.xml b/packages/CompanionDeviceManager/res/values-cs/strings.xml
index f195e54f743c..f89f17ef0c66 100644
--- a/packages/CompanionDeviceManager/res/values-cs/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-cs/strings.xml
@@ -22,18 +22,30 @@
<string name="chooser_title" msgid="2262294130493605839">"Vyberte zařízení <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, které chcete spravovat pomocí aplikace &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="summary_watch" product="default" msgid="7113724443198337683">"Aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> bude moci interagovat s vašimi oznámeními a získá přístup k telefonu, SMS, kontaktům a kalendáři."</string>
<string name="summary_watch" product="tablet" msgid="7113724443198337683">"Aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> bude moci interagovat s vašimi oznámeními a získá přístup k telefonu, SMS, kontaktům a kalendáři."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Povolit aplikaci &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; streamovat aplikace?"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Aplikace"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"Streamujte aplikace v telefonu"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"Povolte aplikaci &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; přístup k těmto informacím z vašeho telefonu"</string>
<string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Povolit aplikaci &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; poskytovat &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; vzdálený přístup k aplikacím nainstalovaným v tomto telefonu, když je připojen."</string>
<string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Povolit aplikaci &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; poskytovat &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; vzdálený přístup k aplikacím nainstalovaným v tomto tabletu, když je připojen."</string>
<string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Povolit aplikaci &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; poskytovat &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; vzdálený přístup k aplikacím nainstalovaným v tomto zařízení, když je připojeno."</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Služby pro více zařízení"</string>
+ <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Tato služba slouží ke streamování aplikací mezi zařízeními"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Povolte aplikaci &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; přístup k těmto informacím z vašeho telefonu"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Oznámení"</string>
+ <string name="permission_notification_summary" msgid="4398672775023193663">"Může číst veškerá oznámení včetně informací, jako jsou kontakty, zprávy a fotky"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"Fotky a média"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Služby Google Play"</string>
+ <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Tato služba sdílí fotky, média a oznámení z telefonu do ostatních zařízení"</string>
+ <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Tato služba sdílí fotky, média a oznámení z telefonu do ostatních zařízení"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"zařízení"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Povolit"</string>
<string name="consent_no" msgid="2640796915611404382">"Nepovolovat"</string>
+ <string name="consent_ok" msgid="3662376764371001106">"OK"</string>
<string name="permission_sync_confirmation_title" msgid="667074294393493186">"Přesunout oprávnění aplikací do hodinek"</string>
<string name="permission_sync_summary" msgid="8873391306499120778">"Abychom vám usnadnili nastavení hodinek, aplikace nainstalované do hodinek během úvodního nastavení budou používat stejná oprávnění jako váš telefon.\n\n Tato oprávnění mohou zahrnovat přístup k mikrofonu a poloze hodinek."</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-da/strings.xml b/packages/CompanionDeviceManager/res/values-da/strings.xml
index a2aa5dddb43c..e366bb91d6ac 100644
--- a/packages/CompanionDeviceManager/res/values-da/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-da/strings.xml
@@ -22,18 +22,30 @@
<string name="chooser_title" msgid="2262294130493605839">"Vælg den enhed (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>), som skal administreres af &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> får tilladelse til at interagere med dine notifikationer og adgang til dine tilladelser for Opkald, Sms, Kontakter og Kalender."</string>
<string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> får tilladelse til at interagere med dine notifikationer og adgang til dine tilladelser for Opkald, Sms, Kontakter og Kalender."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Vil du give &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; tilladelse til at streame apps?"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Apps"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"Stream din telefons apps"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"Giv &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; adgang til disse oplysninger fra din telefon"</string>
<string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Giver &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; tilladelse til at fjernstyre apps, som er installeret på &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;, når telefonen har forbindelse til internettet."</string>
<string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Giver &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; tilladelse til at fjernstyre apps, som er installeret på &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;, når tabletten har forbindelse til internettet."</string>
<string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Giver &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; tilladelse til at fjernstyre apps, som er installeret på &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;, når enheden har forbindelse til internettet."</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Tjenester, som kan tilsluttes en anden enhed"</string>
+ <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Denne tjeneste anvendes til at caste apps mellem dine enheder"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Tillad, at &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; får adgang til disse oplysninger fra din telefon"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Notifikationer"</string>
+ <string name="permission_notification_summary" msgid="4398672775023193663">"Kan læse alle notifikationer, herunder oplysninger som f.eks. kontakter, beskeder og billeder"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"Billeder og medier"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Google Play-tjenester"</string>
+ <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Denne tjeneste deler billeder, medier og notifikationer fra din telefon til andre enheder"</string>
+ <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Denne tjeneste deler billeder, medier og notifikationer fra din telefon til andre enheder"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"enhed"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Tillad"</string>
<string name="consent_no" msgid="2640796915611404382">"Tillad ikke"</string>
+ <string name="consent_ok" msgid="3662376764371001106">"OK"</string>
<string name="permission_sync_confirmation_title" msgid="667074294393493186">"Overfør apptilladelser til dit ur"</string>
<string name="permission_sync_summary" msgid="8873391306499120778">"For at gøre det nemmere at konfigurere dit ur vil de apps, der installeres under konfigurationen, anvende de samme tilladelser som din telefon.\n\n Disse tilladelser kan omfatte adgang til dit urs mikrofon og lokation."</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-de/strings.xml b/packages/CompanionDeviceManager/res/values-de/strings.xml
index 2b5ab117900e..440e06b54304 100644
--- a/packages/CompanionDeviceManager/res/values-de/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-de/strings.xml
@@ -22,18 +22,30 @@
<string name="chooser_title" msgid="2262294130493605839">"Gerät (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>) auswählen, das von &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; verwaltet werden soll"</string>
<string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> darf mit deinen Benachrichtigungen interagieren und auf die Berechtigungen „Telefon“, „SMS“, „Kontakte“ und „Kalender“ zugreifen."</string>
<string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> darf mit deinen Benachrichtigungen interagieren und auf die Berechtigungen „Telefon“, „SMS“, „Kontakte“ und „Kalender“ zugreifen."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Möchtest du &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; erlauben, Apps zu streamen?"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Apps"</string>
+ <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="summary_app_streaming" product="default" msgid="6105916810614498138">"Besteht eine Verbindung, darf &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; Remotezugriff auf die auf diesem Smartphone installierten Apps geben."</string>
<string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Besteht eine Verbindung, darf &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; Remotezugriff auf die auf diesem Tablet installierten Apps geben."</string>
<string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Besteht eine Verbindung, darf &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; Remotezugriff auf die auf diesem Gerät installierten Apps geben."</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Geräteübergreifende Dienste"</string>
+ <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Dieser Dienst wird dazu verwendet, Apps zwischen deinen Geräten zu streamen"</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>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Benachrichtigungen"</string>
+ <string name="permission_notification_summary" msgid="4398672775023193663">"Kann alle Benachrichtigungen lesen, einschließlich Informationen wie Verträgen, Nachrichten und Fotos"</string>
+ <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>
+ <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Dieser Dienst teilt Fotos, Medien und Benachrichtigungen von deinem Smartphone mit anderen Geräten"</string>
+ <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Dieser Dienst teilt Fotos, Medien und Benachrichtigungen von deinem Smartphone mit anderen 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>
+ <string name="consent_ok" msgid="3662376764371001106">"OK"</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-el/strings.xml b/packages/CompanionDeviceManager/res/values-el/strings.xml
index 339f85a58127..326527c5b0a5 100644
--- a/packages/CompanionDeviceManager/res/values-el/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-el/strings.xml
@@ -22,18 +22,30 @@
<string name="chooser_title" msgid="2262294130493605839">"Επιλέξτε ένα προφίλ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> για διαχείριση από την εφαρμογή &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="summary_watch" product="default" msgid="7113724443198337683">"Η εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> θα επιτρέπεται να αλληλεπιδρά με τις ειδοποιήσεις σας και να έχει πρόσβαση στις άδειες Τηλεφώνου, SMS, Επαφών και Ημερολογίου."</string>
<string name="summary_watch" product="tablet" msgid="7113724443198337683">"Η εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> θα επιτρέπεται να αλληλεπιδρά με τις ειδοποιήσεις σας και να έχει πρόσβαση στις άδειες Τηλεφώνου, SMS, Επαφών και Ημερολογίου."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Να επιτρέπεται στην εφαρμογή &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; η ροή εφαρμογών;"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Εφαρμογές"</string>
+ <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="summary_app_streaming" product="default" msgid="6105916810614498138">"Επιτρέψτε στην εφαρμογή &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; να παρέχει απομακρυσμένη πρόσβαση στη συσκευή &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; κατά τη σύνδεση, προκειμένου να έχει πρόσβαση σε εφαρμογές που έχουν εγκατασταθεί σε αυτό το τηλέφωνο."</string>
<string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Επιτρέψτε στην εφαρμογή &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; να παρέχει απομακρυσμένη πρόσβαση στη συσκευή &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; κατά τη σύνδεση, προκειμένου να έχει πρόσβαση σε εφαρμογές που έχουν εγκατασταθεί σε αυτό το tablet."</string>
<string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Επιτρέψτε στην εφαρμογή &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; να παρέχει απομακρυσμένη πρόσβαση στη συσκευή &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; κατά τη σύνδεση, προκειμένου να έχει πρόσβαση σε εφαρμογές που έχουν εγκατασταθεί σε αυτήν τη συσκευή."</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Υπηρεσίες πολλών συσκευών"</string>
+ <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Αυτή η υπηρεσία χρησιμοποιείται για τη ροή εφαρμογών μεταξύ των συσκευών σας"</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>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Ειδοποιήσεις"</string>
+ <string name="permission_notification_summary" msgid="4398672775023193663">"Μπορεί να διαβάσει όλες τις ειδοποιήσεις, συμπεριλαμβανομένων πληροφοριών όπως επαφές, μηνύματα και φωτογραφίες"</string>
+ <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>
+ <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Αυτή η υπηρεσία κοινοποιεί φωτογραφίες, πολυμέσα και ειδοποιήσεις από το τηλέφωνό σας σε άλλες συσκευές"</string>
+ <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Αυτή η υπηρεσία κοινοποιεί φωτογραφίες, πολυμέσα και ειδοποιήσεις από το τηλέφωνό σας σε άλλες συσκευές"</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>
+ <string name="consent_ok" msgid="3662376764371001106">"OK"</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-en-rAU/strings.xml b/packages/CompanionDeviceManager/res/values-en-rAU/strings.xml
index d59641111959..9b8f95942983 100644
--- a/packages/CompanionDeviceManager/res/values-en-rAU/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-en-rAU/strings.xml
@@ -22,18 +22,30 @@
<string name="chooser_title" msgid="2262294130493605839">"Choose a <xliff:g id="PROFILE_NAME">%1$s</xliff:g> to be managed by &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> will be allowed to interact with your notifications and access your Phone, SMS, Contacts and Calendar permissions."</string>
<string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> will be allowed to interact with your notifications and access your Phone, SMS, Contacts and Calendar permissions."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Allow &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to stream applications?"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Apps"</string>
+ <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="summary_app_streaming" product="default" msgid="6105916810614498138">"Let &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; provide &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; remote access to access to applications installed on this phone when connected."</string>
<string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Let &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; provide &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; remote access to access to applications installed on this tablet when connected."</string>
<string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Let &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; provide &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; remote access to access to applications installed on this device when connected."</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Cross-device services"</string>
+ <string name="helper_summary_app_streaming" msgid="5344341720432827388">"This service is used to stream apps between your devices"</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>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Notifications"</string>
+ <string name="permission_notification_summary" msgid="4398672775023193663">"Can read all notifications, including information such as contracts, messages and photos"</string>
+ <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>
+ <string name="helper_summary_computer" product="default" msgid="467996390095403648">"This service shares photos, media and notifications from your phone to other devices"</string>
+ <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"This service shares photos, media and notifications from your phone to other 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>
+ <string name="consent_ok" msgid="3662376764371001106">"OK"</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 d59641111959..9b8f95942983 100644
--- a/packages/CompanionDeviceManager/res/values-en-rCA/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-en-rCA/strings.xml
@@ -22,18 +22,30 @@
<string name="chooser_title" msgid="2262294130493605839">"Choose a <xliff:g id="PROFILE_NAME">%1$s</xliff:g> to be managed by &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> will be allowed to interact with your notifications and access your Phone, SMS, Contacts and Calendar permissions."</string>
<string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> will be allowed to interact with your notifications and access your Phone, SMS, Contacts and Calendar permissions."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Allow &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to stream applications?"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Apps"</string>
+ <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="summary_app_streaming" product="default" msgid="6105916810614498138">"Let &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; provide &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; remote access to access to applications installed on this phone when connected."</string>
<string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Let &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; provide &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; remote access to access to applications installed on this tablet when connected."</string>
<string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Let &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; provide &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; remote access to access to applications installed on this device when connected."</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Cross-device services"</string>
+ <string name="helper_summary_app_streaming" msgid="5344341720432827388">"This service is used to stream apps between your devices"</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>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Notifications"</string>
+ <string name="permission_notification_summary" msgid="4398672775023193663">"Can read all notifications, including information such as contracts, messages and photos"</string>
+ <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>
+ <string name="helper_summary_computer" product="default" msgid="467996390095403648">"This service shares photos, media and notifications from your phone to other devices"</string>
+ <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"This service shares photos, media and notifications from your phone to other 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>
+ <string name="consent_ok" msgid="3662376764371001106">"OK"</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 d59641111959..9b8f95942983 100644
--- a/packages/CompanionDeviceManager/res/values-en-rGB/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-en-rGB/strings.xml
@@ -22,18 +22,30 @@
<string name="chooser_title" msgid="2262294130493605839">"Choose a <xliff:g id="PROFILE_NAME">%1$s</xliff:g> to be managed by &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> will be allowed to interact with your notifications and access your Phone, SMS, Contacts and Calendar permissions."</string>
<string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> will be allowed to interact with your notifications and access your Phone, SMS, Contacts and Calendar permissions."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Allow &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to stream applications?"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Apps"</string>
+ <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="summary_app_streaming" product="default" msgid="6105916810614498138">"Let &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; provide &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; remote access to access to applications installed on this phone when connected."</string>
<string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Let &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; provide &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; remote access to access to applications installed on this tablet when connected."</string>
<string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Let &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; provide &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; remote access to access to applications installed on this device when connected."</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Cross-device services"</string>
+ <string name="helper_summary_app_streaming" msgid="5344341720432827388">"This service is used to stream apps between your devices"</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>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Notifications"</string>
+ <string name="permission_notification_summary" msgid="4398672775023193663">"Can read all notifications, including information such as contracts, messages and photos"</string>
+ <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>
+ <string name="helper_summary_computer" product="default" msgid="467996390095403648">"This service shares photos, media and notifications from your phone to other devices"</string>
+ <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"This service shares photos, media and notifications from your phone to other 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>
+ <string name="consent_ok" msgid="3662376764371001106">"OK"</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 d59641111959..9b8f95942983 100644
--- a/packages/CompanionDeviceManager/res/values-en-rIN/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-en-rIN/strings.xml
@@ -22,18 +22,30 @@
<string name="chooser_title" msgid="2262294130493605839">"Choose a <xliff:g id="PROFILE_NAME">%1$s</xliff:g> to be managed by &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> will be allowed to interact with your notifications and access your Phone, SMS, Contacts and Calendar permissions."</string>
<string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> will be allowed to interact with your notifications and access your Phone, SMS, Contacts and Calendar permissions."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Allow &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to stream applications?"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Apps"</string>
+ <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="summary_app_streaming" product="default" msgid="6105916810614498138">"Let &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; provide &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; remote access to access to applications installed on this phone when connected."</string>
<string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Let &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; provide &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; remote access to access to applications installed on this tablet when connected."</string>
<string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Let &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; provide &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; remote access to access to applications installed on this device when connected."</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Cross-device services"</string>
+ <string name="helper_summary_app_streaming" msgid="5344341720432827388">"This service is used to stream apps between your devices"</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>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Notifications"</string>
+ <string name="permission_notification_summary" msgid="4398672775023193663">"Can read all notifications, including information such as contracts, messages and photos"</string>
+ <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>
+ <string name="helper_summary_computer" product="default" msgid="467996390095403648">"This service shares photos, media and notifications from your phone to other devices"</string>
+ <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"This service shares photos, media and notifications from your phone to other 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>
+ <string name="consent_ok" msgid="3662376764371001106">"OK"</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-rXC/strings.xml b/packages/CompanionDeviceManager/res/values-en-rXC/strings.xml
index 9f17a89099d6..8bd1c4a76735 100644
--- a/packages/CompanionDeviceManager/res/values-en-rXC/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-en-rXC/strings.xml
@@ -22,18 +22,30 @@
<string name="chooser_title" msgid="2262294130493605839">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‏‏‎‏‏‎‎‏‎‏‎‏‎‎‏‎‎‎‏‎‎‎‎‏‏‎‏‎‎‎‏‎‎‏‏‎‎‎‎‏‎‏‏‏‎‎‎‏‏‏‏‏‎‎‏‏‏‏‎Choose a ‎‏‎‎‏‏‎<xliff:g id="PROFILE_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎ to be managed by &lt;strong&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%2$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/strong&gt;‎‏‎‎‏‎"</string>
<string name="summary_watch" product="default" msgid="7113724443198337683">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‏‎‏‎‏‏‏‎‎‏‎‎‎‎‎‏‏‎‏‎‏‏‎‎‎‎‏‏‏‎‎‎‏‎‏‏‎‏‏‎‎‏‏‎‏‏‎‎‏‎‏‎‎‏‎‎‏‏‎‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎ will be allowed to interact with your notifications and access your Phone, SMS, Contacts and Calendar permissions.‎‏‎‎‏‎"</string>
<string name="summary_watch" product="tablet" msgid="7113724443198337683">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‏‎‏‎‏‏‏‎‎‏‎‎‎‎‎‏‏‎‏‎‏‏‎‎‎‎‏‏‏‎‎‎‏‎‏‏‎‏‏‎‎‏‏‎‏‏‎‎‏‎‏‎‎‏‎‎‏‏‎‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎ will be allowed to interact with your notifications and access your Phone, SMS, Contacts and Calendar permissions.‎‏‎‎‏‎"</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‎‏‏‏‏‎‎‎‏‎‎‎‎‎‏‎‎‏‎‎‎‏‏‏‎‎‏‏‎‎‎‏‏‎‏‏‎‎‏‏‎‏‏‎‎‏‎‏‎‏‏‎‎‏‏‏‏‎‎Allow &lt;strong&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/strong&gt; to stream applications?‎‏‎‎‏‎"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‎‏‎‎‏‏‏‏‎‏‎‎‏‏‏‏‎‏‏‎‏‎‏‎‎‏‏‎‎‏‎‎‎‎‏‎‎‎‎‏‎‏‎‏‏‏‎‎‎‎‏‎‎‏‏‏‏‎‎Apps‎‏‎‎‏‎"</string>
+ <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="summary_app_streaming" product="default" msgid="6105916810614498138">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‎‎‏‎‏‏‏‏‎‎‏‎‎‏‎‎‏‎‏‏‏‏‏‏‎‏‎‎‎‏‏‏‎‎‏‏‎‎‎‎‏‏‎‏‏‎‎‎‏‏‎‏‎‏‏‎‏‎‎Let &lt;strong&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/strong&gt; to provide &lt;strong&gt;‎‏‎‎‏‏‎<xliff:g id="DEVICE_NAME">%2$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/strong&gt; remote access to access to applications installed on this phone when connected.‎‏‎‎‏‎"</string>
<string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‎‏‏‎‎‏‎‏‎‏‎‏‎‎‎‎‏‎‎‎‎‎‎‏‎‎‏‏‏‎‏‎‏‎‎‏‏‏‏‏‎‎‏‎‏‎‎‏‎‏‎‎‎‏‏‎‎‎‎Let &lt;strong&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/strong&gt; to provide &lt;strong&gt;‎‏‎‎‏‏‎<xliff:g id="DEVICE_NAME">%2$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/strong&gt; remote access to access to applications installed on this tablet when connected.‎‏‎‎‏‎"</string>
<string name="summary_app_streaming" product="device" msgid="7614171699434639963">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‏‏‎‏‎‏‎‏‎‏‏‏‏‏‎‎‎‏‏‎‏‎‎‎‏‏‎‏‎‏‎‏‏‏‎‏‎‎‎‏‎‎‏‎‏‎‎‏‎‎‏‎‏‏‎‏‏‎Let &lt;strong&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/strong&gt; to provide &lt;strong&gt;‎‏‎‎‏‏‎<xliff:g id="DEVICE_NAME">%2$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/strong&gt; remote access to access to applications installed on this device when connected.‎‏‎‎‏‎"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‎‏‏‎‎‏‏‏‎‏‏‏‎‎‎‎‎‏‎‏‎‏‎‏‎‏‎‏‎‎‎‎‏‎‏‎‏‎‎‏‎‏‎‎‏‏‎‏‎‏‏‏‏‎‎‏‎‏‎Cross-device services‎‏‎‎‏‎"</string>
+ <string name="helper_summary_app_streaming" msgid="5344341720432827388">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‏‎‎‎‏‎‏‎‏‎‏‏‏‎‏‎‏‎‎‏‏‏‏‎‏‎‏‎‏‎‏‏‎‎‏‎‏‏‎‎‏‎‏‏‎‏‏‎‏‏‏‏‏‏‏‏‎‎‎This service is used to stream apps between your devices‎‏‎‎‏‎"</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>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‎‏‏‎‏‎‎‎‎‎‏‎‏‏‏‏‎‏‎‏‏‎‎‎‎‏‎‏‎‎‎‏‏‏‏‎‏‏‎‏‏‏‎‏‏‏‏‏‎‏‎‎‎‏‎‎‏‏‎Notifications‎‏‎‎‏‎"</string>
+ <string name="permission_notification_summary" msgid="4398672775023193663">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‎‏‎‎‎‎‏‎‏‏‎‎‏‏‏‎‎‏‏‎‎‏‎‏‎‏‎‏‏‎‏‏‏‎‎‏‏‏‎‎‎‎‎‏‏‎‏‏‏‎‎‎‏‏‏‏‏‏‎Can read all notifications, including information like contracts, messages, and photos‎‏‎‎‏‎"</string>
+ <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>
+ <string name="helper_summary_computer" product="default" msgid="467996390095403648">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‏‎‎‏‏‏‏‏‏‎‏‎‏‎‏‎‎‎‎‎‏‏‏‏‎‎‏‎‏‏‏‎‏‏‏‏‎‎‏‏‎‏‎‎‏‏‏‎‏‎‏‎‎‎‎‎‎‎‎This service shares photos, media, and notifications form your phone to other devices‎‏‎‎‏‎"</string>
+ <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‏‎‎‏‏‏‏‏‏‎‏‎‏‎‏‎‎‎‎‎‏‏‏‏‎‎‏‎‏‏‏‎‏‏‏‏‎‎‏‏‎‏‎‎‏‏‏‎‏‎‏‎‎‎‎‎‎‎‎This service shares photos, media, and notifications form your phone to other 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>
+ <string name="consent_ok" msgid="3662376764371001106">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‏‎‏‏‎‏‎‎‏‏‎‏‏‎‎‎‎‎‎‏‎‎‎‎‏‏‎‏‎‏‏‎‎‏‏‏‏‏‏‎‏‎‎‏‎‏‏‏‏‏‎‎‎‏‎‎‏‎‎OK‎‏‎‎‏‎"</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-es-rUS/strings.xml b/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml
index 5423d3eeff87..e5b22a2ed01b 100644
--- a/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml
@@ -22,18 +22,30 @@
<string name="chooser_title" msgid="2262294130493605839">"Elige un <xliff:g id="PROFILE_NAME">%1$s</xliff:g> para que &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; lo administre"</string>
<string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> podrá interactuar con tus notificaciones y acceder a los permisos de Teléfono, SMS, Contactos y Calendario."</string>
<string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> podrá interactuar con tus notificaciones y acceder a los permisos de Teléfono, SMS, Contactos y Calendario."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"¿Deseas permitir que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; transmita aplicaciones?"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Apps"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"Transmitir las apps de tu teléfono"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"Permite que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; acceda a esta información de tu teléfono"</string>
<string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Permite que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; proporcione a &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; acceso remoto a las aplicaciones instaladas en este teléfono cuando esté conectado."</string>
<string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Permite que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; proporcione &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; acceso remoto a las aplicaciones instaladas en esta tablet cuando esté conectada."</string>
<string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Permite que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; proporcione a &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; acceso remoto a las aplicaciones instaladas en este dispositivo cuando esté conectado."</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Servicios multidispositivo"</string>
+ <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Este servicio se utiliza para transmitir apps entre tus dispositivos"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Permite que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; acceda a esta información de tu teléfono"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Notificaciones"</string>
+ <string name="permission_notification_summary" msgid="4398672775023193663">"Puede leer todas las notificaciones, incluso con información como contratos, mensajes y fotos"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"Fotos y contenido multimedia"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Servicios de Google Play"</string>
+ <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Este servicio comparte fotos, contenido multimedia y notificaciones de tu teléfono a otros dispositivos"</string>
+ <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Este servicio comparte fotos, contenido multimedia y notificaciones de tu teléfono a otros dispositivos"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Permitir"</string>
<string name="consent_no" msgid="2640796915611404382">"No permitir"</string>
+ <string name="consent_ok" msgid="3662376764371001106">"Aceptar"</string>
<string name="permission_sync_confirmation_title" msgid="667074294393493186">"Transfiere los permisos de la app a tu reloj"</string>
<string name="permission_sync_summary" msgid="8873391306499120778">"Para que sea más fácil configurar tu reloj, las apps que se instalen en este durante la configuración usarán los mismos permisos que tu teléfono.\n\n Es posible que estos permisos incluyan el acceso al micrófono y a la ubicación del reloj."</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-es/strings.xml b/packages/CompanionDeviceManager/res/values-es/strings.xml
index ccbdd250dad2..1a988e96aaef 100644
--- a/packages/CompanionDeviceManager/res/values-es/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-es/strings.xml
@@ -22,18 +22,30 @@
<string name="chooser_title" msgid="2262294130493605839">"Elige un <xliff:g id="PROFILE_NAME">%1$s</xliff:g> para gestionarlo con &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> podrá interactuar con tus notificaciones y acceder a tus permisos de teléfono, SMS, contactos y calendario."</string>
<string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> podrá interactuar con tus notificaciones y acceder a tus permisos de teléfono, SMS, contactos y calendario."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"¿Permitir que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; inicie aplicaciones?"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Aplicaciones"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"Emite las aplicaciones de tu teléfono"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"Permitir que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; acceda a esta información desde tu teléfono"</string>
<string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Permite que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; acceda de forma remota a las aplicaciones instaladas en este teléfono cuando &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; esté conectado a Internet."</string>
<string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Permite que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; acceda de forma remota a las aplicaciones instaladas en este tablet cuando &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; esté conectado a Internet."</string>
<string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Permite que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; acceda de forma remota a las aplicaciones instaladas en este dispositivo cuando &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; esté conectado a Internet."</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Servicios multidispositivo"</string>
+ <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Este servicio se usa para emitir aplicaciones en otros dispositivos tuyos"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Permitir que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; acceda a esta información desde tu teléfono"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Notificaciones"</string>
+ <string name="permission_notification_summary" msgid="4398672775023193663">"Puede leer todas las notificaciones, incluida información como contactos, mensajes y fotos"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"Fotos y elementos multimedia"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Servicios de Google Play"</string>
+ <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Este servicio comparte fotos, archivos multimedia y notificaciones de tu teléfono con otros dispositivos"</string>
+ <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Este servicio comparte fotos, archivos multimedia y notificaciones de tu teléfono con otros dispositivos"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Permitir"</string>
<string name="consent_no" msgid="2640796915611404382">"No permitir"</string>
+ <string name="consent_ok" msgid="3662376764371001106">"Aceptar"</string>
<string name="permission_sync_confirmation_title" msgid="667074294393493186">"Transferir permisos de aplicaciones a tu reloj"</string>
<string name="permission_sync_summary" msgid="8873391306499120778">"Para configurar fácilmente tu reloj, las aplicaciones que instales en él durante la configuración usarán los mismos permisos que tengan en tu teléfono.\n\n Estos permisos pueden incluir acceso al micrófono y a la ubicación del reloj."</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-et/strings.xml b/packages/CompanionDeviceManager/res/values-et/strings.xml
index d8f1e9920736..f3b8ea92817c 100644
--- a/packages/CompanionDeviceManager/res/values-et/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-et/strings.xml
@@ -22,18 +22,30 @@
<string name="chooser_title" msgid="2262294130493605839">"Valige seade <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, mida haldab rakendus &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> saab kasutada teie märguandeid ning pääseda juurde teie telefoni, SMS-ide, kontaktide ja kalendri lubadele."</string>
<string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> saab kasutada teie märguandeid ning pääseda juurde teie telefoni, SMS-ide, kontaktide ja kalendri lubadele."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Kas lubada rakendusel &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; rakendusi voogesituse kaudu üle kanda?"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Rakendused"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"Telefoni rakenduste voogesitamine"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"Lubage rakendusel &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; pääseda teie telefonis juurde sellele teabele"</string>
<string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Rakendusel &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; lubatakse seadmele &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; pakkuda kaugjuurdepääsu, et ühendatuna pääseda juurde sellesse telefoni installitud rakendustele."</string>
<string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Rakendusel &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; lubatakse seadmele &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; pakkuda kaugjuurdepääsu, et ühendatuna pääseda juurde sellesse tahvelarvutisse installitud rakendustele."</string>
<string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Rakendusel &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; lubatakse seadmele &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; pakkuda kaugjuurdepääsu, et ühendatuna pääseda juurde sellesse seadmesse installitud rakendustele."</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Seadmeülesed teenused"</string>
+ <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Seda teenust kasutatakse rakenduste voogesitamiseks teie seadmete vahel"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Lubage rakendusel &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; pääseda teie telefonis juurde sellele teabele"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Märguanded"</string>
+ <string name="permission_notification_summary" msgid="4398672775023193663">"Kõikide märguannete, sealhulgas teabe, nagu kontaktid, sõnumid ja fotod, lugemine"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"Fotod ja meedia"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Google Play teenused"</string>
+ <string name="helper_summary_computer" product="default" msgid="467996390095403648">"See teenus jagab muude seadmetega teie telefonist pärit fotosid, meediat ja märguandeid"</string>
+ <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"See teenus jagab muude seadmetega teie telefonist pärit fotosid, meediat ja märguandeid"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"seade"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Luba"</string>
<string name="consent_no" msgid="2640796915611404382">"Ära luba"</string>
+ <string name="consent_ok" msgid="3662376764371001106">"OK"</string>
<string name="permission_sync_confirmation_title" msgid="667074294393493186">"Rakenduste lubade kellale ülekandmine"</string>
<string name="permission_sync_summary" msgid="8873391306499120778">"Selleks et muuta kella seadistamine lihtsamaks, kasutavad teie kellas seadistamise ajal installitud rakendused samasid lubasid, mis neile telefonis antud on.\n\n Need load võivad hõlmata juurdepääsuluba kella mikrofonile ja asukohale."</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-eu/strings.xml b/packages/CompanionDeviceManager/res/values-eu/strings.xml
index de768249916c..0d4f073be50b 100644
--- a/packages/CompanionDeviceManager/res/values-eu/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-eu/strings.xml
@@ -22,18 +22,30 @@
<string name="chooser_title" msgid="2262294130493605839">"Aukeratu &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; aplikazioak kudeatu beharreko <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
<string name="summary_watch" product="default" msgid="7113724443198337683">"Jakinarazpenekin interakzioan aritzeko eta telefonoa, SMSak, kontaktuak eta egutegia erabiltzeko baimenak izango ditu <xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioak."</string>
<string name="summary_watch" product="tablet" msgid="7113724443198337683">"Jakinarazpenekin interakzioan aritzeko eta telefonoa, SMSak, kontaktuak eta egutegia erabiltzeko baimenak izango ditu <xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioak."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Aplikazioak igortzeko baimena eman nahi diozu &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; aplikazioari?"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Aplikazioak"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"Igorri zuzenean telefonoko aplikazioak"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"Eman informazioa telefonotik hartzeko baimena &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; aplikazioari"</string>
<string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Utzi &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; aplikazioari &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; urrunetik atzitzen, telefonoa konektatuta dagoenean bertan instalatuta dauden aplikazioetarako sarbidea izateko."</string>
<string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Utzi &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; aplikazioari &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; urrunetik atzitzen, tableta konektatuta dagoenean bertan instalatuta dauden aplikazioetarako sarbidea izateko."</string>
<string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Utzi &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; aplikazioari &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; urrunetik atzitzen, gailua konektatuta dagoenean bertan instalatuta dauden aplikazioetarako sarbidea izateko."</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Gailu bat baino gehiagotarako zerbitzuak"</string>
+ <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Gailuen artean aplikazioak igortzeko erabiltzen da zerbitzua"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Eman informazio hori telefonotik hartzeko baimena &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; aplikazioari"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Jakinarazpenak"</string>
+ <string name="permission_notification_summary" msgid="4398672775023193663">"Jakinarazpen guztiak irakur ditzake; besteak beste, kontaktuak, mezuak, argazkiak eta antzeko informazioa"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"Argazkiak eta multimedia-edukia"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Google Play Services"</string>
+ <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Zerbitzuak telefonoko argazkiak, multimedia-edukia eta jakinarazpenak partekatzen ditu beste gailuekin"</string>
+ <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Zerbitzuak telefonoko argazkiak, multimedia-edukia eta jakinarazpenak partekatzen ditu beste gailuekin"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"gailua"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Eman baimena"</string>
<string name="consent_no" msgid="2640796915611404382">"Ez eman baimenik"</string>
+ <string name="consent_ok" msgid="3662376764371001106">"Ados"</string>
<string name="permission_sync_confirmation_title" msgid="667074294393493186">"Transferitu aplikazio-baimenak erlojura"</string>
<string name="permission_sync_summary" msgid="8873391306499120778">"Erlojua errazago konfiguratzeko, konfigurazio-prozesua abian zen bitartean erlojuan instalatutako aplikazioek telefonoak darabiltzan baimen berak erabiliko dituzte.\n\n Baliteke baimen horien artean erlojuaren mikrofonoa eta kokapena atzitzeko baimenak egotea."</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-fa/strings.xml b/packages/CompanionDeviceManager/res/values-fa/strings.xml
index 65ed2dde864f..cb14c27c333e 100644
--- a/packages/CompanionDeviceManager/res/values-fa/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-fa/strings.xml
@@ -22,18 +22,30 @@
<string name="chooser_title" msgid="2262294130493605839">"‏انتخاب <xliff:g id="PROFILE_NAME">%1$s</xliff:g> برای مدیریت کردن با &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>‏&lt;/strong&gt;"</string>
<string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> می‌تواند با اعلان‌های شما تعامل داشته باشد و به اجازه‌های «تلفن»، «پیامک»، «مخاطبین»، و «تقویم» دسترسی پیدا کند."</string>
<string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> می‌تواند با اعلان‌های شما تعامل داشته باشد و به اجازه‌های «تلفن»، «پیامک»، «مخاطبین»، و «تقویم» دسترسی پیدا کند."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"‏به &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; اجازه می‌دهید برنامه‌ها را جاری‌سازی کند؟"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"برنامه‌ها"</string>
+ <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="summary_app_streaming" product="default" msgid="6105916810614498138">"‏به &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; اجازه می‌دهد برای &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; دسترسی ازراه‌دور ارائه دهد تا دستگاه موردنظر بتواند هنگام اتصال، به برنامه‌های نصب‌شده در این تلفن دسترسی داشته باشد."</string>
<string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"‏به &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; اجازه می‌دهد برای &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; دسترسی ازراه‌دور ارائه دهد تا دستگاه موردنظر بتواند هنگام اتصال، به برنامه‌های نصب‌شده در این رایانه لوحی دسترسی داشته باشد."</string>
<string name="summary_app_streaming" product="device" msgid="7614171699434639963">"‏به &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; اجازه می‌دهد برای &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; دسترسی ازراه‌دور ارائه دهد تا دستگاه موردنظر بتواند هنگام اتصال، به برنامه‌های نصب‌شده در این دستگاه دسترسی داشته باشد."</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"سرویس‌های بین‌دستگاهی"</string>
+ <string name="helper_summary_app_streaming" msgid="5344341720432827388">"از این سرویس برای جاری‌سازی برنامه‌ها میان دستگاه‌هایتان استفاده می‌شود"</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>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"اعلان‌ها"</string>
+ <string name="permission_notification_summary" msgid="4398672775023193663">"می‌تواند همه اعلان‌ها، ازجمله اطلاعاتی مثل قراردادها، پیام‌ها، و عکس‌ها را بخواند"</string>
+ <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>
+ <string name="helper_summary_computer" product="default" msgid="467996390095403648">"این سرویس عکس‌ها، رسانه، و اعلان‌های تلفن را با دستگاه‌های دیگر هم‌رسانی می‌کند"</string>
+ <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"این سرویس عکس‌ها، رسانه، و اعلان‌های تلفن را با دستگاه‌های دیگر هم‌رسانی می‌کند"</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>
+ <string name="consent_ok" msgid="3662376764371001106">"تأیید"</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-fi/strings.xml b/packages/CompanionDeviceManager/res/values-fi/strings.xml
index c8dbeb54402a..a1c15f131892 100644
--- a/packages/CompanionDeviceManager/res/values-fi/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-fi/strings.xml
@@ -22,18 +22,30 @@
<string name="chooser_title" msgid="2262294130493605839">"Valitse <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, jota &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; hallinnoi"</string>
<string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> saa luvan hallinnoida ilmoituksiasi sekä pääsyn puhelimeesi, tekstiviesteihisi, kontakteihisi ja kalenteriisi."</string>
<string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> saa luvan hallinnoida ilmoituksiasi sekä pääsyn puhelimeesi, tekstiviesteihisi, kontakteihisi ja kalenteriisi."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Saako &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; striimata sovelluksia?"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Sovellukset"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"Striimaa puhelimen sovelluksia"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"Salli, että &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; saa pääsyn näihin puhelimesi tietoihin"</string>
<string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Salli, että &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; voi saada sovellukselta (&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>) etäpääsyoikeuden tälle puhelimelle asennettuihin sovelluksiin, kun laitteet on yhdistetty."</string>
<string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Salli, että &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; voi saada sovellukselta (&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>) etäpääsyoikeuden tälle tabletille asennettuihin sovelluksiin, kun laitteet on yhdistetty."</string>
<string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Salli, että &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; voi saada sovellukselta (&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>) etäpääsyoikeuden tälle laitteelle asennettuihin sovelluksiin, kun laitteet on yhdistetty."</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Laitteidenväliset palvelut"</string>
+ <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Palvelua käytetään sovellusten striimaukseen laitteiden välillä"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Salli pääsy tähän tietoon puhelimellasi: &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Ilmoitukset"</string>
+ <string name="permission_notification_summary" msgid="4398672775023193663">"Voi lukea kaikkia ilmoituksia, kuten sopimuksiin, viesteihin ja kuviin liittyviä tietoja"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"Kuvat ja media"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Google Play Palvelut"</string>
+ <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Palvelu jakaa kuvia, mediaa ja ilmoituksia puhelimelta muille laitteille"</string>
+ <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Palvelu jakaa kuvia, mediaa ja ilmoituksia puhelimelta muille laitteille"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"laite"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Salli"</string>
<string name="consent_no" msgid="2640796915611404382">"Älä salli"</string>
+ <string name="consent_ok" msgid="3662376764371001106">"OK"</string>
<string name="permission_sync_confirmation_title" msgid="667074294393493186">"Siirrä sovellusluvat kelloon"</string>
<string name="permission_sync_summary" msgid="8873391306499120778">"Sovellukset, jotka on asennettu kelloon käyttöönoton aikana, käyttävät samoja lupia kuin puhelin. Näin kello on helpompi ottaa käyttöön.\n\n Näihin lupiin saattaa kuulua pääsy kellon mikrofoniin ja sijaintiin."</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml b/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml
index 3d5898b0a5a9..5bc04397f5fa 100644
--- a/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml
@@ -22,18 +22,30 @@
<string name="chooser_title" msgid="2262294130493605839">"Choisissez un <xliff:g id="PROFILE_NAME">%1$s</xliff:g> qui sera géré par &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> aura l\'autorisation d\'interagir avec vos notifications et d\'accéder aux autorisations pour votre téléphone, vos messages texte, vos contacts et votre agenda."</string>
<string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> aura l\'autorisation d\'interagir avec vos notifications et d\'accéder aux autorisations pour votre téléphone, vos messages texte, vos contacts et votre agenda."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Permettre à l\'application &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; de diffuser des applications?"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Applications"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"Diffusez les applications de votre téléphone"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"Autorisez &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; à accéder à ces informations à partir de votre téléphone"</string>
<string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Permettez à l\'application &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; de donner à l\'appareil &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; un accès à distance aux applications installées sur ce téléphone lorsqu\'il est connecté."</string>
<string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Permettez à l\'application &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; de donner à l\'appareil &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; un accès à distance aux applications installées sur cette tablette lorsqu\'elle est connectée."</string>
<string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Permettez à l\'application &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; de donner à l\'appareil &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; un accès à distance aux applications installées sur cet appareil lorsqu\'il est connecté."</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Services multiappareils"</string>
+ <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Ce service est utilisé pour diffuser des applications entre vos appareils"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Autorisez &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; à accéder à ces informations à partir de votre téléphone"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Notifications"</string>
+ <string name="permission_notification_summary" msgid="4398672775023193663">"Peut lire toutes les notifications, y compris les renseignements tels que les contacts, les messages et les photos"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"Photos et fichiers multimédias"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Services Google Play"</string>
+ <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Ce service partage des photos, du contenu multimédia et des notifications à partir de votre téléphone vers d\'autres appareils"</string>
+ <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Ce service partage des photos, du contenu multimédia et des notifications à partir de votre téléphone vers d\'autres appareils"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"appareil"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Autoriser"</string>
<string name="consent_no" msgid="2640796915611404382">"Ne pas autoriser"</string>
+ <string name="consent_ok" msgid="3662376764371001106">"OK"</string>
<string name="permission_sync_confirmation_title" msgid="667074294393493186">"Transférer les autorisations de l\'application à votre montre"</string>
<string name="permission_sync_summary" msgid="8873391306499120778">"Pour faciliter la configuration de votre montre, les applications installées sur celle-ci reprennent les mêmes autorisations que celles installées sur votre téléphone.\n\n Ces autorisations peuvent comprendre l\'accès au microphone et à la position de votre montre."</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-fr/strings.xml b/packages/CompanionDeviceManager/res/values-fr/strings.xml
index ecd89aa97ec9..acf4cd6d2ef2 100644
--- a/packages/CompanionDeviceManager/res/values-fr/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-fr/strings.xml
@@ -22,18 +22,30 @@
<string name="chooser_title" msgid="2262294130493605839">"Sélectionner le/la <xliff:g id="PROFILE_NAME">%1$s</xliff:g> qui sera géré(e) par &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> aura l\'autorisation d\'interagir avec vos notifications et d\'accéder au téléphone, aux SMS, aux contacts et à l\'agenda."</string>
<string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> aura l\'autorisation d\'interagir avec vos notifications et d\'accéder au téléphone, aux SMS, aux contacts et à l\'agenda."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Autoriser &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; à diffuser des applis en streaming ?"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Applis"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"Caster les applis de votre téléphone"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"Autoriser &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; à accéder à ces informations depuis votre téléphone"</string>
<string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Autoriser &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; à accéder à distance aux applis installées sur &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; quand ce téléphone est connecté à Internet."</string>
<string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Autoriser &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; à accéder à distance aux applis installées sur &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; quand cette tablette est connectée à Internet."</string>
<string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Autoriser &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; à accéder à distance aux applis installées sur &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; quand cet appareil est connecté à Internet."</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Services inter-appareils"</string>
+ <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Ce service est utilisé pour caster des applis d\'un appareil à l\'autre"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Autoriser &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; à accéder à ces informations depuis votre téléphone"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Notifications"</string>
+ <string name="permission_notification_summary" msgid="4398672775023193663">"Peut lire toutes les notifications, y compris des informations, comme les contacts, messages et photos"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"Photos et contenus multimédias"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Services Google Play"</string>
+ <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Ce service partage les photos, les contenus multimédias et les notifications de votre téléphone vers d\'autres appareils"</string>
+ <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Ce service partage les photos, les contenus multimédias et les notifications de votre téléphone vers d\'autres appareils"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"appareil"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Autoriser"</string>
<string name="consent_no" msgid="2640796915611404382">"Ne pas autoriser"</string>
+ <string name="consent_ok" msgid="3662376764371001106">"OK"</string>
<string name="permission_sync_confirmation_title" msgid="667074294393493186">"Transférer les autorisations de l\'appli vers la montre"</string>
<string name="permission_sync_summary" msgid="8873391306499120778">"Pour que votre montre soit plus facile à configurer, les applis qui y sont installées pendant la configuration utiliseront les mêmes autorisations que votre téléphone.\n\n Il peut s\'agir, par exemple, de l\'accès au micro et à la position de votre montre."</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-gl/strings.xml b/packages/CompanionDeviceManager/res/values-gl/strings.xml
index d060f29a7e02..d5f851580839 100644
--- a/packages/CompanionDeviceManager/res/values-gl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-gl/strings.xml
@@ -22,18 +22,30 @@
<string name="chooser_title" msgid="2262294130493605839">"Escolle un perfil (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>) para que o xestione a aplicación &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> poderá interactuar coas túas notificacións e acceder aos permisos do teu teléfono, das mensaxes, dos contactos e do calendario."</string>
<string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> poderá interactuar coas túas notificacións e acceder aos permisos do teu teléfono, das mensaxes, dos contactos e do calendario."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Queres permitir que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; emita aplicacións noutros dispositivos?"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Aplicacións"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"Emite as aplicacións do teu teléfono"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"Permitir que a aplicación &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; acceda a esta información desde o teu teléfono"</string>
<string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Permite que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; lle outorgue a &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; acceso remoto a aplicacións instaladas neste teléfono cando teña conexión a Internet."</string>
<string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Permite que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; lle outorgue a &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; acceso remoto a aplicacións instaladas nesta tableta cando teña conexión a Internet."</string>
<string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Permite que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; lle outorgue a &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; acceso remoto a aplicacións instaladas neste dispositivo cando teña conexión a Internet."</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Servizos multidispositivo"</string>
+ <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Este servizo utilízase para reproducir aplicacións en tempo real entre os teus dispositivos"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Permitir que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; acceda a esta información desde o teu teléfono"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Notificacións"</string>
+ <string name="permission_notification_summary" msgid="4398672775023193663">"Pode ler todas as notificacións (que poden incluír información como contactos, mensaxes e fotos)"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"Fotos e contido multimedia"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Servizos de Google Play"</string>
+ <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Este servizo comparte con outros dispositivos as fotos, o contido multimedia e as notificacións do teu teléfono"</string>
+ <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Este servizo comparte con outros dispositivos as fotos, o contido multimedia e as notificacións do teu teléfono"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Permitir"</string>
<string name="consent_no" msgid="2640796915611404382">"Non permitir"</string>
+ <string name="consent_ok" msgid="3662376764371001106">"Aceptar"</string>
<string name="permission_sync_confirmation_title" msgid="667074294393493186">"Transferir os permisos de aplicacións ao reloxo"</string>
<string name="permission_sync_summary" msgid="8873391306499120778">"Para que che resulte máis doado configurar o reloxo, as aplicacións que instales nel durante a configuración usarán os mesmos permisos que o teléfono.\n\n Entre estes permisos poden estar incluídos os de acceso ao micrófono e á localización do teléfono."</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-gu/strings.xml b/packages/CompanionDeviceManager/res/values-gu/strings.xml
index d06d8c677fd4..adfc6a0cc938 100644
--- a/packages/CompanionDeviceManager/res/values-gu/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-gu/strings.xml
@@ -22,18 +22,30 @@
<string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; દ્વારા મેનેજ કરવા માટે કોઈ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> પસંદ કરો"</string>
<string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g>ને તમારા નોટિફિકેશન સાથે ક્રિયાપ્રતિક્રિયા કરવાની તેમજ તમારો ફોન, SMS, સંપર્કો તેમજ કૅલેન્ડરની પરવાનગીઓ ઍક્સેસ કરવાની મંજૂરી આપવામાં આવશે."</string>
<string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g>ને તમારા નોટિફિકેશન સાથે ક્રિયાપ્રતિક્રિયા કરવાની તેમજ તમારો ફોન, SMS, સંપર્કો તેમજ કૅલેન્ડરની પરવાનગીઓ ઍક્સેસ કરવાની મંજૂરી આપવામાં આવશે."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"શું &lt;/strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;ને ઍપ્લિકેશનો સ્ટ્રીમ કરવાની મંજૂરી આપીએ?"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"ઍપ"</string>
+ <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="summary_app_streaming" product="default" msgid="6105916810614498138">"જ્યારે કનેક્ટ કરવામાં આવે, ત્યારે આ ફોન પર ઇન્સ્ટૉલ કરવામાં આવેલી ઍપ્લિકેશનોનો રિમોટ ઍક્સેસ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;ને &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;ને પ્રદાન કરવા દો."</string>
<string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"જ્યારે કનેક્ટ કરવામાં આવે, ત્યારે આ ટૅબ્લેટ પર ઇન્સ્ટૉલ કરવામાં આવેલી ઍપ્લિકેશનોનો રિમોટ ઍક્સેસ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;ને &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;ને પ્રદાન કરવા દો."</string>
<string name="summary_app_streaming" product="device" msgid="7614171699434639963">"જ્યારે કનેક્ટ કરવામાં આવે, ત્યારે આ ડિવાઇસ પર ઇન્સ્ટૉલ કરવામાં આવેલી ઍપ્લિકેશનોનો રિમોટ ઍક્સેસ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;ને &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;ને પ્રદાન કરવા દો."</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"ક્રોસ-ડિવાઇસ સેવાઓ"</string>
+ <string name="helper_summary_app_streaming" msgid="5344341720432827388">"આ સેવાનો ઉપયોગ તમારા ડિવાઇસ વચ્ચે ઍપ સ્ટ્રીમ કરવા માટે કરવામાં આવે છે"</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>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"નોટિફિકેશન"</string>
+ <string name="permission_notification_summary" msgid="4398672775023193663">"સંપર્કો, મેસેજ અને ફોટા જેવી માહિતી સહિતના બધા નોટિફિકેશન વાંચી શકે છે"</string>
+ <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>
+ <string name="helper_summary_computer" product="default" msgid="467996390095403648">"આ સેવા ફોટા, મીડિયા અને નોટિફિકેશનને તમારા ફોન પરથી અન્ય ડિવાઇસ પર શેર કરે છે"</string>
+ <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"આ સેવા ફોટા, મીડિયા અને નોટિફિકેશનને તમારા ફોન પરથી અન્ય ડિવાઇસ પર શેર કરે છે"</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>
+ <string name="consent_ok" msgid="3662376764371001106">"ઓકે"</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 1be6af8af0ec..71c5f12d4ac2 100644
--- a/packages/CompanionDeviceManager/res/values-hi/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-hi/strings.xml
@@ -22,18 +22,30 @@
<string name="chooser_title" msgid="2262294130493605839">"कोई <xliff:g id="PROFILE_NAME">%1$s</xliff:g> चुनें, ताकि उसे &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; की मदद से प्रबंधित किया जा सके"</string>
<string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> आपकी सूचनाओं पर कार्रवाई कर पाएगा. साथ ही, यह आपके फ़ोन, एसएमएस, संपर्कों, और कैलेंडर की अनुमतियों को भी ऐक्सेस कर पाएगा."</string>
<string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> आपकी सूचनाओं पर कार्रवाई कर पाएगा. साथ ही, यह आपके फ़ोन, एसएमएस, संपर्कों, और कैलेंडर की अनुमतियों को भी ऐक्सेस कर पाएगा."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; को ऐप्लिकेशन स्ट्रीम करने की अनुमति देनी है?"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"ऐप्लिकेशन"</string>
+ <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="summary_app_streaming" product="default" msgid="6105916810614498138">"कनेक्ट होने पर, &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; को &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; के रिमोट ऐक्सेस की अनुमति दें, ताकि इस फ़ोन पर इंस्टॉल किए गए ऐप्लिकेशन ऐक्सेस किए जा सकें."</string>
<string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"कनेक्ट होने पर, &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; को &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; के रिमोट ऐक्सेस की अनुमति दें, ताकि इस टैबलेट पर इंस्टॉल किए गए ऐप्लिकेशन ऐक्सेस किए जा सकें."</string>
<string name="summary_app_streaming" product="device" msgid="7614171699434639963">"कनेक्ट होने पर, &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; को &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; के रिमोट ऐक्सेस की अनुमति दें, ताकि इस डिवाइस पर इंस्टॉल किए गए ऐप्लिकेशन ऐक्सेस किए जा सकें."</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"क्रॉस-डिवाइस से जुड़ी सेवाएं"</string>
+ <string name="helper_summary_app_streaming" msgid="5344341720432827388">"इस सेवा का इस्तेमाल, आपके डिवाइसों के बीच ऐप्लिकेशन कास्ट करने के लिए किया जाता है"</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>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"सूचनाएं"</string>
+ <string name="permission_notification_summary" msgid="4398672775023193663">"इससे सभी सूचनाएं देखी जा सकती हैं. इसमें संपर्क, मैसेज, और फ़ोटो जैसी जानकारी शामिल है"</string>
+ <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>
+ <string name="helper_summary_computer" product="default" msgid="467996390095403648">"इस सेवा की मदद से, आपके फ़ोन से फ़ोटो, मीडिया, और सूचनाओं को दूसरे डिवाइसों के साथ शेयर किया जाता है"</string>
+ <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"इस सेवा की मदद से, आपके फ़ोन से फ़ोटो, मीडिया, और सूचनाओं को दूसरे डिवाइसों के साथ शेयर किया जाता है"</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>
+ <string name="consent_ok" msgid="3662376764371001106">"ठीक है"</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 610b7bdffa70..fd7e30275ddf 100644
--- a/packages/CompanionDeviceManager/res/values-hr/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-hr/strings.xml
@@ -22,18 +22,30 @@
<string name="chooser_title" msgid="2262294130493605839">"Odaberite profil <xliff:g id="PROFILE_NAME">%1$s</xliff:g> kojim će upravljati aplikacija &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="summary_watch" product="default" msgid="7113724443198337683">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> moći će stupati u interakciju s vašim obavijestima i pristupati dopuštenjima za telefon, SMS-ove, kontakte i kalendar."</string>
<string name="summary_watch" product="tablet" msgid="7113724443198337683">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> moći će stupati u interakciju s vašim obavijestima i pristupati dopuštenjima za telefon, SMS-ove, kontakte i kalendar."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Dopustiti aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; pokretanje streama aplikacija?"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Aplikacije"</string>
+ <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="summary_app_streaming" product="default" msgid="6105916810614498138">"Dopustite aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; da telefonu &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; omogući udaljeni pristup aplikacijama koje su instalirane na tom telefonu kada su povezani."</string>
<string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Dopustite aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; da tabletu &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; omogući udaljeni pristup aplikacijama koje su instalirane na tom tabletu kada su povezani."</string>
<string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Dopustite aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; da uređaju &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; omogući udaljeni pristup aplikacijama koje su instalirane na tom uređaju kada su povezani."</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Usluge na različitim uređajima"</string>
+ <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Ova se usluga koristi za streaming aplikacija između vaših uređaja"</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>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Obavijesti"</string>
+ <string name="permission_notification_summary" msgid="4398672775023193663">"Može čitati sve obavijesti, uključujući informacije kao što su kontakti, poruke i fotografije"</string>
+ <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>
+ <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Ova usluga dijeli fotografije, medijske sadržaje i obavijesti s vašeg telefona na druge uređaje"</string>
+ <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Ova usluga dijeli fotografije, medijske sadržaje i obavijesti s vašeg telefona na druge uređaje"</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>
+ <string name="consent_ok" msgid="3662376764371001106">"U redu"</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-hu/strings.xml b/packages/CompanionDeviceManager/res/values-hu/strings.xml
index 625a3e9cd4aa..c9ef48ad83f7 100644
--- a/packages/CompanionDeviceManager/res/values-hu/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-hu/strings.xml
@@ -22,18 +22,30 @@
<string name="chooser_title" msgid="2262294130493605839">"A(z) &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; alkalmazással kezelni kívánt <xliff:g id="PROFILE_NAME">%1$s</xliff:g> kiválasztása"</string>
<string name="summary_watch" product="default" msgid="7113724443198337683">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> műveleteket végezhet majd az értesítésekkel, és hozzáférhet a telefonra, az SMS-ekre, a névjegyekre és a naptárra vonatkozó engedélyekhez."</string>
<string name="summary_watch" product="tablet" msgid="7113724443198337683">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> műveleteket végezhet majd az értesítésekkel, és hozzáférhet a telefonra, az SMS-ekre, a névjegyekre és a naptárra vonatkozó engedélyekhez."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Engedélyezi a(z) &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; alkalmazásnak appok streamelését?"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Alkalmazások"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"A telefon alkalmazásainak streamelése"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"Engedélyezi a(z) „<xliff:g id="APP_NAME">%1$s</xliff:g>” alkalmazás számára az információhoz való hozzáférést a telefonról"</string>
<string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Engedélyezheti a(z) &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; alkalmazásnak, hogy a(z) &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; eszköz számára távoli hozzáférést biztosítson a telefonra telepített alkalmazásokhoz, amikor a telefon csatlakoztatva van."</string>
<string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Engedélyezheti a(z) &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; alkalmazásnak, hogy a(z) &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; eszköz számára távoli hozzáférést biztosítson a táblagépre telepített alkalmazásokhoz, amikor a táblagép csatlakoztatva van."</string>
<string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Engedélyezheti a(z) &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; alkalmazásnak, hogy a(z) &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; eszköz számára távoli hozzáférést biztosítson az eszközre telepített alkalmazásokhoz, amikor az eszköz csatlakoztatva van."</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Többeszközös szolgáltatások"</string>
+ <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Ez a szolgáltatás az eszközök közötti alkalmazásstreamelésre szolgál"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Engedélyezi a(z) „<xliff:g id="APP_NAME">%1$s</xliff:g>” alkalmazás számára az információhoz való hozzáférést a telefonról"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Értesítések"</string>
+ <string name="permission_notification_summary" msgid="4398672775023193663">"Elolvashat minden értesítést, ideértve az olyan információkat, mint a névjegyek, az üzenetek és a fotók"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"Fotók és médiatartalmak"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Google Play-szolgáltatások"</string>
+ <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Ezzel a szolgáltatással fényképeket, médiatartalmakat és értesítéseket küldhet át a telefonjáról más eszközökre"</string>
+ <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Ezzel a szolgáltatással fényképeket, médiatartalmakat és értesítéseket küldhet át a telefonjáról más eszközökre"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"eszköz"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Engedélyezés"</string>
<string name="consent_no" msgid="2640796915611404382">"Tiltás"</string>
+ <string name="consent_ok" msgid="3662376764371001106">"OK"</string>
<string name="permission_sync_confirmation_title" msgid="667074294393493186">"Alkalmazásengedélyek átvitele az órára"</string>
<string name="permission_sync_summary" msgid="8873391306499120778">"Az óra beállításának megkönnyítése érdekében a beállítás során az órára telepített alkalmazások ugyanazokat az engedélyeket használják majd, mint a telefonja.\n\n Ezek az engedélyek magukban foglalhatják az óra mikrofonjához és helyadataihoz való hozzáférést."</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-hy/strings.xml b/packages/CompanionDeviceManager/res/values-hy/strings.xml
index f09441fcdb4c..77c8befc6e24 100644
--- a/packages/CompanionDeviceManager/res/values-hy/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-hy/strings.xml
@@ -22,18 +22,30 @@
<string name="chooser_title" msgid="2262294130493605839">"Ընտրեք <xliff:g id="PROFILE_NAME">%1$s</xliff:g>ը, որը պետք է կառավարվի &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; հավելվածի կողմից"</string>
<string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածը կկարողանա փոխազդել ձեր ծանուցումների հետ և կստանա «Հեռախոս», «SMS», «Կոնտակտներ» և «Օրացույց» ծառայությունների թույլտվությունները։"</string>
<string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածը կկարողանա փոխազդել ձեր ծանուցումների հետ և կստանա «Հեռախոս», «SMS», «Կոնտակտներ» և «Օրացույց» ծառայությունների թույլտվությունները։"</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Թույլատրե՞լ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; հավելվածին բացել հավելվածներ"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Հավելվածներ"</string>
+ <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="summary_app_streaming" product="default" msgid="6105916810614498138">"Թույլ տվեք, որ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; հավելվածը կապի հաստատման դեպքում &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;-ին տրամադրի այս հեռախոսում տեղադրված հավելվածներ հեռակա մուտք գործելու թույլտվություն։"</string>
<string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Թույլ տվեք, որ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; հավելվածը կապի հաստատման դեպքում &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;-ին տրամադրի այս պլանշետում տեղադրված հավելվածներ հեռակա մուտք գործելու թույլտվություն։"</string>
<string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Թույլ տվեք, որ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; հավելվածը ինտերնետ կապի հաստատման դեպքում &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;-ին տրամադրի այս սարքում տեղադրված հավելվածներ հեռակա մուտք գործելու թույլտվություն։"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Միջսարքային ծառայություններ"</string>
+ <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Այս ծառայությունն օգտագործվում է ձեր սարքերի միջև հավելվածներ հեռարձակելու համար"</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>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Ծանուցումներ"</string>
+ <string name="permission_notification_summary" msgid="4398672775023193663">"Կարող է կարդալ բոլոր ծանուցումները, ներառյալ տեղեկությունները, օրինակ՝ կոնտակտները, հաղորդագրությունները և լուսանկարները"</string>
+ <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>
+ <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Այս ծառայությունը ձեր հեռախոսից լուսանկարներ, մեդիա ֆայլեր և ծանուցումներ է ուղարկում այլ սարքերի"</string>
+ <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Այս ծառայությունը ձեր հեռախոսից լուսանկարներ, մեդիա ֆայլեր և ծանուցումներ է ուղարկում այլ սարքերի"</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>
+ <string name="consent_ok" msgid="3662376764371001106">"Եղավ"</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-in/strings.xml b/packages/CompanionDeviceManager/res/values-in/strings.xml
index ef52808cd5ff..ff4363cc7c59 100644
--- a/packages/CompanionDeviceManager/res/values-in/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-in/strings.xml
@@ -22,18 +22,30 @@
<string name="chooser_title" msgid="2262294130493605839">"Pilih <xliff:g id="PROFILE_NAME">%1$s</xliff:g> untuk dikelola oleh &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> akan diizinkan berinteraksi dengan notifikasi dan mengakses izin Telepon, SMS, Kontak, dan Kalender."</string>
<string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> akan diizinkan berinteraksi dengan notifikasi dan mengakses izin Telepon, SMS, Kontak, dan Kalender."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Izinkan &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; men-streaming aplikasi?"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Aplikasi"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"Melakukan streaming aplikasi ponsel Anda"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"Izinkan &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; untuk mengakses informasi ini dari ponsel Anda"</string>
<string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Izinkan &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; memberikan akses jarak jauh ke &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; guna mengakses aplikasi yang diinstal di ponsel ini saat terhubung."</string>
<string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Izinkan &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; memberikan akses jarak jauh ke &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; guna mengakses aplikasi yang diinstal di tablet ini saat terhubung."</string>
<string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Izinkan &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; memberikan akses jarak jauh ke &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; guna mengakses aplikasi yang diinstal di perangkat ini saat terhubung."</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Layanan lintas perangkat"</string>
+ <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Layanan ini digunakan untuk menstreaming aplikasi antar-perangkat"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Izinkan &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; mengakses informasi ini dari ponsel Anda"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Notifikasi"</string>
+ <string name="permission_notification_summary" msgid="4398672775023193663">"Dapat membaca semua notifikasi, termasuk informasi seperti kontak, pesan, dan foto"</string>
+ <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">"Layanan Google Play"</string>
+ <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Layanan ini membagikan foto, media, dan notifikasi dari ponsel Anda ke perangkat lain"</string>
+ <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Layanan ini membagikan foto, media, dan notifikasi dari ponsel Anda ke perangkat lain"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"perangkat"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Izinkan"</string>
<string name="consent_no" msgid="2640796915611404382">"Jangan izinkan"</string>
+ <string name="consent_ok" msgid="3662376764371001106">"Oke"</string>
<string name="permission_sync_confirmation_title" msgid="667074294393493186">"Transfer izin aplikasi ke smartwatch"</string>
<string name="permission_sync_summary" msgid="8873391306499120778">"Untuk mempermudah penyiapan smartwatch, aplikasi yang diinstal di smartwatch selama penyiapan akan menggunakan izin yang sama dengan ponsel.\n\n Izin ini dapat meliputi akses ke mikrofon dan lokasi smartwatch."</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-is/strings.xml b/packages/CompanionDeviceManager/res/values-is/strings.xml
index c0ca2fcf3ba3..b8646c7ae976 100644
--- a/packages/CompanionDeviceManager/res/values-is/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-is/strings.xml
@@ -22,18 +22,30 @@
<string name="chooser_title" msgid="2262294130493605839">"Velja <xliff:g id="PROFILE_NAME">%1$s</xliff:g> sem &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; á að stjórna"</string>
<string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> fær aðgang að tilkynningum og heimildum síma, SMS, tengiliða og dagatals."</string>
<string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> fær aðgang að tilkynningum og heimildum síma, SMS, tengiliða og dagatals."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Leyfa &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; að streyma forritum?"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Forrit"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"Streymdu forritum símans"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"Veita &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; aðgang að þessum upplýsingum úr símanum þínum"</string>
<string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Leyfa &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; að veita &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; fjaraðgang að forritum sem eru sett upp í þessum síma þegar tenging er á."</string>
<string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Leyfa &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; að veita &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; fjaraðgang að forritum sem eru sett upp í þessari spjaldtölvu þegar tenging er á."</string>
<string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Leyfa &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; að veita &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; fjaraðgang að forritum sem eru sett upp í þessu tæki þegar tenging er á."</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Þjónustur á milli tækja"</string>
+ <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Þessi þjónusta er notuð til að streyma forritum á milli tækjanna þinna"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Veita &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; aðgang að þessum upplýsingum úr símanum þínum"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Tilkynningar"</string>
+ <string name="permission_notification_summary" msgid="4398672775023193663">"Getur lesið allar tilkynningar, þar á meðal upplýsingar á borð við samninga, skilaboð og myndir"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"Myndir og efni"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Þjónusta Google Play"</string>
+ <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Þessi þjónusta deilir myndum, margmiðlunarefni og tilkynningum úr símanum yfir í önnur tæki"</string>
+ <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Þessi þjónusta deilir myndum, margmiðlunarefni og tilkynningum úr símanum yfir í önnur tæki"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"tæki"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Leyfa"</string>
<string name="consent_no" msgid="2640796915611404382">"Ekki leyfa"</string>
+ <string name="consent_ok" msgid="3662376764371001106">"Í lagi"</string>
<string name="permission_sync_confirmation_title" msgid="667074294393493186">"Flytja heimildir forrita yfir í úrið"</string>
<string name="permission_sync_summary" msgid="8873391306499120778">"Til að auðvelda uppsetningu úrsins munu forrit sem eru sett upp í úrinu við uppsetningu nota sömu heimildir og stilltar eru í símanum.\n\n Þessar heimildir kunna að fela í sér aðgang að hljóðnema og staðsetningu úrsins."</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-it/strings.xml b/packages/CompanionDeviceManager/res/values-it/strings.xml
index 5f88b7a68432..4dfb69bbc7d1 100644
--- a/packages/CompanionDeviceManager/res/values-it/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-it/strings.xml
@@ -22,18 +22,30 @@
<string name="chooser_title" msgid="2262294130493605839">"Scegli un <xliff:g id="PROFILE_NAME">%1$s</xliff:g> che sia gestito da &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="summary_watch" product="default" msgid="7113724443198337683">"L\'app <xliff:g id="APP_NAME">%1$s</xliff:g> potrà interagire con le tue notifiche e accedere alle autorizzazioni Telefono, SMS, Contatti e Calendario."</string>
<string name="summary_watch" product="tablet" msgid="7113724443198337683">"L\'app <xliff:g id="APP_NAME">%1$s</xliff:g> potrà interagire con le tue notifiche e accedere alle autorizzazioni Telefono, SMS, Contatti e Calendario."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Vuoi consentire all\'app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; di riprodurre applicazioni in streaming?"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"App"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"Trasmetti in streaming le app del tuo telefono"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"Consenti all\'app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; di accedere a queste informazioni dal tuo telefono"</string>
<string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Consenti all\'app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; di fornire l\'accesso remoto a &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; per accedere alle applicazioni installate su questo telefono quando è connesso."</string>
<string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Consenti all\'app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; di fornire l\'accesso remoto a &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; per accedere alle applicazioni installate su questo tablet quando è connesso."</string>
<string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Consenti all\'app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; di fornire l\'accesso remoto a &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; per accedere alle applicazioni installate su questo dispositivo quando è connesso."</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Servizi cross-device"</string>
+ <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Questo servizio viene utilizzato per trasmettere in streaming le app tra i dispositivi"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Consenti a &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; di accedere a questa informazione dal tuo telefono"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Notifiche"</string>
+ <string name="permission_notification_summary" msgid="4398672775023193663">"Puoi leggere tutte le notifiche, incluse le informazioni come contatti, messaggi e foto"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"Foto e contenuti multimediali"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Google Play Services"</string>
+ <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Questo servizio condivide foto, contenuti multimediali e notifiche del telefono con altri dispositivi"</string>
+ <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Questo servizio condivide foto, contenuti multimediali e notifiche del telefono con altri dispositivi"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Consenti"</string>
<string name="consent_no" msgid="2640796915611404382">"Non consentire"</string>
+ <string name="consent_ok" msgid="3662376764371001106">"OK"</string>
<string name="permission_sync_confirmation_title" msgid="667074294393493186">"Trasferisci le autorizzazioni app all\'orologio"</string>
<string name="permission_sync_summary" msgid="8873391306499120778">"Per facilitare la configurazione dell\'orologio, le app installate su quest\'ultimo durante la configurazione useranno le stesse autorizzazioni delle app sul telefono.\n\n Queste autorizzazioni potrebbero includere l\'accesso al microfono e alla posizione dell\'orologio."</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-iw/strings.xml b/packages/CompanionDeviceManager/res/values-iw/strings.xml
index 4a811f0aef9d..a6373c108b55 100644
--- a/packages/CompanionDeviceManager/res/values-iw/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-iw/strings.xml
@@ -22,18 +22,30 @@
<string name="chooser_title" msgid="2262294130493605839">"‏בחירת <xliff:g id="PROFILE_NAME">%1$s</xliff:g> לניהול באמצעות &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="summary_watch" product="default" msgid="7113724443198337683">"‏האפליקציה <xliff:g id="APP_NAME">%1$s</xliff:g> תוכל לבצע פעולות בהתראות ותקבל הרשאות גישה לטלפון, ל-SMS לאנשי הקשר וליומן."</string>
<string name="summary_watch" product="tablet" msgid="7113724443198337683">"‏האפליקציה <xliff:g id="APP_NAME">%1$s</xliff:g> תוכל לבצע פעולות בהתראות ותקבל הרשאות גישה לטלפון, ל-SMS לאנשי הקשר וליומן."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"‏לאפשר לאפליקציה &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; לשדר אפליקציות?"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"אפליקציות"</string>
+ <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="summary_app_streaming" product="default" msgid="6105916810614498138">"‏האפליקציה &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; יכולה לספק ל-&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; גישה מרחוק כדי לגשת לאפליקציות שמותקנות בטלפון הזה כשיש חיבור."</string>
<string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"‏האפליקציה &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; יכולה לספק ל-&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; גישה מרחוק כדי לגשת לאפליקציות שמותקנות בטאבלט הזה כשיש חיבור."</string>
<string name="summary_app_streaming" product="device" msgid="7614171699434639963">"‏האפליקציה &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; יכולה לספק למכשיר &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; גישה מרחוק כדי לגשת לאפליקציות שמותקנות במכשיר הזה כשיש חיבור."</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"שירותים למספר מכשירים"</string>
+ <string name="helper_summary_app_streaming" msgid="5344341720432827388">"השירות הזה משמש לשידור אפליקציות בין המכשירים שברשותך"</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>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"התראות"</string>
+ <string name="permission_notification_summary" msgid="4398672775023193663">"גישה לכל ההתראות, כולל מידע כמו אנשי קשר, הודעות ותמונות"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"תמונות ומדיה"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Google Play Services"</string>
+ <string name="helper_summary_computer" product="default" msgid="467996390095403648">"השירות הזה משמש לשיתוף של תמונות, מדיה והתראות מהטלפון שלך עם מכשירים אחרים"</string>
+ <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"השירות הזה משמש לשיתוף של תמונות, מדיה והתראות מהטלפון שלך עם מכשירים אחרים"</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>
+ <string name="consent_ok" msgid="3662376764371001106">"אישור"</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-ja/strings.xml b/packages/CompanionDeviceManager/res/values-ja/strings.xml
index 5e8d544d9b6a..392ca0aa74d4 100644
--- a/packages/CompanionDeviceManager/res/values-ja/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ja/strings.xml
@@ -22,18 +22,30 @@
<string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; の管理対象となる<xliff:g id="PROFILE_NAME">%1$s</xliff:g>の選択"</string>
<string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> は通知を使用でき、電話、SMS、連絡先、カレンダーの権限にもアクセスできるようになります。"</string>
<string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> は通知を使用でき、電話、SMS、連絡先、カレンダーの権限にもアクセスできるようになります。"</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; にアプリのストリーミングを許可しますか?"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"アプリ"</string>
+ <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="summary_app_streaming" product="default" msgid="6105916810614498138">"インターネット接続時に &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; がスマートフォン内にインストールされているアプリにリモートでアクセスすることを &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; に許可します。"</string>
<string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"インターネット接続時に &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; がタブレット内にインストールされているアプリにリモートでアクセスすることを &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; に許可します。"</string>
<string name="summary_app_streaming" product="device" msgid="7614171699434639963">"インターネット接続時に &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; がデバイス内にインストールされているアプリにリモートでアクセスすることを &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>
+ <string name="helper_summary_app_streaming" msgid="5344341720432827388">"本サービスは、デバイス間でのアプリのストリーミングに使用されます"</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>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"通知"</string>
+ <string name="permission_notification_summary" msgid="4398672775023193663">"連絡先、メッセージ、写真に関する情報を含め、すべての通知を読み取ることができます"</string>
+ <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>
+ <string name="helper_summary_computer" product="default" msgid="467996390095403648">"本サービスは、スマートフォンから他のデバイスに写真、メディア、通知を共有します"</string>
+ <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"本サービスは、スマートフォンから他のデバイスに写真、メディア、通知を共有します"</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>
+ <string name="consent_ok" msgid="3662376764371001106">"OK"</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-ka/strings.xml b/packages/CompanionDeviceManager/res/values-ka/strings.xml
index 3b179bf237dd..f057b8bcc448 100644
--- a/packages/CompanionDeviceManager/res/values-ka/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ka/strings.xml
@@ -22,18 +22,30 @@
<string name="chooser_title" msgid="2262294130493605839">"აირჩიეთ <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, რომელიც უნდა მართოს &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;-მა"</string>
<string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> შეძლებს თქვენს შეტყობინებებთან ინტერაქციას და თქვენი ტელეფონის, SMS-ების, კონტაქტებისა და კალენდრის ნებართვებზე წვდომას."</string>
<string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> შეძლებს თქვენს შეტყობინებებთან ინტერაქციას და თქვენი ტელეფონის, SMS-ების, კონტაქტებისა და კალენდრის ნებართვებზე წვდომას."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"გსურთ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;-ს მისცეთ აპების სტრიმინგის საშუალება?"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"აპები"</string>
+ <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="summary_app_streaming" product="default" msgid="6105916810614498138">"მიეცით &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;-ს საშუალება, &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;-ისთვის დაუშვას დისტანციური წვდომა ამ ტელეფონზე დაინსტალირებულ აპებზე მასთან დაკავშირებისას."</string>
<string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"მიეცით &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;-ს საშუალება, &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;-ისთვის დაუშვას დისტანციური წვდომა ამ ტაბლეტზე დაინსტალირებულ აპებზე მასთან დაკავშირებისას."</string>
<string name="summary_app_streaming" product="device" msgid="7614171699434639963">"მიეცით &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;-ს საშუალება, &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;-ისთვის დაუშვას დისტანციური წვდომა ამ მოწყობილობაზე დაინსტალირებულ აპებზე მასთან დაკავშირებისას."</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"მოწყობილობათშორისი სერვისები"</string>
+ <string name="helper_summary_app_streaming" msgid="5344341720432827388">"ეს სერვისი გამოიყენება აპების მოწყობილობებს შორის სტრიმინგისთვის"</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>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"შეტყობინებები"</string>
+ <string name="permission_notification_summary" msgid="4398672775023193663">"შეუძლია წაიკითხოს ყველა შეტყობინება, მათ შორის ისეთი ინფორმაცია, როგორიცაა კონტრაქტები, ტექსტური გზავნილები და ფოტოები"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"ფოტოები და მედია"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Google Play services"</string>
+ <string name="helper_summary_computer" product="default" msgid="467996390095403648">"ეს სერვისი ფოტოებს, მედიას და შეტყობინებებს აზიარებს თქვენი ტელეფონიდან სხვა მოწყობილობებზე"</string>
+ <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"ეს სერვისი ფოტოებს, მედიას და შეტყობინებებს აზიარებს თქვენი ტელეფონიდან სხვა მოწყობილობებზე"</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>
+ <string name="consent_ok" msgid="3662376764371001106">"კარგი"</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-kk/strings.xml b/packages/CompanionDeviceManager/res/values-kk/strings.xml
index a7efb15ed0be..365020c58853 100644
--- a/packages/CompanionDeviceManager/res/values-kk/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-kk/strings.xml
@@ -22,18 +22,30 @@
<string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; арқылы басқарылатын <xliff:g id="PROFILE_NAME">%1$s</xliff:g> құрылғысын таңдаңыз"</string>
<string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасы хабарландыруларды, телефонды, SMS хабардарын, контактілерді және күнтізбе рұқсаттарын пайдалана алады."</string>
<string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасы хабарландыруларды, телефонды, SMS хабардарын, контактілерді және күнтізбе рұқсаттарын пайдалана алады."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; қолданбасына қолданбаларды трансляциялауға рұқсат етілсін бе?"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Қолданбалар"</string>
+ <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="summary_app_streaming" product="default" msgid="6105916810614498138">"&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; желіге қосылған кезде, &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; қолданбасына осы телефонға орнатылған қолданбаларды қашықтан пайдалануына рұқсат етіңіз."</string>
<string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; желіге қосылған кезде, &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; қолданбасына осы планшетке орнатылған қолданбаларды қашықтан пайдалануына рұқсат етіңіз."</string>
<string name="summary_app_streaming" product="device" msgid="7614171699434639963">"&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; желіге қосылған кезде, &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>
+ <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Бұл қызмет құрылғылар арасында қолданбаларды трансляциялау үшін пайдаланылады."</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>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Хабарландырулар"</string>
+ <string name="permission_notification_summary" msgid="4398672775023193663">"Барлық хабарландыруды, соның ішінде контактілер, хабарлар және фотосуреттер сияқты ақпаратты оқи алады."</string>
+ <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>
+ <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Бұл қызмет телефоныңыздағы фотосуреттерді, мультимедианы және хабарландыруларды басқа құрылғылармен бөліседі."</string>
+ <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Бұл қызмет телефоныңыздағы фотосуреттерді, мультимедианы және хабарландыруларды басқа құрылғылармен бөліседі."</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>
+ <string name="consent_ok" msgid="3662376764371001106">"Жарайды"</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-km/strings.xml b/packages/CompanionDeviceManager/res/values-km/strings.xml
index b18586316289..e1dbaf5fbc5b 100644
--- a/packages/CompanionDeviceManager/res/values-km/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-km/strings.xml
@@ -22,18 +22,30 @@
<string name="chooser_title" msgid="2262294130493605839">"ជ្រើសរើស <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ដើម្បីឱ្យស្ថិតក្រោម​ការគ្រប់គ្រងរបស់ &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> នឹងត្រូវបានអនុញ្ញាតឱ្យ​ធ្វើអន្តរកម្មជាមួយ​ការជូនដំណឹងរបស់អ្នក និងចូលប្រើការអនុញ្ញាត​ប្រតិទិន, ទូរសព្ទ, SMS និងទំនាក់ទំនងរបស់អ្នក។"</string>
<string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> នឹងត្រូវបានអនុញ្ញាតឱ្យ​ធ្វើអន្តរកម្មជាមួយ​ការជូនដំណឹងរបស់អ្នក និងចូលប្រើការអនុញ្ញាត​ប្រតិទិន, ទូរសព្ទ, SMS និងទំនាក់ទំនងរបស់អ្នក។"</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"អនុញ្ញាតឱ្យ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ផ្សាយកម្មវិធីឬ?"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"កម្មវិធី"</string>
+ <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="summary_app_streaming" product="default" msgid="6105916810614498138">"អនុញ្ញាតឱ្យ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ផ្ដល់ការចូលប្រើពីចម្ងាយដល់ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ដើម្បីចូលប្រើកម្មវិធី ដែលបានដំឡើងនៅលើទូរសព្ទនេះ នៅពេលភ្ជាប់អ៊ីនធឺណិត។"</string>
<string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"អនុញ្ញាតឱ្យ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ផ្ដល់ការចូលប្រើពីចម្ងាយដល់ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ដើម្បីចូលប្រើកម្មវិធី ដែលបានដំឡើងនៅលើថេប្លេតនេះ នៅពេលភ្ជាប់អ៊ីនធឺណិត។"</string>
<string name="summary_app_streaming" product="device" msgid="7614171699434639963">"អនុញ្ញាតឱ្យ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ផ្ដល់ការចូលប្រើពីចម្ងាយដល់ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ដើម្បីចូលប្រើកម្មវិធី ដែលបានដំឡើងនៅលើឧបករណ៍នេះ នៅពេលភ្ជាប់អ៊ីនធឺណិត។"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"សេវាកម្មឆ្លងកាត់ឧបករណ៍"</string>
+ <string name="helper_summary_app_streaming" msgid="5344341720432827388">"សេវាកម្មនេះត្រូវបានប្រើដើម្បីភ្ជាប់កម្មវិធីរវាងឧបករណ៍របស់អ្នក"</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>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"ការ​ជូនដំណឹង"</string>
+ <string name="permission_notification_summary" msgid="4398672775023193663">"អាចអានការជូនដំណឹងទាំងអស់ រួមទាំងព័ត៌មានដូចជាទំនាក់ទំនង សារ និងរូបថត"</string>
+ <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>
+ <string name="helper_summary_computer" product="default" msgid="467996390095403648">"សេវាកម្មនេះចែករំលែករូបថត មេឌៀ និងការជូនដំណឹងពីទូរសព្ទរបស់អ្នកទៅឧបករណ៍ផ្សេងទៀត"</string>
+ <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"សេវាកម្មនេះចែករំលែករូបថត មេឌៀ និងការជូនដំណឹងពីទូរសព្ទរបស់អ្នកទៅឧបករណ៍ផ្សេងទៀត"</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>
+ <string name="consent_ok" msgid="3662376764371001106">"យល់ព្រម"</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-kn/strings.xml b/packages/CompanionDeviceManager/res/values-kn/strings.xml
index 64576ce8aec8..0d01ce7cdce7 100644
--- a/packages/CompanionDeviceManager/res/values-kn/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-kn/strings.xml
@@ -22,18 +22,30 @@
<string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; ಮೂಲಕ ನಿರ್ವಹಿಸಬೇಕಾದ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ಅನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string>
<string name="summary_watch" product="default" msgid="7113724443198337683">"ನಿಮ್ಮ ಅಧಿಸೂಚನೆಗಳೊಂದಿಗೆ ಸಂವಹನ ನಡೆಸಲು ಮತ್ತು ನಿಮ್ಮ ಫೋನ್, SMS, ಸಂಪರ್ಕಗಳು ಮತ್ತು Calendar ಅನುಮತಿಗಳನ್ನು ಪ್ರವೇಶಿಸಲು <xliff:g id="APP_NAME">%1$s</xliff:g> ಗೆ ಅನುಮತಿಸಲಾಗುತ್ತದೆ."</string>
<string name="summary_watch" product="tablet" msgid="7113724443198337683">"ನಿಮ್ಮ ಅಧಿಸೂಚನೆಗಳೊಂದಿಗೆ ಸಂವಹನ ನಡೆಸಲು ಮತ್ತು ನಿಮ್ಮ ಫೋನ್, SMS, ಸಂಪರ್ಕಗಳು ಮತ್ತು Calendar ಅನುಮತಿಗಳನ್ನು ಪ್ರವೇಶಿಸಲು <xliff:g id="APP_NAME">%1$s</xliff:g> ಗೆ ಅನುಮತಿಸಲಾಗುತ್ತದೆ."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"ಆ್ಯಪ್‌ಗಳನ್ನು ಸ್ಟ್ರೀಮ್ ಮಾಡಲು <xliff:g id="APP_NAME">%1$s</xliff:g> ಗೆ ಅನುಮತಿಸಿ?"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"ಆ್ಯಪ್‌ಗಳು"</string>
+ <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="summary_app_streaming" product="default" msgid="6105916810614498138">"ಕನೆಕ್ಟ್ ಆದಾಗ ಈ ಫೋನ್‌ನಲ್ಲಿ ಇನ್‌ಸ್ಟಾಲ್ ಮಾಡಲಾದ ಆ್ಯಪ್‌ಗಳನ್ನು ಪ್ರವೇಶಿಸುವುದಕ್ಕಾಗಿ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ಗೆ ರಿಮೋಟ್ ಪ್ರವೇಶವನ್ನು ಒದಗಿಸಲು &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ಗೆ ಅನುಮತಿಸಿ."</string>
<string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"ಕನೆಕ್ಟ್ ಆದಾಗ ಈ ಟ್ಯಾಬ್ಲೆಟ್‌ನಲ್ಲಿ ಇನ್‌ಸ್ಟಾಲ್ ಮಾಡಲಾದ ಆ್ಯಪ್‌ಗಳನ್ನು ಪ್ರವೇಶಿಸುವುದಕ್ಕಾಗಿ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ಗೆ ರಿಮೋಟ್ ಪ್ರವೇಶವನ್ನು ಒದಗಿಸಲು &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ಗೆ ಅನುಮತಿಸಿ."</string>
<string name="summary_app_streaming" product="device" msgid="7614171699434639963">"ಕನೆಕ್ಟ್ ಆದಾಗ ಈ ಸಾಧನದಲ್ಲಿ ಇನ್‌ಸ್ಟಾಲ್ ಮಾಡಲಾದ ಆ್ಯಪ್‌ಗಳನ್ನು ಪ್ರವೇಶಿಸುವುದಕ್ಕಾಗಿ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ಗೆ ರಿಮೋಟ್ ಪ್ರವೇಶವನ್ನು ಒದಗಿಸಲು &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>
+ <string name="helper_summary_app_streaming" msgid="5344341720432827388">"ನಿಮ್ಮ ಸಾಧನಗಳ ನಡುವೆ ಆ್ಯಪ್‌ಗಳನ್ನು ಸ್ಟ್ರೀಮ್ ಮಾಡಲು ಈ ಸೇವೆಯನ್ನು ಬಳಸಲಾಗುತ್ತದೆ"</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>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"ಅಧಿಸೂಚನೆಗಳು"</string>
+ <string name="permission_notification_summary" msgid="4398672775023193663">"ಒಪ್ಪಂದಗಳು, ಸಂದೇಶಗಳು ಮತ್ತು ಫೋಟೋಗಳಂತಹ ಮಾಹಿತಿಯನ್ನು ಒಳಗೊಂಡಂತೆ ಎಲ್ಲಾ ಅಧಿಸೂಚನೆಗಳನ್ನು ಓದಬಹುದು"</string>
+ <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>
+ <string name="helper_summary_computer" product="default" msgid="467996390095403648">"ಈ ಸೇವೆಯು, ನಿಮ್ಮ ಫೋನ್‍ನಿಂದ ಇತರ ಸಾಧನಗಳಿಗೆ ಫೋಟೋಗಳು, ಮಾಧ್ಯಮ ಮತ್ತು ಅಧಿಸೂಚನೆಗಳನ್ನು ಹಂಚಿಕೊಳ್ಳುತ್ತದೆ"</string>
+ <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"ಈ ಸೇವೆಯು, ನಿಮ್ಮ ಫೋನ್‍ನಿಂದ ಇತರ ಸಾಧನಗಳಿಗೆ ಫೋಟೋಗಳು, ಮಾಧ್ಯಮ ಮತ್ತು ಅಧಿಸೂಚನೆಗಳನ್ನು ಹಂಚಿಕೊಳ್ಳುತ್ತದೆ"</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>
+ <string name="consent_ok" msgid="3662376764371001106">"ಸರಿ"</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-ko/strings.xml b/packages/CompanionDeviceManager/res/values-ko/strings.xml
index 5bf8eb4ae6ac..2b98ce3875c6 100644
--- a/packages/CompanionDeviceManager/res/values-ko/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ko/strings.xml
@@ -22,18 +22,30 @@
<string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;에서 관리할 <xliff:g id="PROFILE_NAME">%1$s</xliff:g>을(를) 선택"</string>
<string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g>에서 알림과 상호작용하고 전화, SMS, 연락처, 캘린더 권한에 액세스할 수 있게 됩니다."</string>
<string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g>에서 알림과 상호작용하고 전화, SMS, 연락처, 캘린더 권한에 액세스할 수 있게 됩니다."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;에서 애플리케이션을 스트리밍하도록 허용하시겠습니까?"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"앱"</string>
+ <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="summary_app_streaming" product="default" msgid="6105916810614498138">"연결 시 &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;에서 &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;에 이 휴대전화에 설치된 애플리케이션에 원격으로 액세스할 수 있는 권한을 제공하도록 허용합니다."</string>
<string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"연결 시 &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;에서 &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;에 이 태블릿에 설치된 애플리케이션에 원격으로 액세스할 수 있는 권한을 제공하도록 허용합니다."</string>
<string name="summary_app_streaming" product="device" msgid="7614171699434639963">"연결 시 &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;에서 &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;에 이 기기에 설치된 애플리케이션에 원격으로 액세스할 수 있는 권한을 제공하도록 허용합니다."</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"교차 기기 서비스"</string>
+ <string name="helper_summary_app_streaming" msgid="5344341720432827388">"이 서비스는 기기 간에 앱을 스트리밍하는 데 사용됩니다."</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>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"알림"</string>
+ <string name="permission_notification_summary" msgid="4398672775023193663">"연락처, 메시지, 사진 등의 정보를 포함한 모든 알림을 읽을 수 있습니다."</string>
+ <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>
+ <string name="helper_summary_computer" product="default" msgid="467996390095403648">"이 서비스는 휴대전화의 사진, 미디어 및 알림을 다른 기기와 공유합니다."</string>
+ <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"이 서비스는 휴대전화의 사진, 미디어 및 알림을 다른 기기와 공유합니다."</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>
+ <string name="consent_ok" msgid="3662376764371001106">"확인"</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-ky/strings.xml b/packages/CompanionDeviceManager/res/values-ky/strings.xml
index 714dc9365bd6..1f320dda3591 100644
--- a/packages/CompanionDeviceManager/res/values-ky/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ky/strings.xml
@@ -22,18 +22,30 @@
<string name="chooser_title" msgid="2262294130493605839">"<xliff:g id="PROFILE_NAME">%1$s</xliff:g> &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; тарабынан башкарылсын"</string>
<string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> билдирмелериңизди көрүп, телефонуңуздун, SMS билдирүүлөрүңүздүн, байланыштарыңыздын жана жылнаамаңыздын уруксаттарын пайдалана алат."</string>
<string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> билдирмелериңизди көрүп, телефонуңуздун, SMS билдирүүлөрүңүздүн, байланыштарыңыздын жана жылнаамаңыздын уруксаттарын пайдалана алат."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; колдонмосуна колдонмолорду алып ойнотууга уруксат бересизби?"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Колдонмолор"</string>
+ <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="summary_app_streaming" product="default" msgid="6105916810614498138">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; колдонмосуна Интернетке туташкан &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; телефонундагы колдонмолорго алыстан кирүү мүмкүнчүлүгүн бериңиз."</string>
<string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; колдонмосуна Интернетке туташкан &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; планшетиндеги колдонмолорго алыстан кирүү мүмкүнчүлүгүн бериңиз."</string>
<string name="summary_app_streaming" product="device" msgid="7614171699434639963">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; колдонмосуна Интернетке туташкан &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; түзмөгүндөгү колдонмолорго алыстан кирүү мүмкүнчүлүгүн бериңиз."</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Түзмөктөр аралык кызматтар"</string>
+ <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Бул кызмат түзмөктөрүңүздүн ортосунда колдонмолорду тышкы экранга чыгаруу үчүн колдонулат"</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>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Билдирмелер"</string>
+ <string name="permission_notification_summary" msgid="4398672775023193663">"Бардык билдирмелерди, анын ичинде байланыштар, билдирүүлөр жана сүрөттөр сыяктуу маалыматты окуй алат"</string>
+ <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>
+ <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Бул кызмат сүрөттөрдү, медиа файлдарды жана билдирмелерди телефонуңуздан башка түзмөктөр менен бөлүшөт"</string>
+ <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Бул кызмат сүрөттөрдү, медиа файлдарды жана билдирмелерди телефонуңуздан башка түзмөктөр менен бөлүшөт"</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>
+ <string name="consent_ok" msgid="3662376764371001106">"Макул"</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-lo/strings.xml b/packages/CompanionDeviceManager/res/values-lo/strings.xml
index 95cab696240f..debbf760fb17 100644
--- a/packages/CompanionDeviceManager/res/values-lo/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-lo/strings.xml
@@ -22,18 +22,30 @@
<string name="chooser_title" msgid="2262294130493605839">"ເລືອກ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ເພື່ອໃຫ້ຖືກຈັດການໂດຍ &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ຈະໄດ້ຮັບອະນຸຍາດໃຫ້ໂຕ້ຕອບກັບການແຈ້ງເຕືອນຂອງທ່ານ ແລະ ເຂົ້າເຖິງການອະນຸຍາດໂທລະສັບ, SMS, ລາຍຊື່ຜູ້ຕິດຕໍ່ ແລະ ປະຕິທິນຂອງທ່ານໄດ້."</string>
<string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ຈະໄດ້ຮັບອະນຸຍາດໃຫ້ໂຕ້ຕອບກັບການແຈ້ງເຕືອນຂອງທ່ານ ແລະ ເຂົ້າເຖິງການອະນຸຍາດໂທລະສັບ, SMS, ລາຍຊື່ຜູ້ຕິດຕໍ່ ແລະ ປະຕິທິນຂອງທ່ານໄດ້."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"ອະນຸຍາດໃຫ້ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ສະຕຣີມແອັບພລິເຄຊັນໄດ້ບໍ?"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"ແອັບ"</string>
+ <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="summary_app_streaming" product="default" msgid="6105916810614498138">"ໃຫ້ສິດ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ເພື່ອເຂົ້າເຖິງ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ຈາກໄລຍະໄກເພື່ອເຂົ້າເຖິງແອັບພລິເຄຊັນທີ່ຕິດຕັ້ງຢູ່ໂທລະສັບນີ້ເມື່ອເຊື່ອມຕໍ່ແລ້ວ."</string>
<string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"ໃຫ້ສິດ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ເພື່ອເຂົ້າເຖິງ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ຈາກໄລຍະໄກເພື່ອເຂົ້າເຖິງແອັບພລິເຄຊັນທີ່ຕິດຕັ້ງຢູ່ແທັບເລັດນີ້ເມື່ອເຊື່ອມຕໍ່ແລ້ວ."</string>
<string name="summary_app_streaming" product="device" msgid="7614171699434639963">"ໃຫ້ສິດ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ເພື່ອເຂົ້າເຖິງ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ຈາກໄລຍະໄກເພື່ອເຂົ້າເຖິງແອັບພລິເຄຊັນທີ່ຕິດຕັ້ງຢູ່ອຸປະກອນນີ້ເມື່ອເຊື່ອມຕໍ່ແລ້ວ."</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"ບໍລິການຂ້າມອຸປະກອນ"</string>
+ <string name="helper_summary_app_streaming" msgid="5344341720432827388">"ບໍລິການນີ້ໃຊ້ເພື່ອສະຕຣີມແອັບລະຫວ່າງອຸປະກອນຂອງທ່ານ"</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>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"ການແຈ້ງເຕືອນ"</string>
+ <string name="permission_notification_summary" msgid="4398672775023193663">"ສາມາດອ່ານການແຈ້ງເຕືອນທັງໝົດ, ຮວມທັງຂໍ້ມູນ ເຊັ່ນ: ລາຍຊື່ຜູ້ຕິດຕໍ່, ຂໍ້ຄວາມ ແລະ ຮູບພາບ"</string>
+ <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>
+ <string name="helper_summary_computer" product="default" msgid="467996390095403648">"ບໍລິການນີ້ຈະແບ່ງປັນຮູບພາບ, ມີເດຍ ແລະ ການແຈ້ງເຕືອນຈາກໂທລະສັບຂອງທ່ານໄປຫາອຸປະກອນອື່ນ"</string>
+ <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"ບໍລິການນີ້ຈະແບ່ງປັນຮູບພາບ, ມີເດຍ ແລະ ການແຈ້ງເຕືອນຈາກໂທລະສັບຂອງທ່ານໄປຫາອຸປະກອນອື່ນ"</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>
+ <string name="consent_ok" msgid="3662376764371001106">"ຕົກລົງ"</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-lt/strings.xml b/packages/CompanionDeviceManager/res/values-lt/strings.xml
index 5d32fbbf9116..3904ad317acb 100644
--- a/packages/CompanionDeviceManager/res/values-lt/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-lt/strings.xml
@@ -22,18 +22,30 @@
<string name="chooser_title" msgid="2262294130493605839">"Jūsų <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, kurį valdys &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; (pasirinkite)"</string>
<string name="summary_watch" product="default" msgid="7113724443198337683">"„<xliff:g id="APP_NAME">%1$s</xliff:g>“ galės sąveikauti su pranešimų funkcija ir pasiekti telefoną, SMS, kontaktus ir kalendorių."</string>
<string name="summary_watch" product="tablet" msgid="7113724443198337683">"„<xliff:g id="APP_NAME">%1$s</xliff:g>“ galės sąveikauti su pranešimų funkcija ir pasiekti telefoną, SMS, kontaktus ir kalendorių."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Leisti &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; perduoti srautu programas?"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Programos"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"Telefono programų perdavimas srautu"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"Leisti &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; pasiekti šią informaciją iš jūsų telefono"</string>
<string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Leiskite &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; prisijungus suteikti &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; nuotolinę prieigą prie šiame telefone įdiegtų programų."</string>
<string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Leiskite &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; prisijungus suteikti &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; nuotolinę prieigą prie šiame planšetiniame kompiuteryje įdiegtų programų."</string>
<string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Leiskite &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; prisijungus suteikti &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; nuotolinę prieigą prie šiame įrenginyje įdiegtų programų."</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Pasl. keliuose įrenginiuose"</string>
+ <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Ši paslauga naudojama perduoti programas srautu tarp jūsų įrenginių"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Leisti &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; pasiekti šią informaciją iš jūsų telefono"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Pranešimai"</string>
+ <string name="permission_notification_summary" msgid="4398672775023193663">"Galima skaityti visus pranešimus, įskaitant tokią informaciją kaip sutartys, pranešimai ir nuotraukos"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"Nuotraukos ir medija"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"„Google Play“ paslaugos"</string>
+ <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Naudojant šią paslaugą, telefone esančias nuotraukas, mediją ir pranešimus galima bendrinti su kitais įrenginiais"</string>
+ <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Naudojant šią paslaugą, telefone esančias nuotraukas, mediją ir pranešimus galima bendrinti su kitais įrenginiais"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"įrenginys"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Leisti"</string>
<string name="consent_no" msgid="2640796915611404382">"Neleisti"</string>
+ <string name="consent_ok" msgid="3662376764371001106">"Gerai"</string>
<string name="permission_sync_confirmation_title" msgid="667074294393493186">"Laikrodžio programų perkėlimo leidimai"</string>
<string name="permission_sync_summary" msgid="8873391306499120778">"Kad būtų lengviau nustatyti laikrodį, jame atliekant sąranką įdiegtoms programoms bus naudojami tie patys leidimai kaip jūsų telefone.\n\n Šie leidimai gali apimti prieigą prie laikrodžio mikrofono ir vietovės."</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-lv/strings.xml b/packages/CompanionDeviceManager/res/values-lv/strings.xml
index cabfc77bb27c..71bc79201f92 100644
--- a/packages/CompanionDeviceManager/res/values-lv/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-lv/strings.xml
@@ -22,18 +22,30 @@
<string name="chooser_title" msgid="2262294130493605839">"Profila (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>) izvēle, ko pārvaldīt lietotnē &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="summary_watch" product="default" msgid="7113724443198337683">"Lietotnei <xliff:g id="APP_NAME">%1$s</xliff:g> tiks atļauts mijiedarboties ar jūsu paziņojumiem un piekļūt šādām atļaujām: Tālrunis, Īsziņas, Kontaktpersonas un Kalendārs."</string>
<string name="summary_watch" product="tablet" msgid="7113724443198337683">"Lietotnei <xliff:g id="APP_NAME">%1$s</xliff:g> tiks atļauts mijiedarboties ar jūsu paziņojumiem un piekļūt šādām atļaujām: Tālrunis, Īsziņas, Kontaktpersonas un Kalendārs."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Vai atļaujat lietotnei &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; straumēt lietojumprogrammas?"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Lietotnes"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"Var straumēt jūsu tālruņa lietotnes"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"Atļaut lietotnei &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; piekļūt šai informācijai no jūsu tālruņa"</string>
<string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Atļaut lietotnei &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; nodrošināt attālu piekļuvi tālrunim &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;, lai piekļūtu šajā tālrunī instalētajām lietojumprogrammām, kamēr ir izveidots savienojums."</string>
<string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Atļaut lietotnei &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; nodrošināt attālu piekļuvi planšetdatoram &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;, lai piekļūtu šajā planšetdatorā instalētajām lietojumprogrammām, kamēr ir izveidots savienojums."</string>
<string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Atļaut lietotnei &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; nodrošināt attālu piekļuvi ierīcei &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;, lai piekļūtu šajā ierīcē instalētajām lietojumprogrammām, kamēr ir izveidots savienojums."</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Vairāku ierīču pakalpojumi"</string>
+ <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Šis pakalpojums tiek izmantots, lai straumētu lietotnes jūsu ierīcēs"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Atļaut lietotnei &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; piekļūt šai informācijai no jūsu tālruņa"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Paziņojumi"</string>
+ <string name="permission_notification_summary" msgid="4398672775023193663">"Var lasīt visus paziņojumus, tostarp tādu informāciju kā kontaktpersonas, ziņojumus un fotoattēlus"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"Fotoattēli un multivides faili"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Google Play pakalpojumi"</string>
+ <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Šis pakalpojums kopīgo fotoattēlus, multivides saturu un paziņojumus no jūsu tālruņa citās ierīcēs"</string>
+ <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Šis pakalpojums kopīgo fotoattēlus, multivides saturu un paziņojumus no jūsu tālruņa citās ierīcēs"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"ierīce"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Atļaut"</string>
<string name="consent_no" msgid="2640796915611404382">"Neatļaut"</string>
+ <string name="consent_ok" msgid="3662376764371001106">"Labi"</string>
<string name="permission_sync_confirmation_title" msgid="667074294393493186">"Lietotņu atļauju pārsūtīšana uz pulksteni"</string>
<string name="permission_sync_summary" msgid="8873391306499120778">"Lai atvieglotu pulksteņa iestatīšanu, iestatīšanas laikā pulkstenī instalētās lietotnes saņems tādas pašas atļaujas, kādas tām ir tālrunī.\n\n Tostarp lietotnes var saņemt atļauju piekļūt pulksteņa mikrofonam un atrašanās vietai."</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-mk/strings.xml b/packages/CompanionDeviceManager/res/values-mk/strings.xml
index b4531b5c864e..851651f59a5f 100644
--- a/packages/CompanionDeviceManager/res/values-mk/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-mk/strings.xml
@@ -22,18 +22,30 @@
<string name="chooser_title" msgid="2262294130493605839">"Изберете <xliff:g id="PROFILE_NAME">%1$s</xliff:g> со којшто ќе управува &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ќе може да остварува интеракција со известувањата и да пристапува до дозволите за телефонот, SMS, контактите и календарот."</string>
<string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ќе може да остварува интеракција со известувањата и да пристапува до дозволите за телефонот, SMS, контактите и календарот."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Да се дозволи &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да стримува апликации?"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Апликации"</string>
+ <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="summary_app_streaming" product="default" msgid="6105916810614498138">"Дозволете &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да обезбеди далечински пристап на &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; за да пристапува до апликации инсталирани на телефонов кога ќе се поврзе."</string>
<string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Дозволете &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да обезбеди далечински пристап на &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; за да пристапува до апликации инсталирани на таблетов кога ќе се поврзе."</string>
<string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Дозволете &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да обезбеди далечински пристап на &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; за да пристапува до апликации инсталирани на уредов кога ќе се поврзе."</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Повеќенаменски услуги"</string>
+ <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Услугава се користи за стриминг на апликации помеѓу вашите уреди"</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>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Известувања"</string>
+ <string name="permission_notification_summary" msgid="4398672775023193663">"може да ги чита сите известувања, вклучително и податоци како договори, пораки и фотографии"</string>
+ <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>
+ <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Услугава споделува фотографии, аудиовизуелни содржини и известувања од вашиот телефон на други уреди"</string>
+ <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Услугава споделува фотографии, аудиовизуелни содржини и известувања од вашиот телефон на други уреди"</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>
+ <string name="consent_ok" msgid="3662376764371001106">"Во ред"</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 85952ca65fce..9e330e64c0e4 100644
--- a/packages/CompanionDeviceManager/res/values-ml/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ml/strings.xml
@@ -22,18 +22,30 @@
<string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; ഉപയോഗിച്ച് മാനേജ് ചെയ്യുന്നതിന് ഒരു <xliff:g id="PROFILE_NAME">%1$s</xliff:g> തിരഞ്ഞെടുക്കുക"</string>
<string name="summary_watch" product="default" msgid="7113724443198337683">"നിങ്ങളുടെ അറിയിപ്പുകളുമായി സംവദിക്കാനും നിങ്ങളുടെ ഫോൺ, SMS, കോൺടാക്റ്റുകൾ, കലണ്ടർ അനുമതികൾ എന്നിവ ആക്‌സസ് ചെയ്യാനും <xliff:g id="APP_NAME">%1$s</xliff:g> എന്നതിനെ അനുവദിക്കും."</string>
<string name="summary_watch" product="tablet" msgid="7113724443198337683">"നിങ്ങളുടെ അറിയിപ്പുകളുമായി സംവദിക്കാനും നിങ്ങളുടെ ഫോൺ, SMS, കോൺടാക്റ്റുകൾ, കലണ്ടർ അനുമതികൾ എന്നിവ ആക്‌സസ് ചെയ്യാനും <xliff:g id="APP_NAME">%1$s</xliff:g> എന്നതിനെ അനുവദിക്കും."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"ആപ്പുകൾ സ്‌ട്രീം ചെയ്യാൻ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; എന്നതിനെ അനുവദിക്കണോ?"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"ആപ്പുകൾ"</string>
+ <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="summary_app_streaming" product="default" msgid="6105916810614498138">"കണക്‌റ്റ് ചെയ്യുമ്പോൾ, ഈ ഫോണിൽ ഇൻസ്‌റ്റാൾ ചെയ്‌തിട്ടുള്ള ആപ്പുകൾ ആക്‌സസ് ചെയ്യാനുള്ള റിമോട്ട് ആക്‌സസ് &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; എന്നതിന് നൽകാൻ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; എന്നതിനെ അനുവദിക്കുക."</string>
<string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"കണക്‌റ്റ് ചെയ്യുമ്പോൾ, ഈ ടാബ്‌ലെറ്റിൽ ഇൻസ്‌റ്റാൾ ചെയ്‌തിട്ടുള്ള ആപ്പുകൾ ആക്‌സസ് ചെയ്യാനുള്ള റിമോട്ട് ആക്‌സസ് &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; എന്നതിന് നൽകാൻ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; എന്നതിനെ അനുവദിക്കുക."</string>
<string name="summary_app_streaming" product="device" msgid="7614171699434639963">"കണക്‌റ്റ് ചെയ്യുമ്പോൾ, ഈ ഉപകരണത്തിൽ ഇൻസ്‌റ്റാൾ ചെയ്‌തിട്ടുള്ള ആപ്പുകൾ ആക്‌സസ് ചെയ്യാനുള്ള റിമോട്ട് ആക്‌സസ് &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; എന്നതിന് നൽകാൻ &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>
+ <string name="helper_summary_app_streaming" msgid="5344341720432827388">"നിങ്ങളുടെ ഉപകരണങ്ങൾക്കിടയിൽ ആപ്പുകൾ സ്‌ട്രീം ചെയ്യാൻ ഈ സേവനം ഉപയോഗിക്കുന്നു"</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>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"അറിയിപ്പുകൾ"</string>
+ <string name="permission_notification_summary" msgid="4398672775023193663">"കോൺടാക്‌റ്റുകൾ, സന്ദേശങ്ങൾ, ഫോട്ടോകൾ എന്നിവ പോലുള്ള വിവരങ്ങൾ ഉൾപ്പെടെ, എല്ലാ അറിയിപ്പുകളും വായിക്കാനാകും"</string>
+ <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>
+ <string name="helper_summary_computer" product="default" msgid="467996390095403648">"ഈ സേവനം നിങ്ങളുടെ ഫോണിൽ നിന്ന് ഫോട്ടോകളും മീഡിയയും അറിയിപ്പുകളും മറ്റ് ഉപകരണങ്ങളിലേക്ക് അയയ്‌ക്കുന്നു"</string>
+ <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"ഈ സേവനം നിങ്ങളുടെ ഫോണിൽ നിന്ന് ഫോട്ടോകളും മീഡിയയും അറിയിപ്പുകളും മറ്റ് ഉപകരണങ്ങളിലേക്ക് അയയ്‌ക്കുന്നു"</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>
+ <string name="consent_ok" msgid="3662376764371001106">"ശരി"</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 c0d589d0aca7..00c032d4aa18 100644
--- a/packages/CompanionDeviceManager/res/values-mn/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-mn/strings.xml
@@ -22,18 +22,30 @@
<string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;-н удирдах<xliff:g id="PROFILE_NAME">%1$s</xliff:g>-г сонгоно уу"</string>
<string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g>-д таны мэдэгдлүүдтэй харилцаж, таны Утас, SMS, Харилцагчид болон Календарийн зөвшөөрөлд хандахыг зөвшөөрнө."</string>
<string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g>-д таны мэдэгдлүүдтэй харилцаж, таны Утас, SMS, Харилцагчид болон Календарийн зөвшөөрөлд хандахыг зөвшөөрнө."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;-д аппуудыг дамжуулахыг зөвшөөрөх үү?"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Аппууд"</string>
+ <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="summary_app_streaming" product="default" msgid="6105916810614498138">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;-д &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;-г холбогдсон үед энэ утсанд суулгасан аппуудад хандахын тулд алсын хандалт өгөхийг зөвшөөрнө үү."</string>
<string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;-д &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;-г холбогдсон үед энэ таблетад суулгасан аппуудад хандахын тулд алсын хандалт өгөхийг зөвшөөрнө үү."</string>
<string name="summary_app_streaming" product="device" msgid="7614171699434639963">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;-д &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;-г холбогдсон үед энэ төхөөрөмжид суулгасан аппуудад хандахын тулд алсын хандалт өгөхийг зөвшөөрнө үү."</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Төхөөрөмж хоорондын үйлчилгээ"</string>
+ <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Энэ үйлчилгээг таны төхөөрөмжүүд хооронд аппууд дамжуулахад ашигладаг"</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>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Мэдэгдэл"</string>
+ <string name="permission_notification_summary" msgid="4398672775023193663">"Гэрээ, мессеж болон зураг зэрэг мэдээллийг оруулаад бүх мэдэгдлийг унших боломжтой"</string>
+ <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>
+ <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Энэ үйлчилгээ зураг, медиа болон мэдэгдлийг таны утаснаас бусад төхөөрөмж рүү хуваалцана"</string>
+ <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Энэ үйлчилгээ зураг, медиа болон мэдэгдлийг таны утаснаас бусад төхөөрөмж рүү хуваалцана"</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>
+ <string name="consent_ok" msgid="3662376764371001106">"OK"</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-mr/strings.xml b/packages/CompanionDeviceManager/res/values-mr/strings.xml
index 0ce6ab712eb0..303b141a72e4 100644
--- a/packages/CompanionDeviceManager/res/values-mr/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-mr/strings.xml
@@ -22,18 +22,30 @@
<string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; द्वारे व्यवस्थापित करण्यासाठी <xliff:g id="PROFILE_NAME">%1$s</xliff:g> निवडा"</string>
<string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ला तुमच्या सूचनांशी संवाद साधण्याची आणि तुमचा फोन, एसएमएस, संपर्क आणि Calendar च्या परवानग्या अ‍ॅक्सेस करण्याची अनुमती मिळेल."</string>
<string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ला तुमच्या सूचनांशी संवाद साधण्याची आणि तुमचा फोन, एसएमएस, संपर्क आणि Calendar च्या परवानग्या अ‍ॅक्सेस करण्याची अनुमती मिळेल."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ला अ‍ॅप्लिकेशन स्ट्रीम करण्याची अनुमती द्यायची आहे का?"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"ॲप्स"</string>
+ <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="summary_app_streaming" product="default" msgid="6105916810614498138">"कनेक्ट केलेले असताना या फोनवरील अ‍ॅप्लिकेशन अ‍ॅक्सेस करता यावीत यासाठी &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ला &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; चा रिमोट अ‍ॅक्सेस द्या."</string>
<string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"कनेक्ट केलेले असताना या टॅबलेटवरील अ‍ॅप्लिकेशन अ‍ॅक्सेस करता यावीत यासाठी &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ला &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; चा रिमोट अ‍ॅक्सेस द्या."</string>
<string name="summary_app_streaming" product="device" msgid="7614171699434639963">"कनेक्ट केलेले असताना या डिव्हाइसवरील अ‍ॅप्लिकेशन अ‍ॅक्सेस करता यावीत यासाठी &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ला &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; चा रिमोट अ‍ॅक्सेस द्या."</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"क्रॉस-डिव्हाइस सेवा"</string>
+ <string name="helper_summary_app_streaming" msgid="5344341720432827388">"ही सेवा तुमच्या डिव्हाइस दरम्यान अ‍ॅप्स स्ट्रीम करण्यासाठी वापरली जाते"</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>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"सूचना"</string>
+ <string name="permission_notification_summary" msgid="4398672775023193663">"करार, मेसेज आणि फोटो यांसारख्या माहितीच्या समावेशासह सर्व सूचना वाचू शकते"</string>
+ <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>
+ <string name="helper_summary_computer" product="default" msgid="467996390095403648">"ही सेवा तुमच्या फोनवरून इतर डिव्हाइसवर फोटो, मीडिया आणि सूचना शेअर करते"</string>
+ <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"ही सेवा तुमच्या फोनवरून इतर डिव्हाइसवर फोटो, मीडिया आणि सूचना शेअर करते"</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>
+ <string name="consent_ok" msgid="3662376764371001106">"ओके"</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 2ca812889342..e234089857d5 100644
--- a/packages/CompanionDeviceManager/res/values-ms/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ms/strings.xml
@@ -22,18 +22,30 @@
<string name="chooser_title" msgid="2262294130493605839">"Pilih <xliff:g id="PROFILE_NAME">%1$s</xliff:g> untuk diurus oleh &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> akan dibenarkan berinteraksi dengan pemberitahuan anda dan mengakses kebenaran Telefon, SMS, Kenalan dan Kalendar anda."</string>
<string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> akan dibenarkan berinteraksi dengan pemberitahuan anda dan mengakses kebenaran Telefon, SMS, Kenalan dan Kalendar anda."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Benarkan &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; menstrim aplikasi?"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Apl"</string>
+ <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="summary_app_streaming" product="default" msgid="6105916810614498138">"Membenarkan &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; memberi akses jauh kepada &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; untuk mengakses aplikasi yang dipasang pada telefon ini apabila disambungkan."</string>
<string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Membenarkan &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; memberi akses jauh kepada &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; untuk mengakses aplikasi yang dipasang pada tablet ini apabila disambungkan."</string>
<string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Membenarkan &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; memberi akses jauh kepada &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; untuk mengakses aplikasi yang dipasang pada peranti ini apabila disambungkan."</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Perkhidmatan silang peranti"</string>
+ <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Perkhidmatan ini digunakan untuk menstrim apl antara peranti 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>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Pemberitahuan"</string>
+ <string name="permission_notification_summary" msgid="4398672775023193663">"Boleh membaca semua pemberitahuan, termasuk maklumat seperti kenalan, mesej dan foto"</string>
+ <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>
+ <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Perkhidmatan ini berkongsi foto, media dan pemberitahuan daripada telefon anda kepada peranti lain"</string>
+ <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Perkhidmatan ini berkongsi foto, media dan pemberitahuan daripada telefon anda kepada peranti lain"</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>
+ <string name="consent_ok" msgid="3662376764371001106">"OK"</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-my/strings.xml b/packages/CompanionDeviceManager/res/values-my/strings.xml
index 1fb20bf2449e..61a60b20fc33 100644
--- a/packages/CompanionDeviceManager/res/values-my/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-my/strings.xml
@@ -22,18 +22,30 @@
<string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; က စီမံခန့်ခွဲရန် <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ကို ရွေးချယ်ပါ"</string>
<string name="summary_watch" product="default" msgid="7113724443198337683">"သင်၏ ‘ဖုန်း’၊ ‘SMS စာတိုစနစ်’၊ ‘အဆက်အသွယ်များ’ နှင့် ‘ပြက္ခဒိန်’ ခွင့်ပြုချက်များကို သုံးရန်နှင့် အကြောင်းကြားချက်များကို ပြန်လှန်တုံ့ပြန်ရန် <xliff:g id="APP_NAME">%1$s</xliff:g> အား ခွင့်ပြုပါမည်။"</string>
<string name="summary_watch" product="tablet" msgid="7113724443198337683">"သင်၏ ‘ဖုန်း’၊ ‘SMS စာတိုစနစ်’၊ ‘အဆက်အသွယ်များ’ နှင့် ‘ပြက္ခဒိန်’ ခွင့်ပြုချက်များကို သုံးရန်နှင့် အကြောင်းကြားချက်များကို ပြန်လှန်တုံ့ပြန်ရန် <xliff:g id="APP_NAME">%1$s</xliff:g> အား ခွင့်ပြုပါမည်။"</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"အပလီကေးရှင်းများကို တိုက်ရိုက်လွှင့်ရန် &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ကိုခွင့်ပြုမလား။"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"အက်ပ်များ"</string>
+ <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="summary_app_streaming" product="default" msgid="6105916810614498138">"ချိတ်ဆက်ထားသည့်အခါ ဤဖုန်းတွင် ထည့်သွင်းထားသော အပလီကေးရှင်းများကို သုံးခွင့်ရရန်အတွက် &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ကိုအဝေးမှ သုံးခွင့်ပေးနိုင်ရန် &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; အားခွင့်ပြုပါ။"</string>
<string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"ချိတ်ဆက်ထားသည့်အခါ ဤတက်ဘလက်တွင် ထည့်သွင်းထားသော အပလီကေးရှင်းများကို သုံးခွင့်ရရန်အတွက် &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ကိုအဝေးမှ သုံးခွင့်ပေးနိုင်ရန် &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; အားခွင့်ပြုပါ။"</string>
<string name="summary_app_streaming" product="device" msgid="7614171699434639963">"ချိတ်ဆက်ထားသည့်အခါ ဤစက်တွင် ထည့်သွင်းထားသော အပလီကေးရှင်းများကို သုံးခွင့်ရရန်အတွက် &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ကိုအဝေးမှ သုံးခွင့်ပေးနိုင်ရန် &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>
+ <string name="helper_summary_app_streaming" msgid="5344341720432827388">"သင့်စက်များကြား အက်ပ်များ တိုက်ရိုက်လွှင့်ရန် ဤဝန်ဆောင်မှုကို အသုံးပြုသည်"</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>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"အကြောင်းကြားချက်များ"</string>
+ <string name="permission_notification_summary" msgid="4398672775023193663">"အဆက်အသွယ်၊ မက်ဆေ့ဂျ်နှင့် ဓာတ်ပုံကဲ့သို့ အချက်အလက်များအပါအဝင် အကြောင်းကြားချက်အားလုံးကို ဖတ်နိုင်သည်"</string>
+ <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>
+ <string name="helper_summary_computer" product="default" msgid="467996390095403648">"ဤဝန်ဆောင်မှုသည် ဓာတ်ပုံ၊ မီဒီယာနှင့် အကြောင်းကြားချက်များကို သင့်ဖုန်းမှ အခြားစက်များသို့ မျှဝေသည်"</string>
+ <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"ဤဝန်ဆောင်မှုသည် ဓာတ်ပုံ၊ မီဒီယာနှင့် အကြောင်းကြားချက်များကို သင့်ဖုန်းမှ အခြားစက်များသို့ မျှဝေသည်"</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>
+ <string name="consent_ok" msgid="3662376764371001106">"OK"</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-nb/strings.xml b/packages/CompanionDeviceManager/res/values-nb/strings.xml
index aa73f5dff065..078a2d4a64cf 100644
--- a/packages/CompanionDeviceManager/res/values-nb/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-nb/strings.xml
@@ -22,18 +22,30 @@
<string name="chooser_title" msgid="2262294130493605839">"Velg <xliff:g id="PROFILE_NAME">%1$s</xliff:g> som skal administreres av &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> får tillatelse til å samhandle med varslene dine og får tilgang til Telefon, SMS, kontakter og Kalender."</string>
<string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> får tillatelse til å samhandle med varslene dine og får tilgang til Telefon, SMS, kontakter og Kalender."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Vil du gi &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; tillatelse til å strømme apper?"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Apper"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"Strøm appene på telefonen"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"Gi &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; tilgang til denne informasjonen fra telefonen din"</string>
<string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Tillat at &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; gir &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ekstern tilgang til apper som er installert på denne telefonen, når den er koblet til internett."</string>
<string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Tillat at &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; gir &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ekstern tilgang til apper som er installert på dette nettbrettet, når det er koblet til internett."</string>
<string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Tillat at &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; gir &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ekstern tilgang til apper som er installert på denne enheten, når den er koblet til internett."</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Tjenester på flere enheter"</string>
+ <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Denne tjenesten brukes til å strømme apper mellom enhetene dine"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Gi &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; tilgang til denne informasjonen fra telefonen din"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Varsler"</string>
+ <string name="permission_notification_summary" msgid="4398672775023193663">"Kan lese alle varsler, inkludert informasjon som kontrakter, meldinger og bilder"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"Bilder og medier"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Google Play-tjenester"</string>
+ <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Denne tjenesten deler bilder, medier og varsler fra telefonen din til andre enheter"</string>
+ <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Denne tjenesten deler bilder, medier og varsler fra telefonen din til andre enheter"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"enhet"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Tillat"</string>
<string name="consent_no" msgid="2640796915611404382">"Ikke tillat"</string>
+ <string name="consent_ok" msgid="3662376764371001106">"OK"</string>
<string name="permission_sync_confirmation_title" msgid="667074294393493186">"Overfør apptillatelser til klokken din"</string>
<string name="permission_sync_summary" msgid="8873391306499120778">"For å gjøre det enklere å konfigurere klokken din bruker apper som installeres på klokken under konfigureringen, samme tillatelser som på telefonen.\n\n Disse tillatelsene kan inkludere tilgang til mikrofonen på klokken og posisjon."</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-ne/strings.xml b/packages/CompanionDeviceManager/res/values-ne/strings.xml
index 3ba75eb31aad..fd8a6cf23ba7 100644
--- a/packages/CompanionDeviceManager/res/values-ne/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ne/strings.xml
@@ -22,18 +22,30 @@
<string name="chooser_title" msgid="2262294130493605839">"आफूले &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; प्रयोग गरी व्यवस्थापन गर्न चाहेको <xliff:g id="PROFILE_NAME">%1$s</xliff:g> चयन गर्नुहोस्"</string>
<string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> लाई तपाईंका सूचना हेर्ने र फोन, SMS, कन्ट्याक्ट तथा पात्रोसम्बन्धी अनुमतिहरू हेर्ने तथा प्रयोग गर्ने अनुमति दिइने छ।"</string>
<string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> लाई तपाईंका सूचना हेर्ने र फोन, SMS, कन्ट्याक्ट तथा पात्रोसम्बन्धी अनुमतिहरू हेर्ने तथा प्रयोग गर्ने अनुमति दिइने छ।"</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; लाई एपहरू स्ट्रिम गर्ने अनुमति दिने हो?"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"एपहरू"</string>
+ <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="summary_app_streaming" product="default" msgid="6105916810614498138">"यो डिभाइस इन्टरनेटमा कनेक्ट भएका बेला, &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;लाई &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; लाई यो फोनमा इन्स्टल गरिएका एप टाढैबाट प्रयोग गर्ने अनुमति दिन दिनुहोस्।"</string>
<string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"यो डिभाइस इन्टरनेटमा कनेक्ट भएका बेला, &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;लाई &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; लाई यो ट्याब्लेटमा इन्स्टल गरिएका एप टाढैबाट प्रयोग गर्ने अनुमति दिन दिनुहोस्।"</string>
<string name="summary_app_streaming" product="device" msgid="7614171699434639963">"यो डिभाइस इन्टरनेटमा कनेक्ट भएका बेला, &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; लाई &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; लाई यो डिभाइसमा इन्स्टल गरिएका एप टाढैबाट प्रयोग गर्ने अनुमति दिन दिनुहोस्।"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"क्रस-डिभाइस सेवाहरू"</string>
+ <string name="helper_summary_app_streaming" msgid="5344341720432827388">"यो सेवा तपाईंको एउटा डिभाइसबाट अर्को डिभाइसमा एपहरू स्ट्रिम गर्न प्रयोग गरिन्छ"</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>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"सूचनाहरू"</string>
+ <string name="permission_notification_summary" msgid="4398672775023193663">"कन्ट्याक्ट, म्यासेज र फोटोलगायतका व्यक्तिगत जानकारीसहित तपाईंका सूचनाहरू पढ्न सक्छ"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"फोटो र मिडिया"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Google Play services"</string>
+ <string name="helper_summary_computer" product="default" msgid="467996390095403648">"यो सेवाले तपाईंको फोनबाट अन्य डिभाइसमा फोटो, मिडिया र सूचनाहरू सेयर गर्छ"</string>
+ <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"यो सेवाले तपाईंको फोनबाट अन्य डिभाइसमा फोटो, मिडिया र सूचनाहरू सेयर गर्छ"</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>
+ <string name="consent_ok" msgid="3662376764371001106">"ठिक छ"</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-night/themes.xml b/packages/CompanionDeviceManager/res/values-night/themes.xml
new file mode 100644
index 000000000000..6eb16e726321
--- /dev/null
+++ b/packages/CompanionDeviceManager/res/values-night/themes.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.
+ -->
+
+<resources>
+
+ <style name="ChooserActivity"
+ parent="@android:style/Theme.DeviceDefault.Dialog.NoActionBar">
+ <item name="*android:windowFixedHeightMajor">100%</item>
+ <item name="*android:windowFixedHeightMinor">100%</item>
+ <item name="android:windowBackground">@android:color/transparent</item>
+ </style>
+
+</resources>
diff --git a/packages/CompanionDeviceManager/res/values-nl/strings.xml b/packages/CompanionDeviceManager/res/values-nl/strings.xml
index bc09a58afee1..76ec957ebf73 100644
--- a/packages/CompanionDeviceManager/res/values-nl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-nl/strings.xml
@@ -22,18 +22,30 @@
<string name="chooser_title" msgid="2262294130493605839">"Een <xliff:g id="PROFILE_NAME">%1$s</xliff:g> kiezen om te beheren met &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> kan interactie hebben met je meldingen en toegang krijgen tot je rechten voor telefoon, sms, contacten en agenda."</string>
<string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> kan interactie hebben met je meldingen en toegang krijgen tot je rechten voor telefoon, sms, contacten en agenda."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Toestaan dat &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; apps streamt?"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Apps"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"De apps van je telefoon streamen"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; toegang geven tot deze informatie op je telefoon"</string>
<string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Toestaan dat &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; als er verbinding is &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; externe toegang geeft tot apps die zijn geïnstalleerd op deze telefoon."</string>
<string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Toestaan dat &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; als er verbinding is &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; externe toegang geeft tot apps die zijn geïnstalleerd op deze tablet."</string>
<string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Toestaan dat &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; als er verbinding is &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; externe toegang geeft tot apps die zijn geïnstalleerd op dit apparaat."</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Cross-device-services"</string>
+ <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Met deze service kun je apps streamen tussen je apparaten"</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; toegang geven tot deze informatie op je telefoon"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Meldingen"</string>
+ <string name="permission_notification_summary" msgid="4398672775023193663">"Kan alle meldingen lezen, waaronder informatie zoals contacten, berichten en foto\'s"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"Foto\'s en media"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Google Play-services"</string>
+ <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Met deze service kun je foto\'s, media en meldingen vanaf je telefoon met andere apparaten delen"</string>
+ <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Met deze service kun je foto\'s, media en meldingen vanaf je telefoon met andere apparaten delen"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"apparaat"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Toestaan"</string>
<string name="consent_no" msgid="2640796915611404382">"Niet toestaan"</string>
+ <string name="consent_ok" msgid="3662376764371001106">"OK"</string>
<string name="permission_sync_confirmation_title" msgid="667074294393493186">"App-rechten overzetten naar je horloge"</string>
<string name="permission_sync_summary" msgid="8873391306499120778">"We willen het makkelijker voor je maken om je horloge in te stellen. Daarom gebruiken apps die tijdens het instellen worden geïnstalleerd op je horloge, dezelfde rechten als op je telefoon.\n\n Deze rechten kunnen toegang tot de microfoon en locatie van je horloge omvatten."</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-or/strings.xml b/packages/CompanionDeviceManager/res/values-or/strings.xml
index 92d0a5ef5f1d..6b6649290802 100644
--- a/packages/CompanionDeviceManager/res/values-or/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-or/strings.xml
@@ -22,18 +22,30 @@
<string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; ଦ୍ୱାରା ପରିଚାଳିତ ହେବା ପାଇଁ ଏକ <xliff:g id="PROFILE_NAME">%1$s</xliff:g>କୁ ବାଛନ୍ତୁ"</string>
<string name="summary_watch" product="default" msgid="7113724443198337683">"ଆପଣଙ୍କ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକ ସହ ଇଣ୍ଟରାକ୍ଟ କରିବା ଏବଂ ଆପଣଙ୍କ ଫୋନ, SMS, ଯୋଗାଯୋଗ ଓ କ୍ୟାଲେଣ୍ଡର ଅନୁମତିଗୁଡ଼ିକୁ ଆକ୍ସେସ କରିବା ପାଇଁ <xliff:g id="APP_NAME">%1$s</xliff:g>କୁ ଅନୁମତି ଦିଆଯିବ।"</string>
<string name="summary_watch" product="tablet" msgid="7113724443198337683">"ଆପଣଙ୍କ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକ ସହ ଇଣ୍ଟରାକ୍ଟ କରିବା ଏବଂ ଆପଣଙ୍କ ଫୋନ, SMS, ଯୋଗାଯୋଗ ଓ କ୍ୟାଲେଣ୍ଡର ଅନୁମତିଗୁଡ଼ିକୁ ଆକ୍ସେସ କରିବା ପାଇଁ <xliff:g id="APP_NAME">%1$s</xliff:g>କୁ ଅନୁମତି ଦିଆଯିବ।"</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;କୁ ଆପ୍ଲିକେସନଗୁଡ଼ିକ ଷ୍ଟ୍ରିମ କରିବା ପାଇଁ ଅନୁମତି ଦେବେ କି?"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"ଆପ୍ସ"</string>
+ <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="summary_app_streaming" product="default" msgid="6105916810614498138">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;କୁ, ଏହି ଫୋନଟି ସଂଯୁକ୍ତ ହୋଇଥିବା ବେଳେ ଏଥିରେ ଇନଷ୍ଟଲ କରାଯାଇଥିବା ଆପ୍ଲିକେସନଗୁଡ଼ିକୁ ଆକ୍ସେସ କରିବା ପାଇଁ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;କୁ ରିମୋଟ ଆକ୍ସେସ ପ୍ରଦାନ କରିବାକୁ ଦିଅନ୍ତୁ।"</string>
<string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;କୁ, ଏହି ଟାବଲେଟଟି ସଂଯୁକ୍ତ ହୋଇଥିବା ବେଳେ ଏଥିରେ ଇନଷ୍ଟଲ କରାଯାଇଥିବା ଆପ୍ଲିକେସନଗୁଡ଼ିକୁ ଆକ୍ସେସ କରିବା ପାଇଁ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;କୁ ରିମୋଟ ଆକ୍ସେସ ପ୍ରଦାନ କରିବାକୁ ଦିଅନ୍ତୁ।"</string>
<string name="summary_app_streaming" product="device" msgid="7614171699434639963">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;କୁ, ଏହି ଡିଭାଇସଟି ସଂଯୁକ୍ତ ହୋଇଥିବା ବେଳେ ଏଥିରେ ଇନଷ୍ଟଲ କରାଯାଇଥିବା ଆପ୍ଲିକେସନଗୁଡ଼ିକୁ ଆକ୍ସେସ କରିବା ପାଇଁ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;କୁ ରିମୋଟ ଆକ୍ସେସ ପ୍ରଦାନ କରିବାକୁ ଦିଅନ୍ତୁ।"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"କ୍ରସ-ଡିଭାଇସ ସେବାଗୁଡ଼ିକ"</string>
+ <string name="helper_summary_app_streaming" msgid="5344341720432827388">"ଆପଣଙ୍କ ଡିଭାଇସଗୁଡ଼ିକ ମଧ୍ୟରେ ଆପ୍ସକୁ ଷ୍ଟ୍ରିମ କରିବା ପାଇଁ ଏହି ସେବାକୁ ବ୍ୟବହାର କରାଯାଏ"</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>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକ"</string>
+ <string name="permission_notification_summary" msgid="4398672775023193663">"ଯୋଗାଯୋଗ, ମେସେଜ ଏବଂ ଫଟୋଗୁଡ଼ିକ ପରି ସୂଚନା ସମେତ ସମସ୍ତ ବିଜ୍ଞପ୍ତିକୁ ପଢ଼ିପାରିବ"</string>
+ <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>
+ <string name="helper_summary_computer" product="default" msgid="467996390095403648">"ଏହି ସେବା ଆପଣଙ୍କ ଫୋନରୁ ଅନ୍ୟ ଡିଭାଇସଗୁଡ଼ିକୁ ଫଟୋ, ମିଡିଆ ଏବଂ ବିଜ୍ଞପ୍ତି ସେୟାର କରେ"</string>
+ <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"ଏହି ସେବା ଆପଣଙ୍କ ଫୋନରୁ ଅନ୍ୟ ଡିଭାଇସଗୁଡ଼ିକୁ ଫଟୋ, ମିଡିଆ ଏବଂ ବିଜ୍ଞପ୍ତି ସେୟାର କରେ"</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>
+ <string name="consent_ok" msgid="3662376764371001106">"ଠିକ୍ ଅଛି"</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-pa/strings.xml b/packages/CompanionDeviceManager/res/values-pa/strings.xml
index c28be2543707..93b018e3e54e 100644
--- a/packages/CompanionDeviceManager/res/values-pa/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-pa/strings.xml
@@ -22,18 +22,30 @@
<string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; ਵੱਲੋਂ ਪ੍ਰਬੰਧਿਤ ਕੀਤੇ ਜਾਣ ਲਈ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ਚੁਣੋ"</string>
<string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਨੂੰ ਤੁਹਾਡੀਆਂ ਸੂਚਨਾਵਾਂ ਨਾਲ ਅੰਤਰਕਿਰਿਆ ਕਰਨ ਅਤੇ ਤੁਹਾਡੇ ਫ਼ੋਨ, SMS, ਸੰਪਰਕ ਅਤੇ ਕੈਲੰਡਰ ਦੀਆਂ ਇਜਾਜ਼ਤਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਹੋਵੇਗੀ।"</string>
<string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਨੂੰ ਤੁਹਾਡੀਆਂ ਸੂਚਨਾਵਾਂ ਨਾਲ ਅੰਤਰਕਿਰਿਆ ਕਰਨ ਅਤੇ ਤੁਹਾਡੇ ਫ਼ੋਨ, SMS, ਸੰਪਰਕ ਅਤੇ ਕੈਲੰਡਰ ਦੀਆਂ ਇਜਾਜ਼ਤਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਹੋਵੇਗੀ।"</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"ਕੀ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&amp;gt ਨੂੰ ਐਪਲੀਕੇਸ਼ਨਾਂ ਸਟ੍ਰੀਮ ਕਰਨ ਦੀ ਆਗਿਆ ਦੇਣੀ ਹੈ?"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"ਐਪਾਂ"</string>
+ <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="summary_app_streaming" product="default" msgid="6105916810614498138">"ਕਨੈਕਟ ਹੋਣ \'ਤੇ ਇਸ ਫ਼ੋਨ \'ਤੇ ਸਥਾਪਤ ਐਪਲੀਕੇਸ਼ਨਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਲਈ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ਨੂੰ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ਨੂੰ ਰਿਮੋਟ ਪਹੁੰਚ ਮੁਹੱਈਆ ਕਰਵਾਉਣ ਦਿਓ।"</string>
<string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"ਕਨੈਕਟ ਹੋਣ \'ਤੇ ਇਸ ਟੈਬਲੈੱਟ \'ਤੇ ਸਥਾਪਤ ਐਪਲੀਕੇਸ਼ਨਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਲਈ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ਨੂੰ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ਨੂੰ ਰਿਮੋਟ ਪਹੁੰਚ ਮੁਹੱਈਆ ਕਰਵਾਉਣ ਦਿਓ।"</string>
<string name="summary_app_streaming" product="device" msgid="7614171699434639963">"ਕਨੈਕਟ ਹੋਣ \'ਤੇ ਇਸ ਡੀਵਾਈਸ \'ਤੇ ਸਥਾਪਤ ਐਪਲੀਕੇਸ਼ਨਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਲਈ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ਨੂੰ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ਨੂੰ ਰਿਮੋਟ ਪਹੁੰਚ ਮੁਹੱਈਆ ਕਰਵਾਉਣ ਦਿਓ।"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"ਕ੍ਰਾਸ-ਡੀਵਾਈਸ ਸੇਵਾਵਾਂ"</string>
+ <string name="helper_summary_app_streaming" msgid="5344341720432827388">"ਇਸ ਸੇਵਾ ਦੀ ਵਰਤੋਂ ਤੁਹਾਡੇ ਡੀਵਾਈਸਾਂ ਵਿਚਕਾਰ ਐਪਾਂ ਨੂੰ ਸਟ੍ਰੀਮ ਕਰਨ ਲਈ ਕੀਤੀ ਜਾਂਦੀ ਹੈ"</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>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"ਸੂਚਨਾਵਾਂ"</string>
+ <string name="permission_notification_summary" msgid="4398672775023193663">"ਤੁਸੀਂ ਸਾਰੀਆਂ ਸੂਚਨਾਵਾਂ ਪੜ੍ਹ ਸਕਦੇ ਹੋ, ਜਿਨ੍ਹਾਂ ਵਿੱਚ ਸੰਪਰਕਾਂ, ਸੁਨੇਹਿਆਂ ਅਤੇ ਫ਼ੋਟੋਆਂ ਵਰਗੀ ਜਾਣਕਾਰੀ ਸ਼ਾਮਲ ਹੁੰਦੀ ਹੈ"</string>
+ <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>
+ <string name="helper_summary_computer" product="default" msgid="467996390095403648">"ਇਹ ਸੇਵਾ ਫ਼ੋਟੋਆਂ, ਮੀਡੀਆ ਅਤੇ ਸੂਚਨਾਵਾਂ ਨੂੰ ਤੁਹਾਡੇ ਫ਼ੋਨ ਤੋਂ ਹੋਰ ਡੀਵਾਈਸਾਂ \'ਤੇ ਸਾਂਝਾ ਕਰਦੀ ਹੈ"</string>
+ <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"ਇਹ ਸੇਵਾ ਫ਼ੋਟੋਆਂ, ਮੀਡੀਆ ਅਤੇ ਸੂਚਨਾਵਾਂ ਨੂੰ ਤੁਹਾਡੇ ਫ਼ੋਨ ਤੋਂ ਹੋਰ ਡੀਵਾਈਸਾਂ \'ਤੇ ਸਾਂਝਾ ਕਰਦੀ ਹੈ"</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>
+ <string name="consent_ok" msgid="3662376764371001106">"ਠੀਕ ਹੈ"</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-pl/strings.xml b/packages/CompanionDeviceManager/res/values-pl/strings.xml
index f9fd206250d9..a15af4b51dfb 100644
--- a/packages/CompanionDeviceManager/res/values-pl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-pl/strings.xml
@@ -22,18 +22,30 @@
<string name="chooser_title" msgid="2262294130493605839">"Wybierz profil <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, którym ma zarządzać aplikacja &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="summary_watch" product="default" msgid="7113724443198337683">"Aplikacja <xliff:g id="APP_NAME">%1$s</xliff:g> będzie mogła korzystać z powiadomień oraz uprawnień dotyczących Telefonu, SMS-ów, Kontaktów i Kalendarza."</string>
<string name="summary_watch" product="tablet" msgid="7113724443198337683">"Aplikacja <xliff:g id="APP_NAME">%1$s</xliff:g> będzie mogła korzystać z powiadomień oraz uprawnień dotyczących Telefonu, SMS-ów, Kontaktów i Kalendarza."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Zezwolić aplikacji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; na strumieniowanie danych z aplikacji?"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Aplikacje"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"Odtwarzaj strumieniowo aplikacje z telefonu"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"Zezwól aplikacji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; na dostęp do tych informacji na Twoim telefonie"</string>
<string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Zezwól na zapewnianie przez aplikację &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; zdalnego dostępu do aplikacji zainstalowanych na telefonie &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; po połączeniu jej z tym telefonem."</string>
<string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Zezwól na zapewnianie przez aplikację &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; zdalnego dostępu do aplikacji zainstalowanych na tablecie &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; po połączeniu jej z tym tabletem."</string>
<string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Zezwól na zapewnianie przez aplikację &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; zdalnego dostępu do aplikacji zainstalowanych na urządzeniu &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; po połączeniu jej z urządzeniem."</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Usługi na innym urządzeniu"</string>
+ <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Ta usługa jest używana do strumieniowego odtwarzania danych z aplikacji między urządzeniami"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Zezwól aplikacji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; na dostęp do tych informacji na Twoim telefonie"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Powiadomienia"</string>
+ <string name="permission_notification_summary" msgid="4398672775023193663">"Może odczytywać wszystkie powiadomienia, w tym informacje takie jak kontakty, wiadomości i zdjęcia"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"Zdjęcia i multimedia"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Usługi Google Play"</string>
+ <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Ta usługa udostępnia zdjęcia, multimedia i powiadomienia z telefonu innym urządzeniom"</string>
+ <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Ta usługa udostępnia zdjęcia, multimedia i powiadomienia z telefonu innym urządzeniom"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"urządzenie"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Zezwól"</string>
<string name="consent_no" msgid="2640796915611404382">"Nie zezwalaj"</string>
+ <string name="consent_ok" msgid="3662376764371001106">"OK"</string>
<string name="permission_sync_confirmation_title" msgid="667074294393493186">"Przenieś uprawnienia aplikacji na zegarek"</string>
<string name="permission_sync_summary" msgid="8873391306499120778">"Aby łatwiej było skonfigurować zegarek, aplikacje zainstalowane na nim podczas konfiguracji będą korzystały z tych samych uprawnień co telefon.\n\n Może to oznaczać dostęp do mikrofonu i lokalizacji na zegarku."</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml b/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml
index 161188c70c6c..7d2282371d39 100644
--- a/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml
@@ -22,18 +22,30 @@
<string name="chooser_title" msgid="2262294130493605839">"Escolha um <xliff:g id="PROFILE_NAME">%1$s</xliff:g> para ser gerenciado pelo app &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="summary_watch" product="default" msgid="7113724443198337683">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> poderá interagir com suas notificações e acessar as permissões do Telefone, de SMS, de Contatos e da Agenda."</string>
<string name="summary_watch" product="tablet" msgid="7113724443198337683">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> poderá interagir com suas notificações e acessar as permissões do Telefone, de SMS, de Contatos e da Agenda."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Permitir que o app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; faça streaming de aplicativos?"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Apps"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"Faça streaming dos apps do seu smartphone"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"Permitir que o app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; acesse essas informações do smartphone"</string>
<string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Permita que o app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; conceda ao &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; acesso remoto aos aplicativos instalados no smartphone quando ele estiver conectado."</string>
<string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Permita que o app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; conceda ao &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; acesso remoto aos aplicativos instalados no tablet quando ele estiver conectado."</string>
<string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Permita que o app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; conceda ao &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; acesso remoto aos aplicativos instalados no dispositivo quando ele estiver conectado."</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Serviços entre dispositivos"</string>
+ <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Este serviço é usado para fazer streaming de apps entre seus dispositivos"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Autorizar que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; acesse essas informações do smartphone"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Notificações"</string>
+ <string name="permission_notification_summary" msgid="4398672775023193663">"Pode ler todas as notificações, incluindo informações como contatos, mensagens e fotos"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"Fotos e mídia"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Google Play Services"</string>
+ <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Este serviço compartilha fotos, mídia e notificações do seu smartphone para outros dispositivos"</string>
+ <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Este serviço compartilha fotos, mídia e notificações do seu smartphone para outros dispositivos"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Permitir"</string>
<string name="consent_no" msgid="2640796915611404382">"Não permitir"</string>
+ <string name="consent_ok" msgid="3662376764371001106">"OK"</string>
<string name="permission_sync_confirmation_title" msgid="667074294393493186">"Transferir as permissões de apps para o relógio"</string>
<string name="permission_sync_summary" msgid="8873391306499120778">"Para facilitar a configuração do relógio, os apps instalados nele durante a configuração vão usar as mesmas permissões que o smartphone.\n\n Essas permissões podem incluir acesso ao microfone ou à localização do relógio."</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml b/packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml
index 9124a405198a..e0c717c1f9ff 100644
--- a/packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml
@@ -22,18 +22,30 @@
<string name="chooser_title" msgid="2262294130493605839">"Escolha um <xliff:g id="PROFILE_NAME">%1$s</xliff:g> para ser gerido pela app &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="summary_watch" product="default" msgid="7113724443198337683">"A app <xliff:g id="APP_NAME">%1$s</xliff:g> poderá interagir com as suas notificações e aceder às autorizações do Telefone, SMS, Contactos e Calendário."</string>
<string name="summary_watch" product="tablet" msgid="7113724443198337683">"A app <xliff:g id="APP_NAME">%1$s</xliff:g> poderá interagir com as suas notificações e aceder às autorizações do Telefone, SMS, Contactos e Calendário."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Permitir que a app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; faça stream de aplicações?"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Apps"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"Faça stream das apps do telemóvel"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"Permita que a app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; aceda a estas informações do seu telemóvel"</string>
<string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Permita que a app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; forneça acesso remoto ao &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; para aceder a aplicações instaladas neste telemóvel quando estiver ligado."</string>
<string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Permita que a app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; forneça acesso remoto ao &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; para aceder a aplicações instaladas neste tablet quando estiver ligado."</string>
<string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Permita que a app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; forneça acesso remoto ao &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; para aceder a aplicações instaladas neste dispositivo quando estiver ligado."</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Serviços entre dispositivos"</string>
+ <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Este serviço é utilizado para fazer stream de apps entre os seus dispositivos"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Permita que a app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; aceda a estas informações do seu telemóvel"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Notificações"</string>
+ <string name="permission_notification_summary" msgid="4398672775023193663">"Pode ler todas as notificações, incluindo informações como contratos, mensagens e fotos"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"Fotos e multimédia"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Serviços do Google Play"</string>
+ <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Este serviço partilha fotos, conteúdo multimédia e notificações do seu telemóvel para outros dispositivos"</string>
+ <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Este serviço partilha fotos, conteúdo multimédia e notificações do seu telemóvel para outros dispositivos"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Permitir"</string>
<string name="consent_no" msgid="2640796915611404382">"Não permitir"</string>
+ <string name="consent_ok" msgid="3662376764371001106">"OK"</string>
<string name="permission_sync_confirmation_title" msgid="667074294393493186">"Transfira as autorizações da app para o seu relógio"</string>
<string name="permission_sync_summary" msgid="8873391306499120778">"Para facilitar a configuração do seu relógio, as apps instaladas no mesmo durante a configuração utilizarão as mesmas autorizações que o telemóvel.\n\n Estas autorizações podem incluir o acesso ao microfone e à localização do seu relógio."</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-pt/strings.xml b/packages/CompanionDeviceManager/res/values-pt/strings.xml
index 161188c70c6c..7d2282371d39 100644
--- a/packages/CompanionDeviceManager/res/values-pt/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-pt/strings.xml
@@ -22,18 +22,30 @@
<string name="chooser_title" msgid="2262294130493605839">"Escolha um <xliff:g id="PROFILE_NAME">%1$s</xliff:g> para ser gerenciado pelo app &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="summary_watch" product="default" msgid="7113724443198337683">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> poderá interagir com suas notificações e acessar as permissões do Telefone, de SMS, de Contatos e da Agenda."</string>
<string name="summary_watch" product="tablet" msgid="7113724443198337683">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> poderá interagir com suas notificações e acessar as permissões do Telefone, de SMS, de Contatos e da Agenda."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Permitir que o app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; faça streaming de aplicativos?"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Apps"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"Faça streaming dos apps do seu smartphone"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"Permitir que o app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; acesse essas informações do smartphone"</string>
<string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Permita que o app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; conceda ao &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; acesso remoto aos aplicativos instalados no smartphone quando ele estiver conectado."</string>
<string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Permita que o app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; conceda ao &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; acesso remoto aos aplicativos instalados no tablet quando ele estiver conectado."</string>
<string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Permita que o app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; conceda ao &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; acesso remoto aos aplicativos instalados no dispositivo quando ele estiver conectado."</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Serviços entre dispositivos"</string>
+ <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Este serviço é usado para fazer streaming de apps entre seus dispositivos"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Autorizar que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; acesse essas informações do smartphone"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Notificações"</string>
+ <string name="permission_notification_summary" msgid="4398672775023193663">"Pode ler todas as notificações, incluindo informações como contatos, mensagens e fotos"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"Fotos e mídia"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Google Play Services"</string>
+ <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Este serviço compartilha fotos, mídia e notificações do seu smartphone para outros dispositivos"</string>
+ <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Este serviço compartilha fotos, mídia e notificações do seu smartphone para outros dispositivos"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Permitir"</string>
<string name="consent_no" msgid="2640796915611404382">"Não permitir"</string>
+ <string name="consent_ok" msgid="3662376764371001106">"OK"</string>
<string name="permission_sync_confirmation_title" msgid="667074294393493186">"Transferir as permissões de apps para o relógio"</string>
<string name="permission_sync_summary" msgid="8873391306499120778">"Para facilitar a configuração do relógio, os apps instalados nele durante a configuração vão usar as mesmas permissões que o smartphone.\n\n Essas permissões podem incluir acesso ao microfone ou à localização do relógio."</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-ro/strings.xml b/packages/CompanionDeviceManager/res/values-ro/strings.xml
index da7ae9e0f1bd..61b47fbb7d71 100644
--- a/packages/CompanionDeviceManager/res/values-ro/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ro/strings.xml
@@ -22,18 +22,30 @@
<string name="chooser_title" msgid="2262294130493605839">"Alegeți un profil <xliff:g id="PROFILE_NAME">%1$s</xliff:g> pe care să îl gestioneze &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> va putea să interacționeze cu notificările dvs. și să vă acceseze permisiunile pentru Telefon, SMS-uri, Agendă și Calendar."</string>
<string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> va putea să interacționeze cu notificările dvs. și să vă acceseze permisiunile pentru Telefon, SMS-uri, Agendă și Calendar."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Lăsați &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; să redea în stream aplicații?"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Aplicații"</string>
+ <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="summary_app_streaming" product="default" msgid="6105916810614498138">"Lăsați &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; să ofere acces la distanță pentru &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ca să se poată accesa aplicațiile instalate pe acest telefon când se conectează utilizatorul."</string>
<string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Lăsați &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; să ofere acces la distanță pentru &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ca să se poată accesa aplicațiile instalate pe această tabletă când se conectează utilizatorul."</string>
<string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Lăsați &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; să ofere acces la distanță pentru &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ca să se poată accesa aplicațiile instalate pe acest dispozitiv când se conectează utilizatorul."</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Servicii pe mai multe dispozitive"</string>
+ <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Acest serviciu se folosește pentru a proiecta aplicații între dispozitive"</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>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Notificări"</string>
+ <string name="permission_notification_summary" msgid="4398672775023193663">"Poate să citească toate notificările, inclusiv informații cum ar fi contracte, mesaje și fotografii"</string>
+ <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>
+ <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Serviciul trimite fotografii, conținut media și notificări de pe telefon pe alte dispozitive"</string>
+ <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Serviciul trimite fotografii, conținut media și notificări de pe telefon pe alte dispozitive"</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>
+ <string name="consent_ok" msgid="3662376764371001106">"OK"</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-ru/strings.xml b/packages/CompanionDeviceManager/res/values-ru/strings.xml
index dbb09c9e7c96..062314f337b6 100644
--- a/packages/CompanionDeviceManager/res/values-ru/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ru/strings.xml
@@ -22,18 +22,30 @@
<string name="chooser_title" msgid="2262294130493605839">"Выберите устройство (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>), которым будет управлять приложение &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="summary_watch" product="default" msgid="7113724443198337683">"Приложению \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" будет предоставлен доступ к уведомлениям, а также следующие разрешения: телефон, SMS, контакты и календарь."</string>
<string name="summary_watch" product="tablet" msgid="7113724443198337683">"Приложению \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" будет предоставлен доступ к уведомлениям, а также следующие разрешения: телефон, SMS, контакты и календарь."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Разрешить приложению &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; транслировать приложения?"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Приложения"</string>
+ <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="summary_app_streaming" product="default" msgid="6105916810614498138">"Разрешить приложению &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; при наличии подключения предоставить устройству &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; удаленный доступ к приложениям, установленным на этом телефоне."</string>
<string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Разрешить приложению &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; при наличии подключения предоставить устройству &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; удаленный доступ к приложениям, установленным на этом планшете."</string>
<string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Разрешить приложению &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; при наличии подключения предоставить устройству &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; удаленный доступ к приложениям, установленным на этом устройстве."</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Сервисы стриминга приложений"</string>
+ <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Этот сервис используется для трансляции приложений с одного устройства на другое."</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>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Уведомления"</string>
+ <string name="permission_notification_summary" msgid="4398672775023193663">"Чтение всех уведомлений, в том числе сведений о контактах, сообщениях и фотографиях."</string>
+ <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>
+ <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Этот сервис используется для отправки фотографий, медиафайлов и уведомлений с вашего телефона на другие устройства."</string>
+ <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Этот сервис используется для отправки фотографий, медиафайлов и уведомлений с вашего телефона на другие устройства."</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>
+ <string name="consent_ok" msgid="3662376764371001106">"ОК"</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-si/strings.xml b/packages/CompanionDeviceManager/res/values-si/strings.xml
index a3de2a393181..65f7865d4671 100644
--- a/packages/CompanionDeviceManager/res/values-si/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-si/strings.xml
@@ -22,18 +22,30 @@
<string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; මගින් කළමනාකරණය කරනු ලැබීමට <xliff:g id="PROFILE_NAME">%1$s</xliff:g>ක් තෝරන්න"</string>
<string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ඔබගේ දැනුම්දීම් සමඟ අන්තර්ක්‍රියා කිරීමට සහ ඔබගේ දුරකථනය, කෙටි පණිවුඩ, සම්බන්ධතා සහ දින දර්ශන අවසර වෙත ප්‍රවේශ වීමට ඉඩ දෙනු ඇත."</string>
<string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ඔබගේ දැනුම්දීම් සමඟ අන්තර්ක්‍රියා කිරීමට සහ ඔබගේ දුරකථනය, කෙටි පණිවුඩ, සම්බන්ධතා සහ දින දර්ශන අවසර වෙත ප්‍රවේශ වීමට ඉඩ දෙනු ඇත."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; හට යෙදුම් ප්‍රවාහ කිරීමට ඉඩ දෙන්නද?"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"යෙදුම්"</string>
+ <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="summary_app_streaming" product="default" msgid="6105916810614498138">"සම්බන්ධ වූ විට මෙම දුරකථනයේ ස්ථාපනය කර ඇති යෙදුම් වෙත ප්‍රවේශ වීමට &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; හට &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; හට දුරස්ථ ප්‍රවේශය ලබා දීමට ඉඩ දෙන්න."</string>
<string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"සම්බන්ධ වූ විට මෙම ටැබ්ලටයේ ස්ථාපනය කර ඇති යෙදුම් වෙත ප්‍රවේශ වීමට &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; හට &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; හට දුරස්ථ ප්‍රවේශය ලබා දීමට ඉඩ දෙන්න."</string>
<string name="summary_app_streaming" product="device" msgid="7614171699434639963">"සම්බන්ධ වූ විට මෙම උපාංගයේ ස්ථාපනය කර ඇති යෙදුම් වෙත ප්‍රවේශ වීමට &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; හට &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; හට දුරස්ථ ප්‍රවේශය ලබා දීමට ඉඩ දෙන්න."</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"හරස්-උපාංග සේවා"</string>
+ <string name="helper_summary_app_streaming" msgid="5344341720432827388">"මෙම සේවාව ඔබගේ උපාංග අතර යෙදුම් ප්‍රවාහ කිරීමට භාවිත වේ"</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>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"දැනුම්දීම්"</string>
+ <string name="permission_notification_summary" msgid="4398672775023193663">"ගිවිසුම්, පණිවිඩ සහ ඡායාරූප වැනි තොරතුරු ඇතුළුව සියලු දැනුම්දීම් කියවිය හැකිය"</string>
+ <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>
+ <string name="helper_summary_computer" product="default" msgid="467996390095403648">"මෙම සේවාව ඔබගේ දුරකථනයෙන් වෙනත් උපාංග වෙත ඡායාරූප, මාධ්‍ය සහ දැනුම්දීම් බෙදා ගනී"</string>
+ <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"මෙම සේවාව ඔබගේ දුරකථනයෙන් වෙනත් උපාංග වෙත ඡායාරූප, මාධ්‍ය සහ දැනුම්දීම් බෙදා ගනී"</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>
+ <string name="consent_ok" msgid="3662376764371001106">"හරි"</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-sk/strings.xml b/packages/CompanionDeviceManager/res/values-sk/strings.xml
index dd75ef590913..167eac8c8fdc 100644
--- a/packages/CompanionDeviceManager/res/values-sk/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sk/strings.xml
@@ -22,18 +22,30 @@
<string name="chooser_title" msgid="2262294130493605839">"Vyberte profil <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, ktorý bude spravovať aplikácia &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> bude môcť interagovať s vašimi upozorneniami a získavať prístup k povoleniam telefónu, SMS, kontaktov a kalendára."</string>
<string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> bude môcť interagovať s vašimi upozorneniami a získavať prístup k povoleniam telefónu, SMS, kontaktov a kalendára."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Chcete aplikácii &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; povoliť streamovanie aplikácií?"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Aplikácie"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"Streamujte aplikácie telefónu"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"Povoľte aplikácii &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; prístup k týmto informáciám z vášho telefónu"</string>
<string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Povoľte aplikácii &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; vzdialený prístup k telefónu &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;, aby mala po pripojení prístup k aplikáciám, ktoré sú v ňom nainštalované."</string>
<string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Povoľte aplikácii &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; vzdialený prístup k tabletu &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;, aby mala po pripojení prístup k aplikáciám, ktoré sú v ňom nainštalované."</string>
<string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Povoľte aplikácii &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; vzdialený prístup k zariadeniu &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;, aby mala po pripojení prístup k aplikáciám, ktoré sú v ňom nainštalované."</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Služby pre viacero zariadení"</string>
+ <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Pomocou tejto služby sa streamujú aplikácie medzi vašimi zariadeniami"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Povoľte aplikácii &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; prístup k týmto informáciám z vášho telefónu"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Upozornenia"</string>
+ <string name="permission_notification_summary" msgid="4398672775023193663">"Môže čítať všetky upozornenia vrátane informácií, ako sú kontakty, správy a fotky"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"Fotky a médiá"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Služby Google Play"</string>
+ <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Táto služba zdieľa fotky, médiá a upozornenia z vášho telefónu do iných zariadení"</string>
+ <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Táto služba zdieľa fotky, médiá a upozornenia z vášho telefónu do iných zariadení"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"zariadenie"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Povoliť"</string>
<string name="consent_no" msgid="2640796915611404382">"Nepovoliť"</string>
+ <string name="consent_ok" msgid="3662376764371001106">"OK"</string>
<string name="permission_sync_confirmation_title" msgid="667074294393493186">"Presun povolení aplikácie do hodiniek"</string>
<string name="permission_sync_summary" msgid="8873391306499120778">"V rámci zjednodušenia nastavenia hodiniek budú aplikácie nainštalované do hodiniek pri nastavovaní používať rovnaké povolenia ako váš telefón.\n\n Tieto povolenia môžu zahrnovať prístup k mikrofónu a polohe hodiniek."</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-sl/strings.xml b/packages/CompanionDeviceManager/res/values-sl/strings.xml
index 7cb5fb58fb60..5b795826c42d 100644
--- a/packages/CompanionDeviceManager/res/values-sl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sl/strings.xml
@@ -22,18 +22,30 @@
<string name="chooser_title" msgid="2262294130493605839">"Izbira naprave <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, ki jo bo upravljala aplikacija &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="summary_watch" product="default" msgid="7113724443198337683">"Aplikaciji <xliff:g id="APP_NAME">%1$s</xliff:g> bosta omogočena interakcija z obvestili in dostop do dovoljenj za telefon, sporočila SMS, stike in koledar."</string>
<string name="summary_watch" product="tablet" msgid="7113724443198337683">"Aplikaciji <xliff:g id="APP_NAME">%1$s</xliff:g> bosta omogočena interakcija z obvestili in dostop do dovoljenj za telefon, sporočila SMS, stike in koledar."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Želite aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; dovoliti pretočno predvajanje aplikacij?"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Aplikacije"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"Pretočno predvajanje aplikacij telefona"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"Dovolite, da &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; dostopa do teh podatkov v vašem telefonu."</string>
<string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; dovoli oddaljen dostop do telefona &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; za dostop do aplikacij, nameščenih v tem telefonu, ko je povezan v internet."</string>
<string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; dovoli oddaljen dostop do tabličnega računalnika &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; za dostop do aplikacij, nameščenih v tem tabličnem računalniku, ko je povezan v internet."</string>
<string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; dovoli oddaljen dostop do naprave &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; za dostop do aplikacij, nameščenih v tej napravi, ko je povezana v internet."</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Storitve za zunanje naprave"</string>
+ <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Ta storitev se uporablja za pretočno predvajanje aplikacij med napravami."</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Dovolite, da &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; dostopa do teh podatkov v vašem telefonu."</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Obvestila"</string>
+ <string name="permission_notification_summary" msgid="4398672775023193663">"Lahko bere vsa obvestila, vključno s podatki, kot so pogodbe, sporočila in fotografije."</string>
+ <string name="permission_storage" msgid="6831099350839392343">"Fotografije in predstavnost"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Storitve Google Play"</string>
+ <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Ta storitev deli fotografije, predstavnost in obvestila v telefonu z drugimi napravami."</string>
+ <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Ta storitev deli fotografije, predstavnost in obvestila v telefonu z drugimi napravami."</string>
<string name="profile_name_generic" msgid="6851028682723034988">"naprava"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Dovoli"</string>
<string name="consent_no" msgid="2640796915611404382">"Ne dovoli"</string>
+ <string name="consent_ok" msgid="3662376764371001106">"V redu"</string>
<string name="permission_sync_confirmation_title" msgid="667074294393493186">"Prenos dovoljenj za aplikacije v uro"</string>
<string name="permission_sync_summary" msgid="8873391306499120778">"Za lažjo nastavitev ure bodo aplikacije, ki so bile med nastavljanjem nameščene v uri, uporabljale enaka dovoljenja kot tiste v telefonu.\n\n Ta dovoljenja lahko vključujejo dostop do mikrofona in lokacije ure."</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-sq/strings.xml b/packages/CompanionDeviceManager/res/values-sq/strings.xml
index 62c711abf398..b69fa8afd092 100644
--- a/packages/CompanionDeviceManager/res/values-sq/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sq/strings.xml
@@ -22,18 +22,30 @@
<string name="chooser_title" msgid="2262294130493605839">"Zgjidh një profil <xliff:g id="PROFILE_NAME">%1$s</xliff:g> që do të menaxhohet nga &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> do të lejohet të ndërveprojë me njoftimet e tua dhe të ketë qasje te lejet e \"Telefonit\", \"SMS-ve\", \"Kontakteve\" dhe \"Kalendarit\"."</string>
<string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> do të lejohet të ndërveprojë me njoftimet e tua dhe të ketë qasje te lejet e \"Telefonit\", \"SMS-ve\", \"Kontakteve\" dhe \"Kalendarit\"."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Të lejohet që &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; të transmetojë aplikacionet?"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Aplikacionet"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"Transmeto aplikacionet e telefonit tënd"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"Lejo që &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; të ketë qasje në këtë informacion nga telefoni yt"</string>
<string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Lejo që &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; të ofrojë &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; qasje në distancë për të pasur qasje në aplikacionet e instaluara në këtë telefon kur lidhet."</string>
<string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Lejo që &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; të ofrojë &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; qasje në distancë për të pasur qasje në aplikacionet e instaluara në këtë tablet kur lidhet."</string>
<string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Lejo që &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; t\'i ofrojë &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; qasje në distancë për të pasur qasje në aplikacionet e instaluara në këtë pajisje kur lidhet."</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Shërbimet mes pajisjeve"</string>
+ <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Ky shërbim përdoret për të transmetuar aplikacione mes pajisjeve të tua"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Lejo që &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; të ketë qasje në këtë informacion nga telefoni yt"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Njoftimet"</string>
+ <string name="permission_notification_summary" msgid="4398672775023193663">"Mund të lexojë të gjitha njoftimet, duke përfshirë informacione si kontaktet, mesazhet dhe fotografitë"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"Fotografitë dhe media"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Shërbimet e Google Play"</string>
+ <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Ky shërbim ndan fotografitë, median dhe njoftimet nga telefoni yt te pajisjet e tjera"</string>
+ <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Ky shërbim ndan fotografitë, median dhe njoftimet nga telefoni yt te pajisjet e tjera"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"pajisja"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Lejo"</string>
<string name="consent_no" msgid="2640796915611404382">"Mos lejo"</string>
+ <string name="consent_ok" msgid="3662376764371001106">"Në rregull"</string>
<string name="permission_sync_confirmation_title" msgid="667074294393493186">"Transfero lejet e aplikacionit te ora jote"</string>
<string name="permission_sync_summary" msgid="8873391306499120778">"Për ta bërë më të lehtë konfigurimin e orës, aplikacionet e instaluara në orën tënde gjatë konfigurimit do të përdorin të njëjtat leje si telefoni yt.\n\n Këto leje mund të përfshijnë qasje në mikrofonin dhe vendndodhjen e orës."</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-sr/strings.xml b/packages/CompanionDeviceManager/res/values-sr/strings.xml
index 8d51c62fd3e7..d40a11295833 100644
--- a/packages/CompanionDeviceManager/res/values-sr/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sr/strings.xml
@@ -22,18 +22,30 @@
<string name="chooser_title" msgid="2262294130493605839">"Одаберите профил <xliff:g id="PROFILE_NAME">%1$s</xliff:g> којим ће управљати апликација &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ће добити дозволу за интеракцију са обавештењима и приступ дозволама за телефон, SMS поруке, контакте и календар."</string>
<string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ће добити дозволу за интеракцију са обавештењима и приступ дозволама за телефон, SMS поруке, контакте и календар."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Желите да дозволите апликацији &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да стримује апликације?"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Апликације"</string>
+ <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="summary_app_streaming" product="default" msgid="6105916810614498138">"Дозволите апликацији &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да даљински приступа апликацијама инсталираним на телефону &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; када је повезан."</string>
<string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Дозволите апликацији &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да даљински приступа апликацијама инсталираним на таблету &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; када је повезан."</string>
<string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Дозволите апликацији &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да даљински приступа апликацијама инсталираним на уређају &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; када је повезан."</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Услуге на више уређаја"</string>
+ <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Ова услуга се користи за стримовање апликација између уређаја"</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>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Обавештења"</string>
+ <string name="permission_notification_summary" msgid="4398672775023193663">"Може да чита сва обавештења, укључујући информације попут уговора, порука и слика"</string>
+ <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>
+ <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Ова услуга дели слике, медијски садржај и обавештења са телефона на друге уређаје"</string>
+ <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Ова услуга дели слике, медијски садржај и обавештења са телефона на друге уређаје"</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>
+ <string name="consent_ok" msgid="3662376764371001106">"Потврди"</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-sv/strings.xml b/packages/CompanionDeviceManager/res/values-sv/strings.xml
index ca1ec8769675..fff01ed727c9 100644
--- a/packages/CompanionDeviceManager/res/values-sv/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sv/strings.xml
@@ -22,18 +22,30 @@
<string name="chooser_title" msgid="2262294130493605839">"Välj en <xliff:g id="PROFILE_NAME">%1$s</xliff:g> för hantering av &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> får behörighet att interagera med dina aviseringar och komma åt behörigheterna för Telefon, Sms, Kontakter och Kalender."</string>
<string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> får behörighet att interagera med dina aviseringar och komma åt behörigheterna för Telefon, Sms, Kontakter och Kalender."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Vill du tillåta att &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; streamar appar?"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Appar"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"Streama telefonens appar"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"Ge &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; åtkomstbehörighet till denna information på telefonen"</string>
<string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Låt &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ge &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; fjärråtkomst till åt appar som är installerade på den här telefonen när den är ansluten."</string>
<string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Låt &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ge &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; fjärråtkomst till appar som är installerade på den här surfplattan när den är ansluten."</string>
<string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Låt &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ge &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; fjärråtkomst till appar som är installerade på den här enheten när den är ansluten."</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Tjänster för flera enheter"</string>
+ <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Den här tjänsten används för att streama appar mellan dina enheter"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Ge &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; åtkomstbehörighet till denna information på telefonen"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Aviseringar"</string>
+ <string name="permission_notification_summary" msgid="4398672775023193663">"Kan läsa alla aviseringar, inklusive information som kontakter, meddelanden och foton"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"Foton och media"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Google Play-tjänster"</string>
+ <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Den här tjänsten delar foton, media och aviseringar från telefonen till andra enheter"</string>
+ <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Den här tjänsten delar foton, media och aviseringar från telefonen till andra enheter"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"enhet"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Tillåt"</string>
<string name="consent_no" msgid="2640796915611404382">"Tillåt inte"</string>
+ <string name="consent_ok" msgid="3662376764371001106">"OK"</string>
<string name="permission_sync_confirmation_title" msgid="667074294393493186">"Överför appbehörigheter till klockan"</string>
<string name="permission_sync_summary" msgid="8873391306499120778">"Appar som installeras på klockan under konfigureringen får samma behörigheter som de har på telefonen så att konfigureringen ska bli enklare.\n\n Behörigheterna kan omfatta åtkomst till klockans mikrofon och plats."</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-sw/strings.xml b/packages/CompanionDeviceManager/res/values-sw/strings.xml
index cf9260087bd2..2533a97550ea 100644
--- a/packages/CompanionDeviceManager/res/values-sw/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sw/strings.xml
@@ -22,18 +22,30 @@
<string name="chooser_title" msgid="2262294130493605839">"Chagua <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ili idhibitiwe na &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> itaruhusiwa kufikia arifa zako na kufikia ruhusa za Simu, SMS, Anwani na Kalenda yako."</string>
<string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> itaruhusiwa kufikia arifa zako na kufikia ruhusa za Simu, SMS, Anwani na Kalenda yako."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Ungependa kuruhusu &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; itiririshe programu?"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Programu"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"Tiririsha programu za simu yako"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"Ruhusu &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ifikie maelezo haya kutoka kwenye simu yako"</string>
<string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Ruhusu &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; iipe &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ufikiaji wa mbali wa programu zilizosakinishwa kwenye simu hii wakati imeunganishwa."</string>
<string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Ruhusu &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; iipe &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ufikiaji wa mbali wa programu zilizosakinishwa kwenye kompyuta hii kibao wakati imeunganishwa."</string>
<string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Ruhusu &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; iipe &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ufikiaji wa mbali wa programu zilizosakinishwa kwenye kifaa hiki wakati kimeunganishwa."</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Huduma za kifaa kilichounganishwa kwingine"</string>
+ <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Huduma hii inatumika kutiririsha programu kati ya vifaa vyako"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Ruhusu &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ifikie maelezo haya kutoka kwenye simu yako"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Arifa"</string>
+ <string name="permission_notification_summary" msgid="4398672775023193663">"Inaweza kusoma arifa zote, ikiwa ni pamoja na maelezo kama vile mikataba, ujumbe na picha"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"Picha na maudhui"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Huduma za Google Play"</string>
+ <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Huduma hii inashiriki picha, maudhui na arifa kutoka kwenye simu yako kwenda kwenye vifaa vingine"</string>
+ <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Huduma hii inashiriki picha, maudhui na arifa kutoka kwenye simu yako kwenda kwenye vifaa vingine"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"kifaa"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Ruhusu"</string>
<string name="consent_no" msgid="2640796915611404382">"Usiruhusu"</string>
+ <string name="consent_ok" msgid="3662376764371001106">"Sawa"</string>
<string name="permission_sync_confirmation_title" msgid="667074294393493186">"Hamishia idhini za programu kwenye saa yako"</string>
<string name="permission_sync_summary" msgid="8873391306499120778">"Ili kurahisisha kuweka mipangilio ya saa yako, programu ambazo zimesakinishwa kwenye saa yako wakati wa kuweka mipangilio zitatumia ruhusa sawa na zinazotumika kwenye simu yako.\n\n Ruhusa hizi huenda zikajumuisha ufikiaji wa maikrofoni ya saa yako na maelezo ya mahali ilipo saa yako."</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-ta/strings.xml b/packages/CompanionDeviceManager/res/values-ta/strings.xml
index b86ea1cffacf..3f55444fa5c9 100644
--- a/packages/CompanionDeviceManager/res/values-ta/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ta/strings.xml
@@ -22,18 +22,30 @@
<string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; ஆப்ஸ் நிர்வகிக்கக்கூடிய <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ஐத் தேர்ந்தெடுங்கள்"</string>
<string name="summary_watch" product="default" msgid="7113724443198337683">"உங்கள் அறிவிப்புகளைப் பார்க்கவும் மொபைல், மெசேஜ், தொடர்புகள், கேலெண்டர் ஆகியவற்றை அணுகவும் <xliff:g id="APP_NAME">%1$s</xliff:g> ஆப்ஸுக்கு அனுமதி வழங்கப்படும்."</string>
<string name="summary_watch" product="tablet" msgid="7113724443198337683">"உங்கள் அறிவிப்புகளைப் பார்க்கவும் மொபைல், மெசேஜ், தொடர்புகள், கேலெண்டர் ஆகியவற்றை அணுகவும் <xliff:g id="APP_NAME">%1$s</xliff:g> ஆப்ஸுக்கு அனுமதி வழங்கப்படும்."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"ஆப்ஸை ஸ்ட்ரீம் செய்ய &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ஆப்ஸை அனுமதிக்கவா?"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"ஆப்ஸ்"</string>
+ <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="summary_app_streaming" product="default" msgid="6105916810614498138">"இணைக்கப்பட்டிருக்கும்போது இந்த மொபைலில் நிறுவப்பட்டிருக்கும் ஆப்ஸை அணுகுவதற்கான தொலைநிலை அணுகலை &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; சாதனத்திற்கு வழங்க &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ஆப்ஸை அனுமதிக்கும்."</string>
<string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"இணைக்கப்பட்டிருக்கும்போது இந்த டேப்லெட்டில் நிறுவப்பட்டிருக்கும் ஆப்ஸை அணுகுவதற்கான தொலைநிலை அணுகலை &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; சாதனத்திற்கு வழங்க &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ஆப்ஸை அனுமதிக்கும்."</string>
<string name="summary_app_streaming" product="device" msgid="7614171699434639963">"இணைக்கப்பட்டிருக்கும்போது இந்தச் சாதனத்தில் நிறுவப்பட்டிருக்கும் ஆப்ஸை அணுகுவதற்கான தொலைநிலை அணுகலை &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; சாதனத்திற்கு வழங்க &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>
+ <string name="helper_summary_app_streaming" msgid="5344341720432827388">"உங்கள் சாதனங்களுக்கு இடையே ஆப்ஸை ஸ்ட்ரீம் செய்ய இந்தச் சேவை பயன்படுத்தப்படுகிறது"</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>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"அறிவிப்புகள்"</string>
+ <string name="permission_notification_summary" msgid="4398672775023193663">"ஒப்பந்தங்கள், மெசேஜ்கள், படங்கள் போன்ற தகவல்கள் உட்பட அனைத்து அறிவிப்புகளையும் படிக்க முடியும்"</string>
+ <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>
+ <string name="helper_summary_computer" product="default" msgid="467996390095403648">"படங்கள், மீடியா, அறிவிப்புகள் ஆகியவற்றை உங்கள் மொபைலில் இருந்து பிற சாதனங்களுக்கு இந்தச் சேவை பகிர்கிறது"</string>
+ <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"படங்கள், மீடியா, அறிவிப்புகள் ஆகியவற்றை உங்கள் மொபைலில் இருந்து பிற சாதனங்களுக்கு இந்தச் சேவை பகிர்கிறது"</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>
+ <string name="consent_ok" msgid="3662376764371001106">"சரி"</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 73cf3e88e180..552834e4ea25 100644
--- a/packages/CompanionDeviceManager/res/values-te/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-te/strings.xml
@@ -22,18 +22,30 @@
<string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; ద్వారా మేనేజ్ చేయబడటానికి ఒక <xliff:g id="PROFILE_NAME">%1$s</xliff:g>ను ఎంచుకోండి"</string>
<string name="summary_watch" product="default" msgid="7113724443198337683">"మీ నోటిఫికేషన్‌లతో ఇంటరాక్ట్ అవ్వడానికి ఇంకా మీ ఫోన్, SMS, కాంటాక్ట్‌లు, Calendar అనుమతులను యాక్సెస్ చేయడానికి <xliff:g id="APP_NAME">%1$s</xliff:g> అనుమతించబడుతుంది."</string>
<string name="summary_watch" product="tablet" msgid="7113724443198337683">"మీ నోటిఫికేషన్‌లతో ఇంటరాక్ట్ అవ్వడానికి ఇంకా మీ ఫోన్, SMS, కాంటాక్ట్‌లు, Calendar అనుమతులను యాక్సెస్ చేయడానికి <xliff:g id="APP_NAME">%1$s</xliff:g> అనుమతించబడుతుంది."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"యాప్‌లను స్ట్రీమ్ చేయడానికి &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;ను అనుమతించాలా?"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"యాప్‌లు"</string>
+ <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="summary_app_streaming" product="default" msgid="6105916810614498138">"కనెక్ట్ అయినప్పుడు ఈ ఫోన్‌లో ఇన్‌స్టాల్ చేయబడిన యాప్‌లను యాక్సెస్ చేయడానికి &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; రిమోట్ యాక్సెస్‌ను అందించడానికి &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;ను అనుమతించండి."</string>
<string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"కనెక్ట్ అయినప్పుడు ఈ టాబ్లెట్‌లో ఇన్‌స్టాల్ చేయబడిన యాప్‌లను యాక్సెస్ చేయడానికి &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; రిమోట్ యాక్సెస్‌ను అందించడానికి &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;ను అనుమతించండి."</string>
<string name="summary_app_streaming" product="device" msgid="7614171699434639963">"కనెక్ట్ అయినప్పుడు ఈ పరికరంలో ఇన్‌స్టాల్ చేయబడిన యాప్‌లను యాక్సెస్ చేయడానికి &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; రిమోట్ యాక్సెస్‌ను అందించడానికి &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>
+ <string name="helper_summary_app_streaming" msgid="5344341720432827388">"మీ పరికరాల మధ్య యాప్‌లను స్ట్రీమ్ చేయడానికి ఈ సర్వీస్ ఉపయోగించబడుతుంది"</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>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"నోటిఫికేషన్‌లు"</string>
+ <string name="permission_notification_summary" msgid="4398672775023193663">"ఒప్పందాలు, మెసేజ్‌లు, ఫోటోల వంటి సమాచారంతో సహా అన్ని నోటిఫికేషన్‌లను చదవగలరు"</string>
+ <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>
+ <string name="helper_summary_computer" product="default" msgid="467996390095403648">"ఈ సర్వీస్ మీ ఫోన్ నుండి ఇతర పరికరాలకు ఫోటోలు, మీడియా, ఇంకా నోటిఫికేషన్‌లను షేర్ చేస్తుంది"</string>
+ <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"ఈ సర్వీస్ మీ ఫోన్ నుండి ఇతర పరికరాలకు ఫోటోలు, మీడియా, ఇంకా నోటిఫికేషన్‌లను షేర్ చేస్తుంది"</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>
+ <string name="consent_ok" msgid="3662376764371001106">"సరే"</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 6f29346debc5..c15ce034aceb 100644
--- a/packages/CompanionDeviceManager/res/values-th/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-th/strings.xml
@@ -22,18 +22,30 @@
<string name="chooser_title" msgid="2262294130493605839">"เลือก<xliff:g id="PROFILE_NAME">%1$s</xliff:g>ที่จะให้มีการจัดการโดย &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> จะได้รับอนุญาตให้โต้ตอบกับการแจ้งเตือนและได้รับสิทธิ์เข้าถึงโทรศัพท์, SMS, รายชื่อติดต่อ และปฏิทิน"</string>
<string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> จะได้รับอนุญาตให้โต้ตอบกับการแจ้งเตือนและได้รับสิทธิ์เข้าถึงโทรศัพท์, SMS, รายชื่อติดต่อ และปฏิทิน"</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"อนุญาตให้ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; สตรีมแอปพลิเคชันใช่ไหม"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"แอป"</string>
+ <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="summary_app_streaming" product="default" msgid="6105916810614498138">"อนุญาตให้ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; มอบสิทธิ์เข้าถึงแอปพลิเคชันที่ติดตั้งในโทรศัพท์เครื่องนี้จากระยะไกลให้แก่ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; เมื่อมีการเชื่อมต่อ"</string>
<string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"อนุญาตให้ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; มอบสิทธิ์เข้าถึงแอปพลิเคชันที่ติดตั้งในแท็บเล็ตเครื่องนี้จากระยะไกลให้แก่ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; เมื่อมีการเชื่อมต่อ"</string>
<string name="summary_app_streaming" product="device" msgid="7614171699434639963">"อนุญาตให้ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; มอบสิทธิ์เข้าถึงแอปพลิเคชันที่ติดตั้งในอุปกรณ์เครื่องนี้จากระยะไกลให้แก่ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; เมื่อมีการเชื่อมต่อ"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"บริการหลายอุปกรณ์"</string>
+ <string name="helper_summary_app_streaming" msgid="5344341720432827388">"บริการนี้ใช้เพื่อสตรีมแอประหว่างอุปกรณ์"</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>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"การแจ้งเตือน"</string>
+ <string name="permission_notification_summary" msgid="4398672775023193663">"สามารถอ่านการแจ้งเตือนทั้งหมด รวมถึงข้อมูลอย่าง รายชื่อผู้ติดต่อ ข้อความ และรูปภาพ"</string>
+ <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>
+ <string name="helper_summary_computer" product="default" msgid="467996390095403648">"บริการนี้แชร์รูปภาพ สื่อ และการแจ้งเตือนจากโทรศัพท์กับอุปกรณ์อื่นๆ"</string>
+ <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"บริการนี้แชร์รูปภาพ สื่อ และการแจ้งเตือนจากโทรศัพท์กับอุปกรณ์อื่นๆ"</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>
+ <string name="consent_ok" msgid="3662376764371001106">"ตกลง"</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 e557a385dd98..ee5ec161c195 100644
--- a/packages/CompanionDeviceManager/res/values-tl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-tl/strings.xml
@@ -22,18 +22,30 @@
<string name="chooser_title" msgid="2262294130493605839">"Pumili ng <xliff:g id="PROFILE_NAME">%1$s</xliff:g> para pamahalaan ng &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="summary_watch" product="default" msgid="7113724443198337683">"Papayagan ang <xliff:g id="APP_NAME">%1$s</xliff:g> na makipag-ugnayan sa mga notification mo at ma-access ang iyong mga pahintulot sa Telepono, SMS, Mga Contact, at Kalendaryo."</string>
<string name="summary_watch" product="tablet" msgid="7113724443198337683">"Papayagan ang <xliff:g id="APP_NAME">%1$s</xliff:g> na makipag-ugnayan sa mga notification mo at ma-access ang iyong mga pahintulot sa Telepono, SMS, Mga Contact, at Kalendaryo."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Payagan ang &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; na mag-stream ng mga application?"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Mga App"</string>
+ <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="summary_app_streaming" product="default" msgid="6105916810614498138">"Payagan ang &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; na bigyan ang &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ng malayuang access para ma-access ang mga application na naka-install sa teleponong ito kapag nakakonekta."</string>
<string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Payagan ang &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; na bigyan ang &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ng malayuang access para ma-access ang mga application na naka-install sa tablet na ito kapag nakakonekta."</string>
<string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Payagan ang &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; na bigyan ang &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ng malayuang access para ma-access ang mga application na naka-install sa device na ito kapag nakakonekta."</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Mga cross-device na serbisyo"</string>
+ <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Ginagamit ang serbisyong ito para mag-stream ng mga app sa pagitan ng iyong mga device"</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>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Mga Notification"</string>
+ <string name="permission_notification_summary" msgid="4398672775023193663">"Mababasa ang lahat ng notification, kasama ang impormasyon gaya ng mga kontrata, mensahe, at larawan"</string>
+ <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>
+ <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Nagbabahagi ang serbisyong ito ng mga larawan, media, at notification mula sa iyong telepono patungo sa iba pang device"</string>
+ <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Nagbabahagi ang serbisyong ito ng mga larawan, media, at notification mula sa iyong telepono patungo sa iba pang device"</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>
+ <string name="consent_ok" msgid="3662376764371001106">"OK"</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-tr/strings.xml b/packages/CompanionDeviceManager/res/values-tr/strings.xml
index c75214bf957e..07a5c2a29fbd 100644
--- a/packages/CompanionDeviceManager/res/values-tr/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-tr/strings.xml
@@ -22,18 +22,30 @@
<string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; tarafından yönetilecek bir <xliff:g id="PROFILE_NAME">%1$s</xliff:g> seçin"</string>
<string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> adlı uygulamanın bildirimlerinizle etkileşimde bulunup Telefon, SMS, Kişiler ve Takvim izinlerinize erişmesine izin verilir."</string>
<string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> adlı uygulamanın bildirimlerinizle etkileşimde bulunup Telefon, SMS, Kişiler ve Takvim izinlerinize erişmesine izin verilir."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; uygulamasının, uygulamalarda akış gerçekleştirmesine izin verilsin mi?"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Uygulamalar"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"Telefonunuzun uygulamalarını akışla aktarın"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; uygulamasının, telefonunuzdaki bu bilgilere erişmesine izin verin"</string>
<string name="summary_app_streaming" product="default" msgid="6105916810614498138">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; uygulamasının, internete bağlanan bu telefondaki yüklü uygulamalara erişebilmesi için &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; adlı cihaza uzaktan erişim izni verin."</string>
<string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; uygulamasının, internete bağlanan bu tabletteki yüklü uygulamalara erişebilmesi için &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; adlı cihaza uzaktan erişim izni verin."</string>
<string name="summary_app_streaming" product="device" msgid="7614171699434639963">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; uygulamasının, internete bağlanan bu cihazdaki yüklü uygulamalara erişebilmesi için &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; adlı cihaza uzaktan erişim izni verin."</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Cihazlar arası hizmetler"</string>
+ <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Bu hizmet, cihazlarınız arasında uygulama aktarmak için kullanılır"</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; uygulamasının, telefonunuzdaki bu bilgilere erişmesine izin verin"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Bildirimler"</string>
+ <string name="permission_notification_summary" msgid="4398672775023193663">"Kişiler, mesajlar ve fotoğraflar da dahil olmak üzere tüm bildirimleri okuyabilir"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"Fotoğraflar ve medya"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Google Play hizmetleri"</string>
+ <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Bu hizmet, telefonunuzdaki fotoğraf, medya ve bildirimleri diğer cihazlarla paylaşır"</string>
+ <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Bu hizmet, telefonunuzdaki fotoğraf, medya ve bildirimleri diğer cihazlarla paylaşır"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"cihaz"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"İzin ver"</string>
<string name="consent_no" msgid="2640796915611404382">"İzin verme"</string>
+ <string name="consent_ok" msgid="3662376764371001106">"Tamam"</string>
<string name="permission_sync_confirmation_title" msgid="667074294393493186">"Uygulama izinlerini saatinize aktarma"</string>
<string name="permission_sync_summary" msgid="8873391306499120778">"Kurulum sırasında saatinize yüklenen uygulamalar, saat kurulumunuzu kolaylaştırmak için telefonunuzla aynı izinleri kullanır.\n\n Saatinizin mikrofonuna ve konumuna erişim bu izinlere dahil olabilir."</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-uk/strings.xml b/packages/CompanionDeviceManager/res/values-uk/strings.xml
index 46a25b2ba185..8ab5bf1c6322 100644
--- a/packages/CompanionDeviceManager/res/values-uk/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-uk/strings.xml
@@ -22,18 +22,30 @@
<string name="chooser_title" msgid="2262294130493605839">"Виберіть <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, яким керуватиме додаток &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="summary_watch" product="default" msgid="7113724443198337683">"Додаток <xliff:g id="APP_NAME">%1$s</xliff:g> зможе взаємодіяти з вашими сповіщеннями та отримає дозволи \"Телефон\", \"SMS\", \"Контакти\" й \"Календар\"."</string>
<string name="summary_watch" product="tablet" msgid="7113724443198337683">"Додаток <xliff:g id="APP_NAME">%1$s</xliff:g> зможе взаємодіяти з вашими сповіщеннями та отримає дозволи \"Телефон\", \"SMS\", \"Контакти\" й \"Календар\"."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Дозволити додатку &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; транслювати інші додатки?"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Додатки"</string>
+ <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="summary_app_streaming" product="default" msgid="6105916810614498138">"Дозвольте додатку &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; за наявності з’єднання надавати пристрою &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; віддалений доступ до додатків, установлених на цьому телефоні."</string>
<string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Дозвольте додатку &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; за наявності з’єднання надавати пристрою &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; віддалений доступ до додатків, установлених на цьому планшеті."</string>
<string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Дозвольте додатку &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; за наявності з’єднання надавати пристрою &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; віддалений доступ до додатків, установлених на цьому пристрої."</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Сервіси для кількох пристроїв"</string>
+ <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Цей сервіс використовується для трансляції додатків між вашими пристроями"</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>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Сповіщення"</string>
+ <string name="permission_notification_summary" msgid="4398672775023193663">"Може читати всі сповіщення, зокрема таку інформацію, як контакти, повідомлення та фотографії"</string>
+ <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>
+ <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Цей сервіс передає фотографії, медіафайли та сповіщення з вашого телефона на інші пристрої"</string>
+ <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Цей сервіс передає фотографії, медіафайли та сповіщення з вашого телефона на інші пристрої"</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>
+ <string name="consent_ok" msgid="3662376764371001106">"OK"</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-ur/strings.xml b/packages/CompanionDeviceManager/res/values-ur/strings.xml
index c9f930f0f54b..0c3686567826 100644
--- a/packages/CompanionDeviceManager/res/values-ur/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ur/strings.xml
@@ -22,18 +22,30 @@
<string name="chooser_title" msgid="2262294130493605839">"‏&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; کے ذریعے نظم کئے جانے کیلئے <xliff:g id="PROFILE_NAME">%1$s</xliff:g> کو منتخب کریں"</string>
<string name="summary_watch" product="default" msgid="7113724443198337683">"‏<xliff:g id="APP_NAME">%1$s</xliff:g> کو آپ کی اطلاعات کے ساتھ تعامل کرنے اور آپ کے فون، SMS، رابطوں اور کیلنڈر کی اجازتوں تک رسائی کی اجازت ہوگی۔"</string>
<string name="summary_watch" product="tablet" msgid="7113724443198337683">"‏<xliff:g id="APP_NAME">%1$s</xliff:g> کو آپ کی اطلاعات کے ساتھ تعامل کرنے اور آپ کے فون، SMS، رابطوں اور کیلنڈر کی اجازتوں تک رسائی کی اجازت ہوگی۔"</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"‏&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; کو ایپلیکیشنز کی سلسلہ بندی کرنے کی اجازت دیں؟"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"ایپس"</string>
+ <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="summary_app_streaming" product="default" msgid="6105916810614498138">"‏منسلک ہونے پر، اس فون پر انسٹال کردہ ایپلیکیشنز تک رسائی حاصل کرنے کے لیے &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; کو &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>‏&lt;/strong&gt; کے لیے ریموٹ تک رسائی فراہم کرنے کی اجازت دیں۔"</string>
<string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"‏منسلک ہونے پر، اس ٹیبلیٹ پر انسٹال کردہ ایپلیکیشنز تک رسائی حاصل کرنے کے لیے &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; کو &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>‏&lt;/strong&gt; کے لیے ریموٹ تک رسائی فراہم کرنے کی اجازت دیں۔"</string>
<string name="summary_app_streaming" product="device" msgid="7614171699434639963">"‏منسلک ہونے پر، اس آلے پر انسٹال کردہ ایپلیکیشنز تک رسائی حاصل کرنے کے لیے &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; کو &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>‏&lt;/strong&gt; کے لیے ریموٹ تک رسائی فراہم کرنے کی اجازت دیں۔"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"کراس آلے کی سروس"</string>
+ <string name="helper_summary_app_streaming" msgid="5344341720432827388">"یہ سروس آپ کے آلات کے درمیان ایپس کو اسٹریم کرنے کے لیے استعمال ہوتی ہے"</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; کرنے کی اجازت دیں"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"اطلاعات"</string>
+ <string name="permission_notification_summary" msgid="4398672775023193663">"معاہدوں، پیغامات اور تصاویر جیسی معلومات سمیت تمام اطلاعات پڑھ سکتے ہیں"</string>
+ <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>
+ <string name="helper_summary_computer" product="default" msgid="467996390095403648">"یہ سروس آپ کے فون سے دیگر آلات پر تصاویر، میڈیا اور اطلاعات کا اشتراک کرتی ہے"</string>
+ <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"یہ سروس آپ کے فون سے دیگر آلات پر تصاویر، میڈیا اور اطلاعات کا اشتراک کرتی ہے"</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>
+ <string name="consent_ok" msgid="3662376764371001106">"ٹھیک ہے"</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-uz/strings.xml b/packages/CompanionDeviceManager/res/values-uz/strings.xml
index 91fdd946edf2..59fc98f5a907 100644
--- a/packages/CompanionDeviceManager/res/values-uz/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-uz/strings.xml
@@ -22,18 +22,30 @@
<string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; boshqaradigan <xliff:g id="PROFILE_NAME">%1$s</xliff:g> qurilmasini tanlang"</string>
<string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ilovasiga bildirishnomalar bilan ishlash va telefon, SMS, kontaktlar va taqvimga kirishga ruxsat beriladi"</string>
<string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ilovasiga bildirishnomalar bilan ishlash va telefon, SMS, kontaktlar va taqvimga kirishga ruxsat beriladi"</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ilovasiga ilovalarni strim qilishi uchun ruxsat berilsinmi?"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Ilovalar"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"Telefondagi ilovalarni translatsiya qilish"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ilovasiga telefondagi ushbu maʼlumot uchun ruxsat bering"</string>
<string name="summary_app_streaming" product="default" msgid="6105916810614498138">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ilovasiga &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ulanganda ushbu telefonda oʻrnatilgan ilovalarga masofadan kirish ruxsatini bering."</string>
<string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ilovasiga &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ulanganda ushbu planshetda oʻrnatilgan ilovalarga masofadan kirish ruxsatini bering."</string>
<string name="summary_app_streaming" product="device" msgid="7614171699434639963">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ilovasiga &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ulanganda ushbu qurilmada oʻrnatilgan ilovalarga masofadan kirish ruxsatini bering."</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Qurilmalararo xizmatlar"</string>
+ <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Bu xizmat ilovalarni qurilmalararo translatsiya qilishda ishlatiladi"</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; ilovasiga telefondagi ushbu maʼlumot uchun ruxsat bering"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Bildirishnomalar"</string>
+ <string name="permission_notification_summary" msgid="4398672775023193663">"Barcha bildirishnomalarni, jumladan, kontaktlar, xabarlar va suratlarni oʻqishi mumkin"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"Suratlar va media"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Google Play xizmatlari"</string>
+ <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Bu xizmat telefondagi rasm, media va bildirishnomalarni boshqa qurilmalarga ulashadi"</string>
+ <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Bu xizmat telefondagi rasm, media va bildirishnomalarni boshqa qurilmalarga ulashadi"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"qurilma"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Ruxsat"</string>
<string name="consent_no" msgid="2640796915611404382">"Ruxsat berilmasin"</string>
+ <string name="consent_ok" msgid="3662376764371001106">"OK"</string>
<string name="permission_sync_confirmation_title" msgid="667074294393493186">"Ilova uchun ruxsatlarni soatingizga uzating"</string>
<string name="permission_sync_summary" msgid="8873391306499120778">"Soatingizni sozlashni qulaylashtirish maqsadida sozlash paytida soatingizga oʻrnatilgan ilovalar telefoningiz bilan bir xil ruxsatlardan foydalanadi.\n\n Bunday ruxsatlarga soatingiz mikrofoni va joylashuv axborotiga ruxsatlar kirishi mumkin."</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-vi/strings.xml b/packages/CompanionDeviceManager/res/values-vi/strings.xml
index 4f96bd4d7f1a..8a96c4a7d1f2 100644
--- a/packages/CompanionDeviceManager/res/values-vi/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-vi/strings.xml
@@ -22,18 +22,30 @@
<string name="chooser_title" msgid="2262294130493605839">"Chọn một <xliff:g id="PROFILE_NAME">%1$s</xliff:g> sẽ do &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; quản lý"</string>
<string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> sẽ được phép tương tác với thông báo cũng như truy cập vào Điện thoại, SMS, Danh bạ và Lịch."</string>
<string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> sẽ được phép tương tác với thông báo cũng như truy cập vào Điện thoại, SMS, Danh bạ và Lịch."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Cho phép &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; truyền trực tuyến ứng dụng?"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Ứng dụng"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"Truyền các ứng dụng trên điện thoại của bạn"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"Cho phép &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; truy cập vào thông tin này trên điện thoại của bạn"</string>
<string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Cho phép &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; truy cập từ xa vào các ứng dụng đã cài đặt trên &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; khi điện thoại này có kết nối."</string>
<string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Cho phép &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; truy cập từ xa vào các ứng dụng đã cài đặt trên &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; khi máy tính bảng này có kết nối."</string>
<string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Cho phép &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; truy cập từ xa vào các ứng dụng đã cài đặt trên &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; khi thiết bị này có kết nối."</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Dịch vụ trên nhiều thiết bị"</string>
+ <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Dịch vụ này được dùng để truyền ứng dụng giữa các thiết bị"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"Cho phép &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; truy cập vào thông tin này trên điện thoại của bạn"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Thông báo"</string>
+ <string name="permission_notification_summary" msgid="4398672775023193663">"Có thể đọc tất cả các thông báo, kể cả những thông tin như hợp đồng, tin nhắn và ảnh"</string>
+ <string name="permission_storage" msgid="6831099350839392343">"Ảnh và nội dung nghe nhìn"</string>
+ <string name="permission_storage_summary" msgid="3918240895519506417"></string>
+ <string name="helper_title_computer" msgid="4671071173916176037">"Dịch vụ Google Play"</string>
+ <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Dịch vụ này chia sẻ ảnh, nội dung nghe nhìn và thông báo từ điện thoại của bạn sang các thiết bị khác"</string>
+ <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Dịch vụ này chia sẻ ảnh, nội dung nghe nhìn và thông báo từ điện thoại của bạn sang các thiết bị khác"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"thiết bị"</string>
<string name="summary_generic" msgid="2346762210105903720"></string>
<string name="consent_yes" msgid="8344487259618762872">"Cho phép"</string>
<string name="consent_no" msgid="2640796915611404382">"Không cho phép"</string>
+ <string name="consent_ok" msgid="3662376764371001106">"OK"</string>
<string name="permission_sync_confirmation_title" msgid="667074294393493186">"Chuyển quyền cho ứng dụng sang đồng hồ"</string>
<string name="permission_sync_summary" msgid="8873391306499120778">"Để thiết lập đồng hồ dễ dàng hơn, trong quá trình thiết lập, các ứng dụng được cài đặt trên đồng hồ của bạn sẽ sử dụng các quyền giống như trên điện thoại.\n\n Các quyền này có thể bao gồm quyền sử dụng micrô và thông tin vị trí của đồng hồ."</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml b/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml
index 3fdccf229bf8..1ee43c91d53b 100644
--- a/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml
@@ -22,18 +22,30 @@
<string name="chooser_title" msgid="2262294130493605839">"选择要由&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;管理的<xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
<string name="summary_watch" product="default" msgid="7113724443198337683">"“<xliff:g id="APP_NAME">%1$s</xliff:g>”将能与通知互动,并可访问电话、短信、通讯录和日历。"</string>
<string name="summary_watch" product="tablet" msgid="7113724443198337683">"“<xliff:g id="APP_NAME">%1$s</xliff:g>”将能与通知互动,并可访问电话、短信、通讯录和日历。"</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"是否允许 &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; 流式传输应用?"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"应用"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"流式传输手机的应用内容"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"允许“<xliff:g id="APP_NAME">%1$s</xliff:g>”&lt;strong&gt;&lt;/strong&gt;访问您手机中的这项信息"</string>
<string name="summary_app_streaming" product="default" msgid="6105916810614498138">"在 &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; 连接到网络后,允许 &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; 远程访问该手机上安装的应用。"</string>
<string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"在 &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; 连接到网络后,允许 &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; 远程访问该平板电脑上安装的应用。"</string>
<string name="summary_app_streaming" product="device" msgid="7614171699434639963">"在 &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; 连接到网络后,允许 &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>
+ <string name="helper_summary_app_streaming" msgid="5344341720432827388">"此服务用于在设备之间流式传输应用内容"</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>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"通知"</string>
+ <string name="permission_notification_summary" msgid="4398672775023193663">"可以读取所有通知,包括合同、消息和照片等信息"</string>
+ <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>
+ <string name="helper_summary_computer" product="default" msgid="467996390095403648">"此服务可将您手机中的照片、媒体内容和通知分享给其他设备"</string>
+ <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"此服务可将您手机中的照片、媒体内容和通知分享给其他设备"</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>
+ <string name="consent_ok" msgid="3662376764371001106">"确定"</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-zh-rHK/strings.xml b/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml
index a4dc0c9b6c81..fa2f0fc0961d 100644
--- a/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml
@@ -22,18 +22,30 @@
<string name="chooser_title" msgid="2262294130493605839">"選擇由 &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; 管理的<xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
<string name="summary_watch" product="default" msgid="7113724443198337683">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」將可存取通知、電話、短訊、聯絡人和日曆資料。"</string>
<string name="summary_watch" product="tablet" msgid="7113724443198337683">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」將可存取通知、電話、短訊、聯絡人和日曆資料。"</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;串流播放應用程式的內容嗎?"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"應用程式"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"串流播放手機應用程式內容"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;存取您手機中的這項資料"</string>
<string name="summary_app_streaming" product="default" msgid="6105916810614498138">"讓「<xliff:g id="APP_NAME">%1$s</xliff:g>」在「<xliff:g id="DEVICE_NAME">%2$s</xliff:g>」連線時可透過遠端方式存取此手機上安裝的應用程式。"</string>
<string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"讓「<xliff:g id="APP_NAME">%1$s</xliff:g>」在「<xliff:g id="DEVICE_NAME">%2$s</xliff:g>」連線時可透過遠端方式存取此平板電腦上安裝的應用程式。"</string>
<string name="summary_app_streaming" product="device" msgid="7614171699434639963">"讓「<xliff:g id="APP_NAME">%1$s</xliff:g>」在「<xliff:g id="DEVICE_NAME">%2$s</xliff:g>」連線時可透過遠端方式存取此裝置上安裝的應用程式。"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"跨裝置服務"</string>
+ <string name="helper_summary_app_streaming" msgid="5344341720432827388">"此服務是用來在裝置間串流應用程式的內容"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;存取您手機中的這項資料"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"通知"</string>
+ <string name="permission_notification_summary" msgid="4398672775023193663">"可以讀取所有通知,包括聯絡人、訊息和電話等資訊"</string>
+ <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>
+ <string name="helper_summary_computer" product="default" msgid="467996390095403648">"此服務可將手機上的相片、媒體及通知分享到其他裝置"</string>
+ <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"此服務可將手機上的相片、媒體及通知分享到其他裝置"</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>
+ <string name="consent_ok" msgid="3662376764371001106">"確定"</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-zh-rTW/strings.xml b/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml
index eec042429ca8..abefde4c0288 100644
--- a/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml
@@ -22,18 +22,30 @@
<string name="chooser_title" msgid="2262294130493605839">"選擇要讓「<xliff:g id="APP_NAME">%2$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;管理的<xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
<string name="summary_watch" product="default" msgid="7113724443198337683">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」將可存取通知、電話、簡訊、聯絡人和日曆資料。"</string>
<string name="summary_watch" product="tablet" msgid="7113724443198337683">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」將可存取通知、電話、簡訊、聯絡人和日曆資料。"</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;串流播放應用程式的內容嗎?"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"應用程式"</string>
+ <string name="permission_apps_summary" msgid="798718816711515431">"串流傳輸手機應用程式內容"</string>
+ <string name="title_app_streaming" msgid="2270331024626446950">"允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;存取手機中的這項資訊"</string>
<string name="summary_app_streaming" product="default" msgid="6105916810614498138">"允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;在「<xliff:g id="DEVICE_NAME">%2$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;連上網際網路時可從遠端存取該手機上安裝的應用程式。"</string>
<string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;在「<xliff:g id="DEVICE_NAME">%2$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;連上網際網路時可從遠端存取該平板電腦上安裝的應用程式。"</string>
<string name="summary_app_streaming" product="device" msgid="7614171699434639963">"允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;在「<xliff:g id="DEVICE_NAME">%2$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;連上網際網路時可從遠端存取該裝置上安裝的應用程式。"</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"跨裝置服務"</string>
+ <string name="helper_summary_app_streaming" msgid="5344341720432827388">"這項服務是用來在裝置間串流傳輸應用程式的內容"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="title_computer" msgid="4693714143506569253">"允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;存取你手機中的這項資訊"</string>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"通知"</string>
+ <string name="permission_notification_summary" msgid="4398672775023193663">"可以讀取所有通知,包括聯絡人、訊息和電話等資訊"</string>
+ <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>
+ <string name="helper_summary_computer" product="default" msgid="467996390095403648">"這項服務可將手機上的相片、媒體及通知分享到其他裝置"</string>
+ <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"這項服務可將手機上的相片、媒體及通知分享到其他裝置"</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>
+ <string name="consent_ok" msgid="3662376764371001106">"確定"</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-zu/strings.xml b/packages/CompanionDeviceManager/res/values-zu/strings.xml
index be5a195fa5f7..1c7cad33c0a7 100644
--- a/packages/CompanionDeviceManager/res/values-zu/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-zu/strings.xml
@@ -22,18 +22,30 @@
<string name="chooser_title" msgid="2262294130493605839">"Khetha i-<xliff:g id="PROFILE_NAME">%1$s</xliff:g> ezophathwa yi-&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
<string name="summary_watch" product="default" msgid="7113724443198337683">"I-<xliff:g id="APP_NAME">%1$s</xliff:g> izovunyelwa ukuxhumana nezaziso zakho futhi ifinyelele izimvume Zefoni yakho, -SMS, Abathintwayo kanye Nekhalenda."</string>
<string name="summary_watch" product="tablet" msgid="7113724443198337683">"I-<xliff:g id="APP_NAME">%1$s</xliff:g> izovunyelwa ukuxhumana nezaziso zakho futhi ifinyelele izimvume Zefoni yakho, -SMS, Abathintwayo kanye Nekhalenda."</string>
- <string name="title_app_streaming" msgid="4459136600249308574">"Vumela &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ukusakaza ama-applications?"</string>
+ <string name="permission_apps" msgid="6142133265286656158">"Ama-app"</string>
+ <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="summary_app_streaming" product="default" msgid="6105916810614498138">"Vumela &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ukunikezela &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ngokufinyelela kwerimothi kuma-applications afakiwe kule foni uma ixhunyiwe."</string>
<string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Vumela &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ukunikezela &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ngokufinyelela kwerimothi kuma-applications afakiwe kule thebhulethi uma ixhunyiwe."</string>
<string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Vumela &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ukunikezela &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ngokufinyelela kwerimothi kuma-applications afakiwe kule divayisi uma ixhunyiwe."</string>
+ <string name="helper_title_app_streaming" msgid="4151687003439969765">"Amasevisi amadivayisi amaningi"</string>
+ <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Le sevisi isetshenziselwa ukusakaza-bukhoma ama-app phakathi kwamadivayisi akho"</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>
<string name="summary_computer" msgid="3798467601598297062"></string>
+ <string name="permission_notification" msgid="693762568127741203">"Izaziso"</string>
+ <string name="permission_notification_summary" msgid="4398672775023193663">"Ingafunda zonke izaziso, okufaka phakathi ulwazi olufana nomakhontilaki, imiyalezo, nezithombe"</string>
+ <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>
+ <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Le sevisi yabelana ngezithombe, imidiya, nezaziso kusukela kufoni yakho ukuya kwamanye amadivaysi"</string>
+ <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Le sevisi yabelana ngezithombe, imidiya, nezaziso kusukela kufoni yakho ukuya kwamanye amadivaysi"</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>
+ <string name="consent_ok" msgid="3662376764371001106">"KULUNGILE"</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/CompanionDeviceManager/res/values/strings.xml b/packages/CompanionDeviceManager/res/values/strings.xml
index 9626751679e1..67fc6c2dc864 100644
--- a/packages/CompanionDeviceManager/res/values/strings.xml
+++ b/packages/CompanionDeviceManager/res/values/strings.xml
@@ -38,8 +38,14 @@
<!-- ================= DEVICE_PROFILE_APP_STREAMING ================= -->
+ <!-- Apps permission will be granted of APP_STREAMING profile [CHAR LIMIT=30] -->
+ <string name="permission_apps">Apps</string>
+
+ <!-- Description of apps permission of APP_STREAMING profile [CHAR LIMIT=NONE] -->
+ <string name="permission_apps_summary">Stream your phone\u2019s apps</string>
+
<!-- Confirmation for associating an application with a companion device of APP_STREAMING profile (type) [CHAR LIMIT=NONE] -->
- <string name="title_app_streaming">Allow &lt;strong&gt;<xliff:g id="app_name" example="Exo">%1$s</xliff:g>&lt;/strong&gt; to access this information for your phone</string>
+ <string name="title_app_streaming">Allow &lt;strong&gt;<xliff:g id="app_name" example="Exo">%1$s</xliff:g>&lt;/strong&gt; to access this information from your phone</string>
<!-- Description of the privileges the application will get if associated with the companion device of APP_STREAMING profile (type) [CHAR LIMIT=NONE] -->
<string name="summary_app_streaming" product="default">Let &lt;strong&gt;<xliff:g id="app_name" example="Exo">%1$s</xliff:g>&lt;/strong&gt; to provide &lt;strong&gt;<xliff:g id="device_name" example="Pixelbook Go">%2$s</xliff:g>&lt;/strong&gt; remote access to access to applications installed on this phone when connected.</string>
@@ -72,6 +78,18 @@
<!-- Description of the privileges the application will get if associated with the companion device of COMPUTER profile (type) [CHAR LIMIT=NONE] -->
<string name="summary_computer"></string>
+ <!-- Notification permission will be granted of COMPUTER profile [CHAR LIMIT=30] -->
+ <string name="permission_notification">Notifications</string>
+
+ <!-- Description of notification permission of COMPUTER profile [CHAR LIMIT=NONE] -->
+ <string name="permission_notification_summary">Can read all notifications, including information like contacts, messages, and photos</string>
+
+ <!-- Storage permission will be granted of COMPUTER profile [CHAR LIMIT=30] -->
+ <string name="permission_storage">Photos and media</string>
+
+ <!-- Description of storage permission of COMPUTER profile [CHAR LIMIT=NONE] -->
+ <string name="permission_storage_summary"></string>
+
<!-- Title of the helper dialog for COMPUTER profile [CHAR LIMIT=30]. -->
<string name="helper_title_computer">Google Play services</string>
diff --git a/packages/CompanionDeviceManager/res/values/styles.xml b/packages/CompanionDeviceManager/res/values/styles.xml
index bba45e9ecf0f..a55f30c9be6a 100644
--- a/packages/CompanionDeviceManager/res/values/styles.xml
+++ b/packages/CompanionDeviceManager/res/values/styles.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2022 The Android Open Source Project
~
@@ -16,23 +17,94 @@
<resources>
<style name="ContainerLayout">
- <item name="android:padding">18dp</item>
- <item name="android:elevation">16dp</item>
- <item name="android:maxHeight">400dp</item>
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:layout_height">wrap_content</item>
<item name="android:orientation">vertical</item>
<item name="android:layout_gravity">center</item>
+ <item name="android:minWidth">340dp</item>
+ <item name="android:background">@drawable/dialog_background</item>
+ </style>
+
+ <style name="Description">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">wrap_content</item>
- <item name="android:background">@drawable/dialog_background</item>
+ <item name="android:orientation">vertical</item>
+ <item name="android:layout_marginTop">18dp</item>
+ <item name="android:layout_marginBottom">18dp</item>
+ <item name="android:layout_marginLeft">24dp</item>
+ <item name="android:layout_marginRight">24dp</item>
+ </style>
+
+ <style name="DescriptionTitle"
+ parent="@*android:style/TextAppearance.Widget.Toolbar.Title">
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:gravity">center</item>
+ <item name="android:layout_marginLeft">14dp</item>
+ <item name="android:layout_marginRight">14dp</item>
+ <item name="android:textSize">20sp</item>
+ <item name="android:textColor">?android:attr/textColorPrimary</item>
+ </style>
+
+ <style name="DescriptionSummary">
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:gravity">center</item>
+ <item name="android:layout_marginTop">18dp</item>
+ <item name="android:layout_marginLeft">18dp</item>
+ <item name="android:layout_marginRight">18dp</item>
+ <item name="android:textSize">14sp</item>
+ <item name="android:textColor">?android:attr/textColorSecondary</item>
</style>
<style name="VendorHelperOkButton"
parent="@android:style/Widget.Material.Button.Borderless.Colored">
<item name="android:layout_width">50dp</item>
- <item name="android:layout_height">35dp</item>
+ <item name="android:layout_height">36dp</item>
<item name="android:layout_marginTop">20dp</item>
<item name="android:textColor">@android:color/system_neutral1_900</item>
<item name="android:background">@drawable/helper_ok_button</item>
</style>
+ <style name="PositiveButton"
+ parent="@android:style/Widget.Material.Button.Borderless.Colored">
+ <item name="android:layout_width">300dp</item>
+ <item name="android:layout_height">56dp</item>
+ <item name="android:layout_marginLeft">24dp</item>
+ <item name="android:layout_marginRight">24dp</item>
+ <item name="android:layout_marginBottom">2dp</item>
+ <item name="android:textAllCaps">false</item>
+ <item name="android:textSize">14sp</item>
+ <item name="android:textColor">@android:color/system_neutral1_900</item>
+ <item name="android:background">@drawable/btn_positive_bottom</item>
+ </style>
+
+ <style name="NegativeButton"
+ parent="@android:style/Widget.Material.Button.Borderless.Colored">
+ <item name="android:layout_width">300dp</item>
+ <item name="android:layout_height">56dp</item>
+ <item name="android:layout_marginLeft">24dp</item>
+ <item name="android:layout_marginRight">24dp</item>
+ <item name="android:layout_marginTop">2dp</item>
+ <item name="android:textAllCaps">false</item>
+ <item name="android:textSize">14sp</item>
+ <item name="android:textColor">@android:color/system_neutral1_900</item>
+ <item name="android:layout_marginTop">4dp</item>
+ <item name="android:background">@drawable/btn_negative_top</item>
+ </style>
+
+ <style name="NegativeButtonMultipleDevices"
+ parent="@android:style/Widget.Material.Button.Colored">
+ <item name="android:layout_width">100dp</item>
+ <item name="android:layout_height">36dp</item>
+ <item name="android:textAllCaps">false</item>
+ <item name="android:background">@drawable/btn_negative_multiple_devices</item>
+ </style>
+
+ <style name="DeviceListBorder">
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:layout_height">1dp</item>
+ <item name="android:background">@android:color/system_accent1_300</item>
+ </style>
+
</resources> \ No newline at end of file
diff --git a/packages/CompanionDeviceManager/res/values/themes.xml b/packages/CompanionDeviceManager/res/values/themes.xml
index 72404322c25e..e3fc67c50d75 100644
--- a/packages/CompanionDeviceManager/res/values/themes.xml
+++ b/packages/CompanionDeviceManager/res/values/themes.xml
@@ -17,11 +17,10 @@
<resources>
<style name="ChooserActivity"
- parent="@android:style/Theme.DeviceDefault.Light.Dialog">
+ parent="@android:style/Theme.DeviceDefault.Light.Dialog.NoActionBar">
<item name="*android:windowFixedHeightMajor">100%</item>
<item name="*android:windowFixedHeightMinor">100%</item>
<item name="android:windowBackground">@android:color/transparent</item>
- <item name="android:forceDarkAllowed">true</item>
</style>
</resources>
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
index 0fba250b200a..5eeb167ee5e0 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
@@ -20,12 +20,22 @@ import static android.companion.AssociationRequest.DEVICE_PROFILE_APP_STREAMING;
import static android.companion.AssociationRequest.DEVICE_PROFILE_AUTOMOTIVE_PROJECTION;
import static android.companion.AssociationRequest.DEVICE_PROFILE_COMPUTER;
import static android.companion.AssociationRequest.DEVICE_PROFILE_WATCH;
+import static android.companion.CompanionDeviceManager.REASON_CANCELED;
+import static android.companion.CompanionDeviceManager.REASON_DISCOVERY_TIMEOUT;
+import static android.companion.CompanionDeviceManager.REASON_USER_REJECTED;
+import static android.companion.CompanionDeviceManager.RESULT_DISCOVERY_TIMEOUT;
+import static android.companion.CompanionDeviceManager.RESULT_INTERNAL_ERROR;
+import static android.companion.CompanionDeviceManager.RESULT_USER_REJECTED;
import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
import static com.android.companiondevicemanager.CompanionDeviceDiscoveryService.DiscoveryState;
import static com.android.companiondevicemanager.CompanionDeviceDiscoveryService.DiscoveryState.FINISHED_TIMEOUT;
+import static com.android.companiondevicemanager.PermissionListAdapter.TYPE_APPS;
+import static com.android.companiondevicemanager.PermissionListAdapter.TYPE_NOTIFICATION;
+import static com.android.companiondevicemanager.PermissionListAdapter.TYPE_STORAGE;
import static com.android.companiondevicemanager.Utils.getApplicationLabel;
import static com.android.companiondevicemanager.Utils.getHtmlFromResources;
+import static com.android.companiondevicemanager.Utils.getIcon;
import static com.android.companiondevicemanager.Utils.getVendorHeaderIcon;
import static com.android.companiondevicemanager.Utils.getVendorHeaderName;
import static com.android.companiondevicemanager.Utils.prepareResultReceiverForIpc;
@@ -53,6 +63,7 @@ import android.widget.Button;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
+import android.widget.ProgressBar;
import android.widget.RelativeLayout;
import android.widget.TextView;
@@ -61,6 +72,7 @@ import androidx.fragment.app.FragmentManager;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
+import java.util.ArrayList;
import java.util.List;
/**
@@ -83,9 +95,6 @@ public class CompanionDeviceActivity extends FragmentActivity implements
private static final String FRAGMENT_DIALOG_TAG = "fragment_dialog";
- // Activity result: Internal Error.
- private static final int RESULT_INTERNAL_ERROR = 2;
-
// AssociationRequestsProcessor -> UI
private static final int RESULT_CODE_ASSOCIATION_CREATED = 0;
private static final String EXTRA_ASSOCIATION = "association";
@@ -102,28 +111,38 @@ public class CompanionDeviceActivity extends FragmentActivity implements
private TextView mTitle;
private TextView mSummary;
+ // Present for single device and multiple device only.
+ private ImageView mProfileIcon;
+
// Only present for selfManaged devices.
private ImageView mVendorHeaderImage;
private TextView mVendorHeaderName;
private ImageButton mVendorHeaderButton;
// Progress indicator is only shown while we are looking for the first suitable device for a
- // "regular" (ie. not self-managed) association.
- private View mProgressIndicator;
+ // multiple device association.
+ private ProgressBar mProgressIndicator;
// Present for self-managed association requests and "single-device" regular association
// regular.
private Button mButtonAllow;
- // Present for all associations.
private Button mButtonNotAllow;
+ // Present for multiple devices' association requests only.
+ private Button mButtonNotAllowMultipleDevices;
private LinearLayout mAssociationConfirmationDialog;
+ private LinearLayout mMultipleDeviceList;
private RelativeLayout mVendorHeader;
// The recycler view is only shown for multiple-device regular association request, after
// at least one matching device is found.
- private @Nullable RecyclerView mRecyclerView;
- private @Nullable DeviceListAdapter mAdapter;
+ private @Nullable RecyclerView mDeviceListRecyclerView;
+ private @Nullable DeviceListAdapter mDeviceAdapter;
+
+
+ // The recycler view is only shown for selfManaged association request.
+ private @Nullable RecyclerView mPermissionListRecyclerView;
+ private @Nullable PermissionListAdapter mPermissionListAdapter;
// The flag used to prevent double taps, that may lead to sending several requests for creating
// an association to CDM.
@@ -133,6 +152,8 @@ public class CompanionDeviceActivity extends FragmentActivity implements
// onActivityResult() after the association is created.
private @Nullable DeviceFilterPair<?> mSelectedDevice;
+ private @Nullable List<Integer> mPermissionTypes;
+
@Override
public void onCreate(Bundle savedInstanceState) {
if (DEBUG) Log.d(TAG, "onCreate()");
@@ -191,7 +212,7 @@ public class CompanionDeviceActivity extends FragmentActivity implements
// TODO: handle config changes without cancelling.
if (!isDone()) {
- cancel(false); // will finish()
+ cancel(/* discoveryTimeOut */ false, /* userRejected */ false); // will finish()
}
}
@@ -232,24 +253,35 @@ public class CompanionDeviceActivity extends FragmentActivity implements
setContentView(R.layout.activity_confirmation);
+ mMultipleDeviceList = findViewById(R.id.multiple_device_list);
mAssociationConfirmationDialog = findViewById(R.id.activity_confirmation);
mVendorHeader = findViewById(R.id.vendor_header);
mTitle = findViewById(R.id.title);
mSummary = findViewById(R.id.summary);
+ mProfileIcon = findViewById(R.id.profile_icon);
+
mVendorHeaderImage = findViewById(R.id.vendor_header_image);
mVendorHeaderName = findViewById(R.id.vendor_header_name);
mVendorHeaderButton = findViewById(R.id.vendor_header_button);
- mRecyclerView = findViewById(R.id.device_list);
- mAdapter = new DeviceListAdapter(this, this::onListItemClick);
+ mDeviceListRecyclerView = findViewById(R.id.device_list);
+
+ mProgressIndicator = findViewById(R.id.spinner);
+ mDeviceAdapter = new DeviceListAdapter(this, this::onListItemClick);
+
+ mPermissionListRecyclerView = findViewById(R.id.permission_list);
+ mPermissionListAdapter = new PermissionListAdapter(this);
mButtonAllow = findViewById(R.id.btn_positive);
mButtonNotAllow = findViewById(R.id.btn_negative);
+ mButtonNotAllowMultipleDevices = findViewById(R.id.btn_negative_multiple_devices);
mButtonAllow.setOnClickListener(this::onPositiveButtonClick);
mButtonNotAllow.setOnClickListener(this::onNegativeButtonClick);
+ mButtonNotAllowMultipleDevices.setOnClickListener(this::onNegativeButtonClick);
+
mVendorHeaderButton.setOnClickListener(this::onShowHelperDialog);
if (mRequest.isSelfManaged()) {
@@ -264,7 +296,7 @@ public class CompanionDeviceActivity extends FragmentActivity implements
private void onDiscoveryStateChanged(DiscoveryState newState) {
if (newState == FINISHED_TIMEOUT
&& CompanionDeviceDiscoveryService.getScanResult().getValue().isEmpty()) {
- cancel(true);
+ cancel(/* discoveryTimeOut */ true, /* userRejected */ false);
}
}
@@ -307,10 +339,12 @@ public class CompanionDeviceActivity extends FragmentActivity implements
setResultAndFinish(association, RESULT_OK);
}
- private void cancel(boolean discoveryTimeout) {
+ private void cancel(boolean discoveryTimeout, boolean userRejected) {
if (DEBUG) {
- Log.i(TAG, "cancel(), discoveryTimeout=" + discoveryTimeout,
- new Exception("Stack Trace Dump"));
+ Log.i(TAG, "cancel(), discoveryTimeout="
+ + discoveryTimeout
+ + ", userRejected="
+ + userRejected, new Exception("Stack Trace Dump"));
}
if (isDone()) {
@@ -324,14 +358,27 @@ public class CompanionDeviceActivity extends FragmentActivity implements
CompanionDeviceDiscoveryService.stop(this);
}
+ final String cancelReason;
+ final int resultCode;
+ if (userRejected) {
+ cancelReason = REASON_USER_REJECTED;
+ resultCode = RESULT_USER_REJECTED;
+ } else if (discoveryTimeout) {
+ cancelReason = REASON_DISCOVERY_TIMEOUT;
+ resultCode = RESULT_DISCOVERY_TIMEOUT;
+ } else {
+ cancelReason = REASON_CANCELED;
+ resultCode = RESULT_CANCELED;
+ }
+
// First send callback to the app directly...
try {
- mAppCallback.onFailure(discoveryTimeout ? "Timeout." : "Cancelled.");
+ mAppCallback.onFailure(cancelReason);
} catch (RemoteException ignore) {
}
// ... then set result and finish ("sending" onActivityResult()).
- setResultAndFinish(null, RESULT_CANCELED);
+ setResultAndFinish(null, resultCode);
}
private void setResultAndFinish(@Nullable AssociationInfo association, int resultCode) {
@@ -359,7 +406,8 @@ public class CompanionDeviceActivity extends FragmentActivity implements
final Drawable vendorIcon;
final CharSequence vendorName;
final Spanned title;
- final Spanned summary;
+
+ mPermissionTypes = new ArrayList<>();
try {
vendorIcon = getVendorHeaderIcon(this, packageName, userId);
@@ -372,33 +420,37 @@ public class CompanionDeviceActivity extends FragmentActivity implements
switch (deviceProfile) {
case DEVICE_PROFILE_APP_STREAMING:
- title = getHtmlFromResources(this, R.string.title_app_streaming, appLabel);
- summary = getHtmlFromResources(
- this, R.string.summary_app_streaming, appLabel, deviceName);
+ title = getHtmlFromResources(this, R.string.title_app_streaming, deviceName);
+ mPermissionTypes.add(TYPE_APPS);
break;
case DEVICE_PROFILE_AUTOMOTIVE_PROJECTION:
- title = getHtmlFromResources(this, R.string.title_automotive_projection, appLabel);
- summary = getHtmlFromResources(
- this, R.string.summary_automotive_projection, appLabel, deviceName);
+ title = getHtmlFromResources(
+ this, R.string.title_automotive_projection, deviceName);
break;
case DEVICE_PROFILE_COMPUTER:
- title = getHtmlFromResources(this, R.string.title_computer, appLabel);
- summary = getHtmlFromResources(
- this, R.string.summary_computer, appLabel, deviceName);
+ title = getHtmlFromResources(this, R.string.title_computer, deviceName);
+ mPermissionTypes.add(TYPE_NOTIFICATION);
+ mPermissionTypes.add(TYPE_STORAGE);
break;
default:
throw new RuntimeException("Unsupported profile " + deviceProfile);
}
+ mSummary.setVisibility(View.GONE);
+
+ mPermissionListAdapter.setPermissionType(mPermissionTypes);
+ mPermissionListRecyclerView.setAdapter(mPermissionListAdapter);
+ mPermissionListRecyclerView.setLayoutManager(new LinearLayoutManager(this));
+
mTitle.setText(title);
- mSummary.setText(summary);
mVendorHeaderImage.setImageDrawable(vendorIcon);
mVendorHeaderName.setText(vendorName);
- mRecyclerView.setVisibility(View.GONE);
+ mDeviceListRecyclerView.setVisibility(View.GONE);
+ mProfileIcon.setVisibility(View.GONE);
mVendorHeader.setVisibility(View.VISIBLE);
}
@@ -411,7 +463,8 @@ public class CompanionDeviceActivity extends FragmentActivity implements
deviceFilterPairs -> updateSingleDeviceUi(
deviceFilterPairs, deviceProfile, appLabel));
- mRecyclerView.setVisibility(View.GONE);
+ mPermissionListRecyclerView.setVisibility(View.GONE);
+ mDeviceListRecyclerView.setVisibility(View.GONE);
}
private void updateSingleDeviceUi(List<DeviceFilterPair<?>> deviceFilterPairs,
@@ -425,17 +478,22 @@ public class CompanionDeviceActivity extends FragmentActivity implements
final Spanned title = getHtmlFromResources(
this, R.string.confirmation_title, appLabel, deviceName);
final Spanned summary;
+ final Drawable profileIcon;
if (deviceProfile == null) {
summary = getHtmlFromResources(this, R.string.summary_generic);
+ profileIcon = getIcon(this, R.drawable.ic_device_other);
+ mSummary.setVisibility(View.GONE);
} else if (deviceProfile.equals(DEVICE_PROFILE_WATCH)) {
summary = getHtmlFromResources(this, R.string.summary_watch, appLabel, deviceName);
+ profileIcon = getIcon(this, R.drawable.ic_watch);
} else {
throw new RuntimeException("Unsupported profile " + deviceProfile);
}
mTitle.setText(title);
mSummary.setText(summary);
+ mProfileIcon.setImageDrawable(profileIcon);
}
private void initUiForMultipleDevices(CharSequence appLabel) {
@@ -445,12 +503,16 @@ public class CompanionDeviceActivity extends FragmentActivity implements
final String profileName;
final Spanned summary;
+ final Drawable profileIcon;
if (deviceProfile == null) {
profileName = getString(R.string.profile_name_generic);
summary = getHtmlFromResources(this, R.string.summary_generic);
+ profileIcon = getIcon(this, R.drawable.ic_device_other);
+ mSummary.setVisibility(View.GONE);
} else if (deviceProfile.equals(DEVICE_PROFILE_WATCH)) {
profileName = getString(R.string.profile_name_watch);
summary = getHtmlFromResources(this, R.string.summary_watch, appLabel);
+ profileIcon = getIcon(this, R.drawable.ic_watch);
} else {
throw new RuntimeException("Unsupported profile " + deviceProfile);
}
@@ -459,32 +521,40 @@ public class CompanionDeviceActivity extends FragmentActivity implements
mTitle.setText(title);
mSummary.setText(summary);
+ mProfileIcon.setImageDrawable(profileIcon);
- mAdapter = new DeviceListAdapter(this, this::onListItemClick);
+ mDeviceListRecyclerView.setAdapter(mDeviceAdapter);
+ mDeviceListRecyclerView.setLayoutManager(new LinearLayoutManager(this));
- // TODO: hide the list and show a spinner until a first device matching device is found.
- mRecyclerView.setAdapter(mAdapter);
- mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
+ CompanionDeviceDiscoveryService.getScanResult().observe(this,
+ deviceFilterPairs -> {
+ // Dismiss the progress bar once there's one device found for multiple devices.
+ if (deviceFilterPairs.size() >= 1) {
+ mProgressIndicator.setVisibility(View.GONE);
+ }
- CompanionDeviceDiscoveryService.getScanResult().observe(
- /* lifecycleOwner */ this,
- /* observer */ mAdapter);
+ mDeviceAdapter.setDevices(deviceFilterPairs);
+ });
// "Remove" consent button: users would need to click on the list item.
mButtonAllow.setVisibility(View.GONE);
+ mButtonNotAllow.setVisibility(View.GONE);
+ mButtonNotAllowMultipleDevices.setVisibility(View.VISIBLE);
+ mMultipleDeviceList.setVisibility(View.VISIBLE);
+ mProgressIndicator.setVisibility(View.VISIBLE);
}
private void onListItemClick(int position) {
if (DEBUG) Log.d(TAG, "onListItemClick() " + position);
- final DeviceFilterPair<?> selectedDevice = mAdapter.getItem(position);
+ final DeviceFilterPair<?> selectedDevice = mDeviceAdapter.getItem(position);
if (mSelectedDevice != null) {
if (DEBUG) Log.w(TAG, "Already selected.");
return;
}
// Notify the adapter to highlight the selected item.
- mAdapter.setSelectedPosition(position);
+ mDeviceAdapter.setSelectedPosition(position);
mSelectedDevice = requireNonNull(selectedDevice);
@@ -510,7 +580,7 @@ public class CompanionDeviceActivity extends FragmentActivity implements
// Disable the button, to prevent more clicks.
v.setEnabled(false);
- cancel(false);
+ cancel(/* discoveryTimeout */ false, /* userRejected */ true);
}
private void onShowHelperDialog(View view) {
@@ -519,7 +589,7 @@ public class CompanionDeviceActivity extends FragmentActivity implements
CompanionVendorHelperDialogFragment.newInstance(mRequest.getPackageName(),
mRequest.getUserId(), mRequest.getDeviceProfile());
- mAssociationConfirmationDialog.setVisibility(View.GONE);
+ mAssociationConfirmationDialog.setVisibility(View.INVISIBLE);
fragmentDialog.show(fragmentManager, /* Tag */ FRAGMENT_DIALOG_TAG);
}
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java
index 5f07fcfd8565..e8a1a5cc1916 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java
@@ -150,6 +150,8 @@ public class CompanionDeviceDiscoveryService extends Service {
mBtAdapter = mBtManager.getAdapter();
mBleScanner = mBtAdapter.getBluetoothLeScanner();
mWifiManager = getSystemService(WifiManager.class);
+
+ sScanResultsLiveData.setValue(Collections.emptyList());
}
@Override
@@ -186,7 +188,6 @@ public class CompanionDeviceDiscoveryService extends Service {
mStopAfterFirstMatch = request.isSingleDevice();
mDiscoveryStarted = true;
sStateLiveData.setValue(DiscoveryState.DISCOVERY_IN_PROGRESS);
- sScanResultsLiveData.setValue(Collections.emptyList());
final List<DeviceFilter<?>> allFilters = request.getDeviceFilters();
final List<BluetoothDeviceFilter> btFilters =
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceListAdapter.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceListAdapter.java
index e5513b074865..328c67ebb216 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceListAdapter.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceListAdapter.java
@@ -15,24 +15,23 @@
*/
package com.android.companiondevicemanager;
+
+import static com.android.companiondevicemanager.Utils.getIcon;
+
import android.content.Context;
-import android.graphics.Color;
-import android.graphics.drawable.Drawable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
-import androidx.lifecycle.Observer;
import androidx.recyclerview.widget.RecyclerView;
import java.util.List;
/**
* Adapter for the list of "found" devices.
*/
-class DeviceListAdapter extends RecyclerView.Adapter<DeviceListAdapter.ViewHolder> implements
- Observer<List<DeviceFilterPair<?>>> {
+class DeviceListAdapter extends RecyclerView.Adapter<DeviceListAdapter.ViewHolder> {
public int mSelectedPosition = RecyclerView.NO_POSITION;
private final Context mContext;
@@ -60,11 +59,11 @@ class DeviceListAdapter extends RecyclerView.Adapter<DeviceListAdapter.ViewHolde
R.layout.list_item_device, parent, false);
ViewHolder viewHolder = new ViewHolder(view);
if (viewType == TYPE_WIFI) {
- viewHolder.mImageView.setImageDrawable(getIcon(
- com.android.internal.R.drawable.ic_wifi_signal_3));
+ viewHolder.mImageView.setImageDrawable(
+ getIcon(mContext, com.android.internal.R.drawable.ic_wifi_signal_3));
} else {
- viewHolder.mImageView.setImageDrawable(getIcon(
- android.R.drawable.stat_sys_data_bluetooth));
+ viewHolder.mImageView.setImageDrawable(
+ getIcon(mContext, android.R.drawable.stat_sys_data_bluetooth));
}
return viewHolder;
}
@@ -95,9 +94,8 @@ class DeviceListAdapter extends RecyclerView.Adapter<DeviceListAdapter.ViewHolde
mSelectedPosition = position;
}
- @Override
- public void onChanged(List<DeviceFilterPair<?>> deviceFilterPairs) {
- mDevices = deviceFilterPairs;
+ void setDevices(List<DeviceFilterPair<?>> devices) {
+ mDevices = devices;
notifyDataSetChanged();
}
@@ -115,12 +113,6 @@ class DeviceListAdapter extends RecyclerView.Adapter<DeviceListAdapter.ViewHolde
return mDevices.get(position).getDevice() instanceof android.net.wifi.ScanResult;
}
- private Drawable getIcon(int resId) {
- Drawable icon = mContext.getResources().getDrawable(resId, null);
- icon.setTint(Color.DKGRAY);
- return icon;
- }
-
public interface OnItemClickListener {
void onItemClick(int position);
}
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/PermissionListAdapter.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/PermissionListAdapter.java
new file mode 100644
index 000000000000..895b729ea8c7
--- /dev/null
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/PermissionListAdapter.java
@@ -0,0 +1,128 @@
+/*
+ * 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.companiondevicemanager;
+
+import static com.android.companiondevicemanager.Utils.getHtmlFromResources;
+import static com.android.companiondevicemanager.Utils.getIcon;
+
+import static java.util.Collections.unmodifiableMap;
+
+import android.content.Context;
+import android.text.Spanned;
+import android.util.ArrayMap;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import androidx.recyclerview.widget.RecyclerView;
+
+import java.util.List;
+import java.util.Map;
+
+class PermissionListAdapter extends RecyclerView.Adapter<PermissionListAdapter.ViewHolder> {
+ private final Context mContext;
+
+ private List<Integer> mPermissions;
+
+ static final int TYPE_NOTIFICATION = 0;
+ static final int TYPE_STORAGE = 1;
+ static final int TYPE_APPS = 2;
+
+ private static final Map<Integer, Integer> sTitleMap;
+ static {
+ final Map<Integer, Integer> map = new ArrayMap<>();
+ map.put(TYPE_NOTIFICATION, R.string.permission_notification);
+ map.put(TYPE_STORAGE, R.string.permission_storage);
+ map.put(TYPE_APPS, R.string.permission_apps);
+ sTitleMap = unmodifiableMap(map);
+ }
+
+ private static final Map<Integer, Integer> sSummaryMap;
+ static {
+ final Map<Integer, Integer> map = new ArrayMap<>();
+ map.put(TYPE_NOTIFICATION, R.string.permission_notification_summary);
+ map.put(TYPE_STORAGE, R.string.permission_storage_summary);
+ map.put(TYPE_APPS, R.string.permission_apps_summary);
+ sSummaryMap = unmodifiableMap(map);
+ }
+
+ private static final Map<Integer, Integer> sIconMap;
+ static {
+ final Map<Integer, Integer> map = new ArrayMap<>();
+ map.put(TYPE_NOTIFICATION, R.drawable.ic_notifications);
+ map.put(TYPE_STORAGE, R.drawable.ic_storage);
+ map.put(TYPE_APPS, R.drawable.ic_apps);
+ sIconMap = unmodifiableMap(map);
+ }
+
+ PermissionListAdapter(Context context) {
+ mContext = context;
+ }
+
+ @Override
+ public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+ View view = LayoutInflater.from(parent.getContext()).inflate(
+ R.layout.list_item_permission, parent, false);
+ ViewHolder viewHolder = new ViewHolder(view);
+ viewHolder.mPermissionIcon.setImageDrawable(getIcon(mContext, sIconMap.get(viewType)));
+
+ return viewHolder;
+ }
+
+ @Override
+ public void onBindViewHolder(ViewHolder holder, int position) {
+ int type = getItemViewType(position);
+ final Spanned title = getHtmlFromResources(mContext, sTitleMap.get(type));
+ final Spanned summary = getHtmlFromResources(mContext, sSummaryMap.get(type));
+
+ holder.mPermissionName.setText(title);
+ holder.mPermissionSummary.setText(summary);
+ }
+
+ @Override
+ public int getItemViewType(int position) {
+ return mPermissions.get(position);
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return position;
+ }
+
+ @Override
+ public int getItemCount() {
+ return mPermissions != null ? mPermissions.size() : 0;
+ }
+
+ static class ViewHolder extends RecyclerView.ViewHolder {
+ private final TextView mPermissionName;
+ private final TextView mPermissionSummary;
+ private final ImageView mPermissionIcon;
+ ViewHolder(View itemView) {
+ super(itemView);
+ mPermissionName = itemView.findViewById(R.id.permission_name);
+ mPermissionSummary = itemView.findViewById(R.id.permission_summary);
+ mPermissionIcon = itemView.findViewById(R.id.permission_icon);
+ }
+ }
+
+ void setPermissionType(List<Integer> permissions) {
+ mPermissions = permissions;
+ }
+}
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/Utils.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/Utils.java
index 76bbcfb79155..1852e82cb9f9 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/Utils.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/Utils.java
@@ -121,6 +121,11 @@ class Utils {
return appInfo;
}
+ static @NonNull Drawable getIcon(@NonNull Context context, int resId) {
+ Drawable icon = context.getResources().getDrawable(resId, null);
+ return icon;
+ }
+
static void runOnMainThread(Runnable runnable) {
if (Thread.currentThread() == Looper.getMainLooper().getThread()) {
runnable.run();
diff --git a/packages/ConnectivityT/framework-t/Android.bp b/packages/ConnectivityT/framework-t/Android.bp
index 66527802a0e4..bc278528570f 100644
--- a/packages/ConnectivityT/framework-t/Android.bp
+++ b/packages/ConnectivityT/framework-t/Android.bp
@@ -131,8 +131,8 @@ filegroup {
"src/android/net/EthernetNetworkUpdateRequest.java",
"src/android/net/EthernetNetworkUpdateRequest.aidl",
"src/android/net/IEthernetManager.aidl",
- "src/android/net/IEthernetNetworkManagementListener.aidl",
"src/android/net/IEthernetServiceListener.aidl",
+ "src/android/net/INetworkInterfaceOutcomeReceiver.aidl",
"src/android/net/ITetheredInterfaceCallback.aidl",
],
path: "src",
@@ -154,17 +154,17 @@ filegroup {
],
}
+// TODO: remove this empty filegroup.
filegroup {
name: "framework-connectivity-tiramisu-sources",
- srcs: [
- ":framework-connectivity-ethernet-sources",
- ],
+ srcs: [],
visibility: ["//frameworks/base"],
}
filegroup {
name: "framework-connectivity-tiramisu-updatable-sources",
srcs: [
+ ":framework-connectivity-ethernet-sources",
":framework-connectivity-ipsec-sources",
":framework-connectivity-netstats-sources",
":framework-connectivity-nsd-sources",
diff --git a/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStats.java b/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStats.java
index 2b6570a6ecb0..74fe4bd46cde 100644
--- a/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStats.java
+++ b/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStats.java
@@ -17,6 +17,7 @@
package android.app.usage;
import android.annotation.IntDef;
+import android.annotation.Nullable;
import android.content.Context;
import android.net.INetworkStatsService;
import android.net.INetworkStatsSession;
@@ -474,10 +475,11 @@ public final class NetworkStats implements AutoCloseable {
/**
* Fills the recycled bucket with data of the next bin in the enumeration.
- * @param bucketOut Bucket to be filled with data.
+ * @param bucketOut Bucket to be filled with data. If null, the method does
+ * nothing and returning false.
* @return true if successfully filled the bucket, false otherwise.
*/
- public boolean getNextBucket(Bucket bucketOut) {
+ public boolean getNextBucket(@Nullable Bucket bucketOut) {
if (mSummary != null) {
return getNextSummaryBucket(bucketOut);
} else {
@@ -651,7 +653,7 @@ public final class NetworkStats implements AutoCloseable {
* @param bucketOut Next item will be set here.
* @return true if a next item could be set.
*/
- private boolean getNextSummaryBucket(Bucket bucketOut) {
+ private boolean getNextSummaryBucket(@Nullable Bucket bucketOut) {
if (bucketOut != null && mEnumerationIndex < mSummary.size()) {
mRecycledSummaryEntry = mSummary.getValues(mEnumerationIndex++, mRecycledSummaryEntry);
fillBucketFromSummaryEntry(bucketOut);
@@ -678,7 +680,7 @@ public final class NetworkStats implements AutoCloseable {
* @param bucketOut Next item will be set here.
* @return true if a next item could be set.
*/
- private boolean getNextHistoryBucket(Bucket bucketOut) {
+ private boolean getNextHistoryBucket(@Nullable Bucket bucketOut) {
if (bucketOut != null && mHistory != null) {
if (mEnumerationIndex < mHistory.size()) {
mRecycledHistoryEntry = mHistory.getValues(mEnumerationIndex++,
diff --git a/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStatsManager.java b/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStatsManager.java
index ca080ce4c64a..f41475bea190 100644
--- a/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStatsManager.java
+++ b/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStatsManager.java
@@ -290,7 +290,7 @@ public class NetworkStatsManager {
* statistics collection.
*/
@WorkerThread
- public Bucket querySummaryForDevice(int networkType, String subscriberId,
+ public Bucket querySummaryForDevice(int networkType, @Nullable String subscriberId,
long startTime, long endTime) throws SecurityException, RemoteException {
NetworkTemplate template;
try {
@@ -335,8 +335,8 @@ public class NetworkStatsManager {
* statistics collection.
*/
@WorkerThread
- public Bucket querySummaryForUser(int networkType, String subscriberId, long startTime,
- long endTime) throws SecurityException, RemoteException {
+ public Bucket querySummaryForUser(int networkType, @Nullable String subscriberId,
+ long startTime, long endTime) throws SecurityException, RemoteException {
NetworkTemplate template;
try {
template = createTemplate(networkType, subscriberId);
@@ -384,7 +384,7 @@ public class NetworkStatsManager {
* statistics collection.
*/
@WorkerThread
- public NetworkStats querySummary(int networkType, String subscriberId, long startTime,
+ public NetworkStats querySummary(int networkType, @Nullable String subscriberId, long startTime,
long endTime) throws SecurityException, RemoteException {
NetworkTemplate template;
try {
@@ -508,15 +508,17 @@ public class NetworkStatsManager {
*
* @see #queryDetailsForUidTagState(int, String, long, long, int, int, int)
*/
+ @NonNull
@WorkerThread
- public NetworkStats queryDetailsForUid(int networkType, String subscriberId,
+ public NetworkStats queryDetailsForUid(int networkType, @Nullable String subscriberId,
long startTime, long endTime, int uid) throws SecurityException {
return queryDetailsForUidTagState(networkType, subscriberId, startTime, endTime, uid,
NetworkStats.Bucket.TAG_NONE, NetworkStats.Bucket.STATE_ALL);
}
/** @hide */
- public NetworkStats queryDetailsForUid(NetworkTemplate template,
+ @NonNull
+ public NetworkStats queryDetailsForUid(@NonNull NetworkTemplate template,
long startTime, long endTime, int uid) throws SecurityException {
return queryDetailsForUidTagState(template, startTime, endTime, uid,
NetworkStats.Bucket.TAG_NONE, NetworkStats.Bucket.STATE_ALL);
@@ -524,23 +526,59 @@ public class NetworkStatsManager {
/**
* Query network usage statistics details for a given uid and tag.
+ *
+ * This may take a long time, and apps should avoid calling this on their main thread.
+ * Only usable for uids belonging to calling user. Result is not aggregated over time.
+ * This means buckets' start and end timestamps are going to be between 'startTime' and
+ * 'endTime' parameters. The uid is going to be the same as the 'uid' parameter, the tag
+ * the same as the 'tag' parameter, and the state the same as the 'state' parameter.
+ * defaultNetwork is going to be {@link NetworkStats.Bucket#DEFAULT_NETWORK_ALL},
+ * metered is going to be {@link NetworkStats.Bucket#METERED_ALL}, and
+ * roaming is going to be {@link NetworkStats.Bucket#ROAMING_ALL}.
+ * <p>Only includes buckets that atomically occur in the inclusive time range. Doesn't
+ * interpolate across partial buckets. Since bucket length is in the order of hours, this
+ * method cannot be used to measure data usage on a fine grained time scale.
* This may take a long time, and apps should avoid calling this on their main thread.
*
- * @see #queryDetailsForUidTagState(int, String, long, long, int, int, int)
+ * @param networkType As defined in {@link ConnectivityManager}, e.g.
+ * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI}
+ * etc.
+ * @param subscriberId If applicable, the subscriber id of the network interface.
+ * <p>Starting with API level 29, the {@code subscriberId} is guarded by
+ * additional restrictions. Calling apps that do not meet the new
+ * requirements to access the {@code subscriberId} can provide a {@code
+ * null} value when querying for the mobile network type to receive usage
+ * for all mobile networks. For additional details see {@link
+ * TelephonyManager#getSubscriberId()}.
+ * <p>Starting with API level 31, calling apps can provide a
+ * {@code subscriberId} with wifi network type to receive usage for
+ * wifi networks which is under the given subscription if applicable.
+ * Otherwise, pass {@code null} when querying all wifi networks.
+ * @param startTime Start of period. Defined in terms of "Unix time", see
+ * {@link java.lang.System#currentTimeMillis}.
+ * @param endTime End of period. Defined in terms of "Unix time", see
+ * {@link java.lang.System#currentTimeMillis}.
+ * @param uid UID of app
+ * @param tag TAG of interest. Use {@link NetworkStats.Bucket#TAG_NONE} for aggregated data
+ * across all the tags.
+ * @return Statistics which is described above.
+ * @throws SecurityException if permissions are insufficient to read network statistics.
*/
+ @NonNull
@WorkerThread
- public NetworkStats queryDetailsForUidTag(int networkType, String subscriberId,
+ public NetworkStats queryDetailsForUidTag(int networkType, @Nullable String subscriberId,
long startTime, long endTime, int uid, int tag) throws SecurityException {
return queryDetailsForUidTagState(networkType, subscriberId, startTime, endTime, uid,
tag, NetworkStats.Bucket.STATE_ALL);
}
/**
- * Query network usage statistics details for a given uid, tag, and state. Only usable for uids
- * belonging to calling user. Result is not aggregated over time. This means buckets' start and
- * end timestamps are going to be between 'startTime' and 'endTime' parameters. The uid is going
- * to be the same as the 'uid' parameter, the tag the same as the 'tag' parameter, and the state
- * the same as the 'state' parameter.
+ * Query network usage statistics details for a given uid, tag, and state.
+ *
+ * Only usable for uids belonging to calling user. Result is not aggregated over time.
+ * This means buckets' start and end timestamps are going to be between 'startTime' and
+ * 'endTime' parameters. The uid is going to be the same as the 'uid' parameter, the tag
+ * the same as the 'tag' parameter, and the state the same as the 'state' parameter.
* defaultNetwork is going to be {@link NetworkStats.Bucket#DEFAULT_NETWORK_ALL},
* metered is going to be {@link NetworkStats.Bucket#METERED_ALL}, and
* roaming is going to be {@link NetworkStats.Bucket#ROAMING_ALL}.
@@ -572,11 +610,12 @@ public class NetworkStatsManager {
* across all the tags.
* @param state state of interest. Use {@link NetworkStats.Bucket#STATE_ALL} to aggregate
* traffic from all states.
- * @return Statistics object or null if an error happened during statistics collection.
+ * @return Statistics which is described above.
* @throws SecurityException if permissions are insufficient to read network statistics.
*/
+ @NonNull
@WorkerThread
- public NetworkStats queryDetailsForUidTagState(int networkType, String subscriberId,
+ public NetworkStats queryDetailsForUidTagState(int networkType, @Nullable String subscriberId,
long startTime, long endTime, int uid, int tag, int state) throws SecurityException {
NetworkTemplate template;
template = createTemplate(networkType, subscriberId);
@@ -669,7 +708,7 @@ public class NetworkStatsManager {
* statistics collection.
*/
@WorkerThread
- public NetworkStats queryDetails(int networkType, String subscriberId, long startTime,
+ public NetworkStats queryDetails(int networkType, @Nullable String subscriberId, long startTime,
long endTime) throws SecurityException, RemoteException {
NetworkTemplate template;
try {
@@ -698,7 +737,7 @@ public class NetworkStatsManager {
*
* @hide
*/
- @SystemApi
+ @SystemApi(client = MODULE_LIBRARIES)
@RequiresPermission(anyOf = {
NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
android.Manifest.permission.NETWORK_STACK})
@@ -724,7 +763,7 @@ public class NetworkStatsManager {
*
* @hide
*/
- @SystemApi
+ @SystemApi(client = MODULE_LIBRARIES)
@RequiresPermission(anyOf = {
NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
android.Manifest.permission.NETWORK_STACK})
@@ -785,10 +824,28 @@ public class NetworkStatsManager {
/**
* Registers to receive notifications about data usage on specified networks.
*
- * @see #registerUsageCallback(int, String, long, UsageCallback, Handler)
+ * <p>The callbacks will continue to be called as long as the process is live or
+ * {@link #unregisterUsageCallback} is called.
+ *
+ * @param networkType Type of network to monitor. Either
+ {@link ConnectivityManager#TYPE_MOBILE} or {@link ConnectivityManager#TYPE_WIFI}.
+ * @param subscriberId If applicable, the subscriber id of the network interface.
+ * <p>Starting with API level 29, the {@code subscriberId} is guarded by
+ * additional restrictions. Calling apps that do not meet the new
+ * requirements to access the {@code subscriberId} can provide a {@code
+ * null} value when registering for the mobile network type to receive
+ * notifications for all mobile networks. For additional details see {@link
+ * TelephonyManager#getSubscriberId()}.
+ * <p>Starting with API level 31, calling apps can provide a
+ * {@code subscriberId} with wifi network type to receive usage for
+ * wifi networks which is under the given subscription if applicable.
+ * Otherwise, pass {@code null} when querying all wifi networks.
+ * @param thresholdBytes Threshold in bytes to be notified on.
+ * @param callback The {@link UsageCallback} that the system will call when data usage
+ * has exceeded the specified threshold.
*/
- public void registerUsageCallback(int networkType, String subscriberId, long thresholdBytes,
- UsageCallback callback) {
+ public void registerUsageCallback(int networkType, @Nullable String subscriberId,
+ long thresholdBytes, @NonNull UsageCallback callback) {
registerUsageCallback(networkType, subscriberId, thresholdBytes, callback,
null /* handler */);
}
@@ -818,8 +875,8 @@ public class NetworkStatsManager {
* @param handler to dispatch callback events through, otherwise if {@code null} it uses
* the calling thread.
*/
- public void registerUsageCallback(int networkType, String subscriberId, long thresholdBytes,
- UsageCallback callback, @Nullable Handler handler) {
+ public void registerUsageCallback(int networkType, @Nullable String subscriberId,
+ long thresholdBytes, @NonNull UsageCallback callback, @Nullable Handler handler) {
NetworkTemplate template = createTemplate(networkType, subscriberId);
if (DBG) {
Log.d(TAG, "registerUsageCallback called with: {"
@@ -839,7 +896,7 @@ public class NetworkStatsManager {
*
* @param callback The {@link UsageCallback} used when registering.
*/
- public void unregisterUsageCallback(UsageCallback callback) {
+ public void unregisterUsageCallback(@NonNull UsageCallback callback) {
if (callback == null || callback.request == null
|| callback.request.requestId == DataUsageRequest.REQUEST_ID_UNSET) {
throw new IllegalArgumentException("Invalid UsageCallback");
@@ -880,7 +937,7 @@ public class NetworkStatsManager {
/**
* Called when data usage has reached the given threshold.
*/
- public abstract void onThresholdReached(int networkType, String subscriberId);
+ public abstract void onThresholdReached(int networkType, @Nullable String subscriberId);
/**
* @hide used for internal bookkeeping
@@ -924,7 +981,7 @@ public class NetworkStatsManager {
@RequiresPermission(anyOf = {
android.Manifest.permission.NETWORK_STATS_PROVIDER,
NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK})
- @NonNull public void registerNetworkStatsProvider(
+ public void registerNetworkStatsProvider(
@NonNull String tag,
@NonNull NetworkStatsProvider provider) {
try {
@@ -950,7 +1007,7 @@ public class NetworkStatsManager {
@RequiresPermission(anyOf = {
android.Manifest.permission.NETWORK_STATS_PROVIDER,
NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK})
- @NonNull public void unregisterNetworkStatsProvider(@NonNull NetworkStatsProvider provider) {
+ public void unregisterNetworkStatsProvider(@NonNull NetworkStatsProvider provider) {
try {
provider.getProviderCallbackBinderOrThrow().unregister();
} catch (RemoteException e) {
@@ -958,7 +1015,7 @@ public class NetworkStatsManager {
}
}
- private static NetworkTemplate createTemplate(int networkType, String subscriberId) {
+ private static NetworkTemplate createTemplate(int networkType, @Nullable String subscriberId) {
final NetworkTemplate template;
switch (networkType) {
case ConnectivityManager.TYPE_MOBILE:
@@ -1061,9 +1118,9 @@ public class NetworkStatsManager {
@RequiresPermission(anyOf = {
NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
android.Manifest.permission.NETWORK_STACK})
- public void setUidForeground(int uid, boolean uidForeground) {
+ public void noteUidForeground(int uid, boolean uidForeground) {
try {
- mService.setUidForeground(uid, uidForeground);
+ mService.noteUidForeground(uid, uidForeground);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/packages/ConnectivityT/framework-t/src/android/net/ConnectivityFrameworkInitializerTiramisu.java b/packages/ConnectivityT/framework-t/src/android/net/ConnectivityFrameworkInitializerTiramisu.java
index 9bffbfb27a8d..61b34d0bcfe6 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/ConnectivityFrameworkInitializerTiramisu.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/ConnectivityFrameworkInitializerTiramisu.java
@@ -34,8 +34,9 @@ public final class ConnectivityFrameworkInitializerTiramisu {
private ConnectivityFrameworkInitializerTiramisu() {}
/**
- * Called by {@link SystemServiceRegistry}'s static initializer and registers nsd services to
- * {@link Context}, so that {@link Context#getSystemService} can return them.
+ * Called by {@link SystemServiceRegistry}'s static initializer and registers NetworkStats, nsd,
+ * ipsec and ethernet services to {@link Context}, so that {@link Context#getSystemService} can
+ * return them.
*
* @throws IllegalStateException if this is called anywhere besides
* {@link SystemServiceRegistry}.
@@ -68,5 +69,14 @@ public final class ConnectivityFrameworkInitializerTiramisu {
return new NetworkStatsManager(context, service);
}
);
+
+ SystemServiceRegistry.registerContextAwareService(
+ Context.ETHERNET_SERVICE,
+ EthernetManager.class,
+ (context, serviceBinder) -> {
+ IEthernetManager service = IEthernetManager.Stub.asInterface(serviceBinder);
+ return new EthernetManager(context, service);
+ }
+ );
}
}
diff --git a/packages/ConnectivityT/framework-t/src/android/net/EthernetManager.java b/packages/ConnectivityT/framework-t/src/android/net/EthernetManager.java
index 72243f9e87d9..e02ea897dbe6 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/EthernetManager.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/EthernetManager.java
@@ -30,17 +30,19 @@ import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Build;
+import android.os.OutcomeReceiver;
import android.os.RemoteException;
import com.android.internal.annotations.GuardedBy;
-import com.android.internal.os.BackgroundThread;
+import com.android.modules.utils.BackgroundThread;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
+import java.util.List;
import java.util.Objects;
import java.util.concurrent.Executor;
-import java.util.function.BiConsumer;
+import java.util.function.IntConsumer;
/**
* A class that manages and configures Ethernet interfaces.
@@ -53,15 +55,31 @@ public class EthernetManager {
private static final String TAG = "EthernetManager";
private final IEthernetManager mService;
- @GuardedBy("mListeners")
- private final ArrayList<ListenerInfo> mListeners = new ArrayList<>();
+ @GuardedBy("mListenerLock")
+ private final ArrayList<ListenerInfo<InterfaceStateListener>> mIfaceListeners =
+ new ArrayList<>();
+ @GuardedBy("mListenerLock")
+ private final ArrayList<ListenerInfo<IntConsumer>> mEthernetStateListeners =
+ new ArrayList<>();
+ final Object mListenerLock = new Object();
private final IEthernetServiceListener.Stub mServiceListener =
new IEthernetServiceListener.Stub() {
@Override
+ public void onEthernetStateChanged(int state) {
+ synchronized (mListenerLock) {
+ for (ListenerInfo<IntConsumer> li : mEthernetStateListeners) {
+ li.executor.execute(() -> {
+ li.listener.accept(state);
+ });
+ }
+ }
+ }
+
+ @Override
public void onInterfaceStateChanged(String iface, int state, int role,
IpConfiguration configuration) {
- synchronized (mListeners) {
- for (ListenerInfo li : mListeners) {
+ synchronized (mListenerLock) {
+ for (ListenerInfo<InterfaceStateListener> li : mIfaceListeners) {
li.executor.execute(() ->
li.listener.onInterfaceStateChanged(iface, state, role,
configuration));
@@ -70,13 +88,29 @@ public class EthernetManager {
}
};
- private static class ListenerInfo {
+ /**
+ * Indicates that Ethernet is disabled.
+ *
+ * @hide
+ */
+ @SystemApi(client = MODULE_LIBRARIES)
+ public static final int ETHERNET_STATE_DISABLED = 0;
+
+ /**
+ * Indicates that Ethernet is enabled.
+ *
+ * @hide
+ */
+ @SystemApi(client = MODULE_LIBRARIES)
+ public static final int ETHERNET_STATE_ENABLED = 1;
+
+ private static class ListenerInfo<T> {
@NonNull
public final Executor executor;
@NonNull
- public final InterfaceStateListener listener;
+ public final T listener;
- private ListenerInfo(@NonNull Executor executor, @NonNull InterfaceStateListener listener) {
+ private ListenerInfo(@NonNull Executor executor, @NonNull T listener) {
this.executor = executor;
this.listener = listener;
}
@@ -289,16 +323,22 @@ public class EthernetManager {
if (listener == null || executor == null) {
throw new NullPointerException("listener and executor must not be null");
}
- synchronized (mListeners) {
- mListeners.add(new ListenerInfo(executor, listener));
- if (mListeners.size() == 1) {
- try {
- mService.addListener(mServiceListener);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
+ synchronized (mListenerLock) {
+ maybeAddServiceListener();
+ mIfaceListeners.add(new ListenerInfo<InterfaceStateListener>(executor, listener));
+ }
+ }
+
+ @GuardedBy("mListenerLock")
+ private void maybeAddServiceListener() {
+ if (!mIfaceListeners.isEmpty() || !mEthernetStateListeners.isEmpty()) return;
+
+ try {
+ mService.addListener(mServiceListener);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
+
}
/**
@@ -323,15 +363,20 @@ public class EthernetManager {
@SystemApi(client = MODULE_LIBRARIES)
public void removeInterfaceStateListener(@NonNull InterfaceStateListener listener) {
Objects.requireNonNull(listener);
- synchronized (mListeners) {
- mListeners.removeIf(l -> l.listener == listener);
- if (mListeners.isEmpty()) {
- try {
- mService.removeListener(mServiceListener);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
+ synchronized (mListenerLock) {
+ mIfaceListeners.removeIf(l -> l.listener == listener);
+ maybeRemoveServiceListener();
+ }
+ }
+
+ @GuardedBy("mListenerLock")
+ private void maybeRemoveServiceListener() {
+ if (!mIfaceListeners.isEmpty() || !mEthernetStateListeners.isEmpty()) return;
+
+ try {
+ mService.removeListener(mServiceListener);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -443,41 +488,45 @@ public class EthernetManager {
return new TetheredInterfaceRequest(mService, cbInternal);
}
- private static final class InternalNetworkManagementListener
- extends IEthernetNetworkManagementListener.Stub {
+ private static final class NetworkInterfaceOutcomeReceiver
+ extends INetworkInterfaceOutcomeReceiver.Stub {
@NonNull
private final Executor mExecutor;
@NonNull
- private final BiConsumer<Network, EthernetNetworkManagementException> mListener;
+ private final OutcomeReceiver<String, EthernetNetworkManagementException> mCallback;
- InternalNetworkManagementListener(
+ NetworkInterfaceOutcomeReceiver(
@NonNull final Executor executor,
- @NonNull final BiConsumer<Network, EthernetNetworkManagementException> listener) {
+ @NonNull final OutcomeReceiver<String, EthernetNetworkManagementException>
+ callback) {
Objects.requireNonNull(executor, "Pass a non-null executor");
- Objects.requireNonNull(listener, "Pass a non-null listener");
+ Objects.requireNonNull(callback, "Pass a non-null callback");
mExecutor = executor;
- mListener = listener;
+ mCallback = callback;
+ }
+
+ @Override
+ public void onResult(@NonNull String iface) {
+ mExecutor.execute(() -> mCallback.onResult(iface));
}
@Override
- public void onComplete(
- @Nullable final Network network,
- @Nullable final EthernetNetworkManagementException e) {
- mExecutor.execute(() -> mListener.accept(network, e));
+ public void onError(@NonNull EthernetNetworkManagementException e) {
+ mExecutor.execute(() -> mCallback.onError(e));
}
}
- private InternalNetworkManagementListener getInternalNetworkManagementListener(
+ private NetworkInterfaceOutcomeReceiver makeNetworkInterfaceOutcomeReceiver(
@Nullable final Executor executor,
- @Nullable final BiConsumer<Network, EthernetNetworkManagementException> listener) {
- if (null != listener) {
- Objects.requireNonNull(executor, "Pass a non-null executor, or a null listener");
+ @Nullable final OutcomeReceiver<String, EthernetNetworkManagementException> callback) {
+ if (null != callback) {
+ Objects.requireNonNull(executor, "Pass a non-null executor, or a null callback");
}
- final InternalNetworkManagementListener proxy;
- if (null == listener) {
+ final NetworkInterfaceOutcomeReceiver proxy;
+ if (null == callback) {
proxy = null;
} else {
- proxy = new InternalNetworkManagementListener(executor, listener);
+ proxy = new NetworkInterfaceOutcomeReceiver(executor, callback);
}
return proxy;
}
@@ -492,14 +541,17 @@ public class EthernetManager {
* Similarly, use {@link NetworkCapabilities.Builder} to build a {@code NetworkCapabilities}
* object for this network to put inside the {@code request}.
*
- * If non-null, the listener will be called exactly once after this is called, unless
- * a synchronous exception was thrown.
+ * This function accepts an {@link OutcomeReceiver} that is called once the operation has
+ * finished execution.
*
* @param iface the name of the interface to act upon.
* @param request the {@link EthernetNetworkUpdateRequest} used to set an ethernet network's
* {@link StaticIpConfiguration} and {@link NetworkCapabilities} values.
- * @param executor an {@link Executor} to execute the listener on. Optional if listener is null.
- * @param listener an optional {@link BiConsumer} to listen for completion of the operation.
+ * @param executor an {@link Executor} to execute the callback on. Optional if callback is null.
+ * @param callback an optional {@link OutcomeReceiver} to listen for completion of the
+ * operation. On success, {@link OutcomeReceiver#onResult} is called with the
+ * interface name. On error, {@link OutcomeReceiver#onError} is called with more
+ * information about the error.
* @throws SecurityException if the process doesn't hold
* {@link android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}.
* @throws UnsupportedOperationException if called on a non-automotive device or on an
@@ -511,16 +563,15 @@ public class EthernetManager {
NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
android.Manifest.permission.NETWORK_STACK,
android.Manifest.permission.MANAGE_ETHERNET_NETWORKS})
- @RequiresFeature(PackageManager.FEATURE_AUTOMOTIVE)
public void updateConfiguration(
@NonNull String iface,
@NonNull EthernetNetworkUpdateRequest request,
@Nullable @CallbackExecutor Executor executor,
- @Nullable BiConsumer<Network, EthernetNetworkManagementException> listener) {
+ @Nullable OutcomeReceiver<String, EthernetNetworkManagementException> callback) {
Objects.requireNonNull(iface, "iface must be non-null");
Objects.requireNonNull(request, "request must be non-null");
- final InternalNetworkManagementListener proxy = getInternalNetworkManagementListener(
- executor, listener);
+ final NetworkInterfaceOutcomeReceiver proxy = makeNetworkInterfaceOutcomeReceiver(
+ executor, callback);
try {
mService.updateConfiguration(iface, request, proxy);
} catch (RemoteException e) {
@@ -529,20 +580,20 @@ public class EthernetManager {
}
/**
- * Set an ethernet network's link state up.
+ * Enable a network interface.
*
- * When the link is successfully turned up, the listener will be called with the resulting
- * network. If any error or unexpected condition happens while the system tries to turn the
- * interface up, the listener will be called with an appropriate exception.
- * The listener is guaranteed to be called exactly once for each call to this method, but this
- * may take an unbounded amount of time depending on the actual network conditions.
+ * Enables a previously disabled network interface.
+ * This function accepts an {@link OutcomeReceiver} that is called once the operation has
+ * finished execution.
*
- * @param iface the name of the interface to act upon.
- * @param executor an {@link Executor} to execute the listener on. Optional if listener is null.
- * @param listener an optional {@link BiConsumer} to listen for completion of the operation.
+ * @param iface the name of the interface to enable.
+ * @param executor an {@link Executor} to execute the callback on. Optional if callback is null.
+ * @param callback an optional {@link OutcomeReceiver} to listen for completion of the
+ * operation. On success, {@link OutcomeReceiver#onResult} is called with the
+ * interface name. On error, {@link OutcomeReceiver#onError} is called with more
+ * information about the error.
* @throws SecurityException if the process doesn't hold
* {@link android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}.
- * @throws UnsupportedOperationException if called on a non-automotive device.
* @hide
*/
@SystemApi
@@ -551,13 +602,13 @@ public class EthernetManager {
android.Manifest.permission.NETWORK_STACK,
android.Manifest.permission.MANAGE_ETHERNET_NETWORKS})
@RequiresFeature(PackageManager.FEATURE_AUTOMOTIVE)
- public void connectNetwork(
+ public void enableInterface(
@NonNull String iface,
@Nullable @CallbackExecutor Executor executor,
- @Nullable BiConsumer<Network, EthernetNetworkManagementException> listener) {
+ @Nullable OutcomeReceiver<String, EthernetNetworkManagementException> callback) {
Objects.requireNonNull(iface, "iface must be non-null");
- final InternalNetworkManagementListener proxy = getInternalNetworkManagementListener(
- executor, listener);
+ final NetworkInterfaceOutcomeReceiver proxy = makeNetworkInterfaceOutcomeReceiver(
+ executor, callback);
try {
mService.connectNetwork(iface, proxy);
} catch (RemoteException e) {
@@ -566,19 +617,21 @@ public class EthernetManager {
}
/**
- * Set an ethernet network's link state down.
+ * Disable a network interface.
*
- * When the link is successfully turned down, the listener will be called with the network that
- * was torn down, if any. If any error or unexpected condition happens while the system tries to
- * turn the interface down, the listener will be called with an appropriate exception.
- * The listener is guaranteed to be called exactly once for each call to this method.
+ * Disables the use of a network interface to fulfill network requests. If the interface
+ * currently serves a request, the network will be torn down.
+ * This function accepts an {@link OutcomeReceiver} that is called once the operation has
+ * finished execution.
*
- * @param iface the name of the interface to act upon.
- * @param executor an {@link Executor} to execute the listener on. Optional if listener is null.
- * @param listener an optional {@link BiConsumer} to listen for completion of the operation.
+ * @param iface the name of the interface to disable.
+ * @param executor an {@link Executor} to execute the callback on. Optional if callback is null.
+ * @param callback an optional {@link OutcomeReceiver} to listen for completion of the
+ * operation. On success, {@link OutcomeReceiver#onResult} is called with the
+ * interface name. On error, {@link OutcomeReceiver#onError} is called with more
+ * information about the error.
* @throws SecurityException if the process doesn't hold
* {@link android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}.
- * @throws UnsupportedOperationException if called on a non-automotive device.
* @hide
*/
@SystemApi
@@ -587,17 +640,90 @@ public class EthernetManager {
android.Manifest.permission.NETWORK_STACK,
android.Manifest.permission.MANAGE_ETHERNET_NETWORKS})
@RequiresFeature(PackageManager.FEATURE_AUTOMOTIVE)
- public void disconnectNetwork(
+ public void disableInterface(
@NonNull String iface,
@Nullable @CallbackExecutor Executor executor,
- @Nullable BiConsumer<Network, EthernetNetworkManagementException> listener) {
+ @Nullable OutcomeReceiver<String, EthernetNetworkManagementException> callback) {
Objects.requireNonNull(iface, "iface must be non-null");
- final InternalNetworkManagementListener proxy = getInternalNetworkManagementListener(
- executor, listener);
+ final NetworkInterfaceOutcomeReceiver proxy = makeNetworkInterfaceOutcomeReceiver(
+ executor, callback);
try {
mService.disconnectNetwork(iface, proxy);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
+
+ /**
+ * Change ethernet setting.
+ *
+ * @param enabled enable or disable ethernet settings.
+ *
+ * @hide
+ */
+ @RequiresPermission(anyOf = {
+ NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
+ android.Manifest.permission.NETWORK_STACK,
+ android.Manifest.permission.NETWORK_SETTINGS})
+ @SystemApi(client = MODULE_LIBRARIES)
+ public void setEthernetEnabled(boolean enabled) {
+ try {
+ mService.setEthernetEnabled(enabled);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Listen to changes in the state of ethernet.
+ *
+ * @param executor to run callbacks on.
+ * @param listener to listen ethernet state changed.
+ *
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
+ @SystemApi(client = MODULE_LIBRARIES)
+ public void addEthernetStateListener(@NonNull Executor executor,
+ @NonNull IntConsumer listener) {
+ Objects.requireNonNull(executor);
+ Objects.requireNonNull(listener);
+ synchronized (mListenerLock) {
+ maybeAddServiceListener();
+ mEthernetStateListeners.add(new ListenerInfo<IntConsumer>(executor, listener));
+ }
+ }
+
+ /**
+ * Removes a listener.
+ *
+ * @param listener to listen ethernet state changed.
+ *
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
+ @SystemApi(client = MODULE_LIBRARIES)
+ public void removeEthernetStateListener(@NonNull IntConsumer listener) {
+ Objects.requireNonNull(listener);
+ synchronized (mListenerLock) {
+ mEthernetStateListeners.removeIf(l -> l.listener == listener);
+ maybeRemoveServiceListener();
+ }
+ }
+
+ /**
+ * Returns an array of existing Ethernet interface names regardless whether the interface
+ * is available or not currently.
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
+ @SystemApi(client = MODULE_LIBRARIES)
+ @NonNull
+ public List<String> getInterfaceList() {
+ try {
+ return mService.getInterfaceList();
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
}
diff --git a/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkUpdateRequest.java b/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkUpdateRequest.java
index a6269711055a..1691942c3675 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkUpdateRequest.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkUpdateRequest.java
@@ -24,36 +24,54 @@ import android.os.Parcelable;
import java.util.Objects;
-/** @hide */
+/**
+ * Represents a request to update an existing Ethernet interface.
+ *
+ * @see EthernetManager#updateConfiguration
+ *
+ * @hide
+ */
@SystemApi
public final class EthernetNetworkUpdateRequest implements Parcelable {
- @NonNull
+ @Nullable
private final IpConfiguration mIpConfig;
- @NonNull
+ @Nullable
private final NetworkCapabilities mNetworkCapabilities;
- @NonNull
+ /**
+ * Setting the {@link IpConfiguration} is optional in {@link EthernetNetworkUpdateRequest}.
+ * When set to null, the existing IpConfiguration is not updated.
+ *
+ * @return the new {@link IpConfiguration} or null.
+ */
+ @Nullable
public IpConfiguration getIpConfiguration() {
- return new IpConfiguration(mIpConfig);
+ return mIpConfig == null ? null : new IpConfiguration(mIpConfig);
}
- @NonNull
+ /**
+ * Setting the {@link NetworkCapabilities} is optional in {@link EthernetNetworkUpdateRequest}.
+ * When set to null, the existing NetworkCapabilities are not updated.
+ *
+ * @return the new {@link NetworkCapabilities} or null.
+ */
+ @Nullable
public NetworkCapabilities getNetworkCapabilities() {
- return new NetworkCapabilities(mNetworkCapabilities);
+ return mNetworkCapabilities == null ? null : new NetworkCapabilities(mNetworkCapabilities);
}
- private EthernetNetworkUpdateRequest(@NonNull final IpConfiguration ipConfig,
- @NonNull final NetworkCapabilities networkCapabilities) {
- Objects.requireNonNull(ipConfig);
- Objects.requireNonNull(networkCapabilities);
- mIpConfig = new IpConfiguration(ipConfig);
- mNetworkCapabilities = new NetworkCapabilities(networkCapabilities);
+ private EthernetNetworkUpdateRequest(@Nullable final IpConfiguration ipConfig,
+ @Nullable final NetworkCapabilities networkCapabilities) {
+ mIpConfig = ipConfig;
+ mNetworkCapabilities = networkCapabilities;
}
private EthernetNetworkUpdateRequest(@NonNull final Parcel source) {
Objects.requireNonNull(source);
- mIpConfig = IpConfiguration.CREATOR.createFromParcel(source);
- mNetworkCapabilities = NetworkCapabilities.CREATOR.createFromParcel(source);
+ mIpConfig = source.readParcelable(IpConfiguration.class.getClassLoader(),
+ IpConfiguration.class);
+ mNetworkCapabilities = source.readParcelable(NetworkCapabilities.class.getClassLoader(),
+ NetworkCapabilities.class);
}
/**
@@ -74,8 +92,10 @@ public final class EthernetNetworkUpdateRequest implements Parcelable {
*/
public Builder(@NonNull final EthernetNetworkUpdateRequest request) {
Objects.requireNonNull(request);
- mBuilderIpConfig = new IpConfiguration(request.mIpConfig);
- mBuilderNetworkCapabilities = new NetworkCapabilities(request.mNetworkCapabilities);
+ mBuilderIpConfig = null == request.mIpConfig
+ ? null : new IpConfiguration(request.mIpConfig);
+ mBuilderNetworkCapabilities = null == request.mNetworkCapabilities
+ ? null : new NetworkCapabilities(request.mNetworkCapabilities);
}
/**
@@ -84,9 +104,8 @@ public final class EthernetNetworkUpdateRequest implements Parcelable {
* @return The builder to facilitate chaining.
*/
@NonNull
- public Builder setIpConfiguration(@NonNull final IpConfiguration ipConfig) {
- Objects.requireNonNull(ipConfig);
- mBuilderIpConfig = new IpConfiguration(ipConfig);
+ public Builder setIpConfiguration(@Nullable final IpConfiguration ipConfig) {
+ mBuilderIpConfig = ipConfig == null ? null : new IpConfiguration(ipConfig);
return this;
}
@@ -96,17 +115,23 @@ public final class EthernetNetworkUpdateRequest implements Parcelable {
* @return The builder to facilitate chaining.
*/
@NonNull
- public Builder setNetworkCapabilities(@NonNull final NetworkCapabilities nc) {
- Objects.requireNonNull(nc);
- mBuilderNetworkCapabilities = new NetworkCapabilities(nc);
+ public Builder setNetworkCapabilities(@Nullable final NetworkCapabilities nc) {
+ mBuilderNetworkCapabilities = nc == null ? null : new NetworkCapabilities(nc);
return this;
}
/**
* Build {@link EthernetNetworkUpdateRequest} return the current update request.
+ *
+ * @throws IllegalStateException when both mBuilderNetworkCapabilities and mBuilderIpConfig
+ * are null.
*/
@NonNull
public EthernetNetworkUpdateRequest build() {
+ if (mBuilderIpConfig == null && mBuilderNetworkCapabilities == null) {
+ throw new IllegalStateException(
+ "Cannot construct an empty EthernetNetworkUpdateRequest");
+ }
return new EthernetNetworkUpdateRequest(mBuilderIpConfig, mBuilderNetworkCapabilities);
}
}
@@ -135,8 +160,8 @@ public final class EthernetNetworkUpdateRequest implements Parcelable {
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
- mIpConfig.writeToParcel(dest, flags);
- mNetworkCapabilities.writeToParcel(dest, flags);
+ dest.writeParcelable(mIpConfig, flags);
+ dest.writeParcelable(mNetworkCapabilities, flags);
}
@Override
diff --git a/packages/ConnectivityT/framework-t/src/android/net/IEthernetManager.aidl b/packages/ConnectivityT/framework-t/src/android/net/IEthernetManager.aidl
index 544d02ba76ff..42e4c1ac55aa 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/IEthernetManager.aidl
+++ b/packages/ConnectivityT/framework-t/src/android/net/IEthernetManager.aidl
@@ -18,10 +18,13 @@ package android.net;
import android.net.IpConfiguration;
import android.net.IEthernetServiceListener;
-import android.net.IEthernetNetworkManagementListener;
+import android.net.EthernetNetworkManagementException;
import android.net.EthernetNetworkUpdateRequest;
+import android.net.INetworkInterfaceOutcomeReceiver;
import android.net.ITetheredInterfaceCallback;
+import java.util.List;
+
/**
* Interface that answers queries about, and allows changing
* ethernet configuration.
@@ -39,7 +42,9 @@ interface IEthernetManager
void requestTetheredInterface(in ITetheredInterfaceCallback callback);
void releaseTetheredInterface(in ITetheredInterfaceCallback callback);
void updateConfiguration(String iface, in EthernetNetworkUpdateRequest request,
- in IEthernetNetworkManagementListener listener);
- void connectNetwork(String iface, in IEthernetNetworkManagementListener listener);
- void disconnectNetwork(String iface, in IEthernetNetworkManagementListener listener);
+ in INetworkInterfaceOutcomeReceiver listener);
+ void connectNetwork(String iface, in INetworkInterfaceOutcomeReceiver listener);
+ void disconnectNetwork(String iface, in INetworkInterfaceOutcomeReceiver listener);
+ void setEthernetEnabled(boolean enabled);
+ List<String> getInterfaceList();
}
diff --git a/packages/ConnectivityT/framework-t/src/android/net/IEthernetServiceListener.aidl b/packages/ConnectivityT/framework-t/src/android/net/IEthernetServiceListener.aidl
index 6d2ba03f78d4..751605bb3849 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/IEthernetServiceListener.aidl
+++ b/packages/ConnectivityT/framework-t/src/android/net/IEthernetServiceListener.aidl
@@ -21,6 +21,7 @@ import android.net.IpConfiguration;
/** @hide */
oneway interface IEthernetServiceListener
{
+ void onEthernetStateChanged(int state);
void onInterfaceStateChanged(String iface, int state, int role,
in IpConfiguration configuration);
}
diff --git a/packages/ConnectivityT/framework-t/src/android/net/IEthernetNetworkManagementListener.aidl b/packages/ConnectivityT/framework-t/src/android/net/INetworkInterfaceOutcomeReceiver.aidl
index 93edccfdafd9..85795ead7aea 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/IEthernetNetworkManagementListener.aidl
+++ b/packages/ConnectivityT/framework-t/src/android/net/INetworkInterfaceOutcomeReceiver.aidl
@@ -17,9 +17,9 @@
package android.net;
import android.net.EthernetNetworkManagementException;
-import android.net.Network;
/** @hide */
-oneway interface IEthernetNetworkManagementListener {
- void onComplete(in Network network, in EthernetNetworkManagementException exception);
+oneway interface INetworkInterfaceOutcomeReceiver {
+ void onResult(in String iface);
+ void onError(in EthernetNetworkManagementException e);
} \ No newline at end of file
diff --git a/packages/ConnectivityT/framework-t/src/android/net/INetworkStatsService.aidl b/packages/ConnectivityT/framework-t/src/android/net/INetworkStatsService.aidl
index efe626d3c939..c86f7fd0890d 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/INetworkStatsService.aidl
+++ b/packages/ConnectivityT/framework-t/src/android/net/INetworkStatsService.aidl
@@ -91,7 +91,7 @@ interface INetworkStatsService {
in INetworkStatsProvider provider);
/** Mark given UID as being in foreground for stats purposes. */
- void setUidForeground(int uid, boolean uidForeground);
+ void noteUidForeground(int uid, boolean uidForeground);
/** Advise persistence threshold; may be overridden internally. */
void advisePersistThreshold(long thresholdBytes);
diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkIdentity.java b/packages/ConnectivityT/framework-t/src/android/net/NetworkIdentity.java
index a48f94b66def..da5f88dc3b7e 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/NetworkIdentity.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/NetworkIdentity.java
@@ -189,14 +189,14 @@ public class NetworkIdentity {
public void dumpDebug(ProtoOutputStream proto, long tag) {
final long start = proto.start(tag);
- proto.write(NetworkIdentityProto.TYPE_FIELD_NUMBER, mType);
+ proto.write(NetworkIdentityProto.TYPE, mType);
// TODO: dump mRatType as well.
- proto.write(NetworkIdentityProto.ROAMING_FIELD_NUMBER, mRoaming);
- proto.write(NetworkIdentityProto.METERED_FIELD_NUMBER, mMetered);
- proto.write(NetworkIdentityProto.DEFAULT_NETWORK_FIELD_NUMBER, mDefaultNetwork);
- proto.write(NetworkIdentityProto.OEM_MANAGED_NETWORK_FIELD_NUMBER, mOemManaged);
+ proto.write(NetworkIdentityProto.ROAMING, mRoaming);
+ proto.write(NetworkIdentityProto.METERED, mMetered);
+ proto.write(NetworkIdentityProto.DEFAULT_NETWORK, mDefaultNetwork);
+ proto.write(NetworkIdentityProto.OEM_MANAGED_NETWORK, mOemManaged);
proto.end(start);
}
diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkIdentitySet.java b/packages/ConnectivityT/framework-t/src/android/net/NetworkIdentitySet.java
index 56461babfe49..ad3a958a680e 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/NetworkIdentitySet.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/NetworkIdentitySet.java
@@ -222,7 +222,7 @@ public class NetworkIdentitySet extends HashSet<NetworkIdentity> {
final long start = proto.start(tag);
for (NetworkIdentity ident : this) {
- ident.dumpDebug(proto, NetworkIdentitySetProto.IDENTITIES_FIELD_NUMBER);
+ ident.dumpDebug(proto, NetworkIdentitySetProto.IDENTITIES);
}
proto.end(start);
diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkStats.java b/packages/ConnectivityT/framework-t/src/android/net/NetworkStats.java
index f681ba1c3853..bcfeab96081a 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/NetworkStats.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/NetworkStats.java
@@ -16,6 +16,8 @@
package android.net;
+import static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
+
import static com.android.net.module.util.NetworkStatsUtils.multiplySafeByRational;
import android.annotation.IntDef;
@@ -124,7 +126,6 @@ public final class NetworkStats implements Parcelable, Iterable<NetworkStats.Ent
public @Nullable static final String[] INTERFACES_ALL = null;
/** {@link #tag} value for total data across all tags. */
- // TODO: Rename TAG_NONE to TAG_ALL.
public static final int TAG_NONE = 0;
/** {@link #metered} value to account for all metered states. */
@@ -327,16 +328,11 @@ public final class NetworkStats implements Parcelable, Iterable<NetworkStats.Ent
* @param uid uid of this {@link Entry}. {@link #UID_TETHERING} if this {@link Entry} is
* for tethering. Or {@link #UID_ALL} if this {@link NetworkStats} is only
* counting iface stats.
- * @param set usage state of this {@link Entry}. Should be one of the following
- * values: {@link #SET_DEFAULT}, {@link #SET_FOREGROUND}.
+ * @param set usage state of this {@link Entry}.
* @param tag tag of this {@link Entry}.
- * @param metered metered state of this {@link Entry}. Should be one of the following
- * values: {link #METERED_YES}, {link #METERED_NO}.
- * @param roaming roaming state of this {@link Entry}. Should be one of the following
- * values: {link #ROAMING_YES}, {link #ROAMING_NO}.
- * @param defaultNetwork default network status of this {@link Entry}. Should be one
- * of the following values: {link #DEFAULT_NETWORK_YES},
- * {link #DEFAULT_NETWORK_NO}.
+ * @param metered metered state of this {@link Entry}.
+ * @param roaming roaming state of this {@link Entry}.
+ * @param defaultNetwork default network status of this {@link Entry}.
* @param rxBytes Number of bytes received for this {@link Entry}. Statistics should
* represent the contents of IP packets, including IP headers.
* @param rxPackets Number of packets received for this {@link Entry}. Statistics should
@@ -395,81 +391,102 @@ public final class NetworkStats implements Parcelable, Iterable<NetworkStats.Ent
/**
* @return the uid of this entry.
+ * @hide
*/
+ @SystemApi(client = MODULE_LIBRARIES)
public int getUid() {
return uid;
}
/**
- * @return the set state of this entry. Should be one of the following
- * values: {@link #SET_DEFAULT}, {@link #SET_FOREGROUND}.
+ * @return the set state of this entry.
+ * @hide
*/
+ @SystemApi(client = MODULE_LIBRARIES)
@State public int getSet() {
return set;
}
/**
* @return the tag value of this entry.
+ * @hide
*/
+ @SystemApi(client = MODULE_LIBRARIES)
public int getTag() {
return tag;
}
/**
- * @return the metered state. Should be one of the following
- * values: {link #METERED_YES}, {link #METERED_NO}.
+ * @return the metered state.
+ * @hide
*/
- @Meteredness public int getMetered() {
+ @Meteredness
+ @SystemApi(client = MODULE_LIBRARIES)
+ public int getMetered() {
return metered;
}
/**
- * @return the roaming state. Should be one of the following
- * values: {link #ROAMING_YES}, {link #ROAMING_NO}.
+ * @return the roaming state.
+ * @hide
*/
- @Roaming public int getRoaming() {
+ @Roaming
+ @SystemApi(client = MODULE_LIBRARIES)
+ public int getRoaming() {
return roaming;
}
/**
- * @return the default network state. Should be one of the following
- * values: {link #DEFAULT_NETWORK_YES}, {link #DEFAULT_NETWORK_NO}.
+ * @return the default network state.
+ * @hide
*/
- @DefaultNetwork public int getDefaultNetwork() {
+ @DefaultNetwork
+ @SystemApi(client = MODULE_LIBRARIES)
+ public int getDefaultNetwork() {
return defaultNetwork;
}
/**
* @return the number of received bytes.
+ * @hide
*/
+ @SystemApi(client = MODULE_LIBRARIES)
public long getRxBytes() {
return rxBytes;
}
/**
* @return the number of received packets.
+ * @hide
*/
+ @SystemApi(client = MODULE_LIBRARIES)
public long getRxPackets() {
return rxPackets;
}
/**
* @return the number of transmitted bytes.
+ * @hide
*/
+ @SystemApi(client = MODULE_LIBRARIES)
public long getTxBytes() {
return txBytes;
}
/**
* @return the number of transmitted packets.
+ * @hide
*/
+ @SystemApi(client = MODULE_LIBRARIES)
public long getTxPackets() {
return txPackets;
}
/**
* @return the count of network operations performed for this entry.
+ * @hide
*/
+ @SystemApi(client = MODULE_LIBRARIES)
public long getOperations() {
return operations;
}
@@ -691,7 +708,7 @@ public final class NetworkStats implements Parcelable, Iterable<NetworkStats.Ent
* The remove() method is not implemented and will throw UnsupportedOperationException.
* @hide
*/
- @SystemApi
+ @SystemApi(client = MODULE_LIBRARIES)
@NonNull public Iterator<Entry> iterator() {
return new Iterator<Entry>() {
int mIndex = 0;
diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsCollection.java b/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsCollection.java
index 67d48f0000d5..e385b33447f0 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsCollection.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsCollection.java
@@ -36,6 +36,7 @@ import static com.android.net.module.util.NetworkStatsUtils.multiplySafeByRation
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
+import android.net.NetworkStats.State;
import android.net.NetworkStatsHistory.Entry;
import android.os.Binder;
import android.service.NetworkStatsCollectionKeyProto;
@@ -102,7 +103,7 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W
private ArrayMap<Key, NetworkStatsHistory> mStats = new ArrayMap<>();
- private final long mBucketDuration;
+ private final long mBucketDurationMillis;
private long mStartMillis;
private long mEndMillis;
@@ -115,8 +116,8 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W
* @param bucketDuration duration of the buckets in this object, in milliseconds.
* @hide
*/
- public NetworkStatsCollection(long bucketDuration) {
- mBucketDuration = bucketDuration;
+ public NetworkStatsCollection(long bucketDurationMillis) {
+ mBucketDurationMillis = bucketDurationMillis;
reset();
}
@@ -148,7 +149,7 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W
if (mStartMillis == Long.MAX_VALUE) {
return Long.MAX_VALUE;
} else {
- return mStartMillis + mBucketDuration;
+ return mStartMillis + mBucketDurationMillis;
}
}
@@ -184,10 +185,10 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W
|| time == SubscriptionPlan.TIME_UNKNOWN) {
return time;
} else {
- final long mod = time % mBucketDuration;
+ final long mod = time % mBucketDurationMillis;
if (mod > 0) {
time -= mod;
- time += mBucketDuration;
+ time += mBucketDurationMillis;
}
return time;
}
@@ -200,7 +201,7 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W
|| time == SubscriptionPlan.TIME_UNKNOWN) {
return time;
} else {
- final long mod = time % mBucketDuration;
+ final long mod = time % mBucketDurationMillis;
if (mod > 0) {
time -= mod;
}
@@ -247,10 +248,10 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W
// 180 days of history should be enough for anyone; if we end up needing
// more, we'll dynamically grow the history object.
final int bucketEstimate = (int) NetworkStatsUtils.constrain(
- ((end - start) / mBucketDuration), 0,
- (180 * DateUtils.DAY_IN_MILLIS) / mBucketDuration);
+ ((end - start) / mBucketDurationMillis), 0,
+ (180 * DateUtils.DAY_IN_MILLIS) / mBucketDurationMillis);
final NetworkStatsHistory combined = new NetworkStatsHistory(
- mBucketDuration, bucketEstimate, fields);
+ mBucketDurationMillis, bucketEstimate, fields);
// shortcut when we know stats will be empty
if (start == end) return combined;
@@ -343,7 +344,7 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W
// Finally we can slice data as originally requested
final NetworkStatsHistory sliced = new NetworkStatsHistory(
- mBucketDuration, bucketEstimate, fields);
+ mBucketDurationMillis, bucketEstimate, fields);
sliced.recordHistory(combined, start, end);
return sliced;
} else {
@@ -458,9 +459,9 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W
// update when no existing, or when bucket duration changed
NetworkStatsHistory updated = null;
if (existing == null) {
- updated = new NetworkStatsHistory(mBucketDuration, 10);
- } else if (existing.getBucketDuration() != mBucketDuration) {
- updated = new NetworkStatsHistory(existing, mBucketDuration);
+ updated = new NetworkStatsHistory(mBucketDurationMillis, 10);
+ } else if (existing.getBucketDuration() != mBucketDurationMillis) {
+ updated = new NetworkStatsHistory(existing, mBucketDurationMillis);
}
if (updated != null) {
@@ -702,7 +703,7 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W
private int estimateBuckets() {
return (int) (Math.min(mEndMillis - mStartMillis, WEEK_IN_MILLIS * 5)
- / mBucketDuration);
+ / mBucketDurationMillis);
}
private ArrayList<Key> getSortedKeys() {
@@ -732,19 +733,19 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W
final long start = proto.start(tag);
for (Key key : getSortedKeys()) {
- final long startStats = proto.start(NetworkStatsCollectionProto.STATS_FIELD_NUMBER);
+ final long startStats = proto.start(NetworkStatsCollectionProto.STATS);
// Key
- final long startKey = proto.start(NetworkStatsCollectionStatsProto.KEY_FIELD_NUMBER);
- key.ident.dumpDebug(proto, NetworkStatsCollectionKeyProto.IDENTITY_FIELD_NUMBER);
- proto.write(NetworkStatsCollectionKeyProto.UID_FIELD_NUMBER, key.uid);
- proto.write(NetworkStatsCollectionKeyProto.SET_FIELD_NUMBER, key.set);
- proto.write(NetworkStatsCollectionKeyProto.TAG_FIELD_NUMBER, key.tag);
+ final long startKey = proto.start(NetworkStatsCollectionStatsProto.KEY);
+ key.ident.dumpDebug(proto, NetworkStatsCollectionKeyProto.IDENTITY);
+ proto.write(NetworkStatsCollectionKeyProto.UID, key.uid);
+ proto.write(NetworkStatsCollectionKeyProto.SET, key.set);
+ proto.write(NetworkStatsCollectionKeyProto.TAG, key.tag);
proto.end(startKey);
// Value
final NetworkStatsHistory history = mStats.get(key);
- history.dumpDebug(proto, NetworkStatsCollectionStatsProto.HISTORY_FIELD_NUMBER);
+ history.dumpDebug(proto, NetworkStatsCollectionStatsProto.HISTORY);
proto.end(startStats);
}
@@ -828,7 +829,7 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W
* Builder class for {@link NetworkStatsCollection}.
*/
public static final class Builder {
- private final long mBucketDuration;
+ private final long mBucketDurationMillis;
private final ArrayMap<Key, NetworkStatsHistory> mEntries = new ArrayMap<>();
/**
@@ -836,8 +837,8 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W
*
* @param bucketDuration Duration of the buckets of the object, in milliseconds.
*/
- public Builder(long bucketDuration) {
- mBucketDuration = bucketDuration;
+ public Builder(long bucketDurationMillis) {
+ mBucketDurationMillis = bucketDurationMillis;
}
/**
@@ -855,7 +856,7 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W
final List<Entry> historyEntries = history.getEntries();
final NetworkStatsHistory.Builder historyBuilder =
- new NetworkStatsHistory.Builder(mBucketDuration, historyEntries.size());
+ new NetworkStatsHistory.Builder(mBucketDurationMillis, historyEntries.size());
for (Entry entry : historyEntries) {
historyBuilder.addEntry(entry);
}
@@ -871,7 +872,8 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W
*/
@NonNull
public NetworkStatsCollection build() {
- final NetworkStatsCollection collection = new NetworkStatsCollection(mBucketDuration);
+ final NetworkStatsCollection collection =
+ new NetworkStatsCollection(mBucketDurationMillis);
for (int i = 0; i < mEntries.size(); i++) {
collection.recordHistory(mEntries.keyAt(i), mEntries.valueAt(i));
}
@@ -883,7 +885,7 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W
* the identifier that associate with the {@link NetworkStatsHistory} object to identify
* a certain record in the {@link NetworkStatsCollection} object.
*/
- public static class Key {
+ public static final class Key {
/** @hide */
public final NetworkIdentitySet ident;
/** @hide */
@@ -903,7 +905,7 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W
* @param set Set of the record, see {@code NetworkStats#SET_*}.
* @param tag Tag of the record, see {@link TrafficStats#setThreadStatsTag(int)}.
*/
- public Key(@NonNull Set<NetworkIdentity> ident, int uid, int set, int tag) {
+ public Key(@NonNull Set<NetworkIdentity> ident, int uid, @State int set, int tag) {
this(new NetworkIdentitySet(Objects.requireNonNull(ident)), uid, set, tag);
}
diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsHistory.java b/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsHistory.java
index 822a16e0bb41..301fef944169 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsHistory.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsHistory.java
@@ -915,18 +915,18 @@ public final class NetworkStatsHistory implements Parcelable {
public void dumpDebug(ProtoOutputStream proto, long tag) {
final long start = proto.start(tag);
- proto.write(NetworkStatsHistoryProto.BUCKET_DURATION_MS_FIELD_NUMBER, bucketDuration);
+ proto.write(NetworkStatsHistoryProto.BUCKET_DURATION_MS, bucketDuration);
for (int i = 0; i < bucketCount; i++) {
- final long startBucket = proto.start(NetworkStatsHistoryProto.BUCKETS_FIELD_NUMBER);
+ final long startBucket = proto.start(NetworkStatsHistoryProto.BUCKETS);
- proto.write(NetworkStatsHistoryBucketProto.BUCKET_START_MS_FIELD_NUMBER,
+ proto.write(NetworkStatsHistoryBucketProto.BUCKET_START_MS,
bucketStart[i]);
- dumpDebug(proto, NetworkStatsHistoryBucketProto.RX_BYTES_FIELD_NUMBER, rxBytes, i);
- dumpDebug(proto, NetworkStatsHistoryBucketProto.RX_PACKETS_FIELD_NUMBER, rxPackets, i);
- dumpDebug(proto, NetworkStatsHistoryBucketProto.TX_BYTES_FIELD_NUMBER, txBytes, i);
- dumpDebug(proto, NetworkStatsHistoryBucketProto.TX_PACKETS_FIELD_NUMBER, txPackets, i);
- dumpDebug(proto, NetworkStatsHistoryBucketProto.OPERATIONS_FIELD_NUMBER, operations, i);
+ dumpDebug(proto, NetworkStatsHistoryBucketProto.RX_BYTES, rxBytes, i);
+ dumpDebug(proto, NetworkStatsHistoryBucketProto.RX_PACKETS, rxPackets, i);
+ dumpDebug(proto, NetworkStatsHistoryBucketProto.TX_BYTES, txBytes, i);
+ dumpDebug(proto, NetworkStatsHistoryBucketProto.TX_PACKETS, txPackets, i);
+ dumpDebug(proto, NetworkStatsHistoryBucketProto.OPERATIONS, operations, i);
proto.end(startBucket);
}
diff --git a/packages/ConnectivityT/framework-t/src/android/net/TrafficStats.java b/packages/ConnectivityT/framework-t/src/android/net/TrafficStats.java
index bc836d857e3e..dc4ac552a4bb 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/TrafficStats.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/TrafficStats.java
@@ -205,7 +205,7 @@ public class TrafficStats {
* server context.
* @hide
*/
- @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ @SystemApi(client = MODULE_LIBRARIES)
@SuppressLint("VisiblySynchronized")
public static synchronized void init(@NonNull final Context context) {
if (sStatsService != null) {
@@ -376,7 +376,7 @@ public class TrafficStats {
*
* @hide
*/
- @SystemApi
+ @SystemApi(client = MODULE_LIBRARIES)
public static void setThreadStatsTagDownload() {
setThreadStatsTag(TAG_SYSTEM_DOWNLOAD);
}
@@ -468,7 +468,7 @@ public class TrafficStats {
*
* @see #setThreadStatsTag(int)
*/
- public static void tagSocket(Socket socket) throws SocketException {
+ public static void tagSocket(@NonNull Socket socket) throws SocketException {
SocketTagger.get().tag(socket);
}
@@ -483,7 +483,7 @@ public class TrafficStats {
* calling {@code untagSocket()} before sending the socket to another
* process.
*/
- public static void untagSocket(Socket socket) throws SocketException {
+ public static void untagSocket(@NonNull Socket socket) throws SocketException {
SocketTagger.get().untag(socket);
}
@@ -496,14 +496,14 @@ public class TrafficStats {
*
* @see #setThreadStatsTag(int)
*/
- public static void tagDatagramSocket(DatagramSocket socket) throws SocketException {
+ public static void tagDatagramSocket(@NonNull DatagramSocket socket) throws SocketException {
SocketTagger.get().tag(socket);
}
/**
* Remove any statistics parameters from the given {@link DatagramSocket}.
*/
- public static void untagDatagramSocket(DatagramSocket socket) throws SocketException {
+ public static void untagDatagramSocket(@NonNull DatagramSocket socket) throws SocketException {
SocketTagger.get().untag(socket);
}
@@ -516,7 +516,7 @@ public class TrafficStats {
*
* @see #setThreadStatsTag(int)
*/
- public static void tagFileDescriptor(FileDescriptor fd) throws IOException {
+ public static void tagFileDescriptor(@NonNull FileDescriptor fd) throws IOException {
SocketTagger.get().tag(fd);
}
@@ -524,7 +524,7 @@ public class TrafficStats {
* Remove any statistics parameters from the given {@link FileDescriptor}
* socket.
*/
- public static void untagFileDescriptor(FileDescriptor fd) throws IOException {
+ public static void untagFileDescriptor(@NonNull FileDescriptor fd) throws IOException {
SocketTagger.get().untag(fd);
}
diff --git a/packages/ConnectivityT/framework-t/src/android/net/netstats/provider/INetworkStatsProviderCallback.aidl b/packages/ConnectivityT/framework-t/src/android/net/netstats/provider/INetworkStatsProviderCallback.aidl
index 7eaa01e262fe..01ff02dfc5b3 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/netstats/provider/INetworkStatsProviderCallback.aidl
+++ b/packages/ConnectivityT/framework-t/src/android/net/netstats/provider/INetworkStatsProviderCallback.aidl
@@ -26,6 +26,7 @@ import android.net.NetworkStats;
oneway interface INetworkStatsProviderCallback {
void notifyStatsUpdated(int token, in NetworkStats ifaceStats, in NetworkStats uidStats);
void notifyAlertReached();
- void notifyWarningOrLimitReached();
+ void notifyWarningReached();
+ void notifyLimitReached();
void unregister();
}
diff --git a/packages/ConnectivityT/framework-t/src/android/net/netstats/provider/NetworkStatsProvider.java b/packages/ConnectivityT/framework-t/src/android/net/netstats/provider/NetworkStatsProvider.java
index 23fc06927ef9..d37a53dbf1e9 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/netstats/provider/NetworkStatsProvider.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/netstats/provider/NetworkStatsProvider.java
@@ -152,19 +152,19 @@ public abstract class NetworkStatsProvider {
try {
// Reuse the code path to notify warning reached with limit reached
// since framework handles them in the same way.
- getProviderCallbackBinderOrThrow().notifyWarningOrLimitReached();
+ getProviderCallbackBinderOrThrow().notifyWarningReached();
} catch (RemoteException e) {
e.rethrowAsRuntimeException();
}
}
/**
- * Notify system that the quota set by {@link #onSetLimit} or limit set by
+ * Notify system that the limit set by {@link #onSetLimit} or limit set by
* {@link #onSetWarningAndLimit} has been reached.
*/
public void notifyLimitReached() {
try {
- getProviderCallbackBinderOrThrow().notifyWarningOrLimitReached();
+ getProviderCallbackBinderOrThrow().notifyLimitReached();
} catch (RemoteException e) {
e.rethrowAsRuntimeException();
}
diff --git a/packages/ConnectivityT/service/Android.bp b/packages/ConnectivityT/service/Android.bp
index 5100e7c5b9a4..4b799c599be9 100644
--- a/packages/ConnectivityT/service/Android.bp
+++ b/packages/ConnectivityT/service/Android.bp
@@ -102,17 +102,16 @@ filegroup {
],
path: "src",
visibility: [
- "//frameworks/opt/net/ethernet",
+ "//frameworks/opt/net/ethernet/tests",
],
}
// Connectivity-T common libraries.
+// TODO: remove this empty filegroup.
filegroup {
name: "services.connectivity-tiramisu-sources",
- srcs: [
- ":services.connectivity-ethernet-sources",
- ],
+ srcs: [],
path: "src",
visibility: ["//frameworks/base/services/core"],
}
@@ -120,6 +119,7 @@ filegroup {
filegroup {
name: "services.connectivity-tiramisu-updatable-sources",
srcs: [
+ ":services.connectivity-ethernet-sources",
":services.connectivity-ipsec-sources",
":services.connectivity-netstats-sources",
":services.connectivity-nsd-sources",
diff --git a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsFactory.java b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsFactory.java
index 151c90dd4155..3b93f1a1905f 100644
--- a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsFactory.java
+++ b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsFactory.java
@@ -25,9 +25,9 @@ import static android.net.NetworkStats.UID_ALL;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
-import android.net.ConnectivityManager;
import android.net.NetworkStats;
import android.net.UnderlyingNetworkInfo;
+import android.os.ServiceSpecificException;
import android.os.StrictMode;
import android.os.SystemClock;
@@ -35,6 +35,7 @@ import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ProcFileReader;
import com.android.net.module.util.CollectionUtils;
+import com.android.server.BpfNetMaps;
import libcore.io.IoUtils;
@@ -74,6 +75,8 @@ public class NetworkStatsFactory {
private final Context mContext;
+ private final BpfNetMaps mBpfNetMaps;
+
/**
* Guards persistent data access in this class
*
@@ -170,6 +173,7 @@ public class NetworkStatsFactory {
mStatsXtIfaceFmt = new File(procRoot, "net/xt_qtaguid/iface_stat_fmt");
mStatsXtUid = new File(procRoot, "net/xt_qtaguid/stats");
mUseBpfStats = useBpfStats;
+ mBpfNetMaps = new BpfNetMaps();
synchronized (mPersistentDataLock) {
mPersistSnapshot = new NetworkStats(SystemClock.elapsedRealtime(), -1);
mTunAnd464xlatAdjustedStats = new NetworkStats(SystemClock.elapsedRealtime(), -1);
@@ -297,12 +301,14 @@ public class NetworkStatsFactory {
}
@GuardedBy("mPersistentDataLock")
- private void requestSwapActiveStatsMapLocked() {
- // Do a active map stats swap. When the binder call successfully returns,
- // the system server should be able to safely read and clean the inactive map
- // without race problem.
- final ConnectivityManager cm = mContext.getSystemService(ConnectivityManager.class);
- cm.swapActiveStatsMap();
+ private void requestSwapActiveStatsMapLocked() throws IOException {
+ try {
+ // Do a active map stats swap. Once the swap completes, this code
+ // can read and clean the inactive map without races.
+ mBpfNetMaps.swapActiveStatsMap();
+ } catch (ServiceSpecificException e) {
+ throw new IOException(e);
+ }
}
/**
@@ -328,11 +334,7 @@ public class NetworkStatsFactory {
final NetworkStats stats =
new NetworkStats(SystemClock.elapsedRealtime(), 0 /* initialSize */);
if (mUseBpfStats) {
- try {
- requestSwapActiveStatsMapLocked();
- } catch (RuntimeException e) {
- throw new IOException(e);
- }
+ requestSwapActiveStatsMapLocked();
// Stats are always read from the inactive map, so they must be read after the
// swap
if (nativeReadNetworkStatsDetail(stats, mStatsXtUid.getAbsolutePath(), UID_ALL,
diff --git a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsRecorder.java b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsRecorder.java
index a006cd597568..f62765d07427 100644
--- a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsRecorder.java
+++ b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsRecorder.java
@@ -471,11 +471,11 @@ public class NetworkStatsRecorder {
public void dumpDebugLocked(ProtoOutputStream proto, long tag) {
final long start = proto.start(tag);
if (mPending != null) {
- proto.write(NetworkStatsRecorderProto.PENDING_TOTAL_BYTES_FIELD_NUMBER,
+ proto.write(NetworkStatsRecorderProto.PENDING_TOTAL_BYTES,
mPending.getTotalBytes());
}
getOrLoadCompleteLocked().dumpDebug(proto,
- NetworkStatsRecorderProto.COMPLETE_HISTORY_FIELD_NUMBER);
+ NetworkStatsRecorderProto.COMPLETE_HISTORY);
proto.end(start);
}
diff --git a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsService.java b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsService.java
index ef6f39a5c040..e3794e441a23 100644
--- a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsService.java
+++ b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsService.java
@@ -565,7 +565,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
return new BpfMap<U32, U8>(UID_COUNTERSET_MAP_PATH, BpfMap.BPF_F_RDWR,
U32.class, U8.class);
} catch (ErrnoException e) {
- Log.wtf(TAG, "Cannot create uid counter set map: " + e);
+ Log.wtf(TAG, "Cannot open uid counter set map: " + e);
return null;
}
}
@@ -576,7 +576,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
return new BpfMap<CookieTagMapKey, CookieTagMapValue>(COOKIE_TAG_MAP_PATH,
BpfMap.BPF_F_RDWR, CookieTagMapKey.class, CookieTagMapValue.class);
} catch (ErrnoException e) {
- Log.wtf(TAG, "Cannot create cookie tag map: " + e);
+ Log.wtf(TAG, "Cannot open cookie tag map: " + e);
return null;
}
}
@@ -587,7 +587,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
return new BpfMap<StatsMapKey, StatsMapValue>(STATS_MAP_A_PATH,
BpfMap.BPF_F_RDWR, StatsMapKey.class, StatsMapValue.class);
} catch (ErrnoException e) {
- Log.wtf(TAG, "Cannot create stats map A: " + e);
+ Log.wtf(TAG, "Cannot open stats map A: " + e);
return null;
}
}
@@ -598,7 +598,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
return new BpfMap<StatsMapKey, StatsMapValue>(STATS_MAP_B_PATH,
BpfMap.BPF_F_RDWR, StatsMapKey.class, StatsMapValue.class);
} catch (ErrnoException e) {
- Log.wtf(TAG, "Cannot create stats map B: " + e);
+ Log.wtf(TAG, "Cannot open stats map B: " + e);
return null;
}
}
@@ -609,7 +609,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
return new BpfMap<UidStatsMapKey, StatsMapValue>(APP_UID_STATS_MAP_PATH,
BpfMap.BPF_F_RDWR, UidStatsMapKey.class, StatsMapValue.class);
} catch (ErrnoException e) {
- Log.wtf(TAG, "Cannot create app uid stats map: " + e);
+ Log.wtf(TAG, "Cannot open app uid stats map: " + e);
return null;
}
}
@@ -1194,7 +1194,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
}
@VisibleForTesting
- public void setUidForeground(int uid, boolean uidForeground) {
+ public void noteUidForeground(int uid, boolean uidForeground) {
PermissionUtils.enforceNetworkStackPermission(mContext);
synchronized (mStatsLock) {
final int set = uidForeground ? SET_FOREGROUND : SET_DEFAULT;
@@ -2132,15 +2132,15 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
// TODO Right now it writes all history. Should it limit to the "since-boot" log?
- dumpInterfaces(proto, NetworkStatsServiceDumpProto.ACTIVE_INTERFACES_FIELD_NUMBER,
+ dumpInterfaces(proto, NetworkStatsServiceDumpProto.ACTIVE_INTERFACES,
mActiveIfaces);
- dumpInterfaces(proto, NetworkStatsServiceDumpProto.ACTIVE_UID_INTERFACES_FIELD_NUMBER,
+ dumpInterfaces(proto, NetworkStatsServiceDumpProto.ACTIVE_UID_INTERFACES,
mActiveUidIfaces);
- mDevRecorder.dumpDebugLocked(proto, NetworkStatsServiceDumpProto.DEV_STATS_FIELD_NUMBER);
- mXtRecorder.dumpDebugLocked(proto, NetworkStatsServiceDumpProto.XT_STATS_FIELD_NUMBER);
- mUidRecorder.dumpDebugLocked(proto, NetworkStatsServiceDumpProto.UID_STATS_FIELD_NUMBER);
+ mDevRecorder.dumpDebugLocked(proto, NetworkStatsServiceDumpProto.DEV_STATS);
+ mXtRecorder.dumpDebugLocked(proto, NetworkStatsServiceDumpProto.XT_STATS);
+ mUidRecorder.dumpDebugLocked(proto, NetworkStatsServiceDumpProto.UID_STATS);
mUidTagRecorder.dumpDebugLocked(proto,
- NetworkStatsServiceDumpProto.UID_TAG_STATS_FIELD_NUMBER);
+ NetworkStatsServiceDumpProto.UID_TAG_STATS);
proto.flush();
}
@@ -2150,8 +2150,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
for (int i = 0; i < ifaces.size(); i++) {
final long start = proto.start(tag);
- proto.write(NetworkInterfaceProto.INTERFACE_FIELD_NUMBER, ifaces.keyAt(i));
- ifaces.valueAt(i).dumpDebug(proto, NetworkInterfaceProto.IDENTITIES_FIELD_NUMBER);
+ proto.write(NetworkInterfaceProto.INTERFACE, ifaces.keyAt(i));
+ ifaces.valueAt(i).dumpDebug(proto, NetworkInterfaceProto.IDENTITIES);
proto.end(start);
}
@@ -2393,10 +2393,17 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
}
@Override
- public void notifyWarningOrLimitReached() {
- Log.d(TAG, mTag + ": notifyWarningOrLimitReached");
+ public void notifyWarningReached() {
+ Log.d(TAG, mTag + ": notifyWarningReached");
BinderUtils.withCleanCallingIdentity(() ->
- mNetworkPolicyManager.notifyStatsProviderWarningOrLimitReached());
+ mNetworkPolicyManager.notifyStatsProviderWarningReached());
+ }
+
+ @Override
+ public void notifyLimitReached() {
+ Log.d(TAG, mTag + ": notifyLimitReached");
+ BinderUtils.withCleanCallingIdentity(() ->
+ mNetworkPolicyManager.notifyStatsProviderLimitReached());
}
@Override
diff --git a/services/tests/servicestests/src/com/android/server/net/IpConfigStoreTest.java b/packages/ConnectivityT/tests/unit/java/com/android/server/net/IpConfigStoreTest.java
index 2f771260ac1b..ad0be5862c5d 100644
--- a/services/tests/servicestests/src/com/android/server/net/IpConfigStoreTest.java
+++ b/packages/ConnectivityT/tests/unit/java/com/android/server/net/IpConfigStoreTest.java
@@ -48,10 +48,16 @@ import java.util.Arrays;
*/
@RunWith(AndroidJUnit4.class)
public class IpConfigStoreTest {
+ private static final int KEY_CONFIG = 17;
+ private static final String IFACE_1 = "eth0";
+ private static final String IFACE_2 = "eth1";
+ private static final String IP_ADDR_1 = "192.168.1.10/24";
+ private static final String IP_ADDR_2 = "192.168.1.20/24";
+ private static final String DNS_IP_ADDR_1 = "1.2.3.4";
+ private static final String DNS_IP_ADDR_2 = "5.6.7.8";
@Test
public void backwardCompatibility2to3() throws IOException {
- final int KEY_CONFIG = 17;
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
DataOutputStream outputStream = new DataOutputStream(byteStream);
@@ -73,13 +79,6 @@ public class IpConfigStoreTest {
@Test
public void staticIpMultiNetworks() throws Exception {
- final String IFACE_1 = "eth0";
- final String IFACE_2 = "eth1";
- final String IP_ADDR_1 = "192.168.1.10/24";
- final String IP_ADDR_2 = "192.168.1.20/24";
- final String DNS_IP_ADDR_1 = "1.2.3.4";
- final String DNS_IP_ADDR_2 = "5.6.7.8";
-
final ArrayList<InetAddress> dnsServers = new ArrayList<>();
dnsServers.add(InetAddresses.parseNumericAddress(DNS_IP_ADDR_1));
dnsServers.add(InetAddresses.parseNumericAddress(DNS_IP_ADDR_2));
@@ -144,11 +143,11 @@ public class IpConfigStoreTest {
/** Synchronously writes into given byte steam */
private static class MockedDelayedDiskWrite extends DelayedDiskWrite {
- final ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
+ final ByteArrayOutputStream mByteStream = new ByteArrayOutputStream();
@Override
public void write(String filePath, Writer w) {
- DataOutputStream outputStream = new DataOutputStream(byteStream);
+ DataOutputStream outputStream = new DataOutputStream(mByteStream);
try {
w.onWriteCalled(outputStream);
diff --git a/packages/DynamicSystemInstallationService/Android.bp b/packages/DynamicSystemInstallationService/Android.bp
index ad86f4667f67..b8f54b3faf63 100644
--- a/packages/DynamicSystemInstallationService/Android.bp
+++ b/packages/DynamicSystemInstallationService/Android.bp
@@ -22,6 +22,9 @@ android_app {
defaults: ["platform_app_defaults"],
srcs: ["src/**/*.java"],
+ static_libs: [
+ "DynamicSystemInstallationService-logtags",
+ ],
resource_dirs: ["res"],
certificate: "platform",
@@ -32,3 +35,8 @@ android_app {
enabled: false,
},
}
+
+java_library {
+ name: "DynamicSystemInstallationService-logtags",
+ srcs: ["src/**/*.logtags"],
+}
diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
index f8cb5d3d2419..02128d480678 100644
--- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
+++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
@@ -58,6 +58,7 @@ import android.os.RemoteException;
import android.os.image.DynamicSystemClient;
import android.os.image.DynamicSystemManager;
import android.text.TextUtils;
+import android.util.EventLog;
import android.util.Log;
import android.widget.Toast;
@@ -104,6 +105,36 @@ public class DynamicSystemInstallationService extends Service
private static final int NOTIFICATION_ID = 1;
/*
+ * Event log tags
+ */
+ private static final int EVENT_DSU_PROGRESS_UPDATE = 120000;
+ private static final int EVENT_DSU_INSTALL_COMPLETE = 120001;
+ private static final int EVENT_DSU_INSTALL_FAILED = 120002;
+
+ protected static void logEventProgressUpdate(
+ String partition,
+ long installedSize,
+ long partitionSize,
+ int partitionNumber,
+ int totalPartitionNumber) {
+ EventLog.writeEvent(
+ EVENT_DSU_PROGRESS_UPDATE,
+ partition,
+ installedSize,
+ partitionSize,
+ partitionNumber,
+ totalPartitionNumber);
+ }
+
+ protected static void logEventComplete() {
+ EventLog.writeEvent(EVENT_DSU_INSTALL_COMPLETE);
+ }
+
+ protected static void logEventFailed(String cause) {
+ EventLog.writeEvent(EVENT_DSU_INSTALL_FAILED, cause);
+ }
+
+ /*
* IPC
*/
/** Keeps track of all current registered clients. */
@@ -132,15 +163,10 @@ public class DynamicSystemInstallationService extends Service
private DynamicSystemManager mDynSystem;
private NotificationManager mNM;
- private int mNumInstalledPartitions;
-
- private String mCurrentPartitionName;
- private long mCurrentPartitionSize;
- private long mCurrentPartitionInstalledSize;
-
// This is for testing only now
private boolean mEnableWhenCompleted;
+ private InstallationAsyncTask.Progress mInstallTaskProgress;
private InstallationAsyncTask mInstallTask;
@@ -203,17 +229,21 @@ public class DynamicSystemInstallationService extends Service
@Override
public void onProgressUpdate(InstallationAsyncTask.Progress progress) {
- mCurrentPartitionName = progress.partitionName;
- mCurrentPartitionSize = progress.partitionSize;
- mCurrentPartitionInstalledSize = progress.installedSize;
- mNumInstalledPartitions = progress.numInstalledPartitions;
-
+ logEventProgressUpdate(
+ progress.partitionName,
+ progress.installedSize,
+ progress.partitionSize,
+ progress.partitionNumber,
+ progress.totalPartitionNumber);
+
+ mInstallTaskProgress = progress;
postStatus(STATUS_IN_PROGRESS, CAUSE_NOT_SPECIFIED, null);
}
@Override
public void onResult(int result, Throwable detail) {
if (result == RESULT_OK) {
+ logEventComplete();
postStatus(STATUS_READY, CAUSE_INSTALL_COMPLETED, null);
// For testing: enable DSU and restart the device when install completed
@@ -223,6 +253,12 @@ public class DynamicSystemInstallationService extends Service
return;
}
+ if (result == RESULT_CANCELLED) {
+ logEventFailed("Dynamic System installation task is canceled by the user.");
+ } else {
+ logEventFailed("error: " + detail);
+ }
+
boolean removeNotification = false;
switch (result) {
case RESULT_CANCELLED:
@@ -251,16 +287,20 @@ public class DynamicSystemInstallationService extends Service
private void executeInstallCommand(Intent intent) {
if (!verifyRequest(intent)) {
Log.e(TAG, "Verification failed. Did you use VerificationActivity?");
+ logEventFailed("VerificationActivity");
return;
}
if (mInstallTask != null) {
Log.e(TAG, "There is already an installation task running");
+ logEventFailed("There is already an ongoing installation task.");
return;
}
if (isInDynamicSystem()) {
Log.e(TAG, "We are already running in DynamicSystem");
+ logEventFailed(
+ "Cannot start a Dynamic System installation task within a Dynamic System.");
return;
}
@@ -445,19 +485,22 @@ public class DynamicSystemInstallationService extends Service
case STATUS_IN_PROGRESS:
builder.setContentText(getString(R.string.notification_install_inprogress));
- int max = 1024;
- int progress = 0;
-
- int currentMax = max >> (mNumInstalledPartitions + 1);
- progress = max - currentMax * 2;
+ if (mInstallTaskProgress != null) {
+ int max = 1024;
+ int progress = 0;
- long currentProgress = (mCurrentPartitionInstalledSize >> 20) * currentMax
- / Math.max(mCurrentPartitionSize >> 20, 1);
+ int currentMax = max >> mInstallTaskProgress.partitionNumber;
+ progress = max - currentMax * 2;
- progress += (int) currentProgress;
+ long currentProgress =
+ (mInstallTaskProgress.installedSize >> 20)
+ * currentMax
+ / Math.max(mInstallTaskProgress.partitionSize >> 20, 1);
- builder.setProgress(max, progress, false);
+ progress += (int) currentProgress;
+ builder.setProgress(max, progress, false);
+ }
builder.addAction(new Notification.Action.Builder(
null, getString(R.string.notification_action_cancel),
createPendingIntent(ACTION_CANCEL_INSTALL)).build());
@@ -563,13 +606,13 @@ public class DynamicSystemInstallationService extends Service
StringBuilder msg = new StringBuilder();
msg.append("status: " + statusString + ", cause: " + causeString);
- if (status == STATUS_IN_PROGRESS) {
+ if (status == STATUS_IN_PROGRESS && mInstallTaskProgress != null) {
msg.append(
String.format(
", partition name: %s, progress: %d/%d",
- mCurrentPartitionName,
- mCurrentPartitionInstalledSize,
- mCurrentPartitionSize));
+ mInstallTaskProgress.partitionName,
+ mInstallTaskProgress.installedSize,
+ mInstallTaskProgress.partitionSize));
}
if (detail != null) {
msg.append(", detail: " + detail);
@@ -594,7 +637,10 @@ public class DynamicSystemInstallationService extends Service
Bundle bundle = new Bundle();
// TODO: send more info to the clients
- bundle.putLong(DynamicSystemClient.KEY_INSTALLED_SIZE, mCurrentPartitionInstalledSize);
+ if (mInstallTaskProgress != null) {
+ bundle.putLong(
+ DynamicSystemClient.KEY_INSTALLED_SIZE, mInstallTaskProgress.installedSize);
+ }
if (detail != null) {
bundle.putSerializable(DynamicSystemClient.KEY_EXCEPTION_DETAIL,
diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/EventLogTags.logtags b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/EventLogTags.logtags
new file mode 100644
index 000000000000..eae9de937700
--- /dev/null
+++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/EventLogTags.logtags
@@ -0,0 +1,7 @@
+# See system/logging/logcat/event.logtags for a description of the format of this file.
+
+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)
+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 f18d4269c3ef..b439f8421b73 100644
--- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java
+++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java
@@ -44,7 +44,7 @@ import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;
-class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Progress, Throwable> {
+class InstallationAsyncTask extends AsyncTask<String, Long, Throwable> {
private static final String TAG = "InstallationAsyncTask";
@@ -106,14 +106,22 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog
static class Progress {
public final String partitionName;
+ public final long installedSize;
public final long partitionSize;
- public final int numInstalledPartitions;
- public long installedSize;
-
- Progress(String partitionName, long partitionSize, int numInstalledPartitions) {
+ public final int partitionNumber;
+ public final int totalPartitionNumber;
+
+ Progress(
+ String partitionName,
+ long installedSize,
+ long partitionSize,
+ int partitionNumber,
+ int totalPartitionNumber) {
this.partitionName = partitionName;
+ this.installedSize = installedSize;
this.partitionSize = partitionSize;
- this.numInstalledPartitions = numInstalledPartitions;
+ this.partitionNumber = partitionNumber;
+ this.totalPartitionNumber = totalPartitionNumber;
}
}
@@ -139,7 +147,10 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog
private boolean mIsZip;
private boolean mIsCompleted;
- private int mNumInstalledPartitions;
+ private String mPartitionName;
+ private long mPartitionSize;
+ private int mPartitionNumber;
+ private int mTotalPartitionNumber;
private InputStream mStream;
private ZipFile mZipFile;
@@ -175,11 +186,15 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog
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);
@@ -198,7 +213,7 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog
return null;
}
- if (Build.IS_DEBUGGABLE) {
+ if (wantScratchPartition) {
// If host is debuggable, then install a scratch partition so that we can do
// adb remount in the guest system.
try {
@@ -262,9 +277,14 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog
}
@Override
- protected void onProgressUpdate(Progress... values) {
- Progress progress = values[0];
- mListener.onProgressUpdate(progress);
+ protected void onProgressUpdate(Long... installedSize) {
+ mListener.onProgressUpdate(
+ new Progress(
+ mPartitionName,
+ installedSize[0],
+ mPartitionSize,
+ mPartitionNumber,
+ mTotalPartitionNumber));
}
private void verifyAndPrepare() throws Exception {
@@ -281,12 +301,16 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog
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();
}
@@ -333,9 +357,13 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog
}
};
- thread.start();
- Progress progress = new Progress(partitionName, partitionSize, mNumInstalledPartitions++);
+ mPartitionName = partitionName;
+ mPartitionSize = partitionSize;
+ ++mPartitionNumber;
+ publishProgress(/* installedSize = */ 0L);
+ long prevInstalledSize = 0;
+ thread.start();
while (thread.isAlive()) {
if (isCancelled()) {
return;
@@ -343,9 +371,9 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog
final long installedSize = mDynSystem.getInstallationProgress().bytes_processed;
- if (installedSize > progress.installedSize + MIN_PROGRESS_TO_PUBLISH) {
- progress.installedSize = installedSize;
- publishProgress(progress);
+ if (installedSize > prevInstalledSize + MIN_PROGRESS_TO_PUBLISH) {
+ publishProgress(installedSize);
+ prevInstalledSize = installedSize;
}
try {
@@ -392,14 +420,42 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog
installImage("system", mSystemSize, new GZIPInputStream(mStream));
}
+ private boolean shouldInstallEntry(String name) {
+ if (!name.endsWith(".img")) {
+ return false;
+ }
+ String partitionName = name.substring(0, name.length() - 4);
+ if (UNSUPPORTED_PARTITIONS.contains(partitionName)) {
+ return false;
+ }
+ return true;
+ }
+
+ private int calculateNumberOfImagesInLocalZip(ZipFile zipFile) {
+ int total = 0;
+ Enumeration<? extends ZipEntry> entries = zipFile.entries();
+ while (entries.hasMoreElements()) {
+ ZipEntry entry = entries.nextElement();
+ if (shouldInstallEntry(entry.getName())) {
+ ++total;
+ }
+ }
+ return total;
+ }
+
private void installStreamingZipUpdate() throws IOException, ImageValidationException {
Log.d(TAG, "To install a streaming ZIP update");
ZipInputStream zis = new ZipInputStream(mStream);
- ZipEntry zipEntry = null;
+ ZipEntry entry = null;
- while ((zipEntry = zis.getNextEntry()) != null) {
- installImageFromAnEntry(zipEntry, zis);
+ while ((entry = zis.getNextEntry()) != null) {
+ String name = entry.getName();
+ if (shouldInstallEntry(name)) {
+ installImageFromAnEntry(entry, zis);
+ } else {
+ Log.d(TAG, name + " installation is not supported, skip it.");
+ }
if (isCancelled()) {
break;
@@ -414,7 +470,12 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog
while (entries.hasMoreElements()) {
ZipEntry entry = entries.nextElement();
- installImageFromAnEntry(entry, mZipFile.getInputStream(entry));
+ String name = entry.getName();
+ if (shouldInstallEntry(name)) {
+ installImageFromAnEntry(entry, mZipFile.getInputStream(entry));
+ } else {
+ Log.d(TAG, name + " installation is not supported, skip it.");
+ }
if (isCancelled()) {
break;
@@ -422,28 +483,16 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog
}
}
- private boolean installImageFromAnEntry(ZipEntry entry, InputStream is)
+ private void installImageFromAnEntry(ZipEntry entry, InputStream is)
throws IOException, ImageValidationException {
String name = entry.getName();
Log.d(TAG, "ZipEntry: " + name);
- if (!name.endsWith(".img")) {
- return false;
- }
-
String partitionName = name.substring(0, name.length() - 4);
-
- if (UNSUPPORTED_PARTITIONS.contains(partitionName)) {
- Log.d(TAG, name + " installation is not supported, skip it.");
- return false;
- }
-
long uncompressedSize = entry.getSize();
installImage(partitionName, uncompressedSize, is);
-
- return true;
}
private void installImage(String partitionName, long uncompressedSize, InputStream is)
@@ -497,8 +546,12 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog
mInstallationSession.setAshmem(pfd, READ_BUFFER_SIZE);
- Progress progress = new Progress(partitionName, partitionSize, mNumInstalledPartitions++);
+ mPartitionName = partitionName;
+ mPartitionSize = partitionSize;
+ ++mPartitionNumber;
+ publishProgress(/* installedSize = */ 0L);
+ long prevInstalledSize = 0;
long installedSize = 0;
byte[] bytes = new byte[READ_BUFFER_SIZE];
int numBytesRead;
@@ -516,9 +569,9 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog
installedSize += numBytesRead;
- if (installedSize > progress.installedSize + MIN_PROGRESS_TO_PUBLISH) {
- progress.installedSize = installedSize;
- publishProgress(progress);
+ if (installedSize > prevInstalledSize + MIN_PROGRESS_TO_PUBLISH) {
+ publishProgress(installedSize);
+ prevInstalledSize = installedSize;
}
}
diff --git a/packages/PackageInstaller/res/values-ar/strings.xml b/packages/PackageInstaller/res/values-ar/strings.xml
index 2d6fca61ce46..51b18d36ad41 100644
--- a/packages/PackageInstaller/res/values-ar/strings.xml
+++ b/packages/PackageInstaller/res/values-ar/strings.xml
@@ -59,7 +59,7 @@
<string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"هل تريد إزالة تثبيت هذا التطبيق من ملفك الشخصي للعمل؟"</string>
<string name="uninstall_update_text" msgid="863648314632448705">"هل تريد استبدال هذا التطبيق بإصدار المصنع؟ ستتم إزالة جميع البيانات."</string>
<string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"هل تريد إعادة ضبط هذا التطبيق على الإعدادات الأصلية؟ سؤدي ذلك إلى إزالة جميع البيانات، كما سيؤثر على جميع مستخدمي هذا الجهاز، بما في ذلك من لديهم ملفات شخصية للعمل."</string>
- <string name="uninstall_keep_data" msgid="7002379587465487550">"الاحتفاظ بالحجم <xliff:g id="SIZE">%1$s</xliff:g> من بيانات التطبيق."</string>
+ <string name="uninstall_keep_data" msgid="7002379587465487550">"الاحتفاظ بـ <xliff:g id="SIZE">%1$s</xliff:g> من بيانات التطبيق."</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"عمليات إلغاء التثبيت الجارية"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"عمليات إلغاء التثبيت غير الناجحة"</string>
<string name="uninstalling" msgid="8709566347688966845">"جارٍ إلغاء التثبيت…"</string>
diff --git a/packages/PackageInstaller/res/values-or/strings.xml b/packages/PackageInstaller/res/values-or/strings.xml
index 20a348091dec..ca01d7f839b8 100644
--- a/packages/PackageInstaller/res/values-or/strings.xml
+++ b/packages/PackageInstaller/res/values-or/strings.xml
@@ -88,7 +88,7 @@
<string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"ଅଜଣା ଆପ୍‌ ଦ୍ୱାରା ଆପଣଙ୍କ ଟାବଲେଟ୍‍ ଏବଂ ବ୍ୟକ୍ତିଗତ ଡାଟାକୁ ନଷ୍ଟ କରାଯାଇପାରିବାର ସମ୍ଭାବନା ବହୁତ ଅଧିକ। ଏହି ଆପ୍‌କୁ ଇନଷ୍ଟଲ୍‌ କରିବାର ଅର୍ଥ ହେଉଛି ଆପଣଙ୍କ ଟାବ୍‌ଲେଟ୍‌ରେ ଘଟିବା କୌଣସି ପ୍ରକାର କ୍ଷତି କିମ୍ବା ସେଗୁଡ଼ିକର ବ୍ୟବହାରରୁ ହେବା କୌଣସି ପ୍ରକାର ଡାଟାର ହାନୀ ପାଇଁ ଆପଣ ଦାୟୀ ରହିବାକୁ ରାଜି ହୁଅନ୍ତି।"</string>
<string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"ଅଜଣା ଆପ୍‌ ଦ୍ୱାରା ଆପଣଙ୍କ ଟିଭି ଏବଂ ବ୍ୟକ୍ତିଗତ ଡାଟାକୁ ନଷ୍ଟ କରାଯାଇପାରିବାର ସମ୍ଭାବନା ବହୁତ ଅଧିକ। ଏହି ଆପ୍‌କୁ ଇନଷ୍ଟଲ୍‌ କରିବାର ଅର୍ଥ ହେଉଛି ଆପଣଙ୍କ ଟିଭିରେ ଘଟିବା କୌଣସି ପ୍ରକାର କ୍ଷତି କିମ୍ବା ସେଗୁଡ଼ିକର ବ୍ୟବହାରରୁ ହେବା କୌଣସି ପ୍ରକାର ଡାଟାର ହାନୀ ପାଇଁ ଆପଣ ଦାୟୀ ରହିବାକୁ ରାଜି ହୁଅନ୍ତି।"</string>
<string name="anonymous_source_continue" msgid="4375745439457209366">"ଜାରି ରଖନ୍ତୁ"</string>
- <string name="external_sources_settings" msgid="4046964413071713807">"ସେଟିଂସ୍"</string>
+ <string name="external_sources_settings" msgid="4046964413071713807">"ସେଟିଂସ"</string>
<string name="wear_app_channel" msgid="1960809674709107850">"ୱିଅର୍‍ ଆପ୍‍ ଇନଷ୍ଟଲ୍‌/ଅନଇନଷ୍ଟଲ୍‍ କରାଯାଉଛି"</string>
<string name="app_installed_notification_channel_description" msgid="2695385797601574123">"ଆପ୍ ଇନ୍‌ଷ୍ଟଲ୍‌ କରାଯାଇଥିବା ବିଜ୍ଞପ୍ତି"</string>
<string name="notification_installation_success_message" msgid="6450467996056038442">"ସଫଳତାପୂର୍ବକ ଇନ୍‌ଷ୍ଟଲ୍‌ କରାଗଲା"</string>
diff --git a/packages/PrintSpooler/res/values-it/strings.xml b/packages/PrintSpooler/res/values-it/strings.xml
index 40b621c7f569..d898b1e62226 100644
--- a/packages/PrintSpooler/res/values-it/strings.xml
+++ b/packages/PrintSpooler/res/values-it/strings.xml
@@ -56,8 +56,8 @@
<string name="print_select_printer" msgid="7388760939873368698">"Seleziona stampante"</string>
<string name="print_forget_printer" msgid="5035287497291910766">"Elimina stampante"</string>
<plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
- <item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g> printers found</item>
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> stampanti trovate</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> stampante trovata</item>
</plurals>
<string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="printer_info_desc" msgid="7181988788991581654">"Ulteriori informazioni su questa stampante"</string>
@@ -76,8 +76,8 @@
<string name="disabled_services_title" msgid="7313253167968363211">"Servizi disattivati"</string>
<string name="all_services_title" msgid="5578662754874906455">"Tutti i servizi"</string>
<plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
- <item quantity="one">Install to discover <xliff:g id="COUNT_1">%1$s</xliff:g> printers</item>
<item quantity="other">Installa per rilevare <xliff:g id="COUNT_1">%1$s</xliff:g> stampanti</item>
+ <item quantity="one">Installa per rilevare <xliff:g id="COUNT_0">%1$s</xliff:g> stampante</item>
</plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"Stampa di <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Annullamento di <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-pt-rPT/strings.xml b/packages/PrintSpooler/res/values-pt-rPT/strings.xml
index 56001d82982d..4517efe0934a 100644
--- a/packages/PrintSpooler/res/values-pt-rPT/strings.xml
+++ b/packages/PrintSpooler/res/values-pt-rPT/strings.xml
@@ -56,8 +56,8 @@
<string name="print_select_printer" msgid="7388760939873368698">"Selecionar impressora"</string>
<string name="print_forget_printer" msgid="5035287497291910766">"Esquecer impressora"</string>
<plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
- <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> impressora encontrada</item>
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> impressoras encontradas</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> impressora encontrada</item>
</plurals>
<string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="printer_info_desc" msgid="7181988788991581654">"Mais informações acerca desta impressora"</string>
@@ -76,8 +76,8 @@
<string name="disabled_services_title" msgid="7313253167968363211">"Serviços desativados"</string>
<string name="all_services_title" msgid="5578662754874906455">"Todos os serviços"</string>
<plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
- <item quantity="one">Instale para detetar <xliff:g id="COUNT_0">%1$s</xliff:g> impressora</item>
<item quantity="other">Instale para detetar <xliff:g id="COUNT_1">%1$s</xliff:g> impressoras</item>
+ <item quantity="one">Instale para detetar <xliff:g id="COUNT_0">%1$s</xliff:g> impressora</item>
</plurals>
<string name="printing_notification_title_template" msgid="295903957762447362">"A imprimir <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"A cancelar <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/ActivityEmbedding/src/com/android/settingslib/activityembedding/ActivityEmbeddingUtils.java b/packages/SettingsLib/ActivityEmbedding/src/com/android/settingslib/activityembedding/ActivityEmbeddingUtils.java
index 44b3b4e8488a..706aba3d156f 100644
--- a/packages/SettingsLib/ActivityEmbedding/src/com/android/settingslib/activityembedding/ActivityEmbeddingUtils.java
+++ b/packages/SettingsLib/ActivityEmbedding/src/com/android/settingslib/activityembedding/ActivityEmbeddingUtils.java
@@ -51,27 +51,34 @@ public class ActivityEmbeddingUtils {
}
/**
- * Whether current activity is embedded in the Settings app or not.
+ * Whether the current activity is embedded in the Settings app or not.
+ *
+ * @param activity Activity that needs the check
*/
public static boolean isActivityEmbedded(Activity activity) {
return SplitController.getInstance().isActivityEmbedded(activity);
}
/**
- * Whether current activity is suggested to show back button or not.
+ * Whether the current activity should hide the navigate up button.
+ *
+ * @param activity Activity that needs the check
+ * @param isSecondLayerPage indicates if the activity(page) is shown in the 2nd layer of
+ * Settings app
*/
- public static boolean shouldHideBackButton(Activity activity, boolean isSecondaryLayerPage) {
+ public static boolean shouldHideNavigateUpButton(Activity activity, boolean isSecondLayerPage) {
if (!BuildCompat.isAtLeastT()) {
return false;
}
- if (!isSecondaryLayerPage) {
+ if (!isSecondLayerPage) {
return false;
}
- final String shouldHideBackButton = Settings.Global.getString(activity.getContentResolver(),
- "settings_hide_secondary_page_back_button_in_two_pane");
+ final String shouldHideNavigateUpButton =
+ Settings.Global.getString(activity.getContentResolver(),
+ "settings_hide_second_layer_page_navigate_up_button_in_two_pane");
- if (TextUtils.isEmpty(shouldHideBackButton)
- || TextUtils.equals("true", shouldHideBackButton)) {
+ if (TextUtils.isEmpty(shouldHideNavigateUpButton)
+ || Boolean.parseBoolean(shouldHideNavigateUpButton)) {
return isActivityEmbedded(activity);
}
return false;
diff --git a/packages/SettingsLib/FooterPreference/res/layout-v31/preference_footer.xml b/packages/SettingsLib/FooterPreference/res/layout-v31/preference_footer.xml
index b1276303b801..212ae528a6b9 100644
--- a/packages/SettingsLib/FooterPreference/res/layout-v31/preference_footer.xml
+++ b/packages/SettingsLib/FooterPreference/res/layout-v31/preference_footer.xml
@@ -46,7 +46,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
- <com.android.settingslib.widget.LinkTextView
+ <TextView
android:id="@android:id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
diff --git a/packages/SettingsLib/FooterPreference/res/layout/preference_footer.xml b/packages/SettingsLib/FooterPreference/res/layout/preference_footer.xml
index 23192b6ce138..d403f9ec8e45 100644
--- a/packages/SettingsLib/FooterPreference/res/layout/preference_footer.xml
+++ b/packages/SettingsLib/FooterPreference/res/layout/preference_footer.xml
@@ -45,7 +45,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
- <com.android.settingslib.widget.LinkTextView
+ <TextView
android:id="@android:id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
diff --git a/packages/SettingsLib/FooterPreference/src/com/android/settingslib/widget/FooterPreference.java b/packages/SettingsLib/FooterPreference/src/com/android/settingslib/widget/FooterPreference.java
index 3eb6ea98f118..ac306361386e 100644
--- a/packages/SettingsLib/FooterPreference/src/com/android/settingslib/widget/FooterPreference.java
+++ b/packages/SettingsLib/FooterPreference/src/com/android/settingslib/widget/FooterPreference.java
@@ -19,7 +19,6 @@ package com.android.settingslib.widget;
import android.content.Context;
import android.text.SpannableString;
import android.text.TextUtils;
-import android.text.method.LinkMovementMethod;
import android.text.style.URLSpan;
import android.util.AttributeSet;
import android.view.View;
@@ -59,10 +58,6 @@ public class FooterPreference extends Preference {
public void onBindViewHolder(PreferenceViewHolder holder) {
super.onBindViewHolder(holder);
TextView title = holder.itemView.findViewById(android.R.id.title);
- title.setMovementMethod(new LinkMovementMethod());
- title.setClickable(false);
- title.setLongClickable(false);
- title.setFocusable(false);
if (!TextUtils.isEmpty(mContentDescription)) {
title.setContentDescription(mContentDescription);
}
@@ -86,7 +81,6 @@ public class FooterPreference extends Preference {
if (!TextUtils.isEmpty(mLearnMoreContentDescription)) {
learnMore.setContentDescription(mLearnMoreContentDescription);
}
- learnMore.setFocusable(false);
} else {
learnMore.setVisibility(View.GONE);
}
@@ -180,6 +174,7 @@ public class FooterPreference extends Preference {
if (TextUtils.isEmpty(getKey())) {
setKey(KEY_FOOTER);
}
+ setSelectable(false);
}
/**
diff --git a/packages/SettingsLib/SearchWidget/res/values-or/strings.xml b/packages/SettingsLib/SearchWidget/res/values-or/strings.xml
index cf824deecd79..322571adc89c 100644
--- a/packages/SettingsLib/SearchWidget/res/values-or/strings.xml
+++ b/packages/SettingsLib/SearchWidget/res/values-or/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="search_menu" msgid="1914043873178389845">"ସେଟିଂସ୍ ସନ୍ଧାନ କରନ୍ତୁ"</string>
+ <string name="search_menu" msgid="1914043873178389845">"ସେଟିଂସ ସନ୍ଧାନ କରନ୍ତୁ"</string>
</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/color-v31/settingslib_text_color_primary.xml b/packages/SettingsLib/SettingsTheme/res/color-v31/settingslib_text_color_primary.xml
new file mode 100644
index 000000000000..221d2db00031
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/color-v31/settingslib_text_color_primary.xml
@@ -0,0 +1,22 @@
+<?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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_enabled="false"
+ android:alpha="?android:attr/disabledAlpha"
+ android:color="@color/settingslib_text_color_primary_device_default"/>
+ <item android:color="@color/settingslib_text_color_primary_device_default"/>
+</selector>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-v31/styles.xml b/packages/SettingsLib/SettingsTheme/res/values-v31/styles.xml
index 9d3991119338..cba1a9cf0003 100644
--- a/packages/SettingsLib/SettingsTheme/res/values-v31/styles.xml
+++ b/packages/SettingsLib/SettingsTheme/res/values-v31/styles.xml
@@ -17,7 +17,7 @@
<resources>
<style name="TextAppearance.PreferenceTitle.SettingsLib"
parent="@android:style/TextAppearance.Material.Subhead">
- <item name="android:textColor">@color/settingslib_text_color_primary_device_default</item>
+ <item name="android:textColor">@color/settingslib_text_color_primary</item>
<item name="android:fontFamily">@string/settingslib_config_headlineFontFamily</item>
<item name="android:textSize">20sp</item>
</style>
diff --git a/packages/SystemUI/res/drawable/ic_account_circle.xml b/packages/SettingsLib/res/drawable/ic_account_circle.xml
index 5ca99f32771b..5ca99f32771b 100644
--- a/packages/SystemUI/res/drawable/ic_account_circle.xml
+++ b/packages/SettingsLib/res/drawable/ic_account_circle.xml
diff --git a/packages/SystemUI/res/drawable/ic_account_circle_filled.xml b/packages/SettingsLib/res/drawable/ic_account_circle_filled.xml
index 47c553b52123..47c553b52123 100644
--- a/packages/SystemUI/res/drawable/ic_account_circle_filled.xml
+++ b/packages/SettingsLib/res/drawable/ic_account_circle_filled.xml
diff --git a/packages/SystemUI/res/drawable/ic_add_supervised_user.xml b/packages/SettingsLib/res/drawable/ic_add_supervised_user.xml
index 627743ed1669..627743ed1669 100644
--- a/packages/SystemUI/res/drawable/ic_add_supervised_user.xml
+++ b/packages/SettingsLib/res/drawable/ic_add_supervised_user.xml
diff --git a/packages/SystemUI/res/drawable/kg_bg_avatar.xml b/packages/SettingsLib/res/drawable/user_avatar_bg.xml
index addb3f7508f5..1f50496f3a5c 100644
--- a/packages/SystemUI/res/drawable/kg_bg_avatar.xml
+++ b/packages/SettingsLib/res/drawable/user_avatar_bg.xml
@@ -22,7 +22,7 @@
android:viewportHeight="100">
<path
- android:fillColor="@color/kg_user_switcher_avatar_background"
+ android:fillColor="@color/user_avatar_color_bg"
android:pathData="M50,50m-50,0a50,50 0,1 1,100 0a50,50 0,1 1,-100 0"/>
</vector>
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index 24d1171cdeac..23f9a133d012 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -533,6 +533,8 @@
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Minder tyd."</string>
<string name="cancel" msgid="5665114069455378395">"Kanselleer"</string>
<string name="okay" msgid="949938843324579502">"OK"</string>
+ <!-- no translation found for done (381184316122520313) -->
+ <skip />
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"Wekkers en onthounotas"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Laat toe dat wekkers en onthounotas gestel word"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Wekkers en onthounotas"</string>
@@ -551,7 +553,9 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Vra elke keer"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"Totdat jy dit afskakel"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"Sopas"</string>
- <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Hierdie foon"</string>
+ <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Hierdie foon"</string>
+ <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+ <skip />
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Hierdie foon"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Kan nie koppel nie. Skakel toestel af en weer aan"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Bedrade oudiotoestel"</string>
@@ -591,7 +595,9 @@
<string name="user_set_lock_button" msgid="1427128184982594856">"Stel slot op"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Skakel oor na <xliff:g id="USER_NAME">%s</xliff:g>"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Skep tans nuwe gebruiker …"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Skep tans nuwe gas …"</string>
<string name="add_user_failed" msgid="4809887794313944872">"Kon nie \'n nuwe gebruiker skep nie"</string>
+ <string name="add_guest_failed" msgid="8074548434469843443">"Kon nie ’n nuwe gas skep nie"</string>
<string name="user_nickname" msgid="262624187455825083">"Bynaam"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Voeg gas by"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Verwyder gas"</string>
@@ -644,4 +650,7 @@
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Uitsaai-inligting"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Kies \'n profielprent"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"Verstekgebruikerikoon"</string>
+ <string name="physical_keyboard_title" msgid="4811935435315835220">"Fisieke sleutelbord"</string>
+ <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Kies sleutelborduitleg"</string>
+ <string name="keyboard_layout_default_label" msgid="1997292217218546957">"Verstek"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
index e6201412ca76..c32e94f9a91c 100644
--- a/packages/SettingsLib/res/values-am/strings.xml
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -533,6 +533,8 @@
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"ያነሰ ጊዜ።"</string>
<string name="cancel" msgid="5665114069455378395">"ይቅር"</string>
<string name="okay" msgid="949938843324579502">"እሺ"</string>
+ <!-- no translation found for done (381184316122520313) -->
+ <skip />
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"ማንቂያዎች እና አስታዋሾች"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"ማንቂያዎች እና አስታዋሾች እንዲዋቀሩ ይፍቀዱ"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"ማንቂያዎች እና አስታዋሾች"</string>
@@ -551,7 +553,9 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"ሁልጊዜ ጠይቅ"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"እስኪያጠፉት ድረስ"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"ልክ አሁን"</string>
- <string name="media_transfer_this_device_name" msgid="2357329267148436433">"ይህ ስልክ"</string>
+ <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"ይህ ስልክ"</string>
+ <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+ <skip />
<string name="media_transfer_this_phone" msgid="7194341457812151531">"ይህ ስልክ"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"መገናኘት ላይ ችግር። መሳሪያውን ያጥፉት እና እንደገና ያብሩት"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ባለገመድ የኦዲዮ መሣሪያ"</string>
@@ -591,7 +595,9 @@
<string name="user_set_lock_button" msgid="1427128184982594856">"ቁልፍ አዘጋጅ"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"ወደ <xliff:g id="USER_NAME">%s</xliff:g> ቀይር"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"አዲስ ተጠቃሚ በመፍጠር ላይ…"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"አዲስ እንግዳ በመፍጠር ላይ…"</string>
<string name="add_user_failed" msgid="4809887794313944872">"አዲስ ተጠቃሚን መፍጠር አልተሳካም"</string>
+ <string name="add_guest_failed" msgid="8074548434469843443">"አዲስ እንግዳ መፍጠር አልተሳካም"</string>
<string name="user_nickname" msgid="262624187455825083">"ቅጽል ስም"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"እንግዳን አክል"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"እንግዳን አስወግድ"</string>
@@ -644,4 +650,7 @@
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"የCast መረጃ"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"የመገለጫ ሥዕል ይምረጡ"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"ነባሪ የተጠቃሚ አዶ"</string>
+ <string name="physical_keyboard_title" msgid="4811935435315835220">"አካላዊ ቁልፍ ሰሌዳ"</string>
+ <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"የቁልፍ ሰሌዳ አቀማመጥን ይምረጡ"</string>
+ <string name="keyboard_layout_default_label" msgid="1997292217218546957">"ነባሪ"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index 65e37e856414..894bc3fd744c 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -533,6 +533,8 @@
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"وقت أقل."</string>
<string name="cancel" msgid="5665114069455378395">"إلغاء"</string>
<string name="okay" msgid="949938843324579502">"حسنًا"</string>
+ <!-- no translation found for done (381184316122520313) -->
+ <skip />
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"المنبّهات والتذكيرات"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"السماح بضبط المنبّهات والتذكيرات"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"المنبّهات والتذكيرات"</string>
@@ -551,7 +553,9 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"السؤال في كل مرة"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"إلى أن يتم إيقاف الوضع"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"للتو"</string>
- <string name="media_transfer_this_device_name" msgid="2357329267148436433">"هذا الهاتف"</string>
+ <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"هذا الهاتف"</string>
+ <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+ <skip />
<string name="media_transfer_this_phone" msgid="7194341457812151531">"هذا الهاتف"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"حدثت مشكلة أثناء الاتصال. يُرجى إيقاف الجهاز ثم إعادة تشغيله."</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"جهاز سماعي سلكي"</string>
@@ -591,7 +595,9 @@
<string name="user_set_lock_button" msgid="1427128184982594856">"تعيين التأمين"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"التبديل إلى <xliff:g id="USER_NAME">%s</xliff:g>"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"جارٍ إنشاء مستخدم جديد…"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"جارٍ إنشاء جلسة ضيف جديدة…"</string>
<string name="add_user_failed" msgid="4809887794313944872">"تعذّر إنشاء مستخدم جديد."</string>
+ <string name="add_guest_failed" msgid="8074548434469843443">"تعذّر إنشاء جلسة ضيف جديدة."</string>
<string name="user_nickname" msgid="262624187455825083">"اللقب"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"إضافة ضيف"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"إزالة جلسة الضيف"</string>
@@ -644,4 +650,10 @@
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"معلومات البث"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"اختيار صورة الملف الشخصي"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"رمز المستخدم التلقائي"</string>
+ <!-- no translation found for physical_keyboard_title (4811935435315835220) -->
+ <skip />
+ <!-- no translation found for keyboard_layout_dialog_title (3927180147005616290) -->
+ <skip />
+ <!-- no translation found for keyboard_layout_default_label (1997292217218546957) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml
index f965a34e857b..4ed2e3824df5 100644
--- a/packages/SettingsLib/res/values-as/strings.xml
+++ b/packages/SettingsLib/res/values-as/strings.xml
@@ -533,6 +533,8 @@
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"কম সময়।"</string>
<string name="cancel" msgid="5665114069455378395">"বাতিল কৰক"</string>
<string name="okay" msgid="949938843324579502">"ঠিক"</string>
+ <!-- no translation found for done (381184316122520313) -->
+ <skip />
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"এলাৰ্ম আৰু ৰিমাইণ্ডাৰ"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"এলাৰ্ম আৰু ৰিমাইণ্ডাৰ ছেট কৰাৰ অনুমতি দিয়ক"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"এলাৰ্ম আৰু ৰিমাইণ্ডাৰ"</string>
@@ -551,7 +553,9 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"প্ৰতিবাৰতে সোধক"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"আপুনি অফ নকৰা পর্যন্ত"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"এই মাত্ৰ"</string>
- <string name="media_transfer_this_device_name" msgid="2357329267148436433">"এই ফ’নটো"</string>
+ <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"এই ফ’নটো"</string>
+ <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+ <skip />
<string name="media_transfer_this_phone" msgid="7194341457812151531">"এই ফ’নটো"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"সংযোগ হোৱাত সমস্যা হৈছে। ডিভাইচটো অফ কৰি পুনৰ অন কৰক"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"তাঁৰযুক্ত অডিঅ’ ডিভাইচ"</string>
@@ -591,7 +595,9 @@
<string name="user_set_lock_button" msgid="1427128184982594856">"লক ছেট কৰক"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g>লৈ সলনি কৰক"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"নতুন ব্যৱহাৰকাৰী সৃষ্টি কৰি থকা হৈছে…"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"নতুন অতিথি সৃষ্টি কৰি থকা হৈছে…"</string>
<string name="add_user_failed" msgid="4809887794313944872">"নতুন ব্যৱহাৰকাৰী সৃষ্টি কৰিব পৰা নগ’ল"</string>
+ <string name="add_guest_failed" msgid="8074548434469843443">"নতুন অতিথি সৃষ্টি কৰিব পৰা নগ’ল"</string>
<string name="user_nickname" msgid="262624187455825083">"উপনাম"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"অতিথি যোগ কৰক"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"অতিথি আঁতৰাওক"</string>
@@ -644,4 +650,7 @@
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"কাষ্টৰ তথ্য"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"এখন প্ৰ’ফাইল চিত্ৰ বাছনি কৰক"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"ডিফ’ল্ট ব্যৱহাৰকাৰীৰ চিহ্ন"</string>
+ <string name="physical_keyboard_title" msgid="4811935435315835220">"কায়িক কীব’ৰ্ড"</string>
+ <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"কীব\'ৰ্ডৰ চানেকি বাছক"</string>
+ <string name="keyboard_layout_default_label" msgid="1997292217218546957">"ডিফ’ল্ট"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-az/strings.xml b/packages/SettingsLib/res/values-az/strings.xml
index 3fb3f2c58db5..4b2fa6c6f94b 100644
--- a/packages/SettingsLib/res/values-az/strings.xml
+++ b/packages/SettingsLib/res/values-az/strings.xml
@@ -533,6 +533,8 @@
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Daha az vaxt."</string>
<string name="cancel" msgid="5665114069455378395">"Ləğv edin"</string>
<string name="okay" msgid="949938843324579502">"Ok"</string>
+ <!-- no translation found for done (381184316122520313) -->
+ <skip />
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"Siqnallar və xatırladıcılar"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Siqnallar və xatırlatmaları ayarlamağa icazə verin"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Siqnallar və xatırlatmalar"</string>
@@ -551,7 +553,9 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Həmişə soruşulsun"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"Deaktiv edilənə qədər"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"İndicə"</string>
- <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Bu telefon"</string>
+ <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Bu telefon"</string>
+ <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+ <skip />
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Bu telefon"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Qoşulmaqla bağlı problem. Cihazı deaktiv edin, sonra yenidən aktiv edin"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Simli audio cihaz"</string>
@@ -591,7 +595,9 @@
<string name="user_set_lock_button" msgid="1427128184982594856">"Kilid ayarlayın"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g> adlı istifadəçiyə keçin"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Yeni istifadəçi yaradılır…"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Yeni qonaq yaradılır…"</string>
<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>
<string name="guest_new_guest" msgid="3482026122932643557">"Qonaq əlavə edin"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Qonağı silin"</string>
@@ -644,4 +650,7 @@
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Yayım məlumatı"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Profil şəkli seçin"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"Defolt istifadəçi ikonası"</string>
+ <string name="physical_keyboard_title" msgid="4811935435315835220">"Fiziki klaviatura"</string>
+ <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Klaviatura düzənini seçin"</string>
+ <string name="keyboard_layout_default_label" msgid="1997292217218546957">"Defolt"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
index a267b46750a1..ffc38bf93820 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -533,6 +533,8 @@
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Manje vremena."</string>
<string name="cancel" msgid="5665114069455378395">"Otkaži"</string>
<string name="okay" msgid="949938843324579502">"Potvrdi"</string>
+ <!-- no translation found for done (381184316122520313) -->
+ <skip />
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarmi i podsetnici"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Omogući podešavanje alarma i podsetnika"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmi i podsetnici"</string>
@@ -551,7 +553,9 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Pitaj svaki put"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"Dok ne isključite"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"Upravo"</string>
- <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Ovaj telefon"</string>
+ <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Ovaj telefon"</string>
+ <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+ <skip />
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Ovaj telefon"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problem pri povezivanju. Isključite uređaj, pa ga ponovo uključite"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Žičani audio uređaj"</string>
@@ -591,7 +595,9 @@
<string name="user_set_lock_button" msgid="1427128184982594856">"Podesi zaključavanje"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Pređi na korisnika <xliff:g id="USER_NAME">%s</xliff:g>"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Pravi se novi korisnik…"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Pravi se novi gost…"</string>
<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>
<string name="guest_new_guest" msgid="3482026122932643557">"Dodaj gosta"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Ukloni gosta"</string>
@@ -644,4 +650,7 @@
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Podaci o prebacivanju"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Odaberite sliku profila"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"Podrazumevana ikona korisnika"</string>
+ <string name="physical_keyboard_title" msgid="4811935435315835220">"Fizička tastatura"</string>
+ <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Odaberite raspored tastature"</string>
+ <string name="keyboard_layout_default_label" msgid="1997292217218546957">"Podrazumevano"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml
index 4a1f387daa86..ddadbead06de 100644
--- a/packages/SettingsLib/res/values-be/strings.xml
+++ b/packages/SettingsLib/res/values-be/strings.xml
@@ -533,6 +533,8 @@
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Менш часу."</string>
<string name="cancel" msgid="5665114069455378395">"Скасаваць"</string>
<string name="okay" msgid="949938843324579502">"ОК"</string>
+ <!-- no translation found for done (381184316122520313) -->
+ <skip />
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"Будзільнікі і напаміны"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Дазволіць усталёўваць будзільнікі і напаміны"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Будзільнікі і напаміны"</string>
@@ -551,7 +553,9 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Заўсёды пытацца"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"Пакуль не выключыце"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"Толькі што"</string>
- <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Гэты тэлефон"</string>
+ <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Гэты тэлефон"</string>
+ <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+ <skip />
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Гэты тэлефон"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Праблема з падключэннем. Выключыце і зноў уключыце прыладу"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Правадная аўдыяпрылада"</string>
@@ -591,7 +595,9 @@
<string name="user_set_lock_button" msgid="1427128184982594856">"Усталёўка блакiроўкi"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Пераключыцца на карыстальніка <xliff:g id="USER_NAME">%s</xliff:g>"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Ствараецца новы карыстальнік…"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Ствараецца новы госць…"</string>
<string name="add_user_failed" msgid="4809887794313944872">"Не ўдалося стварыць новага карыстальніка"</string>
+ <string name="add_guest_failed" msgid="8074548434469843443">"Не ўдалося стварыць новага госця"</string>
<string name="user_nickname" msgid="262624187455825083">"Псеўданім"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Дадаць госця"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Выдаліць госця"</string>
@@ -644,4 +650,10 @@
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Даныя пра трансляцыю"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Выберыце відарыс профілю"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"Стандартны карыстальніцкі значок"</string>
+ <!-- no translation found for physical_keyboard_title (4811935435315835220) -->
+ <skip />
+ <!-- no translation found for keyboard_layout_dialog_title (3927180147005616290) -->
+ <skip />
+ <!-- no translation found for keyboard_layout_default_label (1997292217218546957) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index c3fd0604d50f..42f8782daf8d 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -533,6 +533,8 @@
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"По-малко време."</string>
<string name="cancel" msgid="5665114069455378395">"Отказ"</string>
<string name="okay" msgid="949938843324579502">"ОK"</string>
+ <!-- no translation found for done (381184316122520313) -->
+ <skip />
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"Будилници и напомняния"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Разреш. на задаването на будилници и напомняния"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Будилници и напомняния"</string>
@@ -551,7 +553,9 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Да се пита винаги"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"До изключване"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"Току-що"</string>
- <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Този телефон"</string>
+ <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Този телефон"</string>
+ <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+ <skip />
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Този телефон"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"При свързването възникна проблем. Изключете устройството и го включете отново"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Аудиоустройство с кабел"</string>
@@ -591,7 +595,9 @@
<string name="user_set_lock_button" msgid="1427128184982594856">"Задаване на заключване"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Превключване към: <xliff:g id="USER_NAME">%s</xliff:g>"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Създава се нов потребител…"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Новият гост се създава…"</string>
<string name="add_user_failed" msgid="4809887794313944872">"Неуспешно създаване на нов потребител"</string>
+ <string name="add_guest_failed" msgid="8074548434469843443">"Създаването на нов гост не бе успешно"</string>
<string name="user_nickname" msgid="262624187455825083">"Псевдоним"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Добавяне на гост"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Премахване на госта"</string>
@@ -644,4 +650,7 @@
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Предаване: Инф."</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Изберете снимка на потребителския профил"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"Икона за основния потребител"</string>
+ <string name="physical_keyboard_title" msgid="4811935435315835220">"Физическа клавиатура"</string>
+ <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Избор на клавиатурна подредба"</string>
+ <string name="keyboard_layout_default_label" msgid="1997292217218546957">"По подразбиране"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml
index 2e9360e746f2..d21cfad66b70 100644
--- a/packages/SettingsLib/res/values-bn/strings.xml
+++ b/packages/SettingsLib/res/values-bn/strings.xml
@@ -533,6 +533,8 @@
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"আরও কম।"</string>
<string name="cancel" msgid="5665114069455378395">"বাতিল"</string>
<string name="okay" msgid="949938843324579502">"ঠিক আছে"</string>
+ <!-- no translation found for done (381184316122520313) -->
+ <skip />
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"অ্যালার্ম এবং রিমাইন্ডার"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"অ্যালার্ম এবং রিমাইন্ডার সেট করার অনুমতি দিন"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"অ্যালার্ম এবং রিমাইন্ডার"</string>
@@ -551,7 +553,9 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"প্রতিবার জিজ্ঞেস করা হবে"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"যতক্ষণ না আপনি বন্ধ করছেন"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"এখনই"</string>
- <string name="media_transfer_this_device_name" msgid="2357329267148436433">"এই ফোন"</string>
+ <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"এই ফোন"</string>
+ <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+ <skip />
<string name="media_transfer_this_phone" msgid="7194341457812151531">"এই ফোনটি"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"কানেক্ট করতে সমস্যা হচ্ছে। ডিভাইস বন্ধ করে আবার চালু করুন"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ওয়্যার অডিও ডিভাইস"</string>
@@ -591,7 +595,9 @@
<string name="user_set_lock_button" msgid="1427128184982594856">"লক সেট করুন"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g>-এ পাল্টান"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"নতুন ব্যবহারকারী তৈরি করা হচ্ছে…"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"নতুন অতিথি তৈরি করা হচ্ছে…"</string>
<string name="add_user_failed" msgid="4809887794313944872">"নতুন ব্যবহারকারী যোগ করা যায়নি"</string>
+ <string name="add_guest_failed" msgid="8074548434469843443">"নতুন অতিথি তৈরি করা যায়নি"</string>
<string name="user_nickname" msgid="262624187455825083">"বিশেষ নাম"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"অতিথি যোগ করুন"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"অতিথি সরান"</string>
@@ -644,4 +650,10 @@
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"কাস্ট সম্পর্কিত তথ্য"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"একটি প্রোফাইল ছবি বেছে নিন"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"ডিফল্ট ব্যবহারকারীর আইকন"</string>
+ <!-- no translation found for physical_keyboard_title (4811935435315835220) -->
+ <skip />
+ <!-- no translation found for keyboard_layout_dialog_title (3927180147005616290) -->
+ <skip />
+ <!-- no translation found for keyboard_layout_default_label (1997292217218546957) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml
index 77711cc494a9..c17532b3e811 100644
--- a/packages/SettingsLib/res/values-bs/strings.xml
+++ b/packages/SettingsLib/res/values-bs/strings.xml
@@ -533,6 +533,8 @@
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Manje vremena."</string>
<string name="cancel" msgid="5665114069455378395">"Otkaži"</string>
<string name="okay" msgid="949938843324579502">"Uredu"</string>
+ <!-- no translation found for done (381184316122520313) -->
+ <skip />
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarmi i podsjetnici"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Dozvoli postavljanje alarma i podsjetnika"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmi i podsjetnici"</string>
@@ -551,7 +553,9 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Pitaj svaki put"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"Dok ne isključite"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"Upravo"</string>
- <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Ovaj telefon"</string>
+ <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Ovaj telefon"</string>
+ <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+ <skip />
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Ovaj telefon"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Došlo je do problema prilikom povezivanja. Isključite, pa ponovo uključite uređaj"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Žičani audio uređaj"</string>
@@ -591,7 +595,9 @@
<string name="user_set_lock_button" msgid="1427128184982594856">"Postaviti zaključavanje"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Prebaci na korisnika <xliff:g id="USER_NAME">%s</xliff:g>"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Kreiranje novog korisnika…"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Kreiranje novog gosta…"</string>
<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>
<string name="guest_new_guest" msgid="3482026122932643557">"Dodaj gosta"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Ukloni gosta"</string>
@@ -644,4 +650,7 @@
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Podaci o emitiranju"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Odaberite sliku profila"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"Zadana ikona korisnika"</string>
+ <string name="physical_keyboard_title" msgid="4811935435315835220">"Fizička tastatura"</string>
+ <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Odaberite raspored tastature"</string>
+ <string name="keyboard_layout_default_label" msgid="1997292217218546957">"Zadano"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index 92e7c1ac4978..c7f9ce6fc212 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -533,6 +533,8 @@
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Menys temps"</string>
<string name="cancel" msgid="5665114069455378395">"Cancel·la"</string>
<string name="okay" msgid="949938843324579502">"D\'acord"</string>
+ <!-- no translation found for done (381184316122520313) -->
+ <skip />
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarmes i recordatoris"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Permet la configuració d\'alarmes i recordatoris"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmes i recordatoris"</string>
@@ -551,7 +553,9 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Pregunta sempre"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"Fins que no el desactivis"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"Ara mateix"</string>
- <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Aquest telèfon"</string>
+ <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Aquest telèfon"</string>
+ <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+ <skip />
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Aquest telèfon"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Hi ha hagut un problema amb la connexió. Apaga el dispositiu i torna\'l a encendre."</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Dispositiu d\'àudio amb cable"</string>
@@ -591,7 +595,9 @@
<string name="user_set_lock_button" msgid="1427128184982594856">"Defineix un bloqueig"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Canvia a <xliff:g id="USER_NAME">%s</xliff:g>"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"S\'està creant l\'usuari…"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"S\'està creant un convidat…"</string>
<string name="add_user_failed" msgid="4809887794313944872">"No s\'ha pogut crear l\'usuari"</string>
+ <string name="add_guest_failed" msgid="8074548434469843443">"No s\'ha pogut crear un convidat"</string>
<string name="user_nickname" msgid="262624187455825083">"Àlies"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Afegeix un convidat"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Suprimeix el convidat"</string>
@@ -644,4 +650,7 @@
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Informació d\'emissió"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Tria una foto de perfil"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"Icona d\'usuari predeterminat"</string>
+ <string name="physical_keyboard_title" msgid="4811935435315835220">"Teclat físic"</string>
+ <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Tria una disposició de teclat"</string>
+ <string name="keyboard_layout_default_label" msgid="1997292217218546957">"Predeterminat"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml
index 014eda90bc11..d7c8ed2a453f 100644
--- a/packages/SettingsLib/res/values-cs/strings.xml
+++ b/packages/SettingsLib/res/values-cs/strings.xml
@@ -533,6 +533,8 @@
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Kratší doba"</string>
<string name="cancel" msgid="5665114069455378395">"Zrušit"</string>
<string name="okay" msgid="949938843324579502">"OK"</string>
+ <!-- no translation found for done (381184316122520313) -->
+ <skip />
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"Budíky a připomenutí"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Povolit nastavování budíků a připomenutí"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Budíky a připomenutí"</string>
@@ -551,7 +553,9 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Pokaždé se zeptat"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"Dokud funkci nevypnete"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"Právě teď"</string>
- <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Tento telefon"</string>
+ <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Tento telefon"</string>
+ <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+ <skip />
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Tento telefon"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problém s připojením. Vypněte zařízení a znovu jej zapněte"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Kabelové audiozařízení"</string>
@@ -591,7 +595,9 @@
<string name="user_set_lock_button" msgid="1427128184982594856">"Nastavit zámek"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Přepnout na uživatele <xliff:g id="USER_NAME">%s</xliff:g>"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Vytváření nového uživatele…"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Vytváření nového hosta…"</string>
<string name="add_user_failed" msgid="4809887794313944872">"Nového uživatele se nepodařilo vytvořit"</string>
+ <string name="add_guest_failed" msgid="8074548434469843443">"Vytvoření nového hosta se nezdařilo"</string>
<string name="user_nickname" msgid="262624187455825083">"Přezdívka"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Přidat hosta"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Odstranit hosta"</string>
@@ -644,4 +650,7 @@
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Info o odesílání"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Vyberte profilový obrázek"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"Výchozí uživatelská ikona"</string>
+ <string name="physical_keyboard_title" msgid="4811935435315835220">"Fyzická klávesnice"</string>
+ <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Zvolte rozložení klávesnice"</string>
+ <string name="keyboard_layout_default_label" msgid="1997292217218546957">"Výchozí"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
index d10975de7302..19caaa529286 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -533,6 +533,8 @@
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Mindre tid."</string>
<string name="cancel" msgid="5665114069455378395">"Annuller"</string>
<string name="okay" msgid="949938843324579502">"OK"</string>
+ <!-- no translation found for done (381184316122520313) -->
+ <skip />
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarmer og påmindelser"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Tillad indstilling af alarmer og påmindelser"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmer og påmindelser"</string>
@@ -551,7 +553,9 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Spørg hver gang"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"Indtil du deaktiverer"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"Lige nu"</string>
- <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Denne telefon"</string>
+ <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Denne telefon"</string>
+ <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+ <skip />
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Denne telefon"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Der kunne ikke oprettes forbindelse. Sluk og tænd enheden"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Lydenhed med ledning"</string>
@@ -591,7 +595,9 @@
<string name="user_set_lock_button" msgid="1427128184982594856">"Konfigurer låseskærmen"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Skift til <xliff:g id="USER_NAME">%s</xliff:g>"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Opretter ny bruger…"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Opretter ny gæst…"</string>
<string name="add_user_failed" msgid="4809887794313944872">"Der kunne ikke oprettes en ny bruger"</string>
+ <string name="add_guest_failed" msgid="8074548434469843443">"Der kunne ikke oprettes en ny gæst"</string>
<string name="user_nickname" msgid="262624187455825083">"Kaldenavn"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Tilføj gæst"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Fjern gæsten"</string>
@@ -644,4 +650,7 @@
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Cast-oplysninger"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Vælg et profilbillede"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"Ikon for standardbruger"</string>
+ <string name="physical_keyboard_title" msgid="4811935435315835220">"Fysisk tastatur"</string>
+ <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Vælg tastaturlayout"</string>
+ <string name="keyboard_layout_default_label" msgid="1997292217218546957">"Standard"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index 9b8b3b593156..594129b1678e 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -95,7 +95,7 @@
<string name="bluetooth_disconnecting" msgid="7638892134401574338">"Verbindung wird getrennt..."</string>
<string name="bluetooth_connecting" msgid="5871702668260192755">"Verbindung wird hergestellt..."</string>
<string name="bluetooth_connected" msgid="8065345572198502293">"Mit <xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g> verbunden"</string>
- <string name="bluetooth_pairing" msgid="4269046942588193600">"Verbindung wird hergestellt…"</string>
+ <string name="bluetooth_pairing" msgid="4269046942588193600">"Wird gekoppelt…"</string>
<string name="bluetooth_connected_no_headset" msgid="2224101138659967604">"Mit <xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g> verbunden (kein Telefon-Audio)"</string>
<string name="bluetooth_connected_no_a2dp" msgid="8566874395813947092">"Mit <xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g> verbunden (kein Medien-Audio)"</string>
<string name="bluetooth_connected_no_map" msgid="3381860077002724689">"Mit <xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g> verbunden (kein Nachrichtenzugriff)"</string>
@@ -533,6 +533,8 @@
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Weniger Zeit."</string>
<string name="cancel" msgid="5665114069455378395">"Abbrechen"</string>
<string name="okay" msgid="949938843324579502">"OK"</string>
+ <!-- no translation found for done (381184316122520313) -->
+ <skip />
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"Wecker und Erinnerungen"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Erlauben, Wecker und Erinnerungen einzurichten"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Wecker und Erinnerungen"</string>
@@ -551,7 +553,9 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Jedes Mal fragen"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"Bis zur Deaktivierung"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"Gerade eben"</string>
- <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Dieses Smartphone"</string>
+ <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Dieses Smartphone"</string>
+ <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+ <skip />
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Dieses Smartphone"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Verbindung kann nicht hergestellt werden. Schalte das Gerät aus &amp; und wieder ein."</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Netzbetriebenes Audiogerät"</string>
@@ -591,7 +595,9 @@
<string name="user_set_lock_button" msgid="1427128184982594856">"Sperre einrichten"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Zu <xliff:g id="USER_NAME">%s</xliff:g> wechseln"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Neuer Nutzer wird erstellt…"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Neuer Gast wird erstellt…"</string>
<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>
<string name="guest_new_guest" msgid="3482026122932643557">"Gast hinzufügen"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Gast entfernen"</string>
@@ -644,4 +650,7 @@
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Streaming-Info"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Profilbild auswählen"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"Standardmäßiges Nutzersymbol"</string>
+ <string name="physical_keyboard_title" msgid="4811935435315835220">"Physische Tastatur"</string>
+ <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Tastaturlayout wählen"</string>
+ <string name="keyboard_layout_default_label" msgid="1997292217218546957">"Standard"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index cb6ec174de0b..b913da79bde1 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -533,6 +533,8 @@
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Λιγότερη ώρα."</string>
<string name="cancel" msgid="5665114069455378395">"Ακύρωση"</string>
<string name="okay" msgid="949938843324579502">"ΟΚ"</string>
+ <!-- no translation found for done (381184316122520313) -->
+ <skip />
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"Ξυπνητήρια και ειδοποιήσεις"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Να επιτρέπεται ο ορισμός ξυπνητ. και υπενθυμίσεων"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Ξυπνητήρια και υπενθυμίσεις"</string>
@@ -551,7 +553,9 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Να ερωτώμαι κάθε φορά"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"Μέχρι την απενεργοποίηση"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"Μόλις τώρα"</string>
- <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Αυτό το τηλέφωνο"</string>
+ <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Αυτό το τηλέφωνο"</string>
+ <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+ <skip />
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Αυτό το τηλέφωνο"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Πρόβλημα κατά τη σύνδεση. Απενεργοποιήστε τη συσκευή και ενεργοποιήστε την ξανά"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Ενσύρματη συσκευή ήχου"</string>
@@ -591,7 +595,9 @@
<string name="user_set_lock_button" msgid="1427128184982594856">"Ορισμός κλειδώματος"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Εναλλαγή σε <xliff:g id="USER_NAME">%s</xliff:g>"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Δημιουργία νέου χρήστη…"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Δημιουργία νέου προσκεκλημένου…"</string>
<string name="add_user_failed" msgid="4809887794313944872">"Η δημιουργία νέου χρήστη απέτυχε"</string>
+ <string name="add_guest_failed" msgid="8074548434469843443">"Αποτυχία δημιουργίας νέου προσκεκλημένου"</string>
<string name="user_nickname" msgid="262624187455825083">"Ψευδώνυμο"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Προσθήκη επισκέπτη"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Κατάργηση επισκέπτη"</string>
@@ -644,4 +650,7 @@
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Πληροφορίες ηθοποιών"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Επιλογή φωτογραφίας προφίλ"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"Προεπιλεγμένο εικονίδιο χρήστη"</string>
+ <string name="physical_keyboard_title" msgid="4811935435315835220">"Φυσικό πληκτρολόγιο"</string>
+ <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Επιλέξτε διάταξη πληκτρολογίου"</string>
+ <string name="keyboard_layout_default_label" msgid="1997292217218546957">"Προεπιλογή"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml
index c2c14b4f785d..d6dce9960c21 100644
--- a/packages/SettingsLib/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
@@ -533,6 +533,7 @@
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Less time."</string>
<string name="cancel" msgid="5665114069455378395">"Cancel"</string>
<string name="okay" msgid="949938843324579502">"OK"</string>
+ <string name="done" msgid="381184316122520313">"Done"</string>
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarms and reminders"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Allow setting alarms and reminders"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarms &amp; reminders"</string>
@@ -551,7 +552,9 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Ask every time"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"Until you turn off"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"Just now"</string>
- <string name="media_transfer_this_device_name" msgid="2357329267148436433">"This phone"</string>
+ <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"This phone"</string>
+ <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+ <skip />
<string name="media_transfer_this_phone" msgid="7194341457812151531">"This phone"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problem connecting. Turn device off and back on"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Wired audio device"</string>
@@ -591,7 +594,9 @@
<string name="user_set_lock_button" msgid="1427128184982594856">"Set lock"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Switch to <xliff:g id="USER_NAME">%s</xliff:g>"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Creating new user…"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Creating new guest…"</string>
<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>
<string name="guest_new_guest" msgid="3482026122932643557">"Add guest"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Remove guest"</string>
@@ -644,4 +649,10 @@
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Cast info"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Choose a profile picture"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"Default user icon"</string>
+ <!-- no translation found for physical_keyboard_title (4811935435315835220) -->
+ <skip />
+ <!-- no translation found for keyboard_layout_dialog_title (3927180147005616290) -->
+ <skip />
+ <!-- no translation found for keyboard_layout_default_label (1997292217218546957) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-en-rCA/strings.xml b/packages/SettingsLib/res/values-en-rCA/strings.xml
index 91d4a31d0e36..76d1a94bd7aa 100644
--- a/packages/SettingsLib/res/values-en-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-en-rCA/strings.xml
@@ -533,6 +533,7 @@
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Less time."</string>
<string name="cancel" msgid="5665114069455378395">"Cancel"</string>
<string name="okay" msgid="949938843324579502">"OK"</string>
+ <string name="done" msgid="381184316122520313">"Done"</string>
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarms and reminders"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Allow setting alarms and reminders"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarms &amp; reminders"</string>
@@ -551,7 +552,9 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Ask every time"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"Until you turn off"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"Just now"</string>
- <string name="media_transfer_this_device_name" msgid="2357329267148436433">"This phone"</string>
+ <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"This phone"</string>
+ <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+ <skip />
<string name="media_transfer_this_phone" msgid="7194341457812151531">"This phone"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problem connecting. Turn device off and back on"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Wired audio device"</string>
@@ -591,7 +594,9 @@
<string name="user_set_lock_button" msgid="1427128184982594856">"Set lock"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Switch to <xliff:g id="USER_NAME">%s</xliff:g>"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Creating new user…"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Creating new guest…"</string>
<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>
<string name="guest_new_guest" msgid="3482026122932643557">"Add guest"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Remove guest"</string>
@@ -644,4 +649,10 @@
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Cast info"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Choose a profile picture"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"Default user icon"</string>
+ <!-- no translation found for physical_keyboard_title (4811935435315835220) -->
+ <skip />
+ <!-- no translation found for keyboard_layout_dialog_title (3927180147005616290) -->
+ <skip />
+ <!-- no translation found for keyboard_layout_default_label (1997292217218546957) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml
index c2c14b4f785d..d6dce9960c21 100644
--- a/packages/SettingsLib/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
@@ -533,6 +533,7 @@
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Less time."</string>
<string name="cancel" msgid="5665114069455378395">"Cancel"</string>
<string name="okay" msgid="949938843324579502">"OK"</string>
+ <string name="done" msgid="381184316122520313">"Done"</string>
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarms and reminders"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Allow setting alarms and reminders"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarms &amp; reminders"</string>
@@ -551,7 +552,9 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Ask every time"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"Until you turn off"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"Just now"</string>
- <string name="media_transfer_this_device_name" msgid="2357329267148436433">"This phone"</string>
+ <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"This phone"</string>
+ <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+ <skip />
<string name="media_transfer_this_phone" msgid="7194341457812151531">"This phone"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problem connecting. Turn device off and back on"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Wired audio device"</string>
@@ -591,7 +594,9 @@
<string name="user_set_lock_button" msgid="1427128184982594856">"Set lock"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Switch to <xliff:g id="USER_NAME">%s</xliff:g>"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Creating new user…"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Creating new guest…"</string>
<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>
<string name="guest_new_guest" msgid="3482026122932643557">"Add guest"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Remove guest"</string>
@@ -644,4 +649,10 @@
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Cast info"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Choose a profile picture"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"Default user icon"</string>
+ <!-- no translation found for physical_keyboard_title (4811935435315835220) -->
+ <skip />
+ <!-- no translation found for keyboard_layout_dialog_title (3927180147005616290) -->
+ <skip />
+ <!-- no translation found for keyboard_layout_default_label (1997292217218546957) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml
index c2c14b4f785d..d6dce9960c21 100644
--- a/packages/SettingsLib/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
@@ -533,6 +533,7 @@
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Less time."</string>
<string name="cancel" msgid="5665114069455378395">"Cancel"</string>
<string name="okay" msgid="949938843324579502">"OK"</string>
+ <string name="done" msgid="381184316122520313">"Done"</string>
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarms and reminders"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Allow setting alarms and reminders"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarms &amp; reminders"</string>
@@ -551,7 +552,9 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Ask every time"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"Until you turn off"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"Just now"</string>
- <string name="media_transfer_this_device_name" msgid="2357329267148436433">"This phone"</string>
+ <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"This phone"</string>
+ <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+ <skip />
<string name="media_transfer_this_phone" msgid="7194341457812151531">"This phone"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problem connecting. Turn device off and back on"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Wired audio device"</string>
@@ -591,7 +594,9 @@
<string name="user_set_lock_button" msgid="1427128184982594856">"Set lock"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Switch to <xliff:g id="USER_NAME">%s</xliff:g>"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Creating new user…"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Creating new guest…"</string>
<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>
<string name="guest_new_guest" msgid="3482026122932643557">"Add guest"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Remove guest"</string>
@@ -644,4 +649,10 @@
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Cast info"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Choose a profile picture"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"Default user icon"</string>
+ <!-- no translation found for physical_keyboard_title (4811935435315835220) -->
+ <skip />
+ <!-- no translation found for keyboard_layout_dialog_title (3927180147005616290) -->
+ <skip />
+ <!-- no translation found for keyboard_layout_default_label (1997292217218546957) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-en-rXC/strings.xml b/packages/SettingsLib/res/values-en-rXC/strings.xml
index ebb1d0e596c6..f02d0c5ad376 100644
--- a/packages/SettingsLib/res/values-en-rXC/strings.xml
+++ b/packages/SettingsLib/res/values-en-rXC/strings.xml
@@ -533,6 +533,7 @@
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‏‏‏‏‎‏‏‎‎‎‏‎‏‎‎‎‎‏‎‏‏‏‏‏‏‏‏‏‎‎‎‎‏‎‎‏‏‎‎‏‎‏‎‎‎‎‏‎‎‎‏‎‎‎‏‎‎‏‏‎‏‎Less time.‎‏‎‎‏‎"</string>
<string name="cancel" msgid="5665114069455378395">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‎‏‏‏‎‏‎‎‏‏‏‏‎‏‎‎‎‎‏‏‏‎‎‏‏‏‎‏‏‎‎‏‎‏‎‎‏‏‏‏‏‎‏‎‎‏‎‎‏‎‏‏‏‏‏‎‏‏‎‏‏‎Cancel‎‏‎‎‏‎"</string>
<string name="okay" msgid="949938843324579502">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‎‏‏‎‏‎‎‏‎‏‏‏‎‏‏‎‏‏‏‎‎‎‏‎‏‏‎‎‎‎‏‎‏‎‎‏‎‏‎‏‏‎‏‎‎‏‏‏‏‏‏‏‎‏‎‏‎‏‏‏‎‎OK‎‏‎‎‏‎"</string>
+ <string name="done" msgid="381184316122520313">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‎‏‏‏‎‏‎‏‎‎‏‎‏‎‎‎‏‏‏‏‎‏‎‎‎‏‏‏‎‏‏‎‏‎‏‏‎‎‎‏‏‎‏‏‏‎‏‏‎‏‏‎‏‎‏‏‏‏‏‎‎‏‎Done‎‏‎‎‏‎"</string>
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‎‎‎‎‎‎‎‎‎‎‏‏‎‎‎‏‎‏‎‎‎‎‏‏‎‎‎‎‎‎‏‎‏‏‎‏‏‏‎‏‏‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‏‎‎Alarms and reminders‎‏‎‎‏‎"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‎‎‏‎‎‏‎‎‎‏‏‎‎‎‏‎‎‎‎‎‎‏‎‎‏‎‏‏‏‏‎‏‎‏‏‏‎‏‎‎‏‎‏‎‎‏‏‏‎‏‏‎‎‎‎‏‎‏‏‏‎‎Allow setting alarms and reminders‎‏‎‎‏‎"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‏‏‎‏‎‎‏‏‎‎‏‏‎‏‎‏‏‎‎‏‎‏‎‎‏‎‎‏‎‏‏‏‏‏‏‎‏‎‎‏‏‏‏‏‎‏‎‏‎‎‏‏‎‏‏‎‏‎‎‎‎‎Alarms &amp; reminders‎‏‎‎‏‎"</string>
@@ -551,7 +552,9 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‏‏‎‎‏‎‎‏‎‏‏‎‏‏‎‏‏‎‏‏‏‎‎‏‏‏‏‏‎‎‎‏‎‏‏‎‎‏‏‎‏‏‏‏‏‎‎‎‏‎‏‏‏‎‎‎‎‎‏‏‎Ask every time‎‏‎‎‏‎"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‏‏‏‎‎‏‎‏‎‏‏‏‎‏‎‎‏‏‏‎‏‏‏‏‏‏‎‏‎‎‎‏‎‏‎‏‎‎‎‎‏‏‏‎‎‏‎‎‎‏‎‏‎‎‏‎‏‎‏‏‎Until you turn off‎‏‎‎‏‎"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‏‎‎‏‏‎‏‏‎‏‏‏‏‏‏‎‏‏‏‏‎‎‏‏‎‎‎‎‎‏‎‏‏‏‎‏‎‎‎‏‏‏‎‎‏‎‏‏‏‎‏‏‎‎‏‎‎‎‏‏‎Just now‎‏‎‎‏‎"</string>
- <string name="media_transfer_this_device_name" msgid="2357329267148436433">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‎‎‎‎‏‎‏‏‎‏‏‎‏‏‏‎‏‎‏‎‎‏‏‏‏‎‏‎‏‎‎‏‎‎‏‏‎‎‎‎‎‎‏‏‏‎‏‏‎‎‏‏‏‏‎‏‎‎‎‏‎This phone‎‏‎‎‏‎"</string>
+ <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‎‎‎‎‏‎‏‏‎‏‏‎‏‏‏‎‏‎‏‎‎‏‏‏‏‎‏‎‏‎‎‏‎‎‏‏‎‎‎‎‎‎‏‏‏‎‏‏‎‎‏‏‏‏‎‏‎‎‎‏‎This phone‎‏‎‎‏‎"</string>
+ <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+ <skip />
<string name="media_transfer_this_phone" msgid="7194341457812151531">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‎‎‏‏‏‏‎‏‎‏‏‏‎‏‏‎‏‏‏‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‏‏‏‎‎‎‎‏‎‎‏‎‏‏‏‎‎‏‏‏‎‏‎‏‏‎This phone‎‏‎‎‏‎"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‏‏‎‎‎‎‎‎‏‏‏‎‏‎‎‎‏‎‎‏‎‎‏‎‏‎‏‎‎‎‎‏‎‎‎‏‎‎‎‎‎‎‏‎‎‏‎‎‏‎‏‎‎‎‏‏‏‎‎‎‏‎Problem connecting. Turn device off &amp; back on‎‏‎‎‏‎"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‏‏‏‎‏‏‎‏‏‏‎‏‎‎‎‎‎‏‏‎‎‎‎‎‏‏‏‎‎‏‏‎‏‎‏‎‏‏‎‎‏‏‎‏‎‎‎‏‏‎‎‎‏‏‏‎‎‎‏‏‏‎Wired audio device‎‏‎‎‏‎"</string>
@@ -591,7 +594,9 @@
<string name="user_set_lock_button" msgid="1427128184982594856">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‏‏‎‎‏‏‏‏‎‎‏‏‏‎‎‎‏‎‏‏‎‏‏‎‎‎‎‏‎‏‏‏‏‎‎‎‏‎‏‏‎‏‎‏‎‏‏‏‏‎‎‏‎‏‎‎‏‎‏‎‎‎‎Set lock‎‏‎‎‏‎"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‎‎‎‎‏‏‎‎‏‏‎‏‏‎‏‏‎‎‏‏‎‎‎‏‎‏‎‎‎‎‏‏‎‎‎‎‎‎‏‎‎‎‎‏‎‎‏‏‏‎‏‏‏‏‎‏‏‏‏‏‎Switch to ‎‏‎‎‏‏‎<xliff:g id="USER_NAME">%s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‎‏‎‎‎‏‏‎‎‎‎‎‎‏‎‏‏‎‏‎‎‏‎‎‎‏‎‏‏‏‎‏‎‏‎‏‏‎‎‎‏‎‏‏‏‏‎‏‎‎‏‏‎‎‎‎‎‏‏‏‎Creating new user…‎‏‎‎‏‎"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‎‏‏‏‏‎‏‏‏‏‎‎‎‏‏‏‏‎‎‎‎‏‎‏‏‏‏‎‎‏‏‏‏‏‎‎‎‎‎‎‏‏‏‎‎‏‏‎‎‎‏‎‏‎‎‏‎‎‎‏‎‎Creating new guest…‎‏‎‎‏‎"</string>
<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>
<string name="guest_new_guest" msgid="3482026122932643557">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‏‎‎‎‎‎‏‎‏‎‎‏‎‏‎‏‎‎‏‎‎‎‏‎‎‏‏‏‏‎‏‏‎‏‏‎‎‎‎‎‎‎‏‏‏‏‏‏‎‎‏‏‎‏‏‏‎‎‏‎‏‎Add guest‎‏‎‎‏‎"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‏‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‎‏‎‎‎‏‎‎‏‎‏‎‏‏‏‎‏‎‏‎‎‏‎‎‏‏‎‎‎‎‎‎‏‏‎‎‏‎‎‏‏‏‎‎‎‎Remove guest‎‏‎‎‏‎"</string>
@@ -644,4 +649,7 @@
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‏‏‎‎‎‎‎‎‎‏‏‎‎‏‎‎‏‏‏‎‏‏‏‏‏‎‏‏‏‏‎‏‎‎‏‏‏‏‏‎‎‏‎‎‎‎‎‎‏‏‏‎‏‏‎‎‏‏‏‎‎‎Cast Info‎‏‎‎‏‎"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‏‎‏‎‏‏‏‎‏‏‏‎‎‏‏‎‎‏‎‎‏‎‎‏‎‏‎‎‎‎‏‏‎‏‎‎‏‎‎‎‏‏‎‏‏‎‎‎‏‎‏‏‎‏‏‎‏‏‏‎‎‎Choose a profile picture‎‏‎‎‏‎"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‏‏‎‏‎‏‏‏‏‎‏‎‎‏‎‏‎‎‏‏‏‎‎‏‎‏‏‏‎‏‏‎‏‎‏‎‎‎‎‎‎‏‏‏‎‏‎‎‎‏‏‏‏‏‏‎‏‏‏‏‎‎Default user icon‎‏‎‎‏‎"</string>
+ <string name="physical_keyboard_title" msgid="4811935435315835220">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‎‎‎‏‎‏‏‎‎‎‏‏‏‎‏‏‎‏‏‎‏‏‏‎‎‏‎‎‎‏‎‏‎‎‎‎‎‎‎‎‏‏‏‎‏‎‏‏‏‎‎‎‏‎‏‎‏‎‏‎‎‎Physical keyboard‎‏‎‎‏‎"</string>
+ <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‏‎‏‏‎‏‎‎‎‎‎‎‎‎‎‏‎‎‏‎‏‏‎‎‎‏‎‎‏‎‏‎‏‏‏‏‏‎‎‏‏‏‏‎‎‎‏‏‏‎‎‎‎‏‎‏‎‎‎‏‎‎Choose keyboard layout‎‏‎‎‏‎"</string>
+ <string name="keyboard_layout_default_label" msgid="1997292217218546957">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‏‏‏‎‏‏‏‎‏‏‎‏‏‏‏‏‎‎‏‏‏‎‏‎‏‏‎‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‏‎‏‏‏‏‎‏‎‎‎‎‏‏‎‏‎Default‎‏‎‎‏‎"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index 254d41ed133a..49b4b518fbd0 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -533,6 +533,8 @@
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Menos tiempo"</string>
<string name="cancel" msgid="5665114069455378395">"Cancelar"</string>
<string name="okay" msgid="949938843324579502">"Aceptar"</string>
+ <!-- no translation found for done (381184316122520313) -->
+ <skip />
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarmas y recordatorios"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Permitir configuración de alarmas y recordatorios"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmas y recordatorios"</string>
@@ -551,7 +553,9 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Preguntar siempre"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"Hasta que lo desactives"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"Recién"</string>
- <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Este teléfono"</string>
+ <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Este teléfono"</string>
+ <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+ <skip />
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Este teléfono"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Error al establecer la conexión. Apaga el dispositivo y vuelve a encenderlo."</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Dispositivo de audio con cable"</string>
@@ -591,7 +595,9 @@
<string name="user_set_lock_button" msgid="1427128184982594856">"Configurar bloqueo"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Cambiar a <xliff:g id="USER_NAME">%s</xliff:g>"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Creando usuario nuevo…"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Creando nuevo invitado…"</string>
<string name="add_user_failed" msgid="4809887794313944872">"No se pudo crear el usuario nuevo"</string>
+ <string name="add_guest_failed" msgid="8074548434469843443">"No se pudo crear un nuevo invitado"</string>
<string name="user_nickname" msgid="262624187455825083">"Sobrenombre"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Agregar invitado"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Quitar invitado"</string>
@@ -644,4 +650,10 @@
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Info de reparto"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Elige una foto de perfil"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"Ícono de usuario predeterminado"</string>
+ <!-- no translation found for physical_keyboard_title (4811935435315835220) -->
+ <skip />
+ <!-- no translation found for keyboard_layout_dialog_title (3927180147005616290) -->
+ <skip />
+ <!-- no translation found for keyboard_layout_default_label (1997292217218546957) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index 447475fb4218..d34beed8b19e 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -533,6 +533,8 @@
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Menos tiempo."</string>
<string name="cancel" msgid="5665114069455378395">"Cancelar"</string>
<string name="okay" msgid="949938843324579502">"Aceptar"</string>
+ <!-- no translation found for done (381184316122520313) -->
+ <skip />
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarmas y recordatorios"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Permitir la programación de alarmas y recordatorios"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmas y recordatorios"</string>
@@ -551,7 +553,9 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Preguntar siempre"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"Hasta que lo desactives"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"justo ahora"</string>
- <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Este teléfono"</string>
+ <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Este teléfono"</string>
+ <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+ <skip />
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Este teléfono"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"No se ha podido conectar; reinicia el dispositivo"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Dispositivo de audio con cable"</string>
@@ -591,7 +595,9 @@
<string name="user_set_lock_button" msgid="1427128184982594856">"Establecer bloqueo"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Cambiar a <xliff:g id="USER_NAME">%s</xliff:g>"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Creando usuario…"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Creando nuevo invitado…"</string>
<string name="add_user_failed" msgid="4809887794313944872">"No se ha podido crear el usuario"</string>
+ <string name="add_guest_failed" msgid="8074548434469843443">"No se ha podido crear un nuevo invitado"</string>
<string name="user_nickname" msgid="262624187455825083">"Apodo"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Añadir invitado"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Quitar invitado"</string>
@@ -639,9 +645,12 @@
<string name="accessibility_no_calling" msgid="3540827068323895748">"Sin llamadas."</string>
<string name="dream_complication_title_time" msgid="701747800712893499">"Hora"</string>
<string name="dream_complication_title_date" msgid="8661176085446135789">"Fecha"</string>
- <string name="dream_complication_title_weather" msgid="598609151677172783">"Info. meteorológica"</string>
+ <string name="dream_complication_title_weather" msgid="598609151677172783">"Tiempo"</string>
<string name="dream_complication_title_aqi" msgid="4587552608957834110">"Calidad del aire"</string>
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Info. de emisión"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Elige una imagen de perfil"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"Icono de usuario predeterminado"</string>
+ <string name="physical_keyboard_title" msgid="4811935435315835220">"Teclado físico"</string>
+ <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Elige el diseño del teclado"</string>
+ <string name="keyboard_layout_default_label" msgid="1997292217218546957">"Predeterminado"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml
index 2c8a943f4029..a5fa201e9daa 100644
--- a/packages/SettingsLib/res/values-et/strings.xml
+++ b/packages/SettingsLib/res/values-et/strings.xml
@@ -533,6 +533,8 @@
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Lühem aeg."</string>
<string name="cancel" msgid="5665114069455378395">"Tühista"</string>
<string name="okay" msgid="949938843324579502">"OK"</string>
+ <!-- no translation found for done (381184316122520313) -->
+ <skip />
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarmid ja meeldetuletused"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Luba alarmide ja meeldetuletuste määramine"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmid ja meeldetuletused"</string>
@@ -551,7 +553,9 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Küsi iga kord"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"Kuni välja lülitate"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"Äsja"</string>
- <string name="media_transfer_this_device_name" msgid="2357329267148436433">"See telefon"</string>
+ <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"See telefon"</string>
+ <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+ <skip />
<string name="media_transfer_this_phone" msgid="7194341457812151531">"See telefon"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Probleem ühendamisel. Lülitage seade välja ja uuesti sisse"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Juhtmega heliseade"</string>
@@ -591,7 +595,9 @@
<string name="user_set_lock_button" msgid="1427128184982594856">"Määra lukk"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Lülita kasutajale <xliff:g id="USER_NAME">%s</xliff:g>"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Uue kasutaja loomine …"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Uue külalise loomine …"</string>
<string name="add_user_failed" msgid="4809887794313944872">"Uue kasutaja loomine ebaõnnestus"</string>
+ <string name="add_guest_failed" msgid="8074548434469843443">"Uue külalise loomine ei õnnestunud"</string>
<string name="user_nickname" msgid="262624187455825083">"Hüüdnimi"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Lisa külaline"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Eemalda külaline"</string>
@@ -644,4 +650,7 @@
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Osatäitjate teave"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Valige profiilipilt"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"Vaikekasutajaikoon"</string>
+ <string name="physical_keyboard_title" msgid="4811935435315835220">"Füüsiline klaviatuur"</string>
+ <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Klaviatuuri paigutuse valimine"</string>
+ <string name="keyboard_layout_default_label" msgid="1997292217218546957">"Vaikimisi"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml
index 019119e6af3e..13ffee7a57c4 100644
--- a/packages/SettingsLib/res/values-eu/strings.xml
+++ b/packages/SettingsLib/res/values-eu/strings.xml
@@ -533,6 +533,8 @@
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Denbora gutxiago."</string>
<string name="cancel" msgid="5665114069455378395">"Utzi"</string>
<string name="okay" msgid="949938843324579502">"Ados"</string>
+ <!-- no translation found for done (381184316122520313) -->
+ <skip />
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarmak eta abisuak"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Eman alarmak eta abisuak ezartzeko baimena"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmak eta abisuak"</string>
@@ -551,7 +553,9 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Galdetu beti"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"Zuk desaktibatu arte"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"Oraintxe"</string>
- <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Telefono hau"</string>
+ <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Telefono hau"</string>
+ <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+ <skip />
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Telefono hau"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Arazo bat izan da konektatzean. Itzali gailua eta pitz ezazu berriro."</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Audio-gailu kableduna"</string>
@@ -591,7 +595,9 @@
<string name="user_set_lock_button" msgid="1427128184982594856">"Ezarri blokeoa"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Aldatu <xliff:g id="USER_NAME">%s</xliff:g> erabiltzailera"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Beste erabiltzaile bat sortzen…"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Beste gonbidatu bat sortzen…"</string>
<string name="add_user_failed" msgid="4809887794313944872">"Ezin izan da sortu erabiltzailea"</string>
+ <string name="add_guest_failed" msgid="8074548434469843443">"Ezin izan da sortu beste gonbidatu bat"</string>
<string name="user_nickname" msgid="262624187455825083">"Goitizena"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Gehitu gonbidatua"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Kendu gonbidatua"</string>
@@ -644,4 +650,10 @@
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Igorpenari buruzko informazioa"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Aukeratu profileko argazki bat"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"Erabiltzaile lehenetsiaren ikonoa"</string>
+ <!-- no translation found for physical_keyboard_title (4811935435315835220) -->
+ <skip />
+ <!-- no translation found for keyboard_layout_dialog_title (3927180147005616290) -->
+ <skip />
+ <!-- no translation found for keyboard_layout_default_label (1997292217218546957) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index 5e7ee60be380..c50d247fdb3e 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -533,6 +533,8 @@
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"زمان کمتر."</string>
<string name="cancel" msgid="5665114069455378395">"لغو"</string>
<string name="okay" msgid="949938843324579502">"تأیید"</string>
+ <!-- no translation found for done (381184316122520313) -->
+ <skip />
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"زنگ‌های هشدار و یادآوری‌ها"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"مجاز کردن تنظیم زنگ ساعت و یادآوری"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"زنگ‌های ساعت و یادآوری‌ها"</string>
@@ -551,7 +553,9 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"هربار پرسیده شود"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"تا زمانی‌که آن را خاموش کنید"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"هم‌اکنون"</string>
- <string name="media_transfer_this_device_name" msgid="2357329267148436433">"این تلفن"</string>
+ <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"این تلفن"</string>
+ <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+ <skip />
<string name="media_transfer_this_phone" msgid="7194341457812151531">"این تلفن"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"مشکل در اتصال. دستگاه را خاموش و دوباره روشن کنید"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"دستگاه صوتی سیمی"</string>
@@ -591,7 +595,9 @@
<string name="user_set_lock_button" msgid="1427128184982594856">"تنظیم قفل"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"رفتن به <xliff:g id="USER_NAME">%s</xliff:g>"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"درحال ایجاد کاربر جدید…"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"درحال ایجاد مهمان جدید…"</string>
<string name="add_user_failed" msgid="4809887794313944872">"کاربر جدید ایجاد نشد"</string>
+ <string name="add_guest_failed" msgid="8074548434469843443">"مهمان جدید ایجاد نشد"</string>
<string name="user_nickname" msgid="262624187455825083">"نام مستعار"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"افزودن مهمان"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"حذف مهمان"</string>
@@ -644,4 +650,7 @@
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"اطلاعات ارسال محتوا"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"انتخاب عکس نمایه"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"نماد کاربر پیش‌فرض"</string>
+ <string name="physical_keyboard_title" msgid="4811935435315835220">"صفحه‌کلید فیزیکی"</string>
+ <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"انتخاب طرح‌بندی صفحه‌کلید"</string>
+ <string name="keyboard_layout_default_label" msgid="1997292217218546957">"پیش‌فرض"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index 04df99ff6b75..d958b81a29df 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -533,6 +533,8 @@
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Vähemmän aikaa"</string>
<string name="cancel" msgid="5665114069455378395">"Peru"</string>
<string name="okay" msgid="949938843324579502">"OK"</string>
+ <!-- no translation found for done (381184316122520313) -->
+ <skip />
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"Herätykset ja muistutukset"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Salli herätysten ja muistutusten lisääminen"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Herätykset ja muistutukset"</string>
@@ -551,7 +553,9 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Kysy aina"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"Kunnes laitat pois päältä"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"Äsken"</string>
- <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Tämä puhelin"</string>
+ <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Tämä puhelin"</string>
+ <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+ <skip />
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Tämä puhelin"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Yhteysvirhe. Sammuta laite ja käynnistä se uudelleen."</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Langallinen äänilaite"</string>
@@ -591,7 +595,9 @@
<string name="user_set_lock_button" msgid="1427128184982594856">"Aseta lukitus"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Vaihda tähän käyttäjään: <xliff:g id="USER_NAME">%s</xliff:g>"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Luodaan uutta käyttäjää…"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Luodaan uutta vierasta…"</string>
<string name="add_user_failed" msgid="4809887794313944872">"Uuden käyttäjän luominen epäonnistui"</string>
+ <string name="add_guest_failed" msgid="8074548434469843443">"Uutta vierasta ei voitu luoda"</string>
<string name="user_nickname" msgid="262624187455825083">"Lempinimi"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Lisää vieras"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Poista vieras"</string>
@@ -644,4 +650,7 @@
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Striimaustiedot"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Valitse profiilikuva"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"Oletuskäyttäjäkuvake"</string>
+ <string name="physical_keyboard_title" msgid="4811935435315835220">"Fyysinen näppäimistö"</string>
+ <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Valitse näppäimistöasettelu"</string>
+ <string name="keyboard_layout_default_label" msgid="1997292217218546957">"Oletus"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index 88ddd28d38e1..4999bda0212c 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -533,6 +533,8 @@
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Moins longtemps."</string>
<string name="cancel" msgid="5665114069455378395">"Annuler"</string>
<string name="okay" msgid="949938843324579502">"OK"</string>
+ <!-- no translation found for done (381184316122520313) -->
+ <skip />
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarmes et rappels"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Autoriser la création d\'alarmes et de rappels"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmes et rappels"</string>
@@ -551,7 +553,9 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Toujours demander"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"Jusqu\'à la désactivation"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"À l\'instant"</string>
- <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Ce téléphone"</string>
+ <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Ce téléphone"</string>
+ <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+ <skip />
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Ce téléphone"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problème de connexion. Éteingez et rallumez l\'appareil"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Appareil audio à câble"</string>
@@ -591,7 +595,9 @@
<string name="user_set_lock_button" msgid="1427128184982594856">"Définir verrouillage écran"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Passer à <xliff:g id="USER_NAME">%s</xliff:g>"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Création d\'un utilisateur en cours…"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Création d\'un nouvel invité en cours…"</string>
<string name="add_user_failed" msgid="4809887794313944872">"Impossible de créer un utilisateur"</string>
+ <string name="add_guest_failed" msgid="8074548434469843443">"Impossible de créer un nouvel invité"</string>
<string name="user_nickname" msgid="262624187455825083">"Pseudo"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Ajouter un invité"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Supprimer l\'invité"</string>
@@ -644,4 +650,10 @@
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Info diffusion"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Choisir une photo de profil"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"Icône d\'utilisateur par défaut"</string>
+ <!-- no translation found for physical_keyboard_title (4811935435315835220) -->
+ <skip />
+ <!-- no translation found for keyboard_layout_dialog_title (3927180147005616290) -->
+ <skip />
+ <!-- no translation found for keyboard_layout_default_label (1997292217218546957) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index c7034844b8d9..52575340f11f 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -533,6 +533,8 @@
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Moins longtemps."</string>
<string name="cancel" msgid="5665114069455378395">"Annuler"</string>
<string name="okay" msgid="949938843324579502">"OK"</string>
+ <!-- no translation found for done (381184316122520313) -->
+ <skip />
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarmes et rappels"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Autoriser à définir des alarmes et des rappels"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmes et rappels"</string>
@@ -551,7 +553,9 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Toujours demander"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"Jusqu\'à la désactivation"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"À l\'instant"</string>
- <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Ce téléphone"</string>
+ <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Ce téléphone"</string>
+ <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+ <skip />
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Ce téléphone"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problème de connexion. Éteignez l\'appareil, puis rallumez-le"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Appareil audio filaire"</string>
@@ -591,7 +595,9 @@
<string name="user_set_lock_button" msgid="1427128184982594856">"Définir verrouillage écran"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Passer à <xliff:g id="USER_NAME">%s</xliff:g>"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Création d\'un nouvel utilisateur…"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Création du profil invité…"</string>
<string name="add_user_failed" msgid="4809887794313944872">"Échec de la création d\'un utilisateur"</string>
+ <string name="add_guest_failed" msgid="8074548434469843443">"Impossible de créer un profil invité"</string>
<string name="user_nickname" msgid="262624187455825083">"Pseudo"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Ajouter un invité"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Supprimer l\'invité"</string>
@@ -644,4 +650,10 @@
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Infos distribution"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Choisissez une photo de profil"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"Icône de l\'utilisateur par défaut"</string>
+ <!-- no translation found for physical_keyboard_title (4811935435315835220) -->
+ <skip />
+ <!-- no translation found for keyboard_layout_dialog_title (3927180147005616290) -->
+ <skip />
+ <!-- no translation found for keyboard_layout_default_label (1997292217218546957) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml
index 02fa931fc450..f45c60d45b22 100644
--- a/packages/SettingsLib/res/values-gl/strings.xml
+++ b/packages/SettingsLib/res/values-gl/strings.xml
@@ -533,6 +533,8 @@
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Menos tempo."</string>
<string name="cancel" msgid="5665114069455378395">"Cancelar"</string>
<string name="okay" msgid="949938843324579502">"Aceptar"</string>
+ <!-- no translation found for done (381184316122520313) -->
+ <skip />
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarmas e recordatorios"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Permitir axuste de alarmas e recordatorios"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmas e recordatorios"</string>
@@ -551,7 +553,9 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Preguntar sempre"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"Ata a desactivación"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"Agora mesmo"</string>
- <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Este teléfono"</string>
+ <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Este teléfono"</string>
+ <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+ <skip />
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Este teléfono"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Produciuse un problema coa conexión. Apaga e acende o dispositivo."</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Dispositivo de audio con cable"</string>
@@ -591,7 +595,9 @@
<string name="user_set_lock_button" msgid="1427128184982594856">"Establecer bloqueo"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Cambiar a <xliff:g id="USER_NAME">%s</xliff:g>"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Creando usuario novo…"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Creando novo convidado…"</string>
<string name="add_user_failed" msgid="4809887794313944872">"Non se puido crear un novo usuario"</string>
+ <string name="add_guest_failed" msgid="8074548434469843443">"Produciuse un erro ao crear o convidado"</string>
<string name="user_nickname" msgid="262624187455825083">"Alcume"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Engadir convidado"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Quitar convidado"</string>
@@ -644,4 +650,10 @@
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Datos da emisión"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Escolle unha imaxe do perfil"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"Icona do usuario predeterminado"</string>
+ <!-- no translation found for physical_keyboard_title (4811935435315835220) -->
+ <skip />
+ <!-- no translation found for keyboard_layout_dialog_title (3927180147005616290) -->
+ <skip />
+ <!-- no translation found for keyboard_layout_default_label (1997292217218546957) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml
index b2a9ff3441fe..672bd77d4dce 100644
--- a/packages/SettingsLib/res/values-gu/strings.xml
+++ b/packages/SettingsLib/res/values-gu/strings.xml
@@ -533,6 +533,8 @@
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"ઓછો સમય."</string>
<string name="cancel" msgid="5665114069455378395">"રદ કરો"</string>
<string name="okay" msgid="949938843324579502">"ઓકે"</string>
+ <!-- no translation found for done (381184316122520313) -->
+ <skip />
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"અલાર્મ અને રિમાઇન્ડર"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"અલાર્મ અને રિમાન્ડરના સેટિંગની મંજૂરી આપો"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"અલાર્મ અને રિમાઇન્ડર"</string>
@@ -551,7 +553,9 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"દર વખતે પૂછો"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"તમે બંધ ન કરો ત્યાં સુધી"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"હમણાં જ"</string>
- <string name="media_transfer_this_device_name" msgid="2357329267148436433">"આ ફોન"</string>
+ <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"આ ફોન"</string>
+ <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+ <skip />
<string name="media_transfer_this_phone" msgid="7194341457812151531">"આ ફોન"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"કનેક્ટ કરવામાં સમસ્યા આવી રહી છે. ડિવાઇસને બંધ કરીને ફરી ચાલુ કરો"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"વાયરવાળો ઑડિયો ડિવાઇસ"</string>
@@ -591,7 +595,9 @@
<string name="user_set_lock_button" msgid="1427128184982594856">"લૉક સેટ કરો"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g> પર સ્વિચ કરો"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"નવા વપરાશકર્તા બનાવી રહ્યાં છીએ…"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"નવા અતિથિની પ્રોફાઇલ બનાવી રહ્યાં છીએ…"</string>
<string name="add_user_failed" msgid="4809887794313944872">"નવો વપરાશકર્તા બનાવવામાં નિષ્ફળ"</string>
+ <string name="add_guest_failed" msgid="8074548434469843443">"નવી અતિથિ બનાવવામાં નિષ્ફળ રહ્યાં"</string>
<string name="user_nickname" msgid="262624187455825083">"ઉપનામ"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"અતિથિ ઉમેરો"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"અતિથિને કાઢી નાખો"</string>
@@ -644,4 +650,7 @@
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"કાસ્ટ વિશેની માહિતી"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"પ્રોફાઇલ ફોટો પસંદ કરો"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"ડિફૉલ્ટ વપરાશકર્તાનું આઇકન"</string>
+ <string name="physical_keyboard_title" msgid="4811935435315835220">"ભૌતિક કીબોર્ડ"</string>
+ <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"કીબોર્ડ લેઆઉટ પસંદ કરો"</string>
+ <string name="keyboard_layout_default_label" msgid="1997292217218546957">"ડિફૉલ્ટ"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index fa51dd25b72c..55e3eafff1df 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -533,6 +533,8 @@
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"कम समय."</string>
<string name="cancel" msgid="5665114069455378395">"रद्द करें"</string>
<string name="okay" msgid="949938843324579502">"ठीक है"</string>
+ <!-- no translation found for done (381184316122520313) -->
+ <skip />
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"अलार्म और रिमाइंडर"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"अलार्म और रिमाइंडर सेट करने की अनुमति दें"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"अलार्म और रिमाइंडर"</string>
@@ -551,7 +553,9 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"हर बार पूछें"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"जब तक आप इसे बंद नहीं करते"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"अभी-अभी"</string>
- <string name="media_transfer_this_device_name" msgid="2357329267148436433">"यह फ़ोन"</string>
+ <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"यह फ़ोन"</string>
+ <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+ <skip />
<string name="media_transfer_this_phone" msgid="7194341457812151531">"यह फ़ोन"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"कनेक्ट करने में समस्या हो रही है. डिवाइस को बंद करके चालू करें"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"वायर वाला ऑडियो डिवाइस"</string>
@@ -591,7 +595,9 @@
<string name="user_set_lock_button" msgid="1427128184982594856">"लॉक सेट करें"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g> पर जाएं"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"नया उपयोगकर्ता बनाया जा रहा है…"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"नया मेहमान खाता बनाया जा रहा है…"</string>
<string name="add_user_failed" msgid="4809887794313944872">"नया उपयोगकर्ता जोड़ा नहीं जा सका"</string>
+ <string name="add_guest_failed" msgid="8074548434469843443">"नया मेहमान खाता नहीं बनाया जा सका"</string>
<string name="user_nickname" msgid="262624187455825083">"प्रचलित नाम"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"मेहमान जोड़ें"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"मेहमान हटाएं"</string>
@@ -644,4 +650,7 @@
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"कास्टिंग की जानकारी"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"प्रोफ़ाइल फ़ोटो चुनें"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"उपयोगकर्ता के लिए डिफ़ॉल्ट आइकॉन"</string>
+ <string name="physical_keyboard_title" msgid="4811935435315835220">"फ़िज़िकल कीबोर्ड"</string>
+ <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"कीबोर्ड का लेआउट चुनें"</string>
+ <string name="keyboard_layout_default_label" msgid="1997292217218546957">"डिफ़ॉल्ट"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml
index 12d97455e6f1..fd29bb5f37bf 100644
--- a/packages/SettingsLib/res/values-hr/strings.xml
+++ b/packages/SettingsLib/res/values-hr/strings.xml
@@ -533,6 +533,8 @@
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Manje vremena."</string>
<string name="cancel" msgid="5665114069455378395">"Odustani"</string>
<string name="okay" msgid="949938843324579502">"U redu"</string>
+ <!-- no translation found for done (381184316122520313) -->
+ <skip />
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarmi i podsjetnici"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Dopusti postavljanje alarma i podsjetnika"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmi i podsjetnici"</string>
@@ -551,7 +553,9 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Pitaj svaki put"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"Dok ne isključite"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"Upravo sad"</string>
- <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Ovaj telefon"</string>
+ <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Ovaj telefon"</string>
+ <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+ <skip />
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Ovaj telefon"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problem s povezivanjem. Isključite i ponovo uključite uređaj"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Žičani audiouređaj"</string>
@@ -591,7 +595,9 @@
<string name="user_set_lock_button" msgid="1427128184982594856">"Postavi zaključavanje"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Prelazak na korisnika <xliff:g id="USER_NAME">%s</xliff:g>"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Izrada novog korisnika…"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Izrada novog gosta…"</string>
<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>
<string name="guest_new_guest" msgid="3482026122932643557">"Dodavanje gosta"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Uklanjanje gosta"</string>
@@ -644,4 +650,10 @@
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Inform. o emitiranju"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Odabir profilne slike"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"Ikona zadanog korisnika"</string>
+ <!-- no translation found for physical_keyboard_title (4811935435315835220) -->
+ <skip />
+ <!-- no translation found for keyboard_layout_dialog_title (3927180147005616290) -->
+ <skip />
+ <!-- no translation found for keyboard_layout_default_label (1997292217218546957) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml
index 984df4a27964..dae58549a472 100644
--- a/packages/SettingsLib/res/values-hu/strings.xml
+++ b/packages/SettingsLib/res/values-hu/strings.xml
@@ -533,6 +533,8 @@
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Kevesebb idő."</string>
<string name="cancel" msgid="5665114069455378395">"Mégse"</string>
<string name="okay" msgid="949938843324579502">"OK"</string>
+ <!-- no translation found for done (381184316122520313) -->
+ <skip />
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"Ébresztések és emlékeztetők"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Beállíthat ébresztéseket és emlékeztetőket"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Ébresztések és emlékeztetők"</string>
@@ -551,7 +553,9 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Mindig kérdezzen rá"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"Kikapcsolásig"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"Az imént"</string>
- <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Ez a telefon"</string>
+ <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Ez a telefon"</string>
+ <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+ <skip />
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Ez a telefon"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Sikertelen csatlakozás. Kapcsolja ki az eszközt, majd kapcsolja be újra."</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Vezetékes audioeszköz"</string>
@@ -591,7 +595,9 @@
<string name="user_set_lock_button" msgid="1427128184982594856">"Képernyőzár beállítása"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Váltás erre: <xliff:g id="USER_NAME">%s</xliff:g>"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Új felhasználó létrehozása…"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Új vendég létrehozása…"</string>
<string name="add_user_failed" msgid="4809887794313944872">"Az új felhasználó létrehozása sikertelen"</string>
+ <string name="add_guest_failed" msgid="8074548434469843443">"Az új vendég létrehozása nem sikerült"</string>
<string name="user_nickname" msgid="262624187455825083">"Becenév"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Vendég hozzáadása"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Vendég munkamenet eltávolítása"</string>
@@ -644,4 +650,7 @@
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Átküldési információ"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Profilkép választása"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"Alapértelmezett felhasználó ikonja"</string>
+ <string name="physical_keyboard_title" msgid="4811935435315835220">"Fizikai billentyűzet"</string>
+ <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Billentyűzetkiosztás kiválasztása"</string>
+ <string name="keyboard_layout_default_label" msgid="1997292217218546957">"Alapértelmezett"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml
index 1488aea4a110..61d909333507 100644
--- a/packages/SettingsLib/res/values-hy/strings.xml
+++ b/packages/SettingsLib/res/values-hy/strings.xml
@@ -533,6 +533,8 @@
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Պակասեցնել ժամանակը:"</string>
<string name="cancel" msgid="5665114069455378395">"Չեղարկել"</string>
<string name="okay" msgid="949938843324579502">"Եղավ"</string>
+ <!-- no translation found for done (381184316122520313) -->
+ <skip />
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"Զարթուցիչներ և հիշեցումներ"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Թույլատրել զարթուցիչների և հիշեցումների սահմանումը"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Զարթուցիչներ և հիշեցումներ"</string>
@@ -551,7 +553,9 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Ամեն անգամ հարցնել"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"Մինչև անջատեք"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"Հենց նոր"</string>
- <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Այս հեռախոսը"</string>
+ <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Այս հեռախոսը"</string>
+ <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+ <skip />
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Այս հեռախոսը"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Կապի խնդիր կա: Սարքն անջատեք և նորից միացրեք:"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Լարով աուդիո սարք"</string>
@@ -591,7 +595,9 @@
<string name="user_set_lock_button" msgid="1427128184982594856">"Կարգավորել կողպումը"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Անցնել <xliff:g id="USER_NAME">%s</xliff:g> պրոֆիլին"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Ստեղծվում է օգտատիրոջ նոր պրոֆիլ…"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Նոր հյուրի ստեղծում…"</string>
<string name="add_user_failed" msgid="4809887794313944872">"Չհաջողվեց ստեղծել նոր օգտատեր"</string>
+ <string name="add_guest_failed" msgid="8074548434469843443">"Չհաջողվեց նոր հյուր ստեղծել"</string>
<string name="user_nickname" msgid="262624187455825083">"Կեղծանուն"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Ավելացնել հյուր"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Հեռացնել հյուրին"</string>
@@ -644,4 +650,7 @@
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Հեռարձակման տվյալներ"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Պրոֆիլի նկար ընտրեք"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"Օգտատիրոջ կանխադրված պատկերակ"</string>
+ <string name="physical_keyboard_title" msgid="4811935435315835220">"Ֆիզիկական ստեղնաշար"</string>
+ <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Ընտրեք ստեղնաշարի դասավորությունը"</string>
+ <string name="keyboard_layout_default_label" msgid="1997292217218546957">"Կանխադրված"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index ffa4d4a0aaee..b60e0b70d91b 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -533,6 +533,8 @@
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Lebih cepat."</string>
<string name="cancel" msgid="5665114069455378395">"Batal"</string>
<string name="okay" msgid="949938843324579502">"Oke"</string>
+ <!-- no translation found for done (381184316122520313) -->
+ <skip />
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarm dan pengingat"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Izinkan menyetel alarm dan pengingat"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarm &amp; pengingat"</string>
@@ -551,7 +553,9 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Selalu tanya"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"Sampai Anda menonaktifkannya"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"Baru saja"</string>
- <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Ponsel ini"</string>
+ <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Ponsel ini"</string>
+ <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+ <skip />
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Ponsel ini"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Ada masalah saat menghubungkan. Nonaktifkan perangkat &amp; aktifkan kembali"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Perangkat audio berkabel"</string>
@@ -591,7 +595,9 @@
<string name="user_set_lock_button" msgid="1427128184982594856">"Setel kunci"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Beralih ke <xliff:g id="USER_NAME">%s</xliff:g>"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Membuat pengguna baru …"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Membuat tamu baru …"</string>
<string name="add_user_failed" msgid="4809887794313944872">"Gagal membuat pengguna baru"</string>
+ <string name="add_guest_failed" msgid="8074548434469843443">"Gagal membuat tamu baru"</string>
<string name="user_nickname" msgid="262624187455825083">"Nama panggilan"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Tambahkan tamu"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Hapus tamu"</string>
@@ -644,4 +650,7 @@
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Info Transmisi"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Pilih foto profil"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"Ikon pengguna default"</string>
+ <string name="physical_keyboard_title" msgid="4811935435315835220">"Keyboard fisik"</string>
+ <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Pilih tata letak keyboard"</string>
+ <string name="keyboard_layout_default_label" msgid="1997292217218546957">"Default"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml
index b8a750477c84..40724fda8fbb 100644
--- a/packages/SettingsLib/res/values-is/strings.xml
+++ b/packages/SettingsLib/res/values-is/strings.xml
@@ -533,6 +533,8 @@
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Minni tími."</string>
<string name="cancel" msgid="5665114069455378395">"Hætta við"</string>
<string name="okay" msgid="949938843324579502">"Í lagi"</string>
+ <!-- no translation found for done (381184316122520313) -->
+ <skip />
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"Vekjarar og áminningar"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Leyfa stillingu vekjara og áminninga"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Vekjarar og áminningar"</string>
@@ -551,7 +553,9 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Spyrja í hvert skipti"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"Þar til þú slekkur"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"Rétt í þessu"</string>
- <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Þessi sími"</string>
+ <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Þessi sími"</string>
+ <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+ <skip />
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Þessi sími"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Vandamál í tengingu. Slökktu og kveiktu á tækinu"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Snúrutengt hljómtæki"</string>
@@ -591,7 +595,9 @@
<string name="user_set_lock_button" msgid="1427128184982594856">"Velja lás"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Skipta yfir í <xliff:g id="USER_NAME">%s</xliff:g>"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Stofnar nýjan notanda…"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Býr til nýjan gest…"</string>
<string name="add_user_failed" msgid="4809887794313944872">"Ekki tókst að stofna nýjan notanda"</string>
+ <string name="add_guest_failed" msgid="8074548434469843443">"Ekki tókst að búa til nýjan gest"</string>
<string name="user_nickname" msgid="262624187455825083">"Gælunafn"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Bæta gesti við"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Fjarlægja gest"</string>
@@ -644,4 +650,7 @@
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Útsendingaruppl."</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Veldu prófílmynd"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"Tákn sjálfgefins notanda"</string>
+ <string name="physical_keyboard_title" msgid="4811935435315835220">"Vélbúnaðarlyklaborð"</string>
+ <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Veldu lyklaskipan"</string>
+ <string name="keyboard_layout_default_label" msgid="1997292217218546957">"Sjálfgefið"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index 1552006a68d8..703a0b36bef7 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -528,11 +528,13 @@
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"Non registrato"</string>
<string name="status_unavailable" msgid="5279036186589861608">"Non disponibile"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"Selezione casuale dell\'indirizzo MAC"</string>
- <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{0 dispositivi connessi}=1{1 dispositivo connesso}one{# dispositivo connesso}other{# dispositivi connessi}}"</string>
+ <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{0 dispositivi connessi}=1{1 dispositivo connesso}other{# dispositivi connessi}}"</string>
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"Più tempo."</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Meno tempo."</string>
<string name="cancel" msgid="5665114069455378395">"Annulla"</string>
<string name="okay" msgid="949938843324579502">"OK"</string>
+ <!-- no translation found for done (381184316122520313) -->
+ <skip />
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"Sveglie e promemoria"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Consenti l\'impostazione di sveglie e promemoria"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Sveglie e promemoria"</string>
@@ -551,7 +553,9 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Chiedi ogni volta"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"Fino alla disattivazione"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"Adesso"</string>
- <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Questo telefono"</string>
+ <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Questo telefono"</string>
+ <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+ <skip />
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Questo telefono"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problema di connessione. Spegni e riaccendi il dispositivo"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Dispositivo audio cablato"</string>
@@ -591,7 +595,9 @@
<string name="user_set_lock_button" msgid="1427128184982594856">"Imposta blocco"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Passa a <xliff:g id="USER_NAME">%s</xliff:g>"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Creazione nuovo utente…"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Creazione di un nuovo ospite in corso…"</string>
<string name="add_user_failed" msgid="4809887794313944872">"Creazione nuovo utente non riuscita"</string>
+ <string name="add_guest_failed" msgid="8074548434469843443">"Impossibile creare un nuovo ospite"</string>
<string name="user_nickname" msgid="262624187455825083">"Nickname"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Aggiungi ospite"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Rimuovi ospite"</string>
@@ -644,4 +650,7 @@
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Info sul cast"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Scegli un\'immagine del profilo"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"Icona dell\'utente predefinito"</string>
+ <string name="physical_keyboard_title" msgid="4811935435315835220">"Tastiera fisica"</string>
+ <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Scegli layout tastiera"</string>
+ <string name="keyboard_layout_default_label" msgid="1997292217218546957">"Predefinito"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index 22810e9774e7..987af9ca5f89 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -533,6 +533,8 @@
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"פחות זמן."</string>
<string name="cancel" msgid="5665114069455378395">"ביטול"</string>
<string name="okay" msgid="949938843324579502">"אישור"</string>
+ <!-- no translation found for done (381184316122520313) -->
+ <skip />
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"שעונים מעוררים ותזכורות"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"אישור להגדיר שעונים מעוררים ותזכורות"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"שעונים מעוררים ותזכורות"</string>
@@ -551,7 +553,9 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"יש לשאול בכל פעם"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"עד הכיבוי"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"הרגע"</string>
- <string name="media_transfer_this_device_name" msgid="2357329267148436433">"הטלפון הזה"</string>
+ <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"הטלפון הזה"</string>
+ <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+ <skip />
<string name="media_transfer_this_phone" msgid="7194341457812151531">"הטלפון הזה"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"יש בעיה בחיבור. עליך לכבות את המכשיר ולהפעיל אותו מחדש"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"התקן אודיו חוטי"</string>
@@ -591,7 +595,9 @@
<string name="user_set_lock_button" msgid="1427128184982594856">"הגדרת נעילה"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"מעבר אל <xliff:g id="USER_NAME">%s</xliff:g>"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"בתהליך יצירה של משתמש חדש…"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"מיד ייווצר אורח חדש…"</string>
<string name="add_user_failed" msgid="4809887794313944872">"לא ניתן היה ליצור משתמש חדש"</string>
+ <string name="add_guest_failed" msgid="8074548434469843443">"יצירת אורח חדש נכשלה"</string>
<string name="user_nickname" msgid="262624187455825083">"כינוי"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"הוספת אורח"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"הסרת אורח/ת"</string>
@@ -644,4 +650,7 @@
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"פרטי ההעברה"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"בחירה של תמונת פרופיל"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"סמל המשתמש שמוגדר כברירת מחדל"</string>
+ <string name="physical_keyboard_title" msgid="4811935435315835220">"מקלדת פיזית"</string>
+ <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"בחירה של פריסת המקלדת"</string>
+ <string name="keyboard_layout_default_label" msgid="1997292217218546957">"ברירת מחדל"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
index be98ee44cc22..07b04a8f051d 100644
--- a/packages/SettingsLib/res/values-ja/strings.xml
+++ b/packages/SettingsLib/res/values-ja/strings.xml
@@ -533,6 +533,8 @@
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"短くします。"</string>
<string name="cancel" msgid="5665114069455378395">"キャンセル"</string>
<string name="okay" msgid="949938843324579502">"OK"</string>
+ <!-- no translation found for done (381184316122520313) -->
+ <skip />
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"アラームとリマインダー"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"アラームとリマインダーの設定を許可する"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"アラームとリマインダー"</string>
@@ -551,7 +553,9 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"毎回確認"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"OFF にするまで"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"たった今"</string>
- <string name="media_transfer_this_device_name" msgid="2357329267148436433">"このスマートフォン"</string>
+ <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"このスマートフォン"</string>
+ <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+ <skip />
<string name="media_transfer_this_phone" msgid="7194341457812151531">"このスマートフォン"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"接続エラーです。デバイスを OFF にしてから ON に戻してください"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"有線オーディオ デバイス"</string>
@@ -591,7 +595,9 @@
<string name="user_set_lock_button" msgid="1427128184982594856">"ロックを設定"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g> に切り替え"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"新しいユーザーを作成しています…"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"新しいゲストを作成中…"</string>
<string name="add_user_failed" msgid="4809887794313944872">"新しいユーザーを作成できませんでした"</string>
+ <string name="add_guest_failed" msgid="8074548434469843443">"新しいゲストを作成できませんでした"</string>
<string name="user_nickname" msgid="262624187455825083">"ニックネーム"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"ゲストを追加"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"ゲストを削除"</string>
@@ -644,4 +650,7 @@
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"キャスト情報"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"プロフィール写真の選択"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"デフォルト ユーザー アイコン"</string>
+ <string name="physical_keyboard_title" msgid="4811935435315835220">"物理キーボード"</string>
+ <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"キーボード レイアウトの選択"</string>
+ <string name="keyboard_layout_default_label" msgid="1997292217218546957">"デフォルト"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ka/strings.xml b/packages/SettingsLib/res/values-ka/strings.xml
index f0006d37c4f7..a396600c2644 100644
--- a/packages/SettingsLib/res/values-ka/strings.xml
+++ b/packages/SettingsLib/res/values-ka/strings.xml
@@ -533,6 +533,8 @@
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"ნაკლები დრო."</string>
<string name="cancel" msgid="5665114069455378395">"გაუქმება"</string>
<string name="okay" msgid="949938843324579502">"კარგი"</string>
+ <!-- no translation found for done (381184316122520313) -->
+ <skip />
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"მაღვიძარები და შეხსენებები"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"დაუშვით მაღვიძარების და შეხსენებების დაყენება"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"მაღვიძარები და შეხსენებები"</string>
@@ -551,7 +553,9 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"ყოველთვის მკითხეთ"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"გამორთვამდე"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"ახლახან"</string>
- <string name="media_transfer_this_device_name" msgid="2357329267148436433">"ეს ტელეფონი"</string>
+ <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"ეს ტელეფონი"</string>
+ <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+ <skip />
<string name="media_transfer_this_phone" msgid="7194341457812151531">"ეს ტელეფონი"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"დაკავშირებისას წარმოიქმნა პრობლემა. გამორთეთ და კვლავ ჩართეთ მოწყობილობა"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"სადენიანი აუდიო მოწყობილობა"</string>
@@ -591,7 +595,9 @@
<string name="user_set_lock_button" msgid="1427128184982594856">"საკეტის დაყენება"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g>-ზე გადართვა"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"მიმდინარეობს ახალი მომხმარებლის შექმნა…"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"ახალი სტუმრის შექმნა…"</string>
<string name="add_user_failed" msgid="4809887794313944872">"ახალი მომხმარებლის შექმნა ვერ მოხერხდა"</string>
+ <string name="add_guest_failed" msgid="8074548434469843443">"ახალი სტუმრის შექმნა ვერ მოხერხდა"</string>
<string name="user_nickname" msgid="262624187455825083">"მეტსახელი"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"სტუმრის დამატება"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"სტუმრის ამოშლა"</string>
@@ -644,4 +650,7 @@
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"ტრანსლირების ინფო"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"აირჩიეთ პროფილის სურათი"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"მომხმარებლის ნაგულისხმევი ხატულა"</string>
+ <string name="physical_keyboard_title" msgid="4811935435315835220">"ფიზიკური კლავიატურა"</string>
+ <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"აირჩიე კლავიატურის განლაგება"</string>
+ <string name="keyboard_layout_default_label" msgid="1997292217218546957">"ნაგულისხმევი"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml
index 3724ca57b0c8..ccaf1c43feef 100644
--- a/packages/SettingsLib/res/values-kk/strings.xml
+++ b/packages/SettingsLib/res/values-kk/strings.xml
@@ -533,6 +533,8 @@
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Азырақ уақыт."</string>
<string name="cancel" msgid="5665114069455378395">"Бас тарту"</string>
<string name="okay" msgid="949938843324579502">"Жарайды"</string>
+ <!-- no translation found for done (381184316122520313) -->
+ <skip />
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"Оятқыш және еске салғыш"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Оятқыштар мен еске салғыштарды орнатуға рұқсат беру"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Оятқыштар мен еске салғыштар"</string>
@@ -551,7 +553,9 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Әрдайым сұрау"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"Өшірілгенге дейін"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"Дәл қазір"</string>
- <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Осы телефон"</string>
+ <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Осы телефон"</string>
+ <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+ <skip />
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Осы телефон"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Байланыс орнату қатесі шығуып жатыр. Құрылғыны өшіріп, қайта қосыңыз."</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Сымды аудио құрылғысы"</string>
@@ -591,7 +595,9 @@
<string name="user_set_lock_button" msgid="1427128184982594856">"Бекітпе тағайындау"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g> пайдаланушысына ауысу"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Жаңа пайдаланушы профилі жасалуда…"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Жаңа қонақ профилі жасалуда…"</string>
<string name="add_user_failed" msgid="4809887794313944872">"Жаңа пайдаланушы жасалмады."</string>
+ <string name="add_guest_failed" msgid="8074548434469843443">"Жаңа қонақ профилі жасалмады."</string>
<string name="user_nickname" msgid="262624187455825083">"Лақап ат"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Қонақ қосу"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Қонақты жою"</string>
@@ -644,4 +650,7 @@
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Трансляция ақпараты"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Профиль суретін таңдау"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"Әдепкі пайдаланушы белгішесі"</string>
+ <string name="physical_keyboard_title" msgid="4811935435315835220">"Пернетақта"</string>
+ <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Пернетақтаның орналасу ретін таңдау"</string>
+ <string name="keyboard_layout_default_label" msgid="1997292217218546957">"Әдепкі"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml
index 28211f03348b..370fc4b98cd1 100644
--- a/packages/SettingsLib/res/values-km/strings.xml
+++ b/packages/SettingsLib/res/values-km/strings.xml
@@ -533,6 +533,8 @@
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"រយៈពេល​តិច​ជាង។"</string>
<string name="cancel" msgid="5665114069455378395">"បោះ​បង់​"</string>
<string name="okay" msgid="949938843324579502">"យល់ព្រម"</string>
+ <!-- no translation found for done (381184316122520313) -->
+ <skip />
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"ម៉ោងរោទ៍ និងការរំលឹក"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"អនុញ្ញាតឱ្យ​កំណត់​ម៉ោងរោទ៍ និង​ការរំលឹក"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"ម៉ោងរោទ៍ និង​ការរំលឹក"</string>
@@ -551,7 +553,9 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"សួរគ្រប់ពេល"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"រហូតទាល់តែ​អ្នកបិទ"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"អម្បាញ់មិញ"</string>
- <string name="media_transfer_this_device_name" msgid="2357329267148436433">"ទូរសព្ទនេះ"</string>
+ <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"ទូរសព្ទនេះ"</string>
+ <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+ <skip />
<string name="media_transfer_this_phone" msgid="7194341457812151531">"ទូរសព្ទនេះ"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"មាន​បញ្ហា​ក្នុងការ​ភ្ជាប់។ បិទ រួច​បើក​ឧបករណ៍​វិញ"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ឧបករណ៍​សំឡេងប្រើខ្សែ"</string>
@@ -591,7 +595,9 @@
<string name="user_set_lock_button" msgid="1427128184982594856">"កំណត់​ការ​ចាក់​សោ"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"ប្ដូរទៅ <xliff:g id="USER_NAME">%s</xliff:g>"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"កំពុងបង្កើត​អ្នកប្រើប្រាស់ថ្មី…"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"កំពុងបង្កើតភ្ញៀវថ្មី…"</string>
<string name="add_user_failed" msgid="4809887794313944872">"មិន​អាច​បង្កើត​អ្នកប្រើប្រាស់ថ្មី​បានទេ"</string>
+ <string name="add_guest_failed" msgid="8074548434469843443">"មិនអាចបង្កើតភ្ញៀវថ្មីបានទេ"</string>
<string name="user_nickname" msgid="262624187455825083">"ឈ្មោះ​ហៅក្រៅ"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"បញ្ចូល​ភ្ញៀវ"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"ដកភ្ញៀវចេញ"</string>
@@ -644,4 +650,10 @@
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"ព័ត៌មានអំពីការបញ្ជូន"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"ជ្រើសរើស​រូបភាព​កម្រង​ព័ត៌មាន"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"រូបអ្នកប្រើប្រាស់លំនាំដើម"</string>
+ <!-- no translation found for physical_keyboard_title (4811935435315835220) -->
+ <skip />
+ <!-- no translation found for keyboard_layout_dialog_title (3927180147005616290) -->
+ <skip />
+ <!-- no translation found for keyboard_layout_default_label (1997292217218546957) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml
index 635c6872e2fc..a070ad29162f 100644
--- a/packages/SettingsLib/res/values-kn/strings.xml
+++ b/packages/SettingsLib/res/values-kn/strings.xml
@@ -533,6 +533,8 @@
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"ಕಡಿಮೆ ಸಮಯ."</string>
<string name="cancel" msgid="5665114069455378395">"ರದ್ದುಮಾಡಿ"</string>
<string name="okay" msgid="949938843324579502">"ಸರಿ"</string>
+ <!-- no translation found for done (381184316122520313) -->
+ <skip />
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"ಅಲಾರಾಮ್‌ಗಳು ಮತ್ತು ರಿಮೈಂಡರ್‌ಗಳು"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"ಅಲಾರಂಗಳು ಮತ್ತು ರಿಮೈಂಡರ್‌ಗಳನ್ನು ಹೊಂದಿಸಲು ಅನುಮತಿಸಿ"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"ಅಲಾರಂಗಳು ಮತ್ತು ರಿಮೈಂಡರ್‌ಗಳು"</string>
@@ -551,7 +553,9 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"ಪ್ರತಿ ಬಾರಿ ಕೇಳಿ"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"ನೀವು ಆಫ್ ಮಾಡುವವರೆಗೆ"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"ಇದೀಗ"</string>
- <string name="media_transfer_this_device_name" msgid="2357329267148436433">"ಈ ಫೋನ್"</string>
+ <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"ಈ ಫೋನ್"</string>
+ <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+ <skip />
<string name="media_transfer_this_phone" msgid="7194341457812151531">"ಈ ಫೋನ್"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"ಕನೆಕ್ಟ್ ಮಾಡುವಾಗ ಸಮಸ್ಯೆ ಎದುರಾಗಿದೆ ಸಾಧನವನ್ನು ಆಫ್ ಮಾಡಿ ಹಾಗೂ ನಂತರ ಪುನಃ ಆನ್ ಮಾಡಿ"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ವೈರ್ ಹೊಂದಿರುವ ಆಡಿಯೋ ಸಾಧನ"</string>
@@ -591,7 +595,9 @@
<string name="user_set_lock_button" msgid="1427128184982594856">"ಲಾಕ್ ಹೊಂದಿಸಿ"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g> ಗೆ ಬದಲಿಸಿ"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"ಹೊಸ ಬಳಕೆದಾರರನ್ನು ರಚಿಸಲಾಗುತ್ತಿದೆ…"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"ಹೊಸ ಅತಿಥಿಯನ್ನು ರಚಿಸಲಾಗುತ್ತಿದೆ…"</string>
<string name="add_user_failed" msgid="4809887794313944872">"ಹೊಸ ಬಳಕೆದಾರರನ್ನು ರಚಿಸಲು ವಿಫಲವಾಗಿದೆ"</string>
+ <string name="add_guest_failed" msgid="8074548434469843443">"ಹೊಸ ಅತಿಥಿಯನ್ನು ರಚಿಸಲು ವಿಫಲವಾಗಿದೆ"</string>
<string name="user_nickname" msgid="262624187455825083">"ಅಡ್ಡ ಹೆಸರು"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"ಅತಿಥಿಯನ್ನು ಸೇರಿಸಿ"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"ಅತಿಥಿಯನ್ನು ತೆಗೆದುಹಾಕಿ"</string>
@@ -644,4 +650,7 @@
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"ಬಿತ್ತರಿಸಿದ ಮಾಹಿತಿ"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"ಪ್ರೊಫೈಲ್ ಚಿತ್ರವನ್ನು ಆಯ್ಕೆ ಮಾಡಿ"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"ಡೀಫಾಲ್ಟ್ ಬಳಕೆದಾರರ ಐಕಾನ್"</string>
+ <string name="physical_keyboard_title" msgid="4811935435315835220">"ಭೌತಿಕ ಕೀಬೋರ್ಡ್"</string>
+ <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"ಕೀಬೋರ್ಡ್ ಲೇಔಟ್ ಆರಿಸಿ"</string>
+ <string name="keyboard_layout_default_label" msgid="1997292217218546957">"ಡೀಫಾಲ್ಟ್"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index 40acb1ac6b58..3cd8583bc201 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -533,6 +533,8 @@
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"시간 줄이기"</string>
<string name="cancel" msgid="5665114069455378395">"취소"</string>
<string name="okay" msgid="949938843324579502">"확인"</string>
+ <!-- no translation found for done (381184316122520313) -->
+ <skip />
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"알람 및 리마인더"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"알람 및 리마인더 설정 허용"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"알람 및 리마인더"</string>
@@ -551,7 +553,9 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"항상 확인"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"사용 중지할 때까지"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"조금 전"</string>
- <string name="media_transfer_this_device_name" msgid="2357329267148436433">"이 휴대전화"</string>
+ <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"이 휴대전화"</string>
+ <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+ <skip />
<string name="media_transfer_this_phone" msgid="7194341457812151531">"이 휴대전화"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"연결 중에 문제가 발생했습니다. 기기를 껐다가 다시 켜 보세요."</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"유선 오디오 기기"</string>
@@ -591,7 +595,9 @@
<string name="user_set_lock_button" msgid="1427128184982594856">"잠금 설정"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g>(으)로 전환"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"새로운 사용자를 만드는 중…"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"새 게스트 생성 중…"</string>
<string name="add_user_failed" msgid="4809887794313944872">"새 사용자를 만들지 못함"</string>
+ <string name="add_guest_failed" msgid="8074548434469843443">"새 게스트 생성 실패"</string>
<string name="user_nickname" msgid="262624187455825083">"닉네임"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"게스트 추가"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"게스트 삭제"</string>
@@ -644,4 +650,7 @@
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"전송 정보"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"프로필 사진 선택하기"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"기본 사용자 아이콘"</string>
+ <string name="physical_keyboard_title" msgid="4811935435315835220">"물리적 키보드"</string>
+ <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"키보드 레이아웃 선택"</string>
+ <string name="keyboard_layout_default_label" msgid="1997292217218546957">"기본"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml
index 7a50ece104b1..93c432179d82 100644
--- a/packages/SettingsLib/res/values-ky/strings.xml
+++ b/packages/SettingsLib/res/values-ky/strings.xml
@@ -533,6 +533,8 @@
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Азыраак убакыт."</string>
<string name="cancel" msgid="5665114069455378395">"Жок"</string>
<string name="okay" msgid="949938843324579502">"OK"</string>
+ <!-- no translation found for done (381184316122520313) -->
+ <skip />
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"Ойготкучтар жана эстеткичтер"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Ойготкуч жана эстеткичтерди коюуга уруксат берүү"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Ойготкучтар жана эстеткичтер"</string>
@@ -551,7 +553,9 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Ар дайым суралсын"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"Бул функция өчүрүлгөнгө чейин"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"Жаңы эле"</string>
- <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Ушул телефон"</string>
+ <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Ушул телефон"</string>
+ <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+ <skip />
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Ушул телефон"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Туташууда маселе келип чыкты. Түзмөктү өчүрүп, кайра күйгүзүп көрүңүз"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Зымдуу аудио түзмөк"</string>
@@ -591,7 +595,9 @@
<string name="user_set_lock_button" msgid="1427128184982594856">"Бөгөт коюу"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g> аккаунтуна которулуу"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Жаңы колдонуучу түзүлүүдө…"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Жаңы конок түзүлүүдө…"</string>
<string name="add_user_failed" msgid="4809887794313944872">"Жаңы колдонуучу түзүлбөй калды"</string>
+ <string name="add_guest_failed" msgid="8074548434469843443">"Жаңы конок түзүлгөн жок"</string>
<string name="user_nickname" msgid="262624187455825083">"Ылакап аты"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Конок кошуу"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Конокту өчүрүү"</string>
@@ -644,4 +650,7 @@
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Тышкы экранга чыгаруу маалыматы"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Профилдин сүрөтүн тандоо"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"Демейки колдонуучунун сүрөтчөсү"</string>
+ <string name="physical_keyboard_title" msgid="4811935435315835220">"Аппараттык баскычтоп"</string>
+ <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Тергичтин жайылмасын тандоо"</string>
+ <string name="keyboard_layout_default_label" msgid="1997292217218546957">"Демейки"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-lo/strings.xml b/packages/SettingsLib/res/values-lo/strings.xml
index 2aced9d253e0..e4d677dbee3a 100644
--- a/packages/SettingsLib/res/values-lo/strings.xml
+++ b/packages/SettingsLib/res/values-lo/strings.xml
@@ -533,6 +533,8 @@
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"ຫຼຸດເວລາ."</string>
<string name="cancel" msgid="5665114069455378395">"ຍົກເລີກ"</string>
<string name="okay" msgid="949938843324579502">"ຕົກລົງ"</string>
+ <!-- no translation found for done (381184316122520313) -->
+ <skip />
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"ໂມງປຸກ ແລະ ການແຈ້ງເຕືອນ"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"ອະນຸຍາດໃຫ້ຕັ້ງໂມງປຸກ ແລະ ການແຈ້ງເຕືອນ"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"ໂມງປຸກ ແລະ ການແຈ້ງເຕືອນ"</string>
@@ -551,7 +553,9 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"ຖາມທຸກເທື່ອ"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"ຈົນກວ່າທ່ານຈະປິດ"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"ຕອນນີ້"</string>
- <string name="media_transfer_this_device_name" msgid="2357329267148436433">"ໂທລະສັບນີ້"</string>
+ <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"ໂທລະສັບນີ້"</string>
+ <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+ <skip />
<string name="media_transfer_this_phone" msgid="7194341457812151531">"ໂທລະສັບນີ້"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"ເກີດບັນຫາໃນການເຊື່ອມຕໍ່. ປິດອຸປະກອນແລ້ວເປີດກັບຄືນມາໃໝ່"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ອຸປະກອນສຽງແບບມີສາຍ"</string>
@@ -591,7 +595,9 @@
<string name="user_set_lock_button" msgid="1427128184982594856">"ຕັ້ງການລັອກ"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"ສະຫຼັບໄປ <xliff:g id="USER_NAME">%s</xliff:g>"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"ກຳລັງສ້າງຜູ້ໃຊ້ໃໝ່…"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"ກຳລັງສ້າງແຂກໃໝ່…"</string>
<string name="add_user_failed" msgid="4809887794313944872">"ສ້າງຜູ້ໃຊ້ໃໝ່ບໍ່ສຳເລັດ"</string>
+ <string name="add_guest_failed" msgid="8074548434469843443">"ສ້າງແຂກໃໝ່ບໍ່ສຳເລັດ"</string>
<string name="user_nickname" msgid="262624187455825083">"ຊື່ຫຼິ້ນ"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"ເພີ່ມແຂກ"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"ລຶບແຂກອອກ"</string>
@@ -644,4 +650,7 @@
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"ຂໍ້ມູນການສົ່ງສັນຍານ"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"ເລືອກຮູບໂປຣໄຟລ໌"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"ໄອຄອນຜູ້ໃຊ້ເລີ່ມຕົ້ນ"</string>
+ <string name="physical_keyboard_title" msgid="4811935435315835220">"ແປ້ນພິມພາຍນອກ"</string>
+ <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"ເລືອກຮູບແບບແປ້ນພິມ"</string>
+ <string name="keyboard_layout_default_label" msgid="1997292217218546957">"ຄ່າເລີ່ມຕົ້ນ"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
index 6e7daa715b5a..fbd800c33db7 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -533,6 +533,8 @@
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Mažiau laiko."</string>
<string name="cancel" msgid="5665114069455378395">"Atšaukti"</string>
<string name="okay" msgid="949938843324579502">"Gerai"</string>
+ <!-- no translation found for done (381184316122520313) -->
+ <skip />
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"Signalai ir priminimai"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Leisti nustatyti signalus ir priminimus"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Signalai ir priminimai"</string>
@@ -551,7 +553,9 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Klausti kaskart"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"Kol išjungsite"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"Ką tik"</string>
- <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Šis telefonas"</string>
+ <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Šis telefonas"</string>
+ <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+ <skip />
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Šis telefonas"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Prisijungiant kilo problema. Išjunkite įrenginį ir vėl jį įjunkite"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Laidinis garso įrenginys"</string>
@@ -591,7 +595,9 @@
<string name="user_set_lock_button" msgid="1427128184982594856">"Nustatyti užraktą"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Perjungti į <xliff:g id="USER_NAME">%s</xliff:g>"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Kuriamas naujas naudotojas…"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Kuriamas naujas gestas…"</string>
<string name="add_user_failed" msgid="4809887794313944872">"Nepavyko sukurti naujo naudotojo"</string>
+ <string name="add_guest_failed" msgid="8074548434469843443">"Nepavyko sukurti naujo gesto"</string>
<string name="user_nickname" msgid="262624187455825083">"Slapyvardis"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Pridėti svečią"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Pašalinti svečią"</string>
@@ -644,4 +650,7 @@
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Perdav. informacija"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Pasirinkite profilio nuotrauką"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"Numatytojo naudotojo piktograma"</string>
+ <string name="physical_keyboard_title" msgid="4811935435315835220">"Fizinė klaviatūra"</string>
+ <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Klaviatūros išdėstymo pasirinkimas"</string>
+ <string name="keyboard_layout_default_label" msgid="1997292217218546957">"Numatytasis"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
index 0d6651a7f7a7..5ef979ef8072 100644
--- a/packages/SettingsLib/res/values-lv/strings.xml
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -533,6 +533,8 @@
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Mazāk laika."</string>
<string name="cancel" msgid="5665114069455378395">"Atcelt"</string>
<string name="okay" msgid="949938843324579502">"LABI"</string>
+ <!-- no translation found for done (381184316122520313) -->
+ <skip />
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"Signāli un atgādinājumi"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Atļaut iestatīt signālus un atgādinājumus"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Signāli un atgādinājumi"</string>
@@ -551,7 +553,9 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Vaicāt katru reizi"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"Līdz brīdim, kad izslēgsiet"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"Tikko"</string>
- <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Šis tālrunis"</string>
+ <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Šis tālrunis"</string>
+ <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+ <skip />
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Šis tālrunis"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Radās problēma ar savienojuma izveidi. Izslēdziet un atkal ieslēdziet ierīci."</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Vadu audioierīce"</string>
@@ -591,7 +595,9 @@
<string name="user_set_lock_button" msgid="1427128184982594856">"Iestatīt bloķēšanu"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Pārslēgties uz: <xliff:g id="USER_NAME">%s</xliff:g>"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Notiek jauna lietotāja izveide…"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Notiek jauna viesa profila izveide…"</string>
<string name="add_user_failed" msgid="4809887794313944872">"Neizdevās izveidot jaunu lietotāju"</string>
+ <string name="add_guest_failed" msgid="8074548434469843443">"Neizdevās izveidot jaunu viesa profilu"</string>
<string name="user_nickname" msgid="262624187455825083">"Segvārds"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Pievienot viesi"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Noņemt viesi"</string>
@@ -644,4 +650,7 @@
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Apraides informācija"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Profila attēla izvēle"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"Noklusējuma lietotāja ikona"</string>
+ <string name="physical_keyboard_title" msgid="4811935435315835220">"Fiziskā tastatūra"</string>
+ <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Tastatūras izkārtojuma izvēle"</string>
+ <string name="keyboard_layout_default_label" msgid="1997292217218546957">"Noklusējums"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml
index 8111ec023f70..85788103ac95 100644
--- a/packages/SettingsLib/res/values-mk/strings.xml
+++ b/packages/SettingsLib/res/values-mk/strings.xml
@@ -533,6 +533,8 @@
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Помалку време."</string>
<string name="cancel" msgid="5665114069455378395">"Откажи"</string>
<string name="okay" msgid="949938843324579502">"Во ред"</string>
+ <!-- no translation found for done (381184316122520313) -->
+ <skip />
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"Аларми и потсетници"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Дозволи поставување аларми и потсетници"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Аларми и потсетници"</string>
@@ -551,7 +553,9 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Прашувај секогаш"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"Додека не го исклучите"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"Пред малку"</string>
- <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Овој телефон"</string>
+ <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Овој телефон"</string>
+ <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+ <skip />
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Овој телефон"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Проблем со поврзување. Исклучете го уредот и повторно вклучете го"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Жичен аудиоуред"</string>
@@ -591,7 +595,9 @@
<string name="user_set_lock_button" msgid="1427128184982594856">"Постави заклучување"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Префрли на <xliff:g id="USER_NAME">%s</xliff:g>"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Се создава нов корисник…"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Се создава нов гостин…"</string>
<string name="add_user_failed" msgid="4809887794313944872">"Не успеа да создаде нов корисник"</string>
+ <string name="add_guest_failed" msgid="8074548434469843443">"Не успеа создавањето нов гостин"</string>
<string name="user_nickname" msgid="262624187455825083">"Прекар"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Додајте гостин"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Отстрани гостин"</string>
@@ -644,4 +650,7 @@
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Инфо за улогите"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Изберете профилна слика"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"Икона за стандарден корисник"</string>
+ <string name="physical_keyboard_title" msgid="4811935435315835220">"Физичка тастатура"</string>
+ <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Избери распоред на тастатура"</string>
+ <string name="keyboard_layout_default_label" msgid="1997292217218546957">"Стандардно"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml
index 0ae164b00eaa..5abb78265fee 100644
--- a/packages/SettingsLib/res/values-ml/strings.xml
+++ b/packages/SettingsLib/res/values-ml/strings.xml
@@ -533,6 +533,8 @@
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"കുറഞ്ഞ സമയം."</string>
<string name="cancel" msgid="5665114069455378395">"റദ്ദാക്കുക"</string>
<string name="okay" msgid="949938843324579502">"ശരി"</string>
+ <!-- no translation found for done (381184316122520313) -->
+ <skip />
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"അലാറങ്ങളും റിമെെൻഡറുകളും"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"അലാറവും റിമെെൻഡറും സജ്ജീകരിക്കാൻ അനുവദിക്കുക"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"അലാറങ്ങളും റിമെെൻഡറുകളും"</string>
@@ -551,7 +553,9 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"എപ്പോഴും ചോദിക്കുക"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"നിങ്ങൾ ഓഫാക്കുന്നത് വരെ"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"ഇപ്പോൾ"</string>
- <string name="media_transfer_this_device_name" msgid="2357329267148436433">"ഈ ഫോൺ"</string>
+ <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"ഈ ഫോൺ"</string>
+ <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+ <skip />
<string name="media_transfer_this_phone" msgid="7194341457812151531">"ഈ ഫോൺ"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"കണക്‌റ്റ് ചെയ്യുന്നതിൽ പ്രശ്‌നമുണ്ടായി. ഉപകരണം ഓഫാക്കി വീണ്ടും ഓണാക്കുക"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"വയർ മുഖേന ബന്ധിപ്പിച്ച ഓഡിയോ ഉപകരണം"</string>
@@ -591,7 +595,9 @@
<string name="user_set_lock_button" msgid="1427128184982594856">"ലോക്ക് സജ്ജീകരിക്കുക"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g> എന്നതിലേക്ക് മാറുക"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"പുതിയ ഉപയോക്താവിനെ സൃഷ്‌ടിക്കുന്നു…"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"പുതിയ അതിഥിയെ സൃഷ്‌ടിക്കുന്നു…"</string>
<string name="add_user_failed" msgid="4809887794313944872">"പുതിയ ഉപയോക്താവിനെ സൃഷ്‌ടിക്കാനായില്ല"</string>
+ <string name="add_guest_failed" msgid="8074548434469843443">"പുതിയ അതിഥിയെ സൃഷ്‌ടിക്കാനായില്ല"</string>
<string name="user_nickname" msgid="262624187455825083">"വിളിപ്പേര്"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"അതിഥിയെ ചേർക്കുക"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"അതിഥിയെ നീക്കം ചെയ്യുക"</string>
@@ -644,4 +650,7 @@
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"കാസ്റ്റ് വിവരങ്ങൾ"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"പ്രൊഫൈൽ ചിത്രം തിരഞ്ഞെടുക്കുക"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"ഡിഫോൾട്ട് ഉപയോക്തൃ ഐക്കൺ"</string>
+ <string name="physical_keyboard_title" msgid="4811935435315835220">"ഫിസിക്കൽ കീബോർഡ്"</string>
+ <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"കീബോർഡ് ലേഔട്ട് തിരഞ്ഞെടുക്കുക"</string>
+ <string name="keyboard_layout_default_label" msgid="1997292217218546957">"ഡിഫോൾട്ട്"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml
index 7b74da2e4690..fb11d04c31c5 100644
--- a/packages/SettingsLib/res/values-mn/strings.xml
+++ b/packages/SettingsLib/res/values-mn/strings.xml
@@ -533,6 +533,8 @@
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Бага хугацаа."</string>
<string name="cancel" msgid="5665114069455378395">"Цуцлах"</string>
<string name="okay" msgid="949938843324579502">"OK"</string>
+ <!-- no translation found for done (381184316122520313) -->
+ <skip />
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"Сэрүүлэг болон сануулагч"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Сэрүүлэг болон сануулагч тохируулахыг зөвшөөрөх"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Сэрүүлэг, сануулагч"</string>
@@ -551,7 +553,9 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Тухай бүрд асуух"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"Таныг унтраах хүртэл"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"Дөнгөж сая"</string>
- <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Энэ утас"</string>
+ <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Энэ утас"</string>
+ <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+ <skip />
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Энэ утас"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Холбогдоход асуудал гарлаа. Төхөөрөмжийг унтраагаад дахин асаана уу"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Утастай аудио төхөөрөмж"</string>
@@ -591,7 +595,9 @@
<string name="user_set_lock_button" msgid="1427128184982594856">"Түгжээг тохируулах"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g> руу сэлгэх"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Шинэ хэрэглэгч үүсгэж байна…"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Шинэ зочин үүсгэж байна…"</string>
<string name="add_user_failed" msgid="4809887794313944872">"Шинэ хэрэглэгч үүсгэж чадсангүй"</string>
+ <string name="add_guest_failed" msgid="8074548434469843443">"Шинэ зочин үүсгэж чадсангүй"</string>
<string name="user_nickname" msgid="262624187455825083">"Хоч"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Зочин нэмэх"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Зочин хасах"</string>
@@ -644,4 +650,7 @@
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Дамжуулах мэдээлэл"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Профайл зураг сонгох"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"Өгөгдмөл хэрэглэгчийн дүрс тэмдэг"</string>
+ <string name="physical_keyboard_title" msgid="4811935435315835220">"Биет гар"</string>
+ <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Гарын бүдүүвчийг сонгох"</string>
+ <string name="keyboard_layout_default_label" msgid="1997292217218546957">"Өгөгдмөл"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml
index 451d834351ca..52aa9c6284a5 100644
--- a/packages/SettingsLib/res/values-mr/strings.xml
+++ b/packages/SettingsLib/res/values-mr/strings.xml
@@ -533,6 +533,8 @@
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"कमी वेळ."</string>
<string name="cancel" msgid="5665114069455378395">"रद्द करा"</string>
<string name="okay" msgid="949938843324579502">"ठीक आहे"</string>
+ <!-- no translation found for done (381184316122520313) -->
+ <skip />
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"अलार्म आणि रिमाइंडर"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"अलार्म आणि रिमाइंडर सेट करण्याची अनुमती द्या"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"अलार्म आणि रिमाइंडर"</string>
@@ -551,7 +553,9 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"प्रत्येक वेळी विचारा"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"तुम्ही बंद करेपर्यंत"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"आत्ताच"</string>
- <string name="media_transfer_this_device_name" msgid="2357329267148436433">"हा फोन"</string>
+ <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"हा फोन"</string>
+ <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+ <skip />
<string name="media_transfer_this_phone" msgid="7194341457812151531">"हा फोन"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"कनेक्‍ट करण्‍यात समस्‍या आली. डिव्हाइस बंद करा आणि नंतर सुरू करा"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"वायर असलेले ऑडिओ डिव्हाइस"</string>
@@ -591,7 +595,9 @@
<string name="user_set_lock_button" msgid="1427128184982594856">"लॉक सेट करा"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g> वर स्विच करा"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"नवीन वापरकर्ता तयार करत आहे…"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"नवीन अतिथी तयार करत आहे…"</string>
<string name="add_user_failed" msgid="4809887794313944872">"नवीन वापरकर्ता तयार करता आला नाही"</string>
+ <string name="add_guest_failed" msgid="8074548434469843443">"नवीन अतिथी तयार करता आला नाही"</string>
<string name="user_nickname" msgid="262624187455825083">"टोपणनाव"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"अतिथी जोडा"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"अतिथी काढून टाका"</string>
@@ -644,4 +650,7 @@
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"कास्टसंबंधित माहिती"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"प्रोफाइल फोटो निवडा"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"डीफॉल्ट वापरकर्ता आयकन"</string>
+ <string name="physical_keyboard_title" msgid="4811935435315835220">"वास्तविक कीबोर्ड"</string>
+ <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"किबोर्ड लेआउट निवडा"</string>
+ <string name="keyboard_layout_default_label" msgid="1997292217218546957">"डीफॉल्ट"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml
index d3dfb62ce0be..7c96e993b258 100644
--- a/packages/SettingsLib/res/values-ms/strings.xml
+++ b/packages/SettingsLib/res/values-ms/strings.xml
@@ -533,6 +533,8 @@
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Kurang masa."</string>
<string name="cancel" msgid="5665114069455378395">"Batal"</string>
<string name="okay" msgid="949938843324579502">"OK"</string>
+ <!-- no translation found for done (381184316122520313) -->
+ <skip />
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"Penggera dan peringatan"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Benarkan penetapan penggera dan peringatan"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Penggera &amp; peringatan"</string>
@@ -551,7 +553,9 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Tanya setiap kali"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"Sehingga anda matikan"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"Sebentar tadi"</string>
- <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Telefon ini"</string>
+ <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Telefon ini"</string>
+ <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+ <skip />
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Telefon ini"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Masalah penyambungan. Matikan &amp; hidupkan kembali peranti"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Peranti audio berwayar"</string>
@@ -591,7 +595,9 @@
<string name="user_set_lock_button" msgid="1427128184982594856">"Tetapkan kunci"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Tukar kepada <xliff:g id="USER_NAME">%s</xliff:g>"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Mencipta pengguna baharu…"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Membuat tetamu baharu…"</string>
<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>
<string name="guest_new_guest" msgid="3482026122932643557">"Tambah tetamu"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Alih keluar tetamu"</string>
@@ -644,4 +650,7 @@
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Maklumat Pelakon"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Pilih gambar profil"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"Ikon pengguna lalai"</string>
+ <string name="physical_keyboard_title" msgid="4811935435315835220">"Papan kekunci fizikal"</string>
+ <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Pilih susun atur papan kekunci"</string>
+ <string name="keyboard_layout_default_label" msgid="1997292217218546957">"Lalai"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml
index cc6269f0abe1..6fd1d8bacf0a 100644
--- a/packages/SettingsLib/res/values-my/strings.xml
+++ b/packages/SettingsLib/res/values-my/strings.xml
@@ -533,6 +533,8 @@
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"အချိန်လျှော့ရန်။"</string>
<string name="cancel" msgid="5665114069455378395">"မလုပ်တော့"</string>
<string name="okay" msgid="949938843324579502">"OK"</string>
+ <!-- no translation found for done (381184316122520313) -->
+ <skip />
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"နှိုးစက်နှင့် သတိပေးချက်များ"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"နှိုးစက်နှင့် သတိပေးချက်များ သတ်မှတ်ခွင့်ပြုရန်"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"နှိုးစက်နှင့် သတိပေးချက်များ"</string>
@@ -551,7 +553,9 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"အမြဲမေးရန်"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"သင်ပိတ်လိုက်သည် အထိ"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"ယခုလေးတင်"</string>
- <string name="media_transfer_this_device_name" msgid="2357329267148436433">"ဤဖုန်း"</string>
+ <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"ဤဖုန်း"</string>
+ <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+ <skip />
<string name="media_transfer_this_phone" msgid="7194341457812151531">"ဤဖုန်း"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"ချိတ်ဆက်ရာတွင် ပြဿနာရှိပါသည်။ စက်ကိုပိတ်ပြီး ပြန်ဖွင့်ပါ"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ကြိုးတပ် အသံစက်ပစ္စည်း"</string>
@@ -591,7 +595,9 @@
<string name="user_set_lock_button" msgid="1427128184982594856">"သော့ချရန် သတ်မှတ်ပါ"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g> သို့ ပြောင်းရန်"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"အသုံးပြုသူအသစ် ပြုလုပ်နေသည်…"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"ဧည့်သည်သစ် ပြုလုပ်နေသည်…"</string>
<string name="add_user_failed" msgid="4809887794313944872">"အသုံးပြုသူအသစ် ပြုလုပ်၍မရပါ"</string>
+ <string name="add_guest_failed" msgid="8074548434469843443">"ဧည့်သည်သစ် ပြုလုပ်၍မရပါ"</string>
<string name="user_nickname" msgid="262624187455825083">"နာမည်ပြောင်"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"ဧည့်သည့် ထည့်ရန်"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"ဧည့်သည်ကို ဖယ်ထုတ်ရန်"</string>
@@ -644,4 +650,7 @@
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"ကာစ် အချက်အလက်"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"ပရိုဖိုင်ပုံ ရွေးပါ"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"မူရင်းအသုံးပြုသူ သင်္ကေတ"</string>
+ <string name="physical_keyboard_title" msgid="4811935435315835220">"ပကတိ ကီးဘုတ်"</string>
+ <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"လက်ကွက်အပြင်အဆင်ရွေးချယ်ခြင်း"</string>
+ <string name="keyboard_layout_default_label" msgid="1997292217218546957">"မူရင်း"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index 8900fe7ac27a..e965d60105f9 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -533,6 +533,8 @@
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Mindre tid."</string>
<string name="cancel" msgid="5665114069455378395">"Avbryt"</string>
<string name="okay" msgid="949938843324579502">"OK"</string>
+ <!-- no translation found for done (381184316122520313) -->
+ <skip />
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarmer og påminnelser"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Tillat innstilling av alarmer og påminnelser"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmer og påminnelser"</string>
@@ -551,7 +553,9 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Spør hver gang"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"Til du slår av"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"Nå nettopp"</string>
- <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Denne telefonen"</string>
+ <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Denne telefonen"</string>
+ <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+ <skip />
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Denne telefonen"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Tilkoblingsproblemer. Slå enheten av og på igjen"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Lydenhet med kabel"</string>
@@ -591,7 +595,9 @@
<string name="user_set_lock_button" msgid="1427128184982594856">"Angi lås"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Bytt til <xliff:g id="USER_NAME">%s</xliff:g>"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Oppretter en ny bruker …"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Oppretter en ny gjest …"</string>
<string name="add_user_failed" msgid="4809887794313944872">"Kunne ikke opprette noen ny bruker"</string>
+ <string name="add_guest_failed" msgid="8074548434469843443">"Kunne ikke opprette en ny gjest"</string>
<string name="user_nickname" msgid="262624187455825083">"Kallenavn"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Legg til en gjest"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Fjern gjesten"</string>
@@ -644,4 +650,7 @@
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Castinformasjon"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Velg et profilbilde"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"Standard brukerikon"</string>
+ <string name="physical_keyboard_title" msgid="4811935435315835220">"Fysisk tastatur"</string>
+ <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Velg et tastaturoppsett"</string>
+ <string name="keyboard_layout_default_label" msgid="1997292217218546957">"Standard"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml
index d0270a98d121..3bcc65ad1c57 100644
--- a/packages/SettingsLib/res/values-ne/strings.xml
+++ b/packages/SettingsLib/res/values-ne/strings.xml
@@ -533,6 +533,8 @@
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"कम समय।"</string>
<string name="cancel" msgid="5665114069455378395">"रद्द गर्नुहोस्"</string>
<string name="okay" msgid="949938843324579502">"ठिक छ"</string>
+ <!-- no translation found for done (381184316122520313) -->
+ <skip />
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"अलार्म र रिमाइन्डरहरू"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"अलार्म तथा रिमाइन्डर सेट गर्न दिइयोस्"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"घडी तथा रिमाइन्डरहरू"</string>
@@ -551,7 +553,9 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"प्रत्येक पटक सोधियोस्"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"तपाईंले अफ नगरेसम्म"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"अहिले भर्खरै"</string>
- <string name="media_transfer_this_device_name" msgid="2357329267148436433">"यो फोन"</string>
+ <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"यो फोन"</string>
+ <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+ <skip />
<string name="media_transfer_this_phone" msgid="7194341457812151531">"यो फोन"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"जोड्ने क्रममा समस्या भयो। यन्त्रलाई निष्क्रिय पारेर फेरि सक्रिय गर्नुहोस्"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"तारयुक्त अडियो यन्त्र"</string>
@@ -591,7 +595,9 @@
<string name="user_set_lock_button" msgid="1427128184982594856">"लक सेट गर्नुहोस्"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"प्रयोगकर्ता बदलेर <xliff:g id="USER_NAME">%s</xliff:g> पार्नुहोस्"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"नयाँ प्रयोगकर्ता बनाउँदै…"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"नयाँ अतिथि बनाइँदै छ…"</string>
<string name="add_user_failed" msgid="4809887794313944872">"नयाँ प्रयोगकर्ता सिर्जना गर्न सकिएन"</string>
+ <string name="add_guest_failed" msgid="8074548434469843443">"नयाँ अतिथि बनाउन सकिएन"</string>
<string name="user_nickname" msgid="262624187455825083">"उपनाम"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"अतिथि थप्नुहोस्"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"अतिथि हटाउनुहोस्"</string>
@@ -644,4 +650,7 @@
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"कास्टसम्बन्धी जानकारी"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"प्रोफाइल फोटो छान्नुहोस्"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"प्रयोगकर्ताको डिफल्ट आइकन"</string>
+ <string name="physical_keyboard_title" msgid="4811935435315835220">"भौतिक किबोर्ड"</string>
+ <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"किबोर्ड लेआउट छान्नुहोस्"</string>
+ <string name="keyboard_layout_default_label" msgid="1997292217218546957">"डिफल्ट"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index 5c19a7273677..3d14776ade24 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -533,6 +533,8 @@
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Minder tijd."</string>
<string name="cancel" msgid="5665114069455378395">"Annuleren"</string>
<string name="okay" msgid="949938843324579502">"OK"</string>
+ <!-- no translation found for done (381184316122520313) -->
+ <skip />
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"Wekkers en herinneringen"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Wekkers en herinneringen laten instellen"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Wekkers en herinneringen"</string>
@@ -551,7 +553,9 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Vraag altijd"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"Totdat je uitzet"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"Zojuist"</string>
- <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Deze telefoon"</string>
+ <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Deze telefoon"</string>
+ <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+ <skip />
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Deze telefoon"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Probleem bij verbinding maken. Zet het apparaat uit en weer aan."</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Bedraad audioapparaat"</string>
@@ -591,7 +595,9 @@
<string name="user_set_lock_button" msgid="1427128184982594856">"Vergrendeling instellen"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Overschakelen naar <xliff:g id="USER_NAME">%s</xliff:g>"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Nieuwe gebruiker maken…"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Nieuwe gast maken…"</string>
<string name="add_user_failed" msgid="4809887794313944872">"Kan geen nieuwe gebruiker maken"</string>
+ <string name="add_guest_failed" msgid="8074548434469843443">"Kan geen nieuwe gast maken"</string>
<string name="user_nickname" msgid="262624187455825083">"Bijnaam"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Gast toevoegen"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Gast verwijderen"</string>
@@ -644,4 +650,7 @@
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Castinformatie"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Kies een profielfoto"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"Standaard gebruikersicoon"</string>
+ <string name="physical_keyboard_title" msgid="4811935435315835220">"Fysiek toetsenbord"</string>
+ <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Toetsenbordindeling kiezen"</string>
+ <string name="keyboard_layout_default_label" msgid="1997292217218546957">"Standaard"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-or/strings.xml b/packages/SettingsLib/res/values-or/strings.xml
index 14abf05e0b56..f9ee66c3a933 100644
--- a/packages/SettingsLib/res/values-or/strings.xml
+++ b/packages/SettingsLib/res/values-or/strings.xml
@@ -207,8 +207,8 @@
<string name="tts_status_requires_network" msgid="8327617638884678896">"<xliff:g id="LOCALE">%1$s</xliff:g> ନେଟ୍‌ୱର୍କ ସଂଯୋଜନା ଆବଶ୍ୟକ କରେ"</string>
<string name="tts_status_not_supported" msgid="2702997696245523743">"<xliff:g id="LOCALE">%1$s</xliff:g> ସପୋର୍ଟ କରୁ ନାହିଁ"</string>
<string name="tts_status_checking" msgid="8026559918948285013">"ଯାଞ୍ଚ କରାଯାଉଛି…"</string>
- <string name="tts_engine_settings_title" msgid="7849477533103566291">"<xliff:g id="TTS_ENGINE_NAME">%s</xliff:g> ପାଇଁ ସେଟିଙ୍ଗ"</string>
- <string name="tts_engine_settings_button" msgid="477155276199968948">"ଇଞ୍ଜିନ୍‌ ସେଟିଙ୍ଗ ଆରମ୍ଭ କରନ୍ତୁ"</string>
+ <string name="tts_engine_settings_title" msgid="7849477533103566291">"<xliff:g id="TTS_ENGINE_NAME">%s</xliff:g> ପାଇଁ ସେଟିଂସ"</string>
+ <string name="tts_engine_settings_button" msgid="477155276199968948">"ଇଞ୍ଜିନ୍‌ ସେଟିଂସ ଲଞ୍ଚ କରନ୍ତୁ"</string>
<string name="tts_engine_preference_section_title" msgid="3861562305498624904">"ନିଜ ପସନ୍ଦର ଇଞ୍ଜିନ୍‌"</string>
<string name="tts_general_section_title" msgid="8919671529502364567">"ସାଧାରଣ"</string>
<string name="tts_reset_speech_pitch_title" msgid="7149398585468413246">"ସ୍ପୀଚ୍‌ର ପିଚ୍‌ ରିସେଟ୍‌ କରନ୍ତୁ"</string>
@@ -231,9 +231,9 @@
<string name="development_settings_enable" msgid="4285094651288242183">"ଡେଭଲପର୍‌ ବିକଳ୍ପଗୁଡ଼ିକ ସକ୍ଷମ କରନ୍ତୁ"</string>
<string name="development_settings_summary" msgid="8718917813868735095">"ଆପ୍‌ର ବିକାଶ ପାଇଁ ବିକଳ୍ପମାନ ସେଟ୍‌ କରନ୍ତୁ"</string>
<string name="development_settings_not_available" msgid="355070198089140951">"ଏହି ଉପଯୋଗକର୍ତ୍ତାଙ୍କ ପାଇଁ ଡେଭଲପରଙ୍କ ବିକଳ୍ପସମୂହ ଉପଲବ୍ଧ ନୁହେଁ"</string>
- <string name="vpn_settings_not_available" msgid="2894137119965668920">"VPN ସେଟିଙ୍ଗ ଏହି ଉପଯୋଗକର୍ତ୍ତାଙ୍କ ପାଇଁ ଉପଲବ୍ଧ ନୁହେଁ"</string>
- <string name="tethering_settings_not_available" msgid="266821736434699780">"ଏହି ଉପଯୋଗକର୍ତ୍ତାଙ୍କ ପାଇଁ ଟିଥରିଙ୍ଗ ସେଟିଙ୍ଗ ଉପଲବ୍ଧ ନାହିଁ"</string>
- <string name="apn_settings_not_available" msgid="1147111671403342300">"ଆକ୍ସେସ୍‌ ପଏଣ୍ଟ ନାମର ସେଟିଙ୍ଗ ଏହି ଉପଯୋଗକର୍ତ୍ତାଙ୍କ ପାଇଁ ଉପଲବ୍ଧ ନାହିଁ"</string>
+ <string name="vpn_settings_not_available" msgid="2894137119965668920">"VPN ସେଟିଂସ ଏହି ଉପଯୋଗକର୍ତ୍ତାଙ୍କ ପାଇଁ ଉପଲବ୍ଧ ନାହିଁ"</string>
+ <string name="tethering_settings_not_available" msgid="266821736434699780">"ଏହି ଉପଯୋଗକର୍ତ୍ତାଙ୍କ ପାଇଁ ଟିଥରିଂ ସେଟିଂସ ଉପଲବ୍ଧ ନାହିଁ"</string>
+ <string name="apn_settings_not_available" msgid="1147111671403342300">"ଆକ୍ସେସ ପଏଣ୍ଟ ନାମର ସେଟିଂସ ଏହି ଉପଯୋଗକର୍ତ୍ତାଙ୍କ ପାଇଁ ଉପଲବ୍ଧ ନାହିଁ"</string>
<string name="enable_adb" msgid="8072776357237289039">"USB ଡିବଗିଂ"</string>
<string name="enable_adb_summary" msgid="3711526030096574316">"USB ସଂଯୁକ୍ତ ହେବାବେଳେ ଡିବଗ୍‌ ମୋଡ୍‌"</string>
<string name="clear_adb_keys" msgid="3010148733140369917">"USB ଡିବଗିଂ ଅଧିକାରକୁ ବାତିଲ୍ କରନ୍ତୁ"</string>
@@ -335,8 +335,8 @@
<string name="adbwifi_warning_title" msgid="727104571653031865">"ୱାୟାରଲେସ୍ ଡିବଗିଂ ପାଇଁ ଅନୁମତି ଦେବେ?"</string>
<string name="adbwifi_warning_message" msgid="8005936574322702388">"ୱାୟାରଲେସ୍ ଡିବଗିଂ କେବଳ ଉନ୍ନତି ପାଇଁ ଉଦ୍ଦିଷ୍ଟ ଅଟେ। ଆପଣଙ୍କ କମ୍ପ୍ୟୁଟର ଏବଂ ଡିଭାଇସ୍ ମଧ୍ୟରେ ଡାଟା କପି କରିବାକୁ, ବିନା ବିଜ୍ଞପ୍ତିରେ ଆପଣଙ୍କ ଡିଭାଇସରେ ଆପ୍ସ ଇନଷ୍ଟଲ୍ କରିବାକୁ ଏବଂ ଲଗ୍ ଡାଟା ପଢ଼ିବା ପାଇଁ ଏହାକୁ ବ୍ୟବହାର କରନ୍ତୁ।"</string>
<string name="adb_keys_warning_message" msgid="2968555274488101220">"ଅଧିକୃତ ସମସ୍ତ କମ୍ପ୍ୟୁଟରରୁ USB ଡିବଗ୍‌ କରିବା ଆକ୍ସେସ୍‌ ପ୍ରତ୍ୟାହାର କରିବେ କି?"</string>
- <string name="dev_settings_warning_title" msgid="8251234890169074553">"ଡେଭଲପମେଣ୍ଟ ସେଟିଙ୍ଗ ଅନୁମତି ଦେବେ?"</string>
- <string name="dev_settings_warning_message" msgid="37741686486073668">"ଏହି ସେଟିଙ୍ଗଗୁଡ଼ିକ କେବଳ ବିକାଶ ବ୍ୟବହାର ପାଇଁ ଉଦ୍ଦିଷ୍ଟ। ସେଗୁଡ଼ିକ କାରଣରୁ ଆପଣଙ୍କ ଡିଭାଇସ୍‌ ଓ ଆପ୍ଲିକେଶନ୍‍‍ଗୁଡ଼ିକ ଠିକ୍‌ ଭାବେ କାମ ନକରିପାରେ।"</string>
+ <string name="dev_settings_warning_title" msgid="8251234890169074553">"ଡେଭଲପମେଣ୍ଟ ସେଟିଂସକୁ ଅନୁମତି ଦେବେ?"</string>
+ <string name="dev_settings_warning_message" msgid="37741686486073668">"ଏହି ସେଟିଂସ କେବଳ ବିକାଶର ବ୍ୟବହାର ପାଇଁ ଉଦ୍ଦିଷ୍ଟ। ସେଗୁଡ଼ିକ କାରଣରୁ ଆପଣଙ୍କ ଡିଭାଇସ ଓ ଆପ୍ଲିକେସନଗୁଡ଼ିକ ଖରାପ ହୋଇଯାଇପାରେ କିମ୍ବା ଠିକ୍‌ ଭାବେ କାମ ନକରିପାରେ।"</string>
<string name="verify_apps_over_usb_title" msgid="6031809675604442636">"USB ଜରିଆରେ ଆପ୍‌ଗୁଡ଼ିକୁ ଯାଞ୍ଚ କରନ୍ତୁ"</string>
<string name="verify_apps_over_usb_summary" msgid="1317933737581167839">"ADB/ADT ମାଧ୍ୟମରେ ଇନଷ୍ଟଲ ହୋଇଥିବା ଆପ୍‌ଗୁଡ଼ିକ କ୍ଷତିକାରକ କି ନୁହେଁ ଯାଞ୍ଚ କରନ୍ତୁ।"</string>
<string name="bluetooth_show_devices_without_names_summary" msgid="780964354377854507">"(କେବଳ MAC ଠିକଣା ଥାଇ) ନାମ ବିନା ବ୍ଲୁଟୂଥ ଡିଭାଇସଗୁଡ଼ିକ ପ୍ରଦର୍ଶିତ ହେବ"</string>
@@ -500,7 +500,7 @@
<string name="external_source_trusted" msgid="1146522036773132905">"ଅନୁମତି ଦିଆଯାଇଛି"</string>
<string name="external_source_untrusted" msgid="5037891688911672227">"ଅନୁମତି ନାହିଁ"</string>
<string name="install_other_apps" msgid="3232595082023199454">"ଅଜଣା ଆପ୍‌ ଇନଷ୍ଟଲ୍‌ କରନ୍ତୁ"</string>
- <string name="home" msgid="973834627243661438">"ସେଟିଂସ୍ ହୋମ୍‌"</string>
+ <string name="home" msgid="973834627243661438">"ସେଟିଂସ ହୋମ"</string>
<string-array name="battery_labels">
<item msgid="7878690469765357158">"0%"</item>
<item msgid="8894873528875953317">"50%"</item>
@@ -520,7 +520,7 @@
<string name="retail_demo_reset_title" msgid="1866911701095959800">"ପାସ୍‌ୱର୍ଡ ଆବଶ୍ୟକ"</string>
<string name="active_input_method_subtypes" msgid="4232680535471633046">"ସକ୍ରିୟ ଇନପୁଟ୍‌-ପଦ୍ଧତିଗୁଡ଼ିକ"</string>
<string name="use_system_language_to_select_input_method_subtypes" msgid="4865195835541387040">"ସିଷ୍ଟମ୍‌ ଭାଷା ବ୍ୟବହାର କରନ୍ତୁ"</string>
- <string name="failed_to_open_app_settings_toast" msgid="764897252657692092">"<xliff:g id="SPELL_APPLICATION_NAME">%1$s</xliff:g> ପାଇଁ ସେଟିଙ୍ଗ ଖୋଲିବାରେ ବିଫଳ"</string>
+ <string name="failed_to_open_app_settings_toast" msgid="764897252657692092">"<xliff:g id="SPELL_APPLICATION_NAME">%1$s</xliff:g> ପାଇଁ ସେଟିଂସ ଖୋଲିବାରେ ବିଫଳ"</string>
<string name="ime_security_warning" msgid="6547562217880551450">"ଏହି ଇନ୍‌ପୁଟ୍‌ ପଦ୍ଧତି, ପାସ୍‌ୱର୍ଡ ଓ କ୍ରେଡିଟ୍‌ କାର୍ଡ ନମ୍ୱର୍‌ ଭଳି ବ୍ୟକ୍ତିଗତ ଡାଟା ସମେତ ଆପଣ ଟାଇପ୍‌ କରିଥିବା ସମସ୍ତ ଅକ୍ଷର ସଂଗହ କରିପାରେ।ଏହା, <xliff:g id="IME_APPLICATION_NAME">%1$s</xliff:g> ଆପ୍‌ରୁ ଆସିଛି| ଏହି ଇନ୍‌ପୁଟ୍‌ ପଦ୍ଧତି ବ୍ୟବହାର କରିବେ?"</string>
<string name="direct_boot_unaware_dialog_message" msgid="7845398276735021548">"ଧ୍ୟାନଦିଅନ୍ତୁ: ରିବୁଟ୍‌ କରିବା ପରେ, ଆପଣଙ୍କ ଫୋନ୍‌ ଅନଲକ୍‌ ନହେବା ପର୍ଯ୍ୟନ୍ତ ଏହି ଆପ୍‌ ଆରମ୍ଭ ହୋଇପାରିବ ନାହିଁ"</string>
<string name="ims_reg_title" msgid="8197592958123671062">"IMS ପଞ୍ଜିକରଣ ସ୍ଥିତି"</string>
@@ -533,6 +533,8 @@
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"କମ୍ ସମୟ।"</string>
<string name="cancel" msgid="5665114069455378395">"ବାତିଲ୍"</string>
<string name="okay" msgid="949938843324579502">"ଠିକ୍‌ ଅଛି"</string>
+ <!-- no translation found for done (381184316122520313) -->
+ <skip />
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"ଆଲାରାମ୍ ଏବଂ ରିମାଇଣ୍ଡରଗୁଡ଼ିକ"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"ଆଲାରାମ ଓ ରିମାଇଣ୍ଡରଗୁଡ଼ିକ ସେଟ କରିବାକୁ ଅନୁମତି ଦିଅନ୍ତୁ"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"ଆଲାରାମ୍ ଏବଂ ରିମାଇଣ୍ଡରଗୁଡ଼ିକ"</string>
@@ -551,7 +553,9 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"ପ୍ରତ୍ୟେକ ଥର ପଚାରନ୍ତୁ"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"ଆପଣ ବନ୍ଦ ନକରିବା ପର୍ଯ୍ୟନ୍ତ"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"ଏହିକ୍ଷଣି"</string>
- <string name="media_transfer_this_device_name" msgid="2357329267148436433">"ଏହି ଫୋନ"</string>
+ <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"ଏହି ଫୋନ"</string>
+ <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+ <skip />
<string name="media_transfer_this_phone" msgid="7194341457812151531">"ଏହି ଫୋନ୍"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"ସଂଯୋଗ କରିବାରେ ସମସ୍ୟା ହେଉଛି। ଡିଭାଇସ୍ ବନ୍ଦ କରି ପୁଣି ଚାଲୁ କରନ୍ତୁ"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ତାରଯୁକ୍ତ ଅଡିଓ ଡିଭାଇସ୍"</string>
@@ -591,7 +595,9 @@
<string name="user_set_lock_button" msgid="1427128184982594856">"ଲକ୍‌ ସେଟ୍‌ କରନ୍ତୁ"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g>କୁ ସ୍ୱିଚ୍ କରନ୍ତୁ"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"ନୂଆ ଉପଯୋଗକର୍ତ୍ତା ତିଆରି କରାଯାଉଛି…"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"ନୂଆ ଅତିଥି ତିଆରି କରାଯାଉଛି…"</string>
<string name="add_user_failed" msgid="4809887794313944872">"ନୂଆ ଉପଯୋଗକର୍ତ୍ତା ତିଆରି କରିବାକୁ ବିଫଳ ହେଲା"</string>
+ <string name="add_guest_failed" msgid="8074548434469843443">"ଜଣେ ନୂଆ ଅତିଥି ତିଆରି କରିବାରେ ବିଫଳ ହୋଇଛି"</string>
<string name="user_nickname" msgid="262624187455825083">"ଡାକନାମ"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"ଅତିଥି ଯୋଗ କରନ୍ତୁ"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"ଅତିଥିଙ୍କୁ କାଢ଼ି ଦିଅନ୍ତୁ"</string>
@@ -644,4 +650,10 @@
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"କାଷ୍ଟ ସୂଚନା"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"ଏକ ପ୍ରୋଫାଇଲ ଛବି ବାଛନ୍ତୁ"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"ଡିଫଲ୍ଟ ଉପଯୋଗକର୍ତ୍ତା ଆଇକନ"</string>
+ <!-- no translation found for physical_keyboard_title (4811935435315835220) -->
+ <skip />
+ <!-- no translation found for keyboard_layout_dialog_title (3927180147005616290) -->
+ <skip />
+ <!-- no translation found for keyboard_layout_default_label (1997292217218546957) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml
index 4671454941af..f1a24e45aba0 100644
--- a/packages/SettingsLib/res/values-pa/strings.xml
+++ b/packages/SettingsLib/res/values-pa/strings.xml
@@ -533,6 +533,8 @@
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"ਘੱਟ ਸਮਾਂ।"</string>
<string name="cancel" msgid="5665114069455378395">"ਰੱਦ ਕਰੋ"</string>
<string name="okay" msgid="949938843324579502">"ਠੀਕ ਹੈ"</string>
+ <!-- no translation found for done (381184316122520313) -->
+ <skip />
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"ਅਲਾਰਮ ਅਤੇ ਰਿਮਾਈਂਡਰ"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"ਅਲਾਰਮ ਅਤੇ ਰਿਮਾਈਂਡਰ ਸੈੱਟ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿਓ"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"ਅਲਾਰਮ ਅਤੇ ਰਿਮਾਈਂਡਰ"</string>
@@ -551,7 +553,9 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"ਹਰ ਵਾਰ ਪੁੱਛੋ"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"ਜਦੋਂ ਤੱਕ ਤੁਸੀਂ ਬੰਦ ਨਹੀਂ ਕਰਦੇ"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"ਹੁਣੇ ਹੀ"</string>
- <string name="media_transfer_this_device_name" msgid="2357329267148436433">"ਇਹ ਫ਼ੋਨ"</string>
+ <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"ਇਹ ਫ਼ੋਨ"</string>
+ <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+ <skip />
<string name="media_transfer_this_phone" msgid="7194341457812151531">"ਇਹ ਫ਼ੋਨ"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"ਕਨੈਕਟ ਕਰਨ ਵਿੱਚ ਸਮੱਸਿਆ ਆਈ। ਡੀਵਾਈਸ ਨੂੰ ਬੰਦ ਕਰਕੇ ਵਾਪਸ ਚਾਲੂ ਕਰੋ"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ਤਾਰ ਵਾਲਾ ਆਡੀਓ ਡੀਵਾਈਸ"</string>
@@ -591,7 +595,9 @@
<string name="user_set_lock_button" msgid="1427128184982594856">" ਲਾਕ ਸੈੱਟ ਕਰੋ"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g> \'ਤੇ ਜਾਓ"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"ਨਵਾਂ ਵਰਤੋਂਕਾਰ ਬਣਾਇਆ ਜਾ ਰਿਹਾ ਹੈ…"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"ਨਵਾਂ ਮਹਿਮਾਨ ਪ੍ਰੋਫਾਈਲ ਬਣਾਇਆ ਜਾ ਰਿਹਾ ਹੈ…"</string>
<string name="add_user_failed" msgid="4809887794313944872">"ਨਵਾਂ ਵਰਤੋਂਕਾਰ ਬਣਾਉਣਾ ਅਸਫਲ ਰਿਹਾ"</string>
+ <string name="add_guest_failed" msgid="8074548434469843443">"ਨਵਾਂ ਮਹਿਮਾਨ ਪ੍ਰੋਫਾਈਲ ਬਣਾਉਣਾ ਅਸਫਲ ਰਿਹਾ"</string>
<string name="user_nickname" msgid="262624187455825083">"ਉਪਨਾਮ"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"ਮਹਿਮਾਨ ਸ਼ਾਮਲ ਕਰੋ"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"ਮਹਿਮਾਨ ਹਟਾਓ"</string>
@@ -644,4 +650,7 @@
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"ਕਾਸਟ ਸੰਬੰਧੀ ਜਾਣਕਾਰੀ"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"ਕੋਈ ਪ੍ਰੋਫਾਈਲ ਤਸਵੀਰ ਚੁਣੋ"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"ਪੂਰਵ-ਨਿਰਧਾਰਿਤ ਵਰਤੋਂਕਾਰ ਪ੍ਰਤੀਕ"</string>
+ <string name="physical_keyboard_title" msgid="4811935435315835220">"ਭੌਤਿਕ ਕੀ-ਬੋਰਡ"</string>
+ <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"ਕੀ-ਬੋਰਡ ਖਾਕਾ ਚੁਣੋ"</string>
+ <string name="keyboard_layout_default_label" msgid="1997292217218546957">"ਪੂਰਵ-ਨਿਰਧਾਰਿਤ"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index 073ffbdba2a0..852ed6f26e98 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -533,6 +533,8 @@
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Mniej czasu."</string>
<string name="cancel" msgid="5665114069455378395">"Anuluj"</string>
<string name="okay" msgid="949938843324579502">"OK"</string>
+ <!-- no translation found for done (381184316122520313) -->
+ <skip />
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarmy i przypomnienia"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Zezwalaj na ustawianie alarmów i przypomnień"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmy i przypomnienia"</string>
@@ -551,7 +553,9 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Zawsze pytaj"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"Dopóki nie wyłączysz"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"Przed chwilą"</string>
- <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Ten telefon"</string>
+ <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Ten telefon"</string>
+ <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+ <skip />
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Ten telefon"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problem z połączeniem. Wyłącz i ponownie włącz urządzenie"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Przewodowe urządzenie audio"</string>
@@ -591,7 +595,9 @@
<string name="user_set_lock_button" msgid="1427128184982594856">"Ustaw blokadę"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Przełącz na: <xliff:g id="USER_NAME">%s</xliff:g>"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Tworzę nowego użytkownika…"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Tworzę nowego gościa…"</string>
<string name="add_user_failed" msgid="4809887794313944872">"Nie udało się utworzyć nowego użytkownika"</string>
+ <string name="add_guest_failed" msgid="8074548434469843443">"Nie udało się utworzyć nowego gościa"</string>
<string name="user_nickname" msgid="262624187455825083">"Pseudonim"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Dodaj gościa"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Usuń gościa"</string>
@@ -644,4 +650,7 @@
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Obsada"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Wybierz zdjęcie profilowe"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"Ikona domyślnego użytkownika"</string>
+ <string name="physical_keyboard_title" msgid="4811935435315835220">"Klawiatura fizyczna"</string>
+ <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Wybierz układ klawiatury"</string>
+ <string name="keyboard_layout_default_label" msgid="1997292217218546957">"Domyślny"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
index 8d93b31be90a..cdb364a16a02 100644
--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -533,6 +533,8 @@
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Menos tempo."</string>
<string name="cancel" msgid="5665114069455378395">"Cancelar"</string>
<string name="okay" msgid="949938843324579502">"Ok"</string>
+ <!-- no translation found for done (381184316122520313) -->
+ <skip />
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarmes e lembretes"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Autorizar a definição de alarmes e lembretes"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmes e lembretes"</string>
@@ -551,7 +553,9 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Perguntar sempre"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"Até você desativar"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"Agora"</string>
- <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Este smartphone"</string>
+ <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Este smartphone"</string>
+ <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+ <skip />
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Este smartphone"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Ocorreu um problema na conexão. Desligue o dispositivo e ligue-o novamente"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Dispositivo de áudio com fio"</string>
@@ -591,7 +595,9 @@
<string name="user_set_lock_button" msgid="1427128184982594856">"Definir bloqueio"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Mudar para <xliff:g id="USER_NAME">%s</xliff:g>"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Criando novo usuário…"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Criando novo convidado…"</string>
<string name="add_user_failed" msgid="4809887794313944872">"Falha ao criar um novo usuário"</string>
+ <string name="add_guest_failed" msgid="8074548434469843443">"Falha ao criar um novo convidado"</string>
<string name="user_nickname" msgid="262624187455825083">"Apelido"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Adicionar convidado"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Remover convidado"</string>
@@ -644,4 +650,7 @@
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Info. de transmissão"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Escolher a foto do perfil"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"Ícone de usuário padrão"</string>
+ <string name="physical_keyboard_title" msgid="4811935435315835220">"Teclado físico"</string>
+ <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Escolha o layout do teclado"</string>
+ <string name="keyboard_layout_default_label" msgid="1997292217218546957">"Padrão"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
index 47a49e7472ee..c647a213d254 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -528,11 +528,13 @@
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"Não registado"</string>
<string name="status_unavailable" msgid="5279036186589861608">"Indisponível"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"O MAC é aleatório."</string>
- <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{0 dispositivo ligados}=1{1 dispositivo ligado}one{# dispositivo(s) ligado(s)}other{# dispositivos ligados}}"</string>
+ <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{0 dispositivo ligados}=1{1 dispositivo ligado}other{# dispositivos ligados}}"</string>
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"Mais tempo."</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Menos tempo."</string>
<string name="cancel" msgid="5665114069455378395">"Cancelar"</string>
<string name="okay" msgid="949938843324579502">"OK"</string>
+ <!-- no translation found for done (381184316122520313) -->
+ <skip />
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarmes e lembretes"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Permitir a definição de alarmes e lembretes"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmes e lembretes"</string>
@@ -551,7 +553,9 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Perguntar sempre"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"Até desativar"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"Agora mesmo"</string>
- <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Este telemóvel"</string>
+ <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Este telemóvel"</string>
+ <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+ <skip />
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Este telemóvel"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problema ao ligar. Desligue e volte a ligar o dispositivo."</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Dispositivo de áudio com fios"</string>
@@ -591,7 +595,9 @@
<string name="user_set_lock_button" msgid="1427128184982594856">"Definir bloqueio"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Mudar para <xliff:g id="USER_NAME">%s</xliff:g>"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"A criar novo utilizador…"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"A criar novo convidado…"</string>
<string name="add_user_failed" msgid="4809887794313944872">"Falha ao criar um novo utilizador"</string>
+ <string name="add_guest_failed" msgid="8074548434469843443">"Falha ao criar um novo convidado"</string>
<string name="user_nickname" msgid="262624187455825083">"Alcunha"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Adicionar convidado"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Remover convidado"</string>
@@ -644,4 +650,7 @@
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Info. de transmissão"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Escolha uma imagem do perfil"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"Ícone do utilizador predefinido"</string>
+ <string name="physical_keyboard_title" msgid="4811935435315835220">"Teclado físico"</string>
+ <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Escolha um esquema de teclado"</string>
+ <string name="keyboard_layout_default_label" msgid="1997292217218546957">"Predefinição"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
index 8d93b31be90a..cdb364a16a02 100644
--- a/packages/SettingsLib/res/values-pt/strings.xml
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -533,6 +533,8 @@
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Menos tempo."</string>
<string name="cancel" msgid="5665114069455378395">"Cancelar"</string>
<string name="okay" msgid="949938843324579502">"Ok"</string>
+ <!-- no translation found for done (381184316122520313) -->
+ <skip />
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarmes e lembretes"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Autorizar a definição de alarmes e lembretes"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmes e lembretes"</string>
@@ -551,7 +553,9 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Perguntar sempre"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"Até você desativar"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"Agora"</string>
- <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Este smartphone"</string>
+ <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Este smartphone"</string>
+ <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+ <skip />
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Este smartphone"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Ocorreu um problema na conexão. Desligue o dispositivo e ligue-o novamente"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Dispositivo de áudio com fio"</string>
@@ -591,7 +595,9 @@
<string name="user_set_lock_button" msgid="1427128184982594856">"Definir bloqueio"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Mudar para <xliff:g id="USER_NAME">%s</xliff:g>"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Criando novo usuário…"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Criando novo convidado…"</string>
<string name="add_user_failed" msgid="4809887794313944872">"Falha ao criar um novo usuário"</string>
+ <string name="add_guest_failed" msgid="8074548434469843443">"Falha ao criar um novo convidado"</string>
<string name="user_nickname" msgid="262624187455825083">"Apelido"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Adicionar convidado"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Remover convidado"</string>
@@ -644,4 +650,7 @@
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Info. de transmissão"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Escolher a foto do perfil"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"Ícone de usuário padrão"</string>
+ <string name="physical_keyboard_title" msgid="4811935435315835220">"Teclado físico"</string>
+ <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Escolha o layout do teclado"</string>
+ <string name="keyboard_layout_default_label" msgid="1997292217218546957">"Padrão"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index b110c9c29397..778351ede55e 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -533,6 +533,8 @@
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Mai puțin timp."</string>
<string name="cancel" msgid="5665114069455378395">"Anulați"</string>
<string name="okay" msgid="949938843324579502">"OK"</string>
+ <!-- no translation found for done (381184316122520313) -->
+ <skip />
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarme și mementouri"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Permiteți setarea pentru alarme și mementouri"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarme și mementouri"</string>
@@ -551,7 +553,9 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Întreabă de fiecare dată"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"Până când dezactivați"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"Chiar acum"</string>
- <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Acest telefon"</string>
+ <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Acest telefon"</string>
+ <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+ <skip />
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Acest telefon"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problemă la conectare. Opriți și reporniți dispozitivul."</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Dispozitiv audio cu fir"</string>
@@ -591,7 +595,9 @@
<string name="user_set_lock_button" msgid="1427128184982594856">"Configurați blocarea"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Treceți la <xliff:g id="USER_NAME">%s</xliff:g>"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Se creează un utilizator nou…"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Se creează un invitat nou…"</string>
<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>
<string name="guest_new_guest" msgid="3482026122932643557">"Adăugați un invitat"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Ștergeți invitatul"</string>
@@ -644,4 +650,7 @@
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Informații artiști"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Alegeți o fotografie de profil"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"Pictograma prestabilită a utilizatorului"</string>
+ <string name="physical_keyboard_title" msgid="4811935435315835220">"Tastatură fizică"</string>
+ <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Alegeți aspectul tastaturii"</string>
+ <string name="keyboard_layout_default_label" msgid="1997292217218546957">"Prestabilit"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index 6a2da7f8b210..d07e12b3753d 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -533,6 +533,8 @@
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Уменьшить продолжительность"</string>
<string name="cancel" msgid="5665114069455378395">"Отмена"</string>
<string name="okay" msgid="949938843324579502">"ОК"</string>
+ <!-- no translation found for done (381184316122520313) -->
+ <skip />
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"Будильники и напоминания"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Разрешить установку будильников и напоминаний"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Будильники и напоминания"</string>
@@ -551,7 +553,9 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Всегда спрашивать"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"Пока вы не отключите"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"Только что"</string>
- <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Этот смартфон"</string>
+ <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Этот смартфон"</string>
+ <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+ <skip />
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Этот смартфон"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Ошибка подключения. Выключите и снова включите устройство."</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Проводное аудиоустройство"</string>
@@ -591,7 +595,9 @@
<string name="user_set_lock_button" msgid="1427128184982594856">"Включить блокировку"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Сменить пользователя на <xliff:g id="USER_NAME">%s</xliff:g>"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Создаем нового пользователя…"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Создание гостя…"</string>
<string name="add_user_failed" msgid="4809887794313944872">"Не удалось создать пользователя"</string>
+ <string name="add_guest_failed" msgid="8074548434469843443">"Не удалось создать гостя."</string>
<string name="user_nickname" msgid="262624187455825083">"Псевдоним"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Добавить гостя"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Удалить аккаунт гостя"</string>
@@ -644,4 +650,7 @@
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Данные о трансляции"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Выберите фото профиля"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"Значок пользователя по умолчанию"</string>
+ <string name="physical_keyboard_title" msgid="4811935435315835220">"Физическая клавиатура"</string>
+ <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Выберите раскладку клавиатуры"</string>
+ <string name="keyboard_layout_default_label" msgid="1997292217218546957">"По умолчанию"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-si/strings.xml b/packages/SettingsLib/res/values-si/strings.xml
index b75f548164eb..5140e89e3e78 100644
--- a/packages/SettingsLib/res/values-si/strings.xml
+++ b/packages/SettingsLib/res/values-si/strings.xml
@@ -533,6 +533,8 @@
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"වේලාව අඩුවෙන්."</string>
<string name="cancel" msgid="5665114069455378395">"අවලංගු කරන්න"</string>
<string name="okay" msgid="949938843324579502">"හරි"</string>
+ <!-- no translation found for done (381184316122520313) -->
+ <skip />
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"එලාම සහ සිහිකැඳවීම්"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"එලාම සහ සිහිකැඳවීම් සැකසීමට ඉඩ දෙන්න"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"එලාම සහ සිහිකැඳවීම්"</string>
@@ -551,7 +553,9 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"සෑම විටම ඉල්ලන්න"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"ඔබ ක්‍රියාවිරහිත කරන තුරු"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"මේ දැන්"</string>
- <string name="media_transfer_this_device_name" msgid="2357329267148436433">"මෙම දුරකථනය"</string>
+ <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"මෙම දුරකථනය"</string>
+ <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+ <skip />
<string name="media_transfer_this_phone" msgid="7194341457812151531">"මෙම දුරකථනය"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"සම්බන්ධ කිරීමේ ගැටලුවකි උපාංගය ක්‍රියාවිරහිත කර &amp; ආපසු ක්‍රියාත්මක කරන්න"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"රැහැන්ගත කළ ඕඩියෝ උපාංගය"</string>
@@ -591,7 +595,9 @@
<string name="user_set_lock_button" msgid="1427128184982594856">"අගුල සකසන්න"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g> වෙත මාරු වන්න"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"නව පරිශීලක තනමින්…"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"නව අමුත්තකු තනමින්…"</string>
<string name="add_user_failed" msgid="4809887794313944872">"නව පරිශීලකයෙකු තැනීමට අසමත් විය"</string>
+ <string name="add_guest_failed" msgid="8074548434469843443">"නව අමුත්තකු තැනීම අසාර්ථක විය"</string>
<string name="user_nickname" msgid="262624187455825083">"අපනාමය"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"අමුත්තා එක් කරන්න"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"අමුත්තා ඉවත් කරන්න"</string>
@@ -644,4 +650,7 @@
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"විකාශ තතු"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"පැතිකඩ පින්තූරයක් තේරීම"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"පෙරනිමි පරිශීලක නිරූපකය"</string>
+ <string name="physical_keyboard_title" msgid="4811935435315835220">"භෞතික යතුරු පුවරුව"</string>
+ <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"යතුරු පුවරු පිරිසැලසුම තෝරන්න"</string>
+ <string name="keyboard_layout_default_label" msgid="1997292217218546957">"පෙරනිමි"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
index 83f880dd2271..b53a7997b189 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -533,6 +533,8 @@
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Kratší čas."</string>
<string name="cancel" msgid="5665114069455378395">"Zrušiť"</string>
<string name="okay" msgid="949938843324579502">"OK"</string>
+ <!-- no translation found for done (381184316122520313) -->
+ <skip />
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"Budíky a pripomenutia"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Povoliť nastavovanie budíkov a pripomenutí"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Budíky a pripomenutia"</string>
@@ -551,7 +553,9 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Vždy sa opýtať"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"Dokým funkciu nevypnete"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"Teraz"</string>
- <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Tento telefón"</string>
+ <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Tento telefón"</string>
+ <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+ <skip />
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Tento telefón"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Pri pripájaní sa vyskytol problém. Zariadenie vypnite a znova zapnite."</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Audio zariadenie s káblom"</string>
@@ -591,7 +595,9 @@
<string name="user_set_lock_button" msgid="1427128184982594856">"Nastaviť uzamknutie"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Prepnúť na používateľa <xliff:g id="USER_NAME">%s</xliff:g>"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Vytvára sa nový používateľ…"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Vytvára sa nový hosť…"</string>
<string name="add_user_failed" msgid="4809887794313944872">"Nového použív. sa nepodarilo vytvoriť"</string>
+ <string name="add_guest_failed" msgid="8074548434469843443">"Nového hosťa sa nepodarilo vytvoriť"</string>
<string name="user_nickname" msgid="262624187455825083">"Prezývka"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Pridať hosťa"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Odobrať hosťa"</string>
@@ -644,4 +650,7 @@
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Informácie o prenose"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Výber profilovej fotky"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"Predvolená ikona používateľa"</string>
+ <string name="physical_keyboard_title" msgid="4811935435315835220">"Fyzická klávesnica"</string>
+ <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Vyberte rozloženie klávesnice"</string>
+ <string name="keyboard_layout_default_label" msgid="1997292217218546957">"Predvolené"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
index 6d4078d7601e..67e20b1447b1 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -533,6 +533,8 @@
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Krajši čas."</string>
<string name="cancel" msgid="5665114069455378395">"Prekliči"</string>
<string name="okay" msgid="949938843324579502">"V redu"</string>
+ <!-- no translation found for done (381184316122520313) -->
+ <skip />
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarmi in opomniki"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Dovoli nastavljanje alarmov in opomnikov"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmi in opomniki"</string>
@@ -551,7 +553,9 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Vedno vprašaj"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"Dokler ne izklopite"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"Pravkar"</string>
- <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Ta telefon"</string>
+ <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Ta telefon"</string>
+ <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+ <skip />
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Ta telefon"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Težava pri povezovanju. Napravo izklopite in znova vklopite."</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Žična zvočna naprava"</string>
@@ -591,7 +595,9 @@
<string name="user_set_lock_button" msgid="1427128184982594856">"Nastavi zaklepanje"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Preklopi na račun <xliff:g id="USER_NAME">%s</xliff:g>"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Ustvarjanje novega uporabnika …"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Ustvarjanje novega gosta …"</string>
<string name="add_user_failed" msgid="4809887794313944872">"Ustvarjanje novega uporabnika ni uspelo."</string>
+ <string name="add_guest_failed" msgid="8074548434469843443">"Ustvarjanje novega gosta ni uspelo."</string>
<string name="user_nickname" msgid="262624187455825083">"Vzdevek"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Dodajanje gosta"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Odstranitev gosta"</string>
@@ -644,4 +650,7 @@
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"O zasedbi"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Izbira profilne slike"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"Privzeta ikona uporabnika"</string>
+ <string name="physical_keyboard_title" msgid="4811935435315835220">"Fizična tipkovnica"</string>
+ <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Izbira razporeditve tipkovnice"</string>
+ <string name="keyboard_layout_default_label" msgid="1997292217218546957">"Privzeto"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml
index ef1e59d92f15..fc2639e0e371 100644
--- a/packages/SettingsLib/res/values-sq/strings.xml
+++ b/packages/SettingsLib/res/values-sq/strings.xml
@@ -533,6 +533,8 @@
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Më pak kohë."</string>
<string name="cancel" msgid="5665114069455378395">"Anulo"</string>
<string name="okay" msgid="949938843324579502">"Në rregull"</string>
+ <!-- no translation found for done (381184316122520313) -->
+ <skip />
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarmet dhe alarmet rikujtuese"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Lejo caktimin e alarmeve dhe alarmeve rikujtuese"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmet dhe alarmet rikujtuese"</string>
@@ -551,7 +553,9 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Pyet çdo herë"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"Derisa ta çaktivizosh"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"Pikërisht tani"</string>
- <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Ky telefon"</string>
+ <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Ky telefon"</string>
+ <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+ <skip />
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Ky telefon"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problem me lidhjen. Fike dhe ndize përsëri pajisjen"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Pajisja audio me tel"</string>
@@ -591,7 +595,9 @@
<string name="user_set_lock_button" msgid="1427128184982594856">"Cakto kyçjen"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Kalo te <xliff:g id="USER_NAME">%s</xliff:g>"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Po krijohet një përdorues i ri…"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Po krijohet një vizitor i ri…"</string>
<string name="add_user_failed" msgid="4809887794313944872">"Krijimi i një përdoruesi të ri dështoi"</string>
+ <string name="add_guest_failed" msgid="8074548434469843443">"Profili i vizitorit të ri nuk u krijua"</string>
<string name="user_nickname" msgid="262624187455825083">"Pseudonimi"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Shto të ftuar"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Hiq të ftuarin"</string>
@@ -644,4 +650,7 @@
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Të dhënat e aktorëve"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Zgjidh një fotografi profili"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"Ikona e parazgjedhur e përdoruesit"</string>
+ <string name="physical_keyboard_title" msgid="4811935435315835220">"Tastiera fizike"</string>
+ <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Zgjidh strukturën e tastierës"</string>
+ <string name="keyboard_layout_default_label" msgid="1997292217218546957">"Parazgjedhja"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index 333720e80235..44080faf6604 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -533,6 +533,8 @@
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Мање времена."</string>
<string name="cancel" msgid="5665114069455378395">"Откажи"</string>
<string name="okay" msgid="949938843324579502">"Потврди"</string>
+ <!-- no translation found for done (381184316122520313) -->
+ <skip />
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"Аларми и подсетници"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Омогући подешавање аларма и подсетника"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Аларми и подсетници"</string>
@@ -551,7 +553,9 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Питај сваки пут"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"Док не искључите"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"Управо"</string>
- <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Овај телефон"</string>
+ <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Овај телефон"</string>
+ <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+ <skip />
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Овај телефон"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Проблем при повезивању. Искључите уређај, па га поново укључите"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Жичани аудио уређај"</string>
@@ -591,7 +595,9 @@
<string name="user_set_lock_button" msgid="1427128184982594856">"Подеси закључавање"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Пређи на корисника <xliff:g id="USER_NAME">%s</xliff:g>"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Прави се нови корисник…"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Прави се нови гост…"</string>
<string name="add_user_failed" msgid="4809887794313944872">"Прављење новог корисника није успело"</string>
+ <string name="add_guest_failed" msgid="8074548434469843443">"Прављење новог госта није успело"</string>
<string name="user_nickname" msgid="262624187455825083">"Надимак"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Додај госта"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Уклони госта"</string>
@@ -644,4 +650,7 @@
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Подаци о пребацивању"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Одаберите слику профила"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"Подразумевана икона корисника"</string>
+ <string name="physical_keyboard_title" msgid="4811935435315835220">"Физичка тастатура"</string>
+ <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Одаберите распоред тастатуре"</string>
+ <string name="keyboard_layout_default_label" msgid="1997292217218546957">"Подразумевано"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index 2522d7d95943..fbcc2ba30348 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -533,6 +533,8 @@
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Kortare tid."</string>
<string name="cancel" msgid="5665114069455378395">"Avbryt"</string>
<string name="okay" msgid="949938843324579502">"OK"</string>
+ <!-- no translation found for done (381184316122520313) -->
+ <skip />
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarm och påminnelser"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Tillåt att alarm och påminnelser ställs in"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarm och påminnelser"</string>
@@ -551,7 +553,9 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Fråga varje gång"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"Tills du inaktiverar funktionen"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"Nyss"</string>
- <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Den här telefonen"</string>
+ <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Den här telefonen"</string>
+ <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+ <skip />
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Den här telefonen"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Det gick inte att ansluta. Stäng av enheten och slå på den igen"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Ljudenhet med kabelanslutning"</string>
@@ -591,7 +595,9 @@
<string name="user_set_lock_button" msgid="1427128184982594856">"Konfigurera lås"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Byt till <xliff:g id="USER_NAME">%s</xliff:g>"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Skapar ny användare …"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Skapar ny gäst …"</string>
<string name="add_user_failed" msgid="4809887794313944872">"Det gick inte att skapa en ny användare"</string>
+ <string name="add_guest_failed" msgid="8074548434469843443">"Det gick inte att skapa en ny gäst"</string>
<string name="user_nickname" msgid="262624187455825083">"Smeknamn"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Lägg till gäst"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Ta bort gäst"</string>
@@ -644,4 +650,10 @@
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Info om rollistan"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Välj en profilbild"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"Ikon för standardanvändare"</string>
+ <!-- no translation found for physical_keyboard_title (4811935435315835220) -->
+ <skip />
+ <!-- no translation found for keyboard_layout_dialog_title (3927180147005616290) -->
+ <skip />
+ <!-- no translation found for keyboard_layout_default_label (1997292217218546957) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index d6deb2b786a1..8000841d8e7d 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -533,6 +533,8 @@
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Muda kidogo."</string>
<string name="cancel" msgid="5665114069455378395">"Ghairi"</string>
<string name="okay" msgid="949938843324579502">"Sawa"</string>
+ <!-- no translation found for done (381184316122520313) -->
+ <skip />
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"Ving\'ora na vikumbusho"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Ruhusu iweke kengele na vikumbusho"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Kengele na vikumbusho"</string>
@@ -551,7 +553,9 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Uliza kila wakati"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"Hadi utakapoizima"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"Sasa hivi"</string>
- <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Simu hii"</string>
+ <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Simu hii"</string>
+ <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+ <skip />
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Simu hii"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Kuna tatizo la kuunganisha kwenye Intaneti. Zima kisha uwashe kifaa"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Kifaa cha sauti kinachotumia waya"</string>
@@ -591,7 +595,9 @@
<string name="user_set_lock_button" msgid="1427128184982594856">"Weka ufunguo"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Badili utumie <xliff:g id="USER_NAME">%s</xliff:g>"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Inaweka mtumiaji mpya…"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Inaunda wasifu mpya wa mgeni…"</string>
<string name="add_user_failed" msgid="4809887794313944872">"Imeshindwa kuweka mtumiaji mpya"</string>
+ <string name="add_guest_failed" msgid="8074548434469843443">"Imeshindwa kuunda wasifu mpya wa mgeni"</string>
<string name="user_nickname" msgid="262624187455825083">"Jina wakilishi"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Ongeza mgeni"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Ondoa mgeni"</string>
@@ -644,4 +650,7 @@
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Maelezo ya Wahusika"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Chagua picha ya wasifu"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"Aikoni chaguomsingi ya mtumiaji"</string>
+ <string name="physical_keyboard_title" msgid="4811935435315835220">"Kibodi halisi"</string>
+ <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Chagua mpangilio wa kibodi"</string>
+ <string name="keyboard_layout_default_label" msgid="1997292217218546957">"Chaguomsingi"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml
index 8d5b87604244..30da8140649c 100644
--- a/packages/SettingsLib/res/values-ta/strings.xml
+++ b/packages/SettingsLib/res/values-ta/strings.xml
@@ -533,6 +533,8 @@
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"நேரத்தைக் குறைக்கும்."</string>
<string name="cancel" msgid="5665114069455378395">"ரத்துசெய்"</string>
<string name="okay" msgid="949938843324579502">"சரி"</string>
+ <!-- no translation found for done (381184316122520313) -->
+ <skip />
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"அலாரங்களும் நினைவூட்டல்களும்"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"அலாரங்கள் &amp; நினைவூட்டல்களை அமைக்க அனுமதித்தல்"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"அலாரங்கள் &amp; நினைவூட்டல்கள்"</string>
@@ -551,7 +553,9 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"ஒவ்வொரு முறையும் கேள்"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"ஆஃப் செய்யும் வரை"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"சற்றுமுன்"</string>
- <string name="media_transfer_this_device_name" msgid="2357329267148436433">"இந்த மொபைல்"</string>
+ <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"இந்த மொபைல்"</string>
+ <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+ <skip />
<string name="media_transfer_this_phone" msgid="7194341457812151531">"இந்த மொபைல்"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"இணைப்பதில் சிக்கல். சாதனத்தை ஆஃப் செய்து மீண்டும் ஆன் செய்யவும்"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"வயருடன்கூடிய ஆடியோ சாதனம்"</string>
@@ -591,7 +595,9 @@
<string name="user_set_lock_button" msgid="1427128184982594856">"பூட்டை அமை"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g>க்கு மாறு"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"புதிய பயனரை உருவாக்குகிறது…"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"புதிய விருந்தினரை உருவாக்குகிறது…"</string>
<string name="add_user_failed" msgid="4809887794313944872">"புதிய பயனரை உருவாக்க முடியவில்லை"</string>
+ <string name="add_guest_failed" msgid="8074548434469843443">"புதிய விருந்தினரை உருவாக்க முடியவில்லை"</string>
<string name="user_nickname" msgid="262624187455825083">"புனைப்பெயர்"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"கெஸ்ட்டைச் சேர்"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"கெஸ்ட்டை அகற்று"</string>
@@ -644,4 +650,7 @@
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"அலைபரப்புத் தகவல்"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"சுயவிவரப் படத்தைத் தேர்வுசெய்யுங்கள்"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"இயல்புநிலைப் பயனர் ஐகான்"</string>
+ <string name="physical_keyboard_title" msgid="4811935435315835220">"கீபோர்டு"</string>
+ <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"கீபோர்டு தளவமைப்பைத் தேர்வுசெய்தல்"</string>
+ <string name="keyboard_layout_default_label" msgid="1997292217218546957">"இயல்பு"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml
index 17448320787b..34a324ecb17a 100644
--- a/packages/SettingsLib/res/values-te/strings.xml
+++ b/packages/SettingsLib/res/values-te/strings.xml
@@ -442,11 +442,11 @@
<string name="select_webview_provider_title" msgid="3917815648099445503">"వెబ్ వీక్షణ అమలు"</string>
<string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"వెబ్ వీక్షణ అమలుని సెట్ చేయండి"</string>
<string name="select_webview_provider_toast_text" msgid="8512254949169359848">"ఈ ఎంపిక ఇప్పుడు లేదు. మళ్లీ ప్రయత్నించండి."</string>
- <string name="convert_to_file_encryption" msgid="2828976934129751818">"ఫైల్ గుప్తీకరణకు మార్చు"</string>
+ <string name="convert_to_file_encryption" msgid="2828976934129751818">"ఫైల్ ఎన్‌క్రిప్షన్‌కు మార్చు"</string>
<string name="convert_to_file_encryption_enabled" msgid="840757431284311754">"మార్చండి…"</string>
- <string name="convert_to_file_encryption_done" msgid="8965831011811180627">"ఫైల్ ఇప్పటికే గుప్తీకరించబడింది"</string>
- <string name="title_convert_fbe" msgid="5780013350366495149">"ఫైల్ ఆధారిత గుప్తీకరణకు మార్చడం"</string>
- <string name="convert_to_fbe_warning" msgid="34294381569282109">"డేటా భాగాన్ని ఫైల్ ఆధారిత గుప్తీకరణకు మార్చండి.\n !!హెచ్చరిక!! దీని వలన మీ డేటా మొత్తం తీసివేయబడుతుంది.\n ఈ లక్షణం ఆల్ఫా, కనుక సరిగ్గా పని చేయకపోవచ్చు.\n కొనసాగించడానికి \'తొలగించి, మార్చు...\' నొక్కండి."</string>
+ <string name="convert_to_file_encryption_done" msgid="8965831011811180627">"ఫైల్ ఇప్పటికే ఎన్‌క్రిప్ట్ చేయబడింది"</string>
+ <string name="title_convert_fbe" msgid="5780013350366495149">"ఫైల్ ఆధారిత ఎన్‌క్రిప్షన్‌కు మార్చడం"</string>
+ <string name="convert_to_fbe_warning" msgid="34294381569282109">"డేటా భాగాన్ని ఫైల్ ఆధారిత ఎన్‌క్రిప్షన్‌కు మార్చండి.\n !!హెచ్చరిక!! దీని వలన మీ డేటా మొత్తం తీసివేయబడుతుంది.\n ఈ లక్షణం ఆల్ఫా, కనుక సరిగ్గా పని చేయకపోవచ్చు.\n కొనసాగించడానికి \'తొలగించి, మార్చు...\' నొక్కండి."</string>
<string name="button_convert_fbe" msgid="1159861795137727671">"తొలగించి, మార్చు…"</string>
<string name="picture_color_mode" msgid="1013807330552931903">"చిత్రం రంగు మోడ్"</string>
<string name="picture_color_mode_desc" msgid="151780973768136200">"sRGB ఉపయోగిస్తుంది"</string>
@@ -533,6 +533,8 @@
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"తక్కువ సమయం."</string>
<string name="cancel" msgid="5665114069455378395">"రద్దు చేయి"</string>
<string name="okay" msgid="949938843324579502">"సరే"</string>
+ <!-- no translation found for done (381184316122520313) -->
+ <skip />
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"అలారాలు, రిమైండర్‌లు"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"అలారాలు, రిమైండర్‌లను సెట్ చేయడానికి అనుమతించండి"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"అలారాలు &amp; రిమైండర్‌లు"</string>
@@ -551,7 +553,9 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"ప్రతిసారి అడుగు"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"మీరు ఆఫ్‌ చేసే వరకు"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"ఇప్పుడే"</string>
- <string name="media_transfer_this_device_name" msgid="2357329267148436433">"ఈ ఫోన్"</string>
+ <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"ఈ ఫోన్"</string>
+ <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+ <skip />
<string name="media_transfer_this_phone" msgid="7194341457812151531">"ఈ ఫోన్"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"కనెక్ట్ చేయడంలో సమస్య ఉంది. పరికరాన్ని ఆఫ్ చేసి, ఆపై తిరిగి ఆన్ చేయండి"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"వైర్ గల ఆడియో పరికరం"</string>
@@ -575,7 +579,7 @@
<string name="user_add_user_item_title" msgid="2394272381086965029">"యూజర్"</string>
<string name="user_add_profile_item_title" msgid="3111051717414643029">"పరిమితం చేయబడిన ప్రొఫైల్"</string>
<string name="user_add_user_title" msgid="5457079143694924885">"కొత్త వినియోగదారుని జోడించాలా?"</string>
- <string name="user_add_user_message_long" msgid="1527434966294733380">"అదనపు యూజర్‌లను సృష్టించడం ద్వారా మీరు ఈ దేవైజ్‌ను ఇతరులతో షేర్ చేయవచ్చు. ప్రతి యూజర్‌కు‌ వారికంటూ ప్రత్యేక స్థలం ఉంటుంది, వారు ఆ స్థలాన్ని యాప్‌లు, వాల్‌పేపర్ మొదలైనవాటితో అనుకూలీకరించవచ్చు. యూజర్‌లు ప్రతి ఒక్కరిపై ప్రభావం చూపే Wi‑Fi వంటి పరికర సెట్టింగ్‌లను కూడా సర్దుబాటు చేయవచ్చు.\n\nమీరు కొత్త యూజర్ ను జోడించినప్పుడు, ఆ వ్యక్తి వారికంటూ స్వంత స్థలం సెట్ చేసుకోవాలి.\n\nఏ వినియోగదారు అయినా మిగిలిన అందరు యూజర్‌ల కోసం యాప్‌లను అప్‌డేట్ చేయవచ్చు. యాక్సెస్ సామర్ధ్యం సెట్టింగ్‌లు మరియు సేవలు కొత్త యూజర్‌కి బదిలీ కాకపోవచ్చు."</string>
+ <string name="user_add_user_message_long" msgid="1527434966294733380">"అదనపు యూజర్‌లను క్రియేట్ చేయడం ద్వారా మీరు ఈ దేవైజ్‌ను ఇతరులతో షేర్ చేయవచ్చు. ప్రతి యూజర్‌కు‌ వారికంటూ ప్రత్యేక స్థలం ఉంటుంది, వారు ఆ స్థలాన్ని యాప్‌లు, వాల్‌పేపర్ మొదలైనవాటితో అనుకూలీకరించవచ్చు. యూజర్‌లు ప్రతి ఒక్కరిపై ప్రభావం చూపే Wi‑Fi వంటి పరికర సెట్టింగ్‌లను కూడా సర్దుబాటు చేయవచ్చు.\n\nమీరు కొత్త యూజర్ ను జోడించినప్పుడు, ఆ వ్యక్తి వారికంటూ స్వంత స్థలం సెట్ చేసుకోవాలి.\n\nఏ వినియోగదారు అయినా మిగిలిన అందరు యూజర్‌ల కోసం యాప్‌లను అప్‌డేట్ చేయవచ్చు. యాక్సెస్ సామర్ధ్యం సెట్టింగ్‌లు మరియు సేవలు కొత్త యూజర్‌కి బదిలీ కాకపోవచ్చు."</string>
<string name="user_add_user_message_short" msgid="3295959985795716166">"మీరు కొత్త వినియోగదారుని జోడించినప్పుడు, ఆ వ్యక్తి తన స్థలాన్ని సెటప్ చేసుకోవాలి.\n\nఏ వినియోగదారు అయినా మిగతా అందరు వినియోగదారుల కోసం యాప్‌లను అప్‌డేట్‌ చేయగలరు."</string>
<string name="user_setup_dialog_title" msgid="8037342066381939995">"యూజర్‌ను ఇప్పుడే సెటప్ చేయాలా?"</string>
<string name="user_setup_dialog_message" msgid="269931619868102841">"పరికరాన్ని తీసుకోవడానికి వ్యక్తి అందుబాటులో ఉన్నారని నిర్ధారించుకొని, ఆపై వారికి నిల్వ స్థలాన్ని సెటప్ చేయండి"</string>
@@ -587,11 +591,13 @@
<string name="user_new_profile_name" msgid="2405500423304678841">"కొత్త ప్రొఫైల్"</string>
<string name="user_info_settings_title" msgid="6351390762733279907">"వినియోగదారు సమాచారం"</string>
<string name="profile_info_settings_title" msgid="105699672534365099">"ప్రొఫైల్ సమాచారం"</string>
- <string name="user_need_lock_message" msgid="4311424336209509301">"మీరు పరిమితం చేయబడిన ప్రొఫైల్‌ను సృష్టించడానికి ముందు, మీ యాప్‌లు మరియు వ్యక్తిగత డేటాను రక్షించడానికి స్క్రీన్ లాక్‌ను సెటప్ చేయాల్సి ఉంటుంది."</string>
+ <string name="user_need_lock_message" msgid="4311424336209509301">"మీరు పరిమితం చేయబడిన ప్రొఫైల్‌ను క్రియేట్ చేయడానికి ముందు, మీ యాప్‌లు మరియు వ్యక్తిగత డేటాను రక్షించడానికి స్క్రీన్ లాక్‌ను సెటప్ చేయాల్సి ఉంటుంది."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"లాక్‌ను సెట్ చేయి"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g>కు స్విచ్ చేయి"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"కొత్త యూజర్‌ను క్రియేట్ చేస్తోంది…"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"కొత్త అతిథిని క్రియేట్ చేస్తోంది…"</string>
<string name="add_user_failed" msgid="4809887794313944872">"కొత్త యూజర్‌ను క్రియేట్ చేయడం విఫలమైంది"</string>
+ <string name="add_guest_failed" msgid="8074548434469843443">"కొత్త అతిథిని క్రియేట్ చేయడం విఫలమైంది"</string>
<string name="user_nickname" msgid="262624187455825083">"మారుపేరు"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"గెస్ట్‌ను జోడించండి"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"గెస్ట్‌ను తీసివేయండి"</string>
@@ -644,4 +650,7 @@
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"కాస్ట్ సమాచారం"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"ప్రొఫైల్ ఫోటోను ఎంచుకోండి"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"ఆటోమేటిక్ సెట్టింగ్ యూజర్ చిహ్నం"</string>
+ <string name="physical_keyboard_title" msgid="4811935435315835220">"భౌతిక కీబోర్డ్"</string>
+ <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"కీబోర్డ్ లేఅవుట్‌ను ఎంచుకోండి"</string>
+ <string name="keyboard_layout_default_label" msgid="1997292217218546957">"ఆటోమేటిక్ సెట్టింగ్"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index c2c34ed02e87..900ac51e18f3 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -533,6 +533,8 @@
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"เวลาน้อยลง"</string>
<string name="cancel" msgid="5665114069455378395">"ยกเลิก"</string>
<string name="okay" msgid="949938843324579502">"ตกลง"</string>
+ <!-- no translation found for done (381184316122520313) -->
+ <skip />
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"การปลุกและการช่วยเตือน"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"อนุญาตให้ตั้งปลุกและการช่วยเตือน"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"การปลุกและการช่วยเตือน"</string>
@@ -551,7 +553,9 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"ถามทุกครั้ง"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"จนกว่าคุณจะปิด"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"เมื่อสักครู่"</string>
- <string name="media_transfer_this_device_name" msgid="2357329267148436433">"โทรศัพท์เครื่องนี้"</string>
+ <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"โทรศัพท์เครื่องนี้"</string>
+ <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+ <skip />
<string name="media_transfer_this_phone" msgid="7194341457812151531">"โทรศัพท์เครื่องนี้"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"เกิดปัญหาในการเชื่อมต่อ ปิดอุปกรณ์แล้วเปิดใหม่อีกครั้ง"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"อุปกรณ์เสียงแบบมีสาย"</string>
@@ -591,7 +595,9 @@
<string name="user_set_lock_button" msgid="1427128184982594856">"ตั้งค่าล็อก"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"เปลี่ยนเป็น <xliff:g id="USER_NAME">%s</xliff:g>"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"กำลังสร้างผู้ใช้ใหม่…"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"กำลังสร้างผู้เข้าร่วมใหม่…"</string>
<string name="add_user_failed" msgid="4809887794313944872">"สร้างผู้ใช้ใหม่ไม่ได้"</string>
+ <string name="add_guest_failed" msgid="8074548434469843443">"สร้างผู้เข้าร่วมใหม่ไม่สำเร็จ"</string>
<string name="user_nickname" msgid="262624187455825083">"ชื่อเล่น"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"เพิ่มผู้ใช้ชั่วคราว"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"นำผู้ใช้ชั่วคราวออก"</string>
@@ -644,4 +650,7 @@
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"ข้อมูลแคสต์"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"เลือกรูปโปรไฟล์"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"ไอคอนผู้ใช้เริ่มต้น"</string>
+ <string name="physical_keyboard_title" msgid="4811935435315835220">"แป้นพิมพ์จริง"</string>
+ <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"เลือกรูปแบบแป้นพิมพ์"</string>
+ <string name="keyboard_layout_default_label" msgid="1997292217218546957">"ค่าเริ่มต้น"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml
index a8dcb02bfabf..5bfb3ef6a254 100644
--- a/packages/SettingsLib/res/values-tl/strings.xml
+++ b/packages/SettingsLib/res/values-tl/strings.xml
@@ -533,6 +533,8 @@
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Bawasan ang oras."</string>
<string name="cancel" msgid="5665114069455378395">"Kanselahin"</string>
<string name="okay" msgid="949938843324579502">"OK"</string>
+ <!-- no translation found for done (381184316122520313) -->
+ <skip />
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"Mga alarm at paalala"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Payagan ang pagtakda ng mga alarm at paalala"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Mga alarm at paalala"</string>
@@ -551,7 +553,9 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Magtanong palagi"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"Hanggang sa i-off mo"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"Ngayon lang"</string>
- <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Ang teleponong ito"</string>
+ <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Ang teleponong ito"</string>
+ <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+ <skip />
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Ang teleponong ito"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Nagkaproblema sa pagkonekta. I-off at pagkatapos ay i-on ang device"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Wired na audio device"</string>
@@ -591,7 +595,9 @@
<string name="user_set_lock_button" msgid="1427128184982594856">"Itakda ang lock"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Lumipat sa <xliff:g id="USER_NAME">%s</xliff:g>"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Gumagawa ng bagong user…"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Gumagawa ng bagong guest…"</string>
<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>
<string name="guest_new_guest" msgid="3482026122932643557">"Magdagdag ng bisita"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Alisin ang bisita"</string>
@@ -644,4 +650,7 @@
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Impormasyon ng Cast"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Pumili ng larawan sa profile"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"Icon ng default na user"</string>
+ <string name="physical_keyboard_title" msgid="4811935435315835220">"Pisikal na keyboard"</string>
+ <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Pumili ng layout ng keyboard"</string>
+ <string name="keyboard_layout_default_label" msgid="1997292217218546957">"Default"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index 592bbae45255..98ed832a0611 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -533,6 +533,8 @@
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Daha kısa süre."</string>
<string name="cancel" msgid="5665114069455378395">"İptal"</string>
<string name="okay" msgid="949938843324579502">"Tamam"</string>
+ <!-- no translation found for done (381184316122520313) -->
+ <skip />
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarmlar ve hatırlatıcılar"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Alarm ve hatırlatıcı ayarlanmasına izin ver"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmlar ve hatırlatıcılar"</string>
@@ -551,7 +553,9 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Her zaman sor"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"Siz kapatana kadar"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"Az önce"</string>
- <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Bu telefon"</string>
+ <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Bu telefon"</string>
+ <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+ <skip />
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Bu telefon"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Bağlanırken sorun oluştu. Cihazı kapatıp tekrar açın"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Kablolu ses cihazı"</string>
@@ -591,7 +595,9 @@
<string name="user_set_lock_button" msgid="1427128184982594856">"Kilidi ayarla"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g> hesabına geç"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Yeni kullanıcı oluşturuluyor…"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Yeni misafir oluşturuluyor…"</string>
<string name="add_user_failed" msgid="4809887794313944872">"Yeni kullanıcı oluşturulamadı"</string>
+ <string name="add_guest_failed" msgid="8074548434469843443">"Yeni misafir oluşturulamadı"</string>
<string name="user_nickname" msgid="262624187455825083">"Takma ad"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Misafir ekle"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Misafir oturumunu kaldır"</string>
@@ -644,4 +650,7 @@
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Yayın Bilgisi"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Profil fotoğrafı seç"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"Varsayılan kullanıcı simgesi"</string>
+ <string name="physical_keyboard_title" msgid="4811935435315835220">"Fiziksel klavye"</string>
+ <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Klavye düzenini seçin"</string>
+ <string name="keyboard_layout_default_label" msgid="1997292217218546957">"Varsayılan"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index a219f98d8ba7..a09dc11f23a9 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -533,6 +533,8 @@
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Менше часу."</string>
<string name="cancel" msgid="5665114069455378395">"Скасувати"</string>
<string name="okay" msgid="949938843324579502">"ОК"</string>
+ <!-- no translation found for done (381184316122520313) -->
+ <skip />
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"Будильники й нагадування"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Дозволити встановлювати будильники й нагадування"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Будильники й нагадування"</string>
@@ -551,7 +553,9 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Запитувати щоразу"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"Доки не вимкнути"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"Щойно"</string>
- <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Цей телефон"</string>
+ <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Цей телефон"</string>
+ <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+ <skip />
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Цей телефон"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Не вдається підключитися. Перезавантажте пристрій."</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Дротовий аудіопристрій"</string>
@@ -591,7 +595,9 @@
<string name="user_set_lock_button" msgid="1427128184982594856">"Налаштувати блокування"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Перейти до користувача <xliff:g id="USER_NAME">%s</xliff:g>"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Створення нового користувача…"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Створення гостя…"</string>
<string name="add_user_failed" msgid="4809887794313944872">"Не вдалося створити користувача"</string>
+ <string name="add_guest_failed" msgid="8074548434469843443">"Не вдалося створити гостя"</string>
<string name="user_nickname" msgid="262624187455825083">"Псевдонім"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Додати гостя"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Видалити гостя"</string>
@@ -644,4 +650,10 @@
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Акторський склад"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Вибрати зображення профілю"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"Значок користувача за умовчанням"</string>
+ <!-- no translation found for physical_keyboard_title (4811935435315835220) -->
+ <skip />
+ <!-- no translation found for keyboard_layout_dialog_title (3927180147005616290) -->
+ <skip />
+ <!-- no translation found for keyboard_layout_default_label (1997292217218546957) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml
index 3a2d2efb2e5f..ab7c5177b73b 100644
--- a/packages/SettingsLib/res/values-ur/strings.xml
+++ b/packages/SettingsLib/res/values-ur/strings.xml
@@ -533,6 +533,8 @@
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"کم وقت۔"</string>
<string name="cancel" msgid="5665114069455378395">"منسوخ کریں"</string>
<string name="okay" msgid="949938843324579502">"ٹھیک ہے"</string>
+ <!-- no translation found for done (381184316122520313) -->
+ <skip />
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"الارمز اور یاد دہانیاں"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"الارمز اور یاد دہانیاں سیٹ کرنے کی اجازت دیں"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"الارمز اور یاد دہانیاں"</string>
@@ -551,7 +553,9 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"ہر بار پوچھیں"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"یہاں تک کہ آپ آف کر دیں"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"ابھی ابھی"</string>
- <string name="media_transfer_this_device_name" msgid="2357329267148436433">"یہ فون"</string>
+ <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"یہ فون"</string>
+ <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+ <skip />
<string name="media_transfer_this_phone" msgid="7194341457812151531">"یہ فون"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"منسلک کرنے میں مسئلہ پیش آ گیا۔ آلہ کو آف اور بیک آن کریں"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"وائرڈ آڈیو آلہ"</string>
@@ -591,7 +595,9 @@
<string name="user_set_lock_button" msgid="1427128184982594856">"لاک سیٹ کریں"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"‫<xliff:g id="USER_NAME">%s</xliff:g> پر سوئچ کریں"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"نیا صارف تخلیق ہو رہا ہے…"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"نیا مہمان تخلیق کیا جا رہا ہے…"</string>
<string name="add_user_failed" msgid="4809887794313944872">"نیا صارف بنانے میں ناکام"</string>
+ <string name="add_guest_failed" msgid="8074548434469843443">"نیا مہمان بنانے میں ناکام"</string>
<string name="user_nickname" msgid="262624187455825083">"عرفی نام"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"مہمان کو شامل کریں"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"مہمان کو ہٹائیں"</string>
@@ -644,4 +650,7 @@
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"کاسٹ کرنے کی معلومات"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"پروفائل کی تصویر منتخب کریں"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"ڈیفالٹ صارف کا آئیکن"</string>
+ <string name="physical_keyboard_title" msgid="4811935435315835220">"فزیکل کی بورڈ"</string>
+ <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"کی بورڈ لے آؤٹ منتخب کریں"</string>
+ <string name="keyboard_layout_default_label" msgid="1997292217218546957">"ڈیفالٹ"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml
index 3e3db6933e9d..c1748a30c71b 100644
--- a/packages/SettingsLib/res/values-uz/strings.xml
+++ b/packages/SettingsLib/res/values-uz/strings.xml
@@ -533,6 +533,8 @@
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Kamroq vaqt."</string>
<string name="cancel" msgid="5665114069455378395">"Bekor qilish"</string>
<string name="okay" msgid="949938843324579502">"OK"</string>
+ <!-- no translation found for done (381184316122520313) -->
+ <skip />
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"Signal va eslatmalar"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Signal va eslatmalarni sozlashga ruxsat berish"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Signal va eslatmalar"</string>
@@ -551,7 +553,9 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Har safar so‘ralsin"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"Rejimdan chiqilgunicha"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"Hozir"</string>
- <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Shu telefon"</string>
+ <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Shu telefon"</string>
+ <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+ <skip />
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Shu telefon"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Ulanishda muammo yuz berdi. Qurilmani oʻchiring va yoqing"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Simli audio qurilma"</string>
@@ -591,7 +595,9 @@
<string name="user_set_lock_button" msgid="1427128184982594856">"Qulf o‘rnatish"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Bunga almashish: <xliff:g id="USER_NAME">%s</xliff:g>"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Yangi foydalanuvchi yaratilmoqda…"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Yangi mehmon yaratilmoqda…"</string>
<string name="add_user_failed" msgid="4809887794313944872">"Yangi foydalanuvchi yaratilmadi"</string>
+ <string name="add_guest_failed" msgid="8074548434469843443">"Yangi mehmon yaratilmadi"</string>
<string name="user_nickname" msgid="262624187455825083">"Nik"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Mehmon kiritish"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Mehmonni olib tashlash"</string>
@@ -644,4 +650,7 @@
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Translatsiya axboroti"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Profil rasmini tanlash"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"Foydalanuvchining standart belgisi"</string>
+ <string name="physical_keyboard_title" msgid="4811935435315835220">"Tashqi klaviatura"</string>
+ <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Klaviatura sxemasini tanlang"</string>
+ <string name="keyboard_layout_default_label" msgid="1997292217218546957">"Asosiy"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-v31/styles.xml b/packages/SettingsLib/res/values-v31/styles.xml
index 343de2cdf47a..0b703c99884b 100644
--- a/packages/SettingsLib/res/values-v31/styles.xml
+++ b/packages/SettingsLib/res/values-v31/styles.xml
@@ -15,7 +15,8 @@
limitations under the License.
-->
<resources>
- <style name="SettingsLibTabsTextAppearance" parent="@android:style/TextAppearance.DeviceDefault.Widget.ActionBar.Title">
+ <style name="SettingsLibTabsTextAppearance"
+ parent="@android:style/TextAppearance.DeviceDefault.Widget.ActionBar.Title">
<item name="android:textSize">16sp</item>
</style>
@@ -25,6 +26,7 @@
<item name="android:layout_height">48dp</item>
<item name="android:layout_marginStart">?android:attr/listPreferredItemPaddingStart</item>
<item name="android:layout_marginEnd">?android:attr/listPreferredItemPaddingEnd</item>
+ <item name="tabMaxWidth">0dp</item>
<item name="tabGravity">fill</item>
<item name="tabBackground">@drawable/settingslib_tabs_background</item>
<item name="tabIndicator">@drawable/settingslib_tabs_indicator_background</item>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index 2094400ed54f..419f1dac99b1 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -533,6 +533,8 @@
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Ít thời gian hơn."</string>
<string name="cancel" msgid="5665114069455378395">"Hủy"</string>
<string name="okay" msgid="949938843324579502">"OK"</string>
+ <!-- no translation found for done (381184316122520313) -->
+ <skip />
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"Chuông báo và lời nhắc"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Cho phép đặt chuông báo và lời nhắc"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Chuông báo và lời nhắc"</string>
@@ -551,7 +553,9 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Luôn hỏi"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"Cho đến khi bạn tắt"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"Vừa xong"</string>
- <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Điện thoại này"</string>
+ <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Điện thoại này"</string>
+ <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+ <skip />
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Điện thoại này"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Sự cố kết nối. Hãy tắt thiết bị rồi bật lại"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Thiết bị âm thanh có dây"</string>
@@ -591,7 +595,9 @@
<string name="user_set_lock_button" msgid="1427128184982594856">"Thiết lập khóa"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Chuyển sang <xliff:g id="USER_NAME">%s</xliff:g>"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Đang tạo người dùng mới…"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Đang tạo khách mới…"</string>
<string name="add_user_failed" msgid="4809887794313944872">"Không tạo được người dùng mới"</string>
+ <string name="add_guest_failed" msgid="8074548434469843443">"Không tạo được khách mới"</string>
<string name="user_nickname" msgid="262624187455825083">"Biệt hiệu"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Thêm khách"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Xóa phiên khách"</string>
@@ -644,4 +650,7 @@
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Thông tin về dàn nghệ sĩ"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Chọn một ảnh hồ sơ"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"Biểu tượng người dùng mặc định"</string>
+ <string name="physical_keyboard_title" msgid="4811935435315835220">"Bàn phím thực"</string>
+ <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Chọn bố cục bàn phím"</string>
+ <string name="keyboard_layout_default_label" msgid="1997292217218546957">"Mặc định"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index 6d5b8e1dd4dd..592e69c39a61 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -533,6 +533,8 @@
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"减少时间。"</string>
<string name="cancel" msgid="5665114069455378395">"取消"</string>
<string name="okay" msgid="949938843324579502">"确定"</string>
+ <!-- no translation found for done (381184316122520313) -->
+ <skip />
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"闹钟和提醒"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"允许设置闹钟和提醒"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"闹钟和提醒"</string>
@@ -551,7 +553,9 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"每次都询问"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"直到您将其关闭"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"刚刚"</string>
- <string name="media_transfer_this_device_name" msgid="2357329267148436433">"这部手机"</string>
+ <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"这部手机"</string>
+ <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+ <skip />
<string name="media_transfer_this_phone" msgid="7194341457812151531">"这部手机"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"连接时遇到问题。请关闭并重新开启设备"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"有线音频设备"</string>
@@ -591,7 +595,9 @@
<string name="user_set_lock_button" msgid="1427128184982594856">"设置屏幕锁定方式"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"切换到<xliff:g id="USER_NAME">%s</xliff:g>"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"正在创建新用户…"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"正在创建新的访客…"</string>
<string name="add_user_failed" msgid="4809887794313944872">"无法创建新用户"</string>
+ <string name="add_guest_failed" msgid="8074548434469843443">"未能创建新的访客"</string>
<string name="user_nickname" msgid="262624187455825083">"昵称"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"添加访客"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"移除访客"</string>
@@ -644,4 +650,7 @@
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"投射信息"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"选择个人资料照片"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"默认用户图标"</string>
+ <string name="physical_keyboard_title" msgid="4811935435315835220">"实体键盘"</string>
+ <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"选择键盘布局"</string>
+ <string name="keyboard_layout_default_label" msgid="1997292217218546957">"默认"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
index d18c0c953f5a..41f399453af0 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -533,6 +533,8 @@
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"減少時間。"</string>
<string name="cancel" msgid="5665114069455378395">"取消"</string>
<string name="okay" msgid="949938843324579502">"確定"</string>
+ <!-- no translation found for done (381184316122520313) -->
+ <skip />
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"鬧鐘和提醒"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"允許設定鬧鐘和提醒"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"鬧鐘和提醒"</string>
@@ -551,7 +553,9 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"每次都詢問"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"直至您關閉為止"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"剛剛"</string>
- <string name="media_transfer_this_device_name" msgid="2357329267148436433">"此手機"</string>
+ <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"此手機"</string>
+ <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+ <skip />
<string name="media_transfer_this_phone" msgid="7194341457812151531">"這部手機"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"無法連接,請關閉裝置然後重新開機"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"有線音響裝置"</string>
@@ -591,7 +595,9 @@
<string name="user_set_lock_button" msgid="1427128184982594856">"設定上鎖畫面"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"切換至<xliff:g id="USER_NAME">%s</xliff:g>"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"正在建立新使用者…"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"正在建立新訪客…"</string>
<string name="add_user_failed" msgid="4809887794313944872">"無法建立新使用者"</string>
+ <string name="add_guest_failed" msgid="8074548434469843443">"無法建立新訪客"</string>
<string name="user_nickname" msgid="262624187455825083">"暱稱"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"新增訪客"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"移除訪客"</string>
@@ -644,4 +650,7 @@
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"投放資料"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"選擇個人檔案相片"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"預設使用者圖示"</string>
+ <string name="physical_keyboard_title" msgid="4811935435315835220">"實體鍵盤"</string>
+ <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"選擇鍵盤配置"</string>
+ <string name="keyboard_layout_default_label" msgid="1997292217218546957">"預設"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index bec3c93077ee..975e6501ef3a 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -533,6 +533,8 @@
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"減少時間。"</string>
<string name="cancel" msgid="5665114069455378395">"取消"</string>
<string name="okay" msgid="949938843324579502">"確定"</string>
+ <!-- no translation found for done (381184316122520313) -->
+ <skip />
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"鬧鐘與提醒"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"允許設定鬧鐘和提醒"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"鬧鐘和提醒"</string>
@@ -551,7 +553,9 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"每次都詢問"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"直到你關閉為止"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"剛剛"</string>
- <string name="media_transfer_this_device_name" msgid="2357329267148436433">"這支手機"</string>
+ <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"這支手機"</string>
+ <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+ <skip />
<string name="media_transfer_this_phone" msgid="7194341457812151531">"這支手機"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"無法連線,請關閉裝置後再重新開啟"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"有線音訊裝置"</string>
@@ -591,7 +595,9 @@
<string name="user_set_lock_button" msgid="1427128184982594856">"設定鎖定"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"切換至<xliff:g id="USER_NAME">%s</xliff:g>"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"正在建立新使用者…"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"正在建立新訪客…"</string>
<string name="add_user_failed" msgid="4809887794313944872">"無法建立新的使用者"</string>
+ <string name="add_guest_failed" msgid="8074548434469843443">"無法建立新訪客"</string>
<string name="user_nickname" msgid="262624187455825083">"暱稱"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"新增訪客"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"移除訪客"</string>
@@ -644,4 +650,7 @@
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"演出者資訊"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"選擇個人資料相片"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"預設使用者圖示"</string>
+ <string name="physical_keyboard_title" msgid="4811935435315835220">"實體鍵盤"</string>
+ <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"選擇鍵盤配置"</string>
+ <string name="keyboard_layout_default_label" msgid="1997292217218546957">"預設"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml
index 16b601c2cb73..119c91b06506 100644
--- a/packages/SettingsLib/res/values-zu/strings.xml
+++ b/packages/SettingsLib/res/values-zu/strings.xml
@@ -533,6 +533,8 @@
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Isikhathi esincane."</string>
<string name="cancel" msgid="5665114069455378395">"Khansela"</string>
<string name="okay" msgid="949938843324579502">"KULUNGILE"</string>
+ <!-- no translation found for done (381184316122520313) -->
+ <skip />
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"Ama-alamu nezikhumbuzi"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Vumela ukusetha ama-alamu nezikhumbuzi"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Ama-alamu nezikhumbuzi"</string>
@@ -551,7 +553,9 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Buza njalo"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"Uze uvale isikrini"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"Khona manje"</string>
- <string name="media_transfer_this_device_name" msgid="2357329267148436433">"Le foni"</string>
+ <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Le foni"</string>
+ <!-- no translation found for media_transfer_this_device_name (3714653244000242800) -->
+ <skip />
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Le foni"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Inkinga yokuxhumeka. Vala idivayisi futhi uphinde uyivule"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Idivayisi yomsindo enentambo"</string>
@@ -591,7 +595,9 @@
<string name="user_set_lock_button" msgid="1427128184982594856">"Setha ukukhiya"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Shintshela ku-<xliff:g id="USER_NAME">%s</xliff:g>"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Idala umsebenzisi omusha…"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Isungula isimenywa esisha…"</string>
<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>
<string name="guest_new_guest" msgid="3482026122932643557">"Engeza isivakashi"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Susa isihambeli"</string>
@@ -644,4 +650,7 @@
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Ulwazi Lokusakaza"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Khetha isithombe sephrofayela"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"Isithonjana somsebenzisi sokuzenzakalelayo"</string>
+ <string name="physical_keyboard_title" msgid="4811935435315835220">"Ikhibhodi ephathekayo"</string>
+ <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Khetha isendlalelo sekhibhodi"</string>
+ <string name="keyboard_layout_default_label" msgid="1997292217218546957">"Zenzekela"</string>
</resources>
diff --git a/packages/SettingsLib/res/values/colors.xml b/packages/SettingsLib/res/values/colors.xml
index 5e8779fa289a..7ab2ed9481b7 100644
--- a/packages/SettingsLib/res/values/colors.xml
+++ b/packages/SettingsLib/res/values/colors.xml
@@ -36,7 +36,8 @@
<color name="bt_color_bg_6">#e9d2fd</color> <!-- Material Purple 100 -->
<color name="bt_color_bg_7">#cbf0f8</color> <!-- Material Cyan 100 -->
-
<color name="dark_mode_icon_color_single_tone">#99000000</color>
<color name="light_mode_icon_color_single_tone">#ffffff</color>
+
+ <color name="user_avatar_color_bg">?android:attr/colorBackgroundFloating</color>
</resources>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index da0381b68278..ca064c9a441d 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -228,6 +228,13 @@
<!-- Connected devices settings. Message when Bluetooth is connected and active but no battery information, showing remote device status. [CHAR LIMIT=NONE] -->
<string name="bluetooth_active_no_battery_level">Active</string>
+ <!-- Connected device settings. Message when the left-side hearing aid device is active. [CHAR LIMIT=NONE] -->
+ <string name="bluetooth_hearing_aid_left_active">Active, left ear</string>
+ <!-- Connected device settings. Message when the right-side hearing aid device is active. [CHAR LIMIT=NONE] -->
+ <string name="bluetooth_hearing_aid_right_active">Active, right ear</string>
+ <!-- Connected device settings. Message when the left-side and right-side hearing aids device are active. [CHAR LIMIT=NONE] -->
+ <string name="bluetooth_hearing_aid_left_and_right_active">Active, left and right ears</string>
+
<!-- Bluetooth settings. The user-visible string that is used whenever referring to the A2DP profile. -->
<string name="bluetooth_profile_a2dp">Media audio</string>
<!-- Bluetooth settings. The user-visible string that is used whenever referring to the headset or handsfree profile. -->
@@ -347,15 +354,6 @@
<!-- Message for telling the user the kind of BT device being displayed in list. [CHAR LIMIT=30 BACKUP_MESSAGE_ID=5615463912185280812] -->
<string name="bluetooth_talkback_bluetooth">Bluetooth</string>
- <!-- Message for telling the user the left-side hearing aid device is doing its pairing operation [CHAR LIMIT=NONE] -->
- <string name="bluetooth_hearingaid_left_pairing_message">Pairing left hearing aid\u2026</string>
- <!-- Message for telling the user the right-side hearing aid device is doing its pairing operation [CHAR LIMIT=NONE] -->
- <string name="bluetooth_hearingaid_right_pairing_message">Pairing right hearing aid\u2026</string>
- <!-- Bluetooth settings. Message when connected to a left-side Hearing Aid device, showing remote device battery level. [CHAR LIMIT=NONE] -->
- <string name="bluetooth_hearingaid_left_battery_level">Left - <xliff:g id="battery_level_as_percentage">%1$s</xliff:g> battery</string>
- <!-- Bluetooth settings. Message when connected to a right-side Hearing Aid device, showing remote device battery level. [CHAR LIMIT=NONE] -->
- <string name="bluetooth_hearingaid_right_battery_level">Right - <xliff:g id="battery_level_as_percentage">%1$s</xliff:g> battery</string>
-
<!-- Content description of the WIFI signal when WIFI is disabled for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_wifi_off">Wifi off.</string>
<!-- Content description of the WIFI signal when no signal for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
@@ -1038,23 +1036,6 @@
<!-- Developer settings: text for the WebView provider selection toast shown if an invalid provider was chosen (i.e. the setting list was stale). [CHAR LIMIT=NONE] -->
<string name="select_webview_provider_toast_text">This choice is no longer valid. Try again.</string>
- <!-- Developer settings screen, convert userdata to file encryption option name -->
- <string name="convert_to_file_encryption">Convert to file encryption</string>
- <!-- Developer settings screen, convert userdata to file encryption summary when option is available -->
- <string name="convert_to_file_encryption_enabled">Convert\u2026</string>
- <!-- Developer settings screen, convert userdata to file encryption summary when option is already done -->
- <string name="convert_to_file_encryption_done">Already file encrypted</string>
- <!-- Title used on dialog with final prompt for converting to file encryption -->
- <string name="title_convert_fbe">Converting to file based encryption</string>
- <!-- Warning displayed on dialog with final prompt for converting to file encryption -->
- <string name="convert_to_fbe_warning">
- Convert data partition to file based encryption.\n
- !!Warning!! This will erase all your data.\n
- This feature is alpha, and may not work correctly.\n
- Press \'Wipe and convert\u2026\' to continue.</string>
- <!-- Button on dialog that triggers convertion to file encryption -->
- <string name="button_convert_fbe">Wipe and convert\u2026</string>
-
<!-- Name of feature to change color setting for the display [CHAR LIMIT=60] -->
<string name="picture_color_mode">Picture color mode</string>
@@ -1293,6 +1274,8 @@
<string name="cancel">Cancel</string>
<!-- Button label for generic OK action [CHAR LIMIT=20] -->
<string name="okay">OK</string>
+ <!-- Button label for generic Done action, to be pressed when an action has been completed [CHAR LIMIT=20] -->
+ <string name="done">Done</string>
<!-- Label for the settings activity for controlling apps that can schedule alarms [CHAR LIMIT=30] -->
<string name="alarms_and_reminders_label">Alarms and reminders</string>
@@ -1342,7 +1325,9 @@
<string name="notice_header" translatable="false"></string>
<!-- Name of the phone device. [CHAR LIMIT=30] -->
- <string name="media_transfer_this_device_name">This phone</string>
+ <string name="media_transfer_this_device_name" product="default">This phone</string>
+ <!-- Name of the tablet device. [CHAR LIMIT=30] -->
+ <string name="media_transfer_this_device_name" product="tablet">This tablet</string>
<!-- Name of the phone device with an active remote session. [CHAR LIMIT=30] -->
<string name="media_transfer_this_phone">This phone</string>
@@ -1426,8 +1411,12 @@
<string name="user_switch_to_user">Switch to <xliff:g id="user_name" example="John Doe">%s</xliff:g></string>
<!-- Dialog message when creating a new user [CHAR LIMIT=NONE] -->
<string name="creating_new_user_dialog_message">Creating new user…</string>
+ <!-- Dialog message when creating a new guest [CHAR LIMIT=NONE] -->
+ <string name="creating_new_guest_dialog_message">Creating new guest…</string>
<!-- Text shown to notify that the creation of new user has failed. [CHAR LIMIT=40] -->
<string name="add_user_failed">Failed to create a new user</string>
+ <!-- Text shown to notify that the creation of new guest has failed. [CHAR LIMIT=40] -->
+ <string name="add_guest_failed">Failed to create a new guest</string>
<!-- Title for the preference to enter the nickname of the user to display in the user switcher [CHAR LIMIT=25]-->
<string name="user_nickname">Nickname</string>
@@ -1568,4 +1557,17 @@
<!-- Content description for a default user icon. [CHAR LIMIT=NONE] -->
<string name="default_user_icon_description">Default user icon</string>
+ <!-- Title for the 'physical keyboard' settings screen. [CHAR LIMIT=35] -->
+ <string name="physical_keyboard_title">Physical keyboard</string>
+ <!-- Title for the keyboard layout preference dialog. [CHAR LIMIT=35] -->
+ <string name="keyboard_layout_dialog_title">Choose keyboard layout</string>
+ <!-- Label of the default keyboard layout. [CHAR LIMIT=35] -->
+ <string name="keyboard_layout_default_label">Default</string>
+
+ <!-- Special access > Title for managing turn screen on settings. [CHAR LIMIT=50] -->
+ <string name="turn_screen_on_title">Turn screen on</string>
+ <!-- Label for a setting which controls whether an app can turn the screen on [CHAR LIMIT=45] -->
+ <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>
</resources>
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java
index 17db45dcaeb3..3a4a8d27b2f3 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java
@@ -30,11 +30,11 @@ import android.util.AttributeSet;
import android.util.TypedValue;
import android.widget.TextView;
+import androidx.annotation.RequiresApi;
+import androidx.core.os.BuildCompat;
import androidx.preference.Preference;
import androidx.preference.PreferenceViewHolder;
-import com.android.internal.util.Preconditions;
-
/**
* Helper class for managing settings preferences that can be disabled
* by device admins via user restrictions.
@@ -42,8 +42,8 @@ import com.android.internal.util.Preconditions;
public class RestrictedPreferenceHelper {
private final Context mContext;
private final Preference mPreference;
- final String packageName;
- final int uid;
+ String packageName;
+ int uid;
private boolean mDisabledByAdmin;
private EnforcedAdmin mEnforcedAdmin;
@@ -105,11 +105,9 @@ public class RestrictedPreferenceHelper {
if (mDisabledSummary) {
final TextView summaryView = (TextView) holder.findViewById(android.R.id.summary);
if (summaryView != null) {
- final CharSequence disabledText = mContext
- .getSystemService(DevicePolicyManager.class)
- .getString(CONTROLLED_BY_ADMIN_SUMMARY,
- () -> summaryView.getContext().getString(
- R.string.disabled_by_admin_summary_text));
+ final CharSequence disabledText = BuildCompat.isAtLeastT()
+ ? getDisabledByAdminUpdatableString()
+ : mContext.getString(R.string.disabled_by_admin_summary_text);
if (mDisabledByAdmin) {
summaryView.setText(disabledText);
} else if (mDisabledByAppOps) {
@@ -122,6 +120,13 @@ public class RestrictedPreferenceHelper {
}
}
+ @RequiresApi(Build.VERSION_CODES.TIRAMISU)
+ private String getDisabledByAdminUpdatableString() {
+ return mContext.getSystemService(DevicePolicyManager.class).getResources().getString(
+ CONTROLLED_BY_ADMIN_SUMMARY,
+ () -> mContext.getString(R.string.disabled_by_admin_summary_text));
+ }
+
public void useAdminDisabledSummary(boolean useSummary) {
mDisabledSummary = useSummary;
}
@@ -219,6 +224,11 @@ public class RestrictedPreferenceHelper {
return mDisabledByAppOps;
}
+ public void updatePackageDetails(String packageName, int uid) {
+ this.packageName = packageName;
+ this.uid = uid;
+ }
+
private void updateDisabledState() {
if (!(mPreference instanceof RestrictedTopLevelPreference)) {
mPreference.setEnabled(!(mDisabledByAdmin || mDisabledByAppOps));
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java
index c607d742938a..091e3228d437 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java
@@ -18,8 +18,11 @@ package com.android.settingslib;
import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
+import android.annotation.NonNull;
+import android.app.AppOpsManager;
import android.content.Context;
import android.content.res.TypedArray;
+import android.os.Process;
import android.os.UserHandle;
import android.util.AttributeSet;
import android.util.TypedValue;
@@ -28,6 +31,7 @@ import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
+import androidx.annotation.VisibleForTesting;
import androidx.core.content.res.TypedArrayUtils;
import androidx.preference.PreferenceManager;
import androidx.preference.PreferenceViewHolder;
@@ -39,6 +43,7 @@ import androidx.preference.SwitchPreference;
*/
public class RestrictedSwitchPreference extends SwitchPreference {
RestrictedPreferenceHelper mHelper;
+ AppOpsManager mAppOpsManager;
boolean mUseAdditionalSummary = false;
CharSequence mRestrictedSwitchSummary;
private int mIconSize;
@@ -90,6 +95,11 @@ public class RestrictedSwitchPreference extends SwitchPreference {
this(context, null);
}
+ @VisibleForTesting
+ public void setAppOps(AppOpsManager appOps) {
+ mAppOpsManager = appOps;
+ }
+
public void setIconSize(int iconSize) {
mIconSize = iconSize;
}
@@ -97,6 +107,12 @@ public class RestrictedSwitchPreference extends SwitchPreference {
@Override
public void onBindViewHolder(PreferenceViewHolder holder) {
super.onBindViewHolder(holder);
+ final View switchView = holder.findViewById(android.R.id.switch_widget);
+ if (switchView != null) {
+ final View rootView = switchView.getRootView();
+ rootView.setFilterTouchesWhenObscured(true);
+ }
+
mHelper.onBindViewHolder(holder);
CharSequence switchSummary;
@@ -164,11 +180,18 @@ public class RestrictedSwitchPreference extends SwitchPreference {
@Override
public void setEnabled(boolean enabled) {
+ boolean changed = false;
if (enabled && isDisabledByAdmin()) {
mHelper.setDisabledByAdmin(null);
- return;
+ changed = true;
+ }
+ if (enabled && isDisabledByAppOps()) {
+ mHelper.setDisabledByAppOps(false);
+ changed = true;
+ }
+ if (!changed) {
+ super.setEnabled(enabled);
}
- super.setEnabled(enabled);
}
public void setDisabledByAdmin(EnforcedAdmin admin) {
@@ -180,4 +203,38 @@ public class RestrictedSwitchPreference extends SwitchPreference {
public boolean isDisabledByAdmin() {
return mHelper.isDisabledByAdmin();
}
+
+ private void setDisabledByAppOps(boolean disabled) {
+ if (mHelper.setDisabledByAppOps(disabled)) {
+ notifyChanged();
+ }
+ }
+
+ public boolean isDisabledByAppOps() {
+ return mHelper.isDisabledByAppOps();
+ }
+
+ public int getUid() {
+ return mHelper != null ? mHelper.uid : Process.INVALID_UID;
+ }
+
+ public String getPackageName() {
+ return mHelper != null ? mHelper.packageName : null;
+ }
+
+ public void updateState(@NonNull String packageName, int uid, boolean isEnabled) {
+ mHelper.updatePackageDetails(packageName, uid);
+ if (mAppOpsManager == null) {
+ mAppOpsManager = getContext().getSystemService(AppOpsManager.class);
+ }
+ final int mode = mAppOpsManager.noteOpNoThrow(
+ AppOpsManager.OP_ACCESS_RESTRICTED_SETTINGS,
+ uid, packageName);
+ final boolean appOpsAllowed = mode == AppOpsManager.MODE_ALLOWED;
+ if (appOpsAllowed || isEnabled) {
+ setEnabled(true);
+ } else {
+ setDisabledByAppOps(true);
+ }
+ }
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java
index 19114cf147e4..f639022f222d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/Utils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java
@@ -30,6 +30,7 @@ import android.net.TetheringManager;
import android.net.vcn.VcnTransportInfo;
import android.net.wifi.WifiInfo;
import android.os.BatteryManager;
+import android.os.Build;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
@@ -41,8 +42,10 @@ import android.telephony.ServiceState;
import android.telephony.TelephonyManager;
import androidx.annotation.NonNull;
+import androidx.annotation.RequiresApi;
import androidx.core.graphics.drawable.RoundedBitmapDrawable;
import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory;
+import androidx.core.os.BuildCompat;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.UserIcons;
@@ -127,8 +130,9 @@ public class Utils {
String name = info != null ? info.name : null;
if (info.isManagedProfile()) {
// We use predefined values for managed profiles
- return context.getSystemService(DevicePolicyManager.class).getString(
- WORK_PROFILE_USER_LABEL, () -> context.getString(R.string.managed_user_title));
+ return BuildCompat.isAtLeastT()
+ ? getUpdatableManagedUserTitle(context)
+ : context.getString(R.string.managed_user_title);
} else if (info.isGuest()) {
name = context.getString(R.string.user_guest);
}
@@ -140,6 +144,13 @@ public class Utils {
return context.getResources().getString(R.string.running_process_item_user_label, name);
}
+ @RequiresApi(Build.VERSION_CODES.TIRAMISU)
+ private static String getUpdatableManagedUserTitle(Context context) {
+ return context.getSystemService(DevicePolicyManager.class).getResources().getString(
+ WORK_PROFILE_USER_LABEL,
+ () -> context.getString(R.string.managed_user_title));
+ }
+
/**
* Returns a circular icon for a user.
*/
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
index 389892ed15e4..62c83cf04a4f 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
@@ -371,7 +371,7 @@ public class BluetoothEventManager {
|| cachedDevice.getHiSyncId() != BluetoothHearingAid.HI_SYNC_ID_INVALID) {
mDeviceManager.onDeviceUnpaired(cachedDevice);
}
- int reason = intent.getIntExtra(BluetoothDevice.EXTRA_REASON,
+ int reason = intent.getIntExtra(BluetoothDevice.EXTRA_UNBOND_REASON,
BluetoothDevice.ERROR);
showUnbondMessage(context, cachedDevice.getName(), reason);
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index 1c9d9cf376f1..2a28891e9158 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -285,6 +285,12 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
public void disconnect() {
synchronized (mProfileLock) {
+ if (getGroupId() != BluetoothCsipSetCoordinator.GROUP_ID_INVALID) {
+ for (CachedBluetoothDevice member : getMemberDevice()) {
+ Log.d(TAG, "Disconnect the member(" + member.getAddress() + ")");
+ member.disconnect();
+ }
+ }
mDevice.disconnect();
}
// Disconnect PBAP server in case its connected
@@ -399,6 +405,12 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
}
mDevice.connect();
+ if (getGroupId() != BluetoothCsipSetCoordinator.GROUP_ID_INVALID) {
+ for (CachedBluetoothDevice member : getMemberDevice()) {
+ Log.d(TAG, "connect the member(" + member.getAddress() + ")");
+ member.connect();
+ }
+ }
}
}
@@ -741,7 +753,10 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
ParcelUuid[] uuids = mDevice.getUuids();
if (uuids == null) return false;
- ParcelUuid[] localUuids = mLocalAdapter.getUuids();
+ List<ParcelUuid> uuidsList = mLocalAdapter.getUuidsList();
+ ParcelUuid[] localUuids = new ParcelUuid[uuidsList.size()];
+ uuidsList.toArray(localUuids);
+
if (localUuids == null) return false;
/*
@@ -1105,7 +1120,8 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
final boolean isOnCall = Utils.isAudioModeOngoingCall(mContext);
if ((mIsActiveDeviceHearingAid)
|| (mIsActiveDeviceHeadset && isOnCall)
- || (mIsActiveDeviceA2dp && !isOnCall)) {
+ || (mIsActiveDeviceA2dp && !isOnCall)
+ || mIsActiveDeviceLeAudio) {
if (isTwsBatteryAvailable(leftBattery, rightBattery) && !shortSummary) {
stringRes = R.string.bluetooth_active_battery_level_untethered;
} else if (batteryLevelPercentageString != null && !shortSummary) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LeAudioProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LeAudioProfile.java
index e203cbaa3da5..19df1e9c0730 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LeAudioProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LeAudioProfile.java
@@ -246,6 +246,13 @@ public class LeAudioProfile implements LocalBluetoothProfile {
return R.drawable.ic_bt_le_audio;
}
+ public int getAudioLocation(BluetoothDevice device) {
+ if (mService == null || device == null) {
+ return BluetoothLeAudio.AUDIO_LOCATION_INVALID;
+ }
+ return mService.getAudioLocation(device);
+ }
+
@RequiresApi(Build.VERSION_CODES.S)
protected void finalize() {
if (DEBUG) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothAdapter.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothAdapter.java
index e7a6b327bacd..31cc6a4ba412 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothAdapter.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothAdapter.java
@@ -126,7 +126,10 @@ public class LocalBluetoothAdapter {
}
public ParcelUuid[] getUuids() {
- return mAdapter.getUuids();
+ List<ParcelUuid> uuidsList = mAdapter.getUuidsList();
+ ParcelUuid[] uuidsArray = new ParcelUuid[uuidsList.size()];
+ uuidsList.toArray(uuidsArray);
+ return uuidsArray;
}
public boolean isDiscovering() {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
index 5e2f31010900..7573177565a4 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
@@ -24,9 +24,9 @@ import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHeadset;
import android.bluetooth.BluetoothHeadsetClient;
import android.bluetooth.BluetoothHearingAid;
-import android.bluetooth.BluetoothLeAudio;
import android.bluetooth.BluetoothHidDevice;
import android.bluetooth.BluetoothHidHost;
+import android.bluetooth.BluetoothLeAudio;
import android.bluetooth.BluetoothMap;
import android.bluetooth.BluetoothMapClient;
import android.bluetooth.BluetoothPan;
@@ -159,10 +159,8 @@ public class LocalBluetoothProfileManager {
if (mHfpClientProfile == null && supportedList.contains(BluetoothProfile.HEADSET_CLIENT)) {
if (DEBUG) Log.d(TAG, "Adding local HfpClient profile");
mHfpClientProfile = new HfpClientProfile(mContext, mDeviceManager, this);
- addHeadsetProfile(mHfpClientProfile, HfpClientProfile.NAME,
- BluetoothHeadsetClient.ACTION_CONNECTION_STATE_CHANGED,
- BluetoothHeadsetClient.ACTION_AUDIO_STATE_CHANGED,
- BluetoothHeadsetClient.STATE_AUDIO_DISCONNECTED);
+ addProfile(mHfpClientProfile, HfpClientProfile.NAME,
+ BluetoothHeadsetClient.ACTION_CONNECTION_STATE_CHANGED);
}
if (mMapClientProfile == null && supportedList.contains(BluetoothProfile.MAP_CLIENT)) {
if (DEBUG) Log.d(TAG, "Adding local MAP CLIENT profile");
diff --git a/packages/SettingsLib/src/com/android/settingslib/connectivity/ConnectivitySubsystemsRecoveryManager.java b/packages/SettingsLib/src/com/android/settingslib/connectivity/ConnectivitySubsystemsRecoveryManager.java
index c61f8a9c3b53..be420ac8bd24 100644
--- a/packages/SettingsLib/src/com/android/settingslib/connectivity/ConnectivitySubsystemsRecoveryManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/connectivity/ConnectivitySubsystemsRecoveryManager.java
@@ -31,6 +31,8 @@ import android.telephony.TelephonyCallback;
import android.telephony.TelephonyManager;
import android.util.Log;
+import androidx.annotation.VisibleForTesting;
+
/**
* An interface class to manage connectivity subsystem recovery/restart operations.
*/
@@ -193,22 +195,30 @@ public class ConnectivitySubsystemsRecoveryManager {
mApmMonitorRegistered = false;
}
- private void startTrackingWifiRestart() {
+ @VisibleForTesting
+ void startTrackingWifiRestart() {
+ if (mWifiManager == null) return;
mWifiManager.registerSubsystemRestartTrackingCallback(new HandlerExecutor(mHandler),
mWifiSubsystemRestartTrackingCallback);
}
- private void stopTrackingWifiRestart() {
+ @VisibleForTesting
+ void stopTrackingWifiRestart() {
+ if (mWifiManager == null) return;
mWifiManager.unregisterSubsystemRestartTrackingCallback(
mWifiSubsystemRestartTrackingCallback);
}
- private void startTrackingTelephonyRestart() {
+ @VisibleForTesting
+ void startTrackingTelephonyRestart() {
+ if (mTelephonyManager == null) return;
mTelephonyManager.registerTelephonyCallback(new HandlerExecutor(mHandler),
mTelephonyCallback);
}
- private void stopTrackingTelephonyRestart() {
+ @VisibleForTesting
+ void stopTrackingTelephonyRestart() {
+ if (mTelephonyManager == null) return;
mTelephonyManager.unregisterTelephonyCallback(mTelephonyCallback);
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawable/UserIconDrawable.java b/packages/SettingsLib/src/com/android/settingslib/drawable/UserIconDrawable.java
index d01f2b42f338..94d90a8eb028 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawable/UserIconDrawable.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawable/UserIconDrawable.java
@@ -98,7 +98,7 @@ public class UserIconDrawable extends Drawable implements Drawable.Callback {
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
private static Drawable getUpdatableManagedUserDrawable(Context context) {
DevicePolicyManager dpm = context.getSystemService(DevicePolicyManager.class);
- return dpm.getDrawableForDensity(
+ return dpm.getResources().getDrawableForDensity(
WORK_PROFILE_USER_ICON,
SOLID_COLORED,
context.getResources().getDisplayMetrics().densityDpi,
@@ -233,7 +233,7 @@ public class UserIconDrawable extends Drawable implements Drawable.Callback {
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
private static Drawable getUpdatableManagementBadge(Context context) {
DevicePolicyManager dpm = context.getSystemService(DevicePolicyManager.class);
- return dpm.getDrawableForDensity(
+ return dpm.getResources().getDrawableForDensity(
WORK_PROFILE_ICON,
SOLID_COLORED,
context.getResources().getDisplayMetrics().densityDpi,
diff --git a/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java b/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java
index fcb56d2f7016..01d0cc40c0bc 100644
--- a/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java
+++ b/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java
@@ -248,9 +248,6 @@ public class DreamBackend {
}
public @WhenToDream int getWhenToDreamSetting() {
- if (!isEnabled()) {
- return NEVER;
- }
return isActivatedOnDock() && isActivatedOnSleep() ? EITHER
: isActivatedOnDock() ? WHILE_DOCKED
: isActivatedOnSleep() ? WHILE_CHARGING
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java
index c7599623c465..3984ee9aa007 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java
@@ -35,6 +35,7 @@ import android.content.Context;
import android.graphics.drawable.Drawable;
import android.media.MediaRoute2Info;
import android.media.MediaRouter2Manager;
+import android.media.NearbyDevice;
import android.text.TextUtils;
import android.util.Log;
@@ -77,6 +78,8 @@ public abstract class MediaDevice implements Comparable<MediaDevice> {
private int mConnectedRecord;
private int mState;
+ @NearbyDevice.RangeZone
+ private int mRangeZone = NearbyDevice.RANGE_UNKNOWN;
protected final Context mContext;
protected final MediaRoute2Info mRouteInfo;
@@ -136,6 +139,14 @@ public abstract class MediaDevice implements Comparable<MediaDevice> {
getId());
}
+ public @NearbyDevice.RangeZone int getRangeZone() {
+ return mRangeZone;
+ }
+
+ public void setRangeZone(@NearbyDevice.RangeZone int rangeZone) {
+ mRangeZone = rangeZone;
+ }
+
/**
* Get name from MediaDevice.
*
@@ -319,6 +330,11 @@ public abstract class MediaDevice implements Comparable<MediaDevice> {
}
}
+ // Both devices have same connection status, compare the range zone
+ if (NearbyDevice.compareRangeZones(getRangeZone(), another.getRangeZone()) != 0) {
+ return NearbyDevice.compareRangeZones(getRangeZone(), another.getRangeZone());
+ }
+
if (mType == another.mType) {
// Check device is muting expected device
if (isMutingExpectedDevice()) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/users/AvatarPhotoController.java b/packages/SettingsLib/src/com/android/settingslib/users/AvatarPhotoController.java
index 0cb2c0b22a4c..63a9f0c5c7f4 100644
--- a/packages/SettingsLib/src/com/android/settingslib/users/AvatarPhotoController.java
+++ b/packages/SettingsLib/src/com/android/settingslib/users/AvatarPhotoController.java
@@ -78,6 +78,11 @@ class AvatarPhotoController {
static final int REQUEST_CODE_TAKE_PHOTO = 1002;
static final int REQUEST_CODE_CROP_PHOTO = 1003;
+ /**
+ * Delay to allow the photo picker exit animation to complete before the crop activity opens.
+ */
+ private static final long DELAY_BEFORE_CROP_MILLIS = 150;
+
private static final String IMAGES_DIR = "multi_user";
private static final String PRE_CROP_PICTURE_FILE_NAME = "PreCropEditUserPhoto.jpg";
private static final String CROP_PICTURE_FILE_NAME = "CropEditUserPhoto.jpg";
@@ -131,13 +136,15 @@ class AvatarPhotoController {
mAvatarUi.returnUriResult(pictureUri);
return true;
case REQUEST_CODE_TAKE_PHOTO:
- case REQUEST_CODE_CHOOSE_PHOTO:
if (mTakePictureUri.equals(pictureUri)) {
cropPhoto(pictureUri);
} else {
- copyAndCropPhoto(pictureUri);
+ copyAndCropPhoto(pictureUri, false);
}
return true;
+ case REQUEST_CODE_CHOOSE_PHOTO:
+ copyAndCropPhoto(pictureUri, true);
+ return true;
}
return false;
}
@@ -154,7 +161,7 @@ class AvatarPhotoController {
mAvatarUi.startActivityForResult(intent, REQUEST_CODE_CHOOSE_PHOTO);
}
- private void copyAndCropPhoto(final Uri pictureUri) {
+ private void copyAndCropPhoto(final Uri pictureUri, boolean delayBeforeCrop) {
try {
ThreadUtils.postOnBackgroundThread(() -> {
final ContentResolver cr = mContextInjector.getContentResolver();
@@ -165,11 +172,17 @@ class AvatarPhotoController {
Log.w(TAG, "Failed to copy photo", e);
return;
}
- ThreadUtils.postOnMainThread(() -> {
+ Runnable cropRunnable = () -> {
if (!mAvatarUi.isFinishing()) {
cropPhoto(mPreCropPictureUri);
}
- });
+ };
+ if (delayBeforeCrop) {
+ ThreadUtils.postOnMainThreadDelayed(cropRunnable, DELAY_BEFORE_CROP_MILLIS);
+ } else {
+ ThreadUtils.postOnMainThread(cropRunnable);
+ }
+
}).get();
} catch (InterruptedException | ExecutionException e) {
Log.e(TAG, "Error performing copy-and-crop", e);
diff --git a/packages/SettingsLib/src/com/android/settingslib/users/AvatarPickerActivity.java b/packages/SettingsLib/src/com/android/settingslib/users/AvatarPickerActivity.java
index 75bb70a123c3..8a1e91b4dcd8 100644
--- a/packages/SettingsLib/src/com/android/settingslib/users/AvatarPickerActivity.java
+++ b/packages/SettingsLib/src/com/android/settingslib/users/AvatarPickerActivity.java
@@ -106,13 +106,13 @@ public class AvatarPickerActivity extends Activity {
FooterButton secondaryButton =
new FooterButton.Builder(this)
- .setText("Cancel")
+ .setText(getString(android.R.string.cancel))
.setListener(view -> cancel())
.build();
mDoneButton =
new FooterButton.Builder(this)
- .setText("Done")
+ .setText(getString(R.string.done))
.setListener(view -> mAdapter.returnSelectionResult())
.build();
mDoneButton.setEnabled(false);
diff --git a/packages/SettingsLib/src/com/android/settingslib/users/UserCreatingDialog.java b/packages/SettingsLib/src/com/android/settingslib/users/UserCreatingDialog.java
index 075635c87b1b..dd86bec9126c 100644
--- a/packages/SettingsLib/src/com/android/settingslib/users/UserCreatingDialog.java
+++ b/packages/SettingsLib/src/com/android/settingslib/users/UserCreatingDialog.java
@@ -31,11 +31,15 @@ import com.android.settingslib.R;
public class UserCreatingDialog extends AlertDialog {
public UserCreatingDialog(Context context) {
+ this(context, false);
+ }
+
+ public UserCreatingDialog(Context context, boolean isGuest) {
// hardcoding theme to be consistent with UserSwitchingDialog's theme
// todo replace both to adapt to the device's theme
super(context, com.android.internal.R.style.Theme_DeviceDefault_Light_Dialog_Alert);
- inflateContent();
+ inflateContent(isGuest);
getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
WindowManager.LayoutParams attrs = getWindow().getAttributes();
@@ -44,12 +48,14 @@ public class UserCreatingDialog extends AlertDialog {
getWindow().setAttributes(attrs);
}
- private void inflateContent() {
+ private void inflateContent(boolean isGuest) {
// using the same design as UserSwitchingDialog
setCancelable(false);
View view = LayoutInflater.from(getContext())
.inflate(R.layout.user_creation_progress_dialog, null);
- String message = getContext().getString(R.string.creating_new_user_dialog_message);
+ String message = getContext().getString(isGuest
+ ? R.string.creating_new_guest_dialog_message
+ : R.string.creating_new_user_dialog_message);
view.setAccessibilityPaneTitle(message);
((TextView) view.findViewById(R.id.message)).setText(message);
setView(view);
diff --git a/packages/SettingsLib/src/com/android/settingslib/utils/ThreadUtils.java b/packages/SettingsLib/src/com/android/settingslib/utils/ThreadUtils.java
index 69f1c17f97b1..2c1d5da5e941 100644
--- a/packages/SettingsLib/src/com/android/settingslib/utils/ThreadUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/utils/ThreadUtils.java
@@ -84,6 +84,13 @@ public class ThreadUtils {
getUiThreadHandler().post(runnable);
}
+ /**
+ * Posts the runnable on the main thread with a delay.
+ */
+ public static void postOnMainThreadDelayed(Runnable runnable, long delayMillis) {
+ getUiThreadHandler().postDelayed(runnable, delayMillis);
+ }
+
private static synchronized ExecutorService getThreadExecutor() {
if (sThreadExecutor == null) {
sThreadExecutor = Executors.newFixedThreadPool(
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java
index 4ab6542d567a..9ef6bdf0fb41 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java
@@ -43,6 +43,31 @@ public class WifiUtils {
private static final int INVALID_RSSI = -127;
/**
+ * The intent action shows Wi-Fi dialog to connect Wi-Fi network.
+ * <p>
+ * Input: The calling package should put the chosen
+ * com.android.wifitrackerlib.WifiEntry#getKey() to a string extra in the request bundle into
+ * the {@link #EXTRA_CHOSEN_WIFI_ENTRY_KEY}.
+ * <p>
+ * Output: Nothing.
+ */
+ @VisibleForTesting
+ static final String ACTION_WIFI_DIALOG = "com.android.settings.WIFI_DIALOG";
+
+ /**
+ * Specify a key that indicates the WifiEntry to be configured.
+ */
+ @VisibleForTesting
+ static final String EXTRA_CHOSEN_WIFI_ENTRY_KEY = "key_chosen_wifientry_key";
+
+ /**
+ * The lookup key for a boolean that indicates whether a chosen WifiEntry request to connect to.
+ * {@code true} means a chosen WifiEntry request to connect to.
+ */
+ @VisibleForTesting
+ static final String EXTRA_CONNECT_FOR_CALLER = "connect_for_caller";
+
+ /**
* The intent action shows network details settings to allow configuration of Wi-Fi.
* <p>
* In some cases, a matching Activity may not exist, so ensure you
@@ -325,6 +350,19 @@ public class WifiUtils {
}
/**
+ * Returns the Intent for Wi-Fi dialog.
+ *
+ * @param key The Wi-Fi entry key
+ * @param connectForCaller True if a chosen WifiEntry request to connect to
+ */
+ public static Intent getWifiDialogIntent(String key, boolean connectForCaller) {
+ final Intent intent = new Intent(ACTION_WIFI_DIALOG);
+ intent.putExtra(EXTRA_CHOSEN_WIFI_ENTRY_KEY, key);
+ intent.putExtra(EXTRA_CONNECT_FOR_CALLER, connectForCaller);
+ return intent;
+ }
+
+ /**
* Returns the Intent for Wi-Fi network details settings.
*
* @param key The Wi-Fi entry key
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/users/AvatarPhotoControllerTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/users/AvatarPhotoControllerTest.java
index 9ebdba300266..d988111c29d5 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/users/AvatarPhotoControllerTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/users/AvatarPhotoControllerTest.java
@@ -89,6 +89,10 @@ public class AvatarPhotoControllerTest {
@After
public void tearDown() {
+ String[] entries = mImagesDir.list();
+ for (String entry : entries) {
+ new File(mImagesDir, entry).delete();
+ }
mImagesDir.delete();
}
@@ -150,23 +154,6 @@ public class AvatarPhotoControllerTest {
}
@Test
- public void takePhotoIsNotFollowedByCropIntentWhenCropNotSupported() throws IOException {
- when(mMockAvatarUi.startSystemActivityForResult(any(), anyInt())).thenReturn(false);
-
- File file = new File(mImagesDir, "file.txt");
- saveBitmapToFile(file);
-
- Intent intent = new Intent();
- intent.setData(Uri.parse(
- "content://com.android.settingslib.test/my_cache/multi_user/file.txt"));
- mController.onActivityResult(
- REQUEST_CODE_TAKE_PHOTO, Activity.RESULT_OK, intent);
-
- verify(mMockAvatarUi, never()).startActivityForResult(any(), anyInt());
- verify(mMockAvatarUi, never()).startSystemActivityForResult(any(), anyInt());
- }
-
- @Test
public void choosePhotoIsFollowedByCrop() throws IOException {
new File(mImagesDir, "file.txt").createNewFile();
@@ -250,7 +237,8 @@ public class AvatarPhotoControllerTest {
public void internalCropUsedIfNoSystemCropperFound() throws IOException {
when(mMockAvatarUi.startSystemActivityForResult(any(), anyInt())).thenReturn(false);
- new File(mImagesDir, "file.txt").createNewFile();
+ File file = new File(mImagesDir, "file.txt");
+ saveBitmapToFile(file);
Intent intent = new Intent();
intent.setData(Uri.parse(
@@ -258,10 +246,6 @@ public class AvatarPhotoControllerTest {
mController.onActivityResult(
REQUEST_CODE_TAKE_PHOTO, Activity.RESULT_OK, intent);
- Intent startIntent = verifyStartSystemActivityForResult(
- "com.android.camera.action.CROP", REQUEST_CODE_CROP_PHOTO);
- assertThat(startIntent.getData()).isNotEqualTo(mTakePhotoUri);
-
verify(mMockAvatarUi, timeout(TIMEOUT_MILLIS)).returnUriResult(mCropPhotoUri);
InputStream imageStream = mContext.getContentResolver().openInputStream(mCropPhotoUri);
diff --git a/packages/SettingsLib/tests/robotests/res/layout/preference_footer.xml b/packages/SettingsLib/tests/robotests/res/layout/preference_footer.xml
index c47bff7104ba..766efa829778 100644
--- a/packages/SettingsLib/tests/robotests/res/layout/preference_footer.xml
+++ b/packages/SettingsLib/tests/robotests/res/layout/preference_footer.xml
@@ -23,32 +23,46 @@
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
android:background="?android:attr/selectableItemBackground"
+ android:orientation="vertical"
android:clipToPadding="false">
<LinearLayout
- android:id="@+id/icon_container"
+ android:id="@+id/icon_frame"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:minWidth="60dp"
+ android:minWidth="56dp"
android:gravity="start|top"
android:orientation="horizontal"
android:paddingEnd="12dp"
- android:paddingTop="20dp"
+ android:paddingTop="16dp"
android:paddingBottom="4dp">
<ImageView
android:id="@android:id/icon"
android:layout_width="wrap_content"
- android:layout_height="wrap_content" />
+ android:layout_height="wrap_content"/>
</LinearLayout>
- <com.android.settingslib.widget.LinkTextView
- android:id="@android:id/title"
+ <LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:paddingBottom="16dp"
- android:paddingTop="16dp"
- android:maxLines="10"
- android:textColor="?android:attr/textColorSecondary"
- android:ellipsize="marquee" />
+ android:orientation="vertical">
+ <TextView
+ android:id="@android:id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingTop="16dp"
+ android:paddingBottom="8dp"
+ android:textColor="?android:attr/textColorSecondary"
+ android:ellipsize="marquee" />
+
+ <com.android.settingslib.widget.LinkTextView
+ android:id="@+id/settingslib_learn_more"
+ android:text="@string/settingslib_learn_more_text"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:clickable="true"
+ android:visibility="gone"
+ style="@style/TextAppearance.Footer.Title.SettingsLib"/>
+ </LinearLayout>
</LinearLayout>
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothEventManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothEventManagerTest.java
index 852ac5ca6abe..7b94492cef4f 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothEventManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothEventManagerTest.java
@@ -357,7 +357,8 @@ public class BluetoothEventManagerTest {
mIntent = new Intent(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
mIntent.putExtra(BluetoothDevice.EXTRA_DEVICE, mBluetoothDevice);
mIntent.putExtra(BluetoothDevice.EXTRA_BOND_STATE, BluetoothDevice.BOND_NONE);
- mIntent.putExtra(BluetoothDevice.EXTRA_REASON, BluetoothDevice.UNBOND_REASON_AUTH_TIMEOUT);
+ mIntent.putExtra(BluetoothDevice.EXTRA_UNBOND_REASON,
+ BluetoothDevice.UNBOND_REASON_AUTH_TIMEOUT);
when(mCachedDeviceManager.findDevice(mBluetoothDevice)).thenReturn(mCachedDevice1);
when(mCachedDevice1.getName()).thenReturn(DEVICE_NAME);
@@ -372,7 +373,7 @@ public class BluetoothEventManagerTest {
mIntent = new Intent(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
mIntent.putExtra(BluetoothDevice.EXTRA_DEVICE, mBluetoothDevice);
mIntent.putExtra(BluetoothDevice.EXTRA_BOND_STATE, BluetoothDevice.BOND_NONE);
- mIntent.putExtra(BluetoothDevice.EXTRA_REASON,
+ mIntent.putExtra(BluetoothDevice.EXTRA_UNBOND_REASON,
BluetoothDevice.UNBOND_REASON_REMOTE_DEVICE_DOWN);
when(mCachedDeviceManager.findDevice(mBluetoothDevice)).thenReturn(mCachedDevice1);
when(mCachedDevice1.getName()).thenReturn(DEVICE_NAME);
@@ -388,7 +389,8 @@ public class BluetoothEventManagerTest {
mIntent = new Intent(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
mIntent.putExtra(BluetoothDevice.EXTRA_DEVICE, mBluetoothDevice);
mIntent.putExtra(BluetoothDevice.EXTRA_BOND_STATE, BluetoothDevice.BOND_NONE);
- mIntent.putExtra(BluetoothDevice.EXTRA_REASON, BluetoothDevice.UNBOND_REASON_AUTH_REJECTED);
+ mIntent.putExtra(BluetoothDevice.EXTRA_UNBOND_REASON,
+ BluetoothDevice.UNBOND_REASON_AUTH_REJECTED);
when(mCachedDeviceManager.findDevice(mBluetoothDevice)).thenReturn(mCachedDevice1);
when(mCachedDevice1.getName()).thenReturn(DEVICE_NAME);
@@ -403,7 +405,8 @@ public class BluetoothEventManagerTest {
mIntent = new Intent(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
mIntent.putExtra(BluetoothDevice.EXTRA_DEVICE, mBluetoothDevice);
mIntent.putExtra(BluetoothDevice.EXTRA_BOND_STATE, BluetoothDevice.BOND_NONE);
- mIntent.putExtra(BluetoothDevice.EXTRA_REASON, BluetoothDevice.UNBOND_REASON_AUTH_FAILED);
+ mIntent.putExtra(BluetoothDevice.EXTRA_UNBOND_REASON,
+ BluetoothDevice.UNBOND_REASON_AUTH_FAILED);
when(mCachedDeviceManager.findDevice(mBluetoothDevice)).thenReturn(mCachedDevice1);
when(mCachedDevice1.getName()).thenReturn(DEVICE_NAME);
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/connectivity/ConnectivitySubsystemsRecoveryManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/connectivity/ConnectivitySubsystemsRecoveryManagerTest.java
new file mode 100644
index 000000000000..ca53a187d6f8
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/connectivity/ConnectivitySubsystemsRecoveryManagerTest.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.settingslib.connectivity;
+
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.Handler;
+
+import androidx.test.core.app.ApplicationProvider;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Spy;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+import org.robolectric.RobolectricTestRunner;
+
+@RunWith(RobolectricTestRunner.class)
+public class ConnectivitySubsystemsRecoveryManagerTest {
+
+ @Rule
+ public final MockitoRule mMockitoRule = MockitoJUnit.rule();
+ @Spy
+ Context mContext = ApplicationProvider.getApplicationContext();
+ @Spy
+ Handler mMainHandler = ApplicationProvider.getApplicationContext().getMainThreadHandler();
+ @Mock
+ PackageManager mPackageManager;
+
+ ConnectivitySubsystemsRecoveryManager mConnectivitySubsystemsRecoveryManager;
+
+ @Before
+ public void setUp() {
+ when(mContext.getPackageManager()).thenReturn(mPackageManager);
+ when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_WIFI)).thenReturn(true);
+ when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)).thenReturn(true);
+ }
+
+ @Test
+ public void startTrackingWifiRestart_hasNoWifiFeature_shouldNotCrash() {
+ when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_WIFI)).thenReturn(false);
+ mConnectivitySubsystemsRecoveryManager =
+ new ConnectivitySubsystemsRecoveryManager(mContext, mMainHandler);
+
+ mConnectivitySubsystemsRecoveryManager.startTrackingWifiRestart();
+ }
+
+ @Test
+ public void stopTrackingWifiRestart_hasNoWifiFeature_shouldNotCrash() {
+ when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_WIFI)).thenReturn(false);
+ mConnectivitySubsystemsRecoveryManager =
+ new ConnectivitySubsystemsRecoveryManager(mContext, mMainHandler);
+
+ mConnectivitySubsystemsRecoveryManager.stopTrackingWifiRestart();
+ }
+
+ @Test
+ public void startTrackingTelephonyRestart_hasNoTelephonyFeature_shouldNotCrash() {
+ when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)).thenReturn(false);
+ mConnectivitySubsystemsRecoveryManager =
+ new ConnectivitySubsystemsRecoveryManager(mContext, mMainHandler);
+
+ mConnectivitySubsystemsRecoveryManager.startTrackingTelephonyRestart();
+ }
+
+ @Test
+ public void stopTrackingTelephonyRestart_hasNoTelephonyFeature_shouldNotCrash() {
+ when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)).thenReturn(false);
+ mConnectivitySubsystemsRecoveryManager =
+ new ConnectivitySubsystemsRecoveryManager(mContext, mMainHandler);
+
+ mConnectivitySubsystemsRecoveryManager.stopTrackingTelephonyRestart();
+ }
+}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaDeviceTest.java
index c122a37d0f79..179a498b7397 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaDeviceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaDeviceTest.java
@@ -31,6 +31,7 @@ import android.bluetooth.BluetoothDevice;
import android.content.Context;
import android.media.MediaRoute2Info;
import android.media.MediaRouter2Manager;
+import android.media.NearbyDevice;
import android.os.Parcel;
import com.android.settingslib.bluetooth.A2dpProfile;
@@ -200,6 +201,18 @@ public class MediaDeviceTest {
}
@Test
+ public void compareTo_differentRange_sortWithRange() {
+ mBluetoothMediaDevice1.setRangeZone(NearbyDevice.RANGE_FAR);
+ mBluetoothMediaDevice2.setRangeZone(NearbyDevice.RANGE_CLOSE);
+ mMediaDevices.add(mBluetoothMediaDevice1);
+ mMediaDevices.add(mBluetoothMediaDevice2);
+
+ assertThat(mMediaDevices.get(0)).isEqualTo(mBluetoothMediaDevice1);
+ Collections.sort(mMediaDevices, COMPARATOR);
+ assertThat(mMediaDevices.get(0)).isEqualTo(mBluetoothMediaDevice2);
+ }
+
+ @Test
public void compareTo_carKit_info_carKitFirst() {
when(mDevice1.getBluetoothClass()).thenReturn(mCarkitClass);
mMediaDevices.add(mInfoMediaDevice1);
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/FooterPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/FooterPreferenceTest.java
index 3b18c57e28fa..61a28aab061f 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/FooterPreferenceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/FooterPreferenceTest.java
@@ -19,7 +19,6 @@ package com.android.settingslib.widget;
import static com.google.common.truth.Truth.assertThat;
import android.content.Context;
-import android.text.method.LinkMovementMethod;
import android.view.LayoutInflater;
import android.widget.TextView;
@@ -46,17 +45,6 @@ public class FooterPreferenceTest {
}
@Test
- public void bindPreference_shouldLinkifyContent() {
- final PreferenceViewHolder holder = PreferenceViewHolder.createInstanceForTests(
- LayoutInflater.from(mContext).inflate(R.layout.preference_footer, null));
-
- mFooterPreference.onBindViewHolder(holder);
-
- assertThat(((TextView) holder.findViewById(android.R.id.title)).getMovementMethod())
- .isInstanceOf(LinkMovementMethod.class);
- }
-
- @Test
public void setSummary_summarySet_shouldSetAsTitle() {
mFooterPreference.setSummary("summary");
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiUtilsTest.java
index e7b3fe9ab8da..69561055ff7f 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiUtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiUtilsTest.java
@@ -156,6 +156,27 @@ public class WifiUtilsTest {
}
@Test
+ public void getWifiDialogIntent_returnsCorrectValues() {
+ String key = "test_key";
+
+ // Test that connectForCaller is true.
+ Intent intent = WifiUtils.getWifiDialogIntent(key, true /* connectForCaller */);
+
+ assertThat(intent.getAction()).isEqualTo(WifiUtils.ACTION_WIFI_DIALOG);
+ assertThat(intent.getStringExtra(WifiUtils.EXTRA_CHOSEN_WIFI_ENTRY_KEY)).isEqualTo(key);
+ assertThat(intent.getBooleanExtra(WifiUtils.EXTRA_CONNECT_FOR_CALLER, true))
+ .isEqualTo(true /* connectForCaller */);
+
+ // Test that connectForCaller is false.
+ intent = WifiUtils.getWifiDialogIntent(key, false /* connectForCaller */);
+
+ assertThat(intent.getAction()).isEqualTo(WifiUtils.ACTION_WIFI_DIALOG);
+ assertThat(intent.getStringExtra(WifiUtils.EXTRA_CHOSEN_WIFI_ENTRY_KEY)).isEqualTo(key);
+ assertThat(intent.getBooleanExtra(WifiUtils.EXTRA_CONNECT_FOR_CALLER, true))
+ .isEqualTo(false /* connectForCaller */);
+ }
+
+ @Test
public void getWifiDetailsSettingsIntent_returnsCorrectValues() {
final String key = "test_key";
diff --git a/packages/SettingsProvider/res/values-or/strings.xml b/packages/SettingsProvider/res/values-or/strings.xml
index 486d8ffaa500..85add41b1ee1 100644
--- a/packages/SettingsProvider/res/values-or/strings.xml
+++ b/packages/SettingsProvider/res/values-or/strings.xml
@@ -19,7 +19,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_label" msgid="4567566098528588863">"ସେଟିଙ୍ଗ ଷ୍ଟୋରେଜ୍‌"</string>
+ <string name="app_label" msgid="4567566098528588863">"ସେଟିଂସ ଷ୍ଟୋରେଜ୍‌"</string>
<string name="wifi_softap_config_change" msgid="5688373762357941645">"ହଟସ୍ପଟ୍ ସେଟିଂସ୍ ବଦଳାଯାଇଛି"</string>
<string name="wifi_softap_config_change_summary" msgid="8946397286141531087">"ବିବରଣୀ ଦେଖିବାକୁ ଟାପ୍ କରନ୍ତୁ"</string>
</resources>
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
index fa3360cd31f6..cbd71c02baf4 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
@@ -328,7 +328,5 @@ public class SecureSettingsValidators {
return true;
});
VALIDATORS.put(Secure.ODI_CAPTIONS_VOLUME_UI_ENABLED, BOOLEAN_VALIDATOR);
- VALIDATORS.put(Secure.FAST_PAIR_SCAN_ENABLED, BOOLEAN_VALIDATOR);
-
}
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index 1c5bf81faf3e..3c29a803ffbb 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -2252,12 +2252,14 @@ class SettingsProtoDumpUtil {
Settings.Secure.MULTI_PRESS_TIMEOUT,
SecureSettingsProto.MULTI_PRESS_TIMEOUT);
+ final long navBar = p.start(SecureSettingsProto.NAV_BAR);
dumpSetting(s, p,
Settings.Secure.NAV_BAR_FORCE_VISIBLE,
SecureSettingsProto.NavBar.NAV_BAR_FORCE_VISIBLE);
dumpSetting(s, p,
Settings.Secure.NAV_BAR_KIDS_MODE,
SecureSettingsProto.NavBar.NAV_BAR_KIDS_MODE);
+ p.end(navBar);
dumpSetting(s, p,
Settings.Secure.NAVIGATION_MODE,
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index 3f4372bd78ff..057a9b05de58 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -271,6 +271,7 @@ public class SettingsBackupTest {
Settings.Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD,
Settings.Global.SMART_REPLIES_IN_NOTIFICATIONS_FLAGS,
Settings.Global.SMART_SUGGESTIONS_IN_NOTIFICATIONS_FLAGS,
+ Settings.Global.STYLUS_HANDWRITING_ENABLED,
Settings.Global.ENABLE_ADB_INCREMENTAL_INSTALL_DEFAULT,
Settings.Global.ENABLE_MULTI_SLOT_TIMEOUT_MILLIS,
Settings.Global.ENHANCED_4G_MODE_ENABLED,
diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderTest.java
index f49e209c09a1..eaf0dcb9b4e7 100644
--- a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderTest.java
+++ b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderTest.java
@@ -188,7 +188,6 @@ public class SettingsProviderTest extends BaseSettingsProviderTest {
int insertedCount = 0;
try {
for (; insertedCount < 1200; insertedCount++) {
- Log.w(LOG_TAG, "Adding app specific setting: " + insertedCount);
insertStringViaProviderApi(SETTING_TYPE_SYSTEM,
String.valueOf(insertedCount), FAKE_SETTING_VALUE, false);
}
@@ -197,7 +196,6 @@ public class SettingsProviderTest extends BaseSettingsProviderTest {
// expected
} finally {
for (; insertedCount >= 0; insertedCount--) {
- Log.w(LOG_TAG, "Removing app specific setting: " + insertedCount);
deleteStringViaProviderApi(SETTING_TYPE_SYSTEM,
String.valueOf(insertedCount));
}
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index c0e2b2ef361f..955aee940513 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -122,6 +122,8 @@
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE"/>
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
+ <!-- BLUETOOTH_PRIVILEGED is needed for testing purposes only. -->
+ <uses-permission android:name="android.permission.BLUETOOTH_PRIVILEGED" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<uses-permission android:name="android.permission.LOCAL_MAC_ADDRESS" />
<uses-permission android:name="android.permission.EXPAND_STATUS_BAR" />
@@ -210,6 +212,7 @@
<uses-permission android:name="android.permission.MANAGE_CREDENTIAL_MANAGEMENT_APP" />
<uses-permission android:name="android.permission.MANAGE_DEVICE_ADMINS" />
<uses-permission android:name="android.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS" />
+ <uses-permission android:name="android.permission.PROVISION_DEMO_DEVICE" />
<uses-permission android:name="android.permission.QUERY_ADMIN_POLICY" />
<uses-permission android:name="android.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES" />
<uses-permission android:name="android.permission.FORCE_DEVICE_POLICY_MANAGER_LOGS" />
@@ -535,10 +538,11 @@
<uses-permission android:name="android.permission.WIFI_ACCESS_COEX_UNSAFE_CHANNELS" />
<uses-permission android:name="android.permission.WIFI_UPDATE_COEX_UNSAFE_CHANNELS" />
<uses-permission android:name="android.permission.NEARBY_WIFI_DEVICES" />
+ <uses-permission android:name="android.permission.MANAGE_WIFI_INTERFACES" />
<uses-permission android:name="android.permission.OVERRIDE_WIFI_CONFIG" />
<!-- Permission needed for CTS test - ConcurrencyTest#testP2pExternalApprover
- P2P external approver API sets require MANAGE_WIFI_AUTO_JOIN permission. -->
- <uses-permission android:name="android.permission.MANAGE_WIFI_AUTO_JOIN" />
+ P2P external approver API sets require MANAGE_WIFI_NETWORK_SELECTION permission. -->
+ <uses-permission android:name="android.permission.MANAGE_WIFI_NETWORK_SELECTION" />
<!-- Permission required for CTS tests to enable/disable rate limiting toasts. -->
<uses-permission android:name="android.permission.MANAGE_TOAST_RATE_LIMITING" />
@@ -667,6 +671,9 @@
<!-- Permission required for CTS test - CtsTelephonyTestCases -->
<uses-permission android:name="android.permission.BIND_TELECOM_CONNECTION_SERVICE" />
+ <!-- Permission required for CTS test - CtsAppEnumerationTestCases -->
+ <uses-permission android:name="android.permission.MAKE_UID_VISIBLE" />
+
<application android:label="@string/app_label"
android:theme="@android:style/Theme.DeviceDefault.DayNight"
android:defaultToDeviceProtectedStorage="true"
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 7f8b2f51754c..4b45cc338a6a 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -314,6 +314,11 @@
<!-- To change system captions state -->
<uses-permission android:name="android.permission.SET_SYSTEM_AUDIO_CAPTION" />
+ <!-- Compat framework -->
+ <uses-permission android:name="android.permission.LOG_COMPAT_CHANGE" />
+ <uses-permission android:name="android.permission.READ_COMPAT_CHANGE_CONFIG" />
+ <uses-permission android:name="android.permission.READ_DEVICE_CONFIG" />
+
<protected-broadcast android:name="com.android.settingslib.action.REGISTER_SLICE_RECEIVER" />
<protected-broadcast android:name="com.android.settingslib.action.UNREGISTER_SLICE_RECEIVER" />
<protected-broadcast android:name="com.android.settings.flashlight.action.FLASHLIGHT_CHANGED" />
@@ -794,7 +799,7 @@
android:noHistory="true"
android:showForAllUsers="true"
android:finishOnTaskLaunch="true"
- android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation|keyboard|keyboardHidden"
+ android:configChanges="screenSize|smallestScreenSize|screenLayout|keyboard|keyboardHidden"
android:visibleToInstantApps="true">
</activity>
@@ -805,7 +810,7 @@
android:showForAllUsers="true"
android:finishOnTaskLaunch="true"
android:launchMode="singleInstance"
- android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation|keyboard|keyboardHidden"
+ android:configChanges="screenSize|smallestScreenSize|screenLayout|keyboard|keyboardHidden"
android:visibleToInstantApps="true">
</activity>
diff --git a/packages/SystemUI/TEST_MAPPING b/packages/SystemUI/TEST_MAPPING
index 9722b1fe2d2e..c8e78c3df5be 100644
--- a/packages/SystemUI/TEST_MAPPING
+++ b/packages/SystemUI/TEST_MAPPING
@@ -180,5 +180,30 @@
}
]
}
+ ],
+ "hubui-presubmit": [
+ {
+ "name": "PlatformScenarioTests",
+ "options": [
+ {
+ "include-annotation": "android.platform.test.annotations.Presubmit"
+ },
+ {
+ "include-annotation": "android.platform.test.scenario.annotation.HubUi"
+ },
+ {
+ "include-filter": "android.platform.test.scenario.hubui"
+ },
+ {
+ "exclude-annotation": "org.junit.Ignore"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ },
+ {
+ "exclude-annotation": "android.platform.test.annotations.Postsubmit"
+ }
+ ]
+ }
]
}
diff --git a/packages/SystemUI/animation/res/values/ids.xml b/packages/SystemUI/animation/res/values/ids.xml
index ef60a248f79a..4e9a4be0060e 100644
--- a/packages/SystemUI/animation/res/values/ids.xml
+++ b/packages/SystemUI/animation/res/values/ids.xml
@@ -15,5 +15,14 @@
limitations under the License.
-->
<resources>
+ <!-- DialogLaunchAnimator -->
<item type="id" name="launch_animation_running"/>
+
+ <!-- ViewBoundsAnimator -->
+ <item type="id" name="tag_animator"/>
+ <item type="id" name="tag_layout_listener"/>
+ <item type="id" name="tag_override_bottom"/>
+ <item type="id" name="tag_override_left"/>
+ <item type="id" name="tag_override_right"/>
+ <item type="id" name="tag_override_top"/>
</resources> \ No newline at end of file
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewLaunchAnimatorController.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewLaunchAnimatorController.kt
index 183584227087..3f7e0f0fb527 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewLaunchAnimatorController.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewLaunchAnimatorController.kt
@@ -33,6 +33,7 @@ import android.view.ViewGroup
import android.view.ViewGroupOverlay
import android.widget.FrameLayout
import com.android.internal.jank.InteractionJankMonitor
+import java.util.LinkedList
import kotlin.math.min
private const val TAG = "GhostedViewLaunchAnimatorController"
@@ -81,21 +82,51 @@ open class GhostedViewLaunchAnimatorController(
* [backgroundView].
*/
private var backgroundDrawable: WrappedDrawable? = null
- private val backgroundInsets by lazy { getBackground()?.opticalInsets ?: Insets.NONE }
+ private val backgroundInsets by lazy { background?.opticalInsets ?: Insets.NONE }
private var startBackgroundAlpha: Int = 0xFF
private val ghostedViewLocation = IntArray(2)
private val ghostedViewState = LaunchAnimator.State()
/**
- * Return the background of the [ghostedView]. This background will be used to draw the
- * background of the background view that is expanding up to the final animation position. This
- * is called at the start of the animation.
+ * The background of the [ghostedView]. This background will be used to draw the background of
+ * the background view that is expanding up to the final animation position.
*
* Note that during the animation, the alpha value value of this background will be set to 0,
* then set back to its initial value at the end of the animation.
*/
- protected open fun getBackground(): Drawable? = ghostedView.background
+ private val background: Drawable?
+
+ init {
+ /** Find the first view with a background in [view] and its children. */
+ fun findBackground(view: View): Drawable? {
+ if (view.background != null) {
+ return view.background
+ }
+
+ // Perform a BFS to find the largest View with background.
+ val views = LinkedList<View>().apply {
+ add(view)
+ }
+
+ while (views.isNotEmpty()) {
+ val v = views.removeFirst()
+ if (v.background != null) {
+ return v.background
+ }
+
+ if (v is ViewGroup) {
+ for (i in 0 until v.childCount) {
+ views.add(v.getChildAt(i))
+ }
+ }
+ }
+
+ return null
+ }
+
+ background = findBackground(ghostedView)
+ }
/**
* Set the corner radius of [background]. The background is the one that was returned by
@@ -113,7 +144,7 @@ open class GhostedViewLaunchAnimatorController(
/** Return the current top corner radius of the background. */
protected open fun getCurrentTopCornerRadius(): Float {
- val drawable = getBackground() ?: return 0f
+ val drawable = background ?: return 0f
val gradient = findGradientDrawable(drawable) ?: return 0f
// TODO(b/184121838): Support more than symmetric top & bottom radius.
@@ -122,7 +153,7 @@ open class GhostedViewLaunchAnimatorController(
/** Return the current bottom corner radius of the background. */
protected open fun getCurrentBottomCornerRadius(): Float {
- val drawable = getBackground() ?: return 0f
+ val drawable = background ?: return 0f
val gradient = findGradientDrawable(drawable) ?: return 0f
// TODO(b/184121838): Support more than symmetric top & bottom radius.
@@ -162,9 +193,8 @@ open class GhostedViewLaunchAnimatorController(
// We wrap the ghosted view background and use it to draw the expandable background. Its
// alpha will be set to 0 as soon as we start drawing the expanding background.
- val drawable = getBackground()
- startBackgroundAlpha = drawable?.alpha ?: 0xFF
- backgroundDrawable = WrappedDrawable(drawable)
+ startBackgroundAlpha = background?.alpha ?: 0xFF
+ backgroundDrawable = WrappedDrawable(background)
backgroundView?.background = backgroundDrawable
// Create a ghost of the view that will be moving and fading out. This allows to fade out
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ViewBoundAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ViewBoundAnimator.kt
new file mode 100644
index 000000000000..5593fdfe5f51
--- /dev/null
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ViewBoundAnimator.kt
@@ -0,0 +1,328 @@
+/*
+ * 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.animation
+
+import android.animation.Animator
+import android.animation.AnimatorListenerAdapter
+import android.animation.ObjectAnimator
+import android.animation.PropertyValuesHolder
+import android.util.IntProperty
+import android.view.View
+import android.view.ViewGroup
+import android.view.animation.Interpolator
+
+/**
+ * A class that allows changes in bounds within a view hierarchy to animate seamlessly between the
+ * start and end state.
+ */
+class ViewBoundAnimator {
+ // 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_BOUNDS = setOf(Bound.LEFT, Bound.TOP, Bound.RIGHT, Bound.BOTTOM)
+
+ /** The properties used to animate the view bounds. */
+ private val PROPERTIES = mapOf(
+ Bound.LEFT to createViewProperty(Bound.LEFT),
+ Bound.TOP to createViewProperty(Bound.TOP),
+ Bound.RIGHT to createViewProperty(Bound.RIGHT),
+ Bound.BOTTOM to createViewProperty(Bound.BOTTOM)
+ )
+
+ private fun createViewProperty(bound: Bound): IntProperty<View> {
+ return object : IntProperty<View>(bound.label) {
+ override fun setValue(view: View, value: Int) {
+ setBound(view, bound, value)
+ }
+
+ override fun get(view: View): Int {
+ return getBound(view, bound) ?: bound.getValue(view)
+ }
+ }
+ }
+
+ /**
+ * Instruct the animator to watch for changes to the layout of [rootView] and its children
+ * and animate them. The animation can be limited to a subset of [bounds]. It uses the
+ * given [interpolator] and [duration].
+ *
+ * If a new layout change happens while an animation is already in progress, the animation
+ * is updated to continue from the current values to the new end state.
+ *
+ * The animator continues to respond to layout changes until [stopAnimating] is called.
+ *
+ * Successive calls to this method override the previous settings ([interpolator] and
+ * [duration]). The changes take effect on the next animation.
+ *
+ * TODO(b/221418522): remove the ability to select which bounds to animate and always
+ * animate all of them.
+ */
+ @JvmOverloads
+ fun animate(
+ rootView: View,
+ bounds: Set<Bound> = DEFAULT_BOUNDS,
+ interpolator: Interpolator = DEFAULT_INTERPOLATOR,
+ duration: Long = DEFAULT_DURATION
+ ) {
+ animate(rootView, bounds, interpolator, duration, false /* ephemeral */)
+ }
+
+ /**
+ * Like [animate], but only takes effect on the next layout update, then unregisters itself
+ * once the first animation is complete.
+ *
+ * TODO(b/221418522): remove the ability to select which bounds to animate and always
+ * animate all of them.
+ */
+ @JvmOverloads
+ fun animateNextUpdate(
+ rootView: View,
+ bounds: Set<Bound> = DEFAULT_BOUNDS,
+ interpolator: Interpolator = DEFAULT_INTERPOLATOR,
+ duration: Long = DEFAULT_DURATION
+ ) {
+ animate(rootView, bounds, interpolator, duration, true /* ephemeral */)
+ }
+
+ private fun animate(
+ rootView: View,
+ bounds: Set<Bound>,
+ interpolator: Interpolator,
+ duration: Long,
+ ephemeral: Boolean
+ ) {
+ val listener = createListener(bounds, interpolator, duration, ephemeral)
+ recursivelyAddListener(rootView, listener)
+ }
+
+ /**
+ * Instruct the animator to stop watching for changes to the layout of [rootView] and its
+ * children.
+ *
+ * Any animations already in progress continue until their natural conclusion.
+ */
+ fun stopAnimating(rootView: View) {
+ val listener = rootView.getTag(R.id.tag_layout_listener)
+ if (listener != null && listener is View.OnLayoutChangeListener) {
+ rootView.setTag(R.id.tag_layout_listener, null /* tag */)
+ rootView.removeOnLayoutChangeListener(listener)
+ }
+
+ if (rootView is ViewGroup) {
+ for (i in 0 until rootView.childCount) {
+ stopAnimating(rootView.getChildAt(i))
+ }
+ }
+ }
+
+ private fun createListener(
+ bounds: Set<Bound>,
+ interpolator: Interpolator,
+ duration: Long,
+ ephemeral: Boolean
+ ): View.OnLayoutChangeListener {
+ return object : View.OnLayoutChangeListener {
+ override fun onLayoutChange(
+ view: View?,
+ left: Int,
+ top: Int,
+ right: Int,
+ bottom: Int,
+ oldLeft: Int,
+ oldTop: Int,
+ oldRight: Int,
+ oldBottom: 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
+
+ (view.getTag(R.id.tag_animator) as? ObjectAnimator)?.cancel()
+
+ if (view.visibility == View.GONE || view.visibility == View.INVISIBLE) {
+ setBound(view, Bound.LEFT, left)
+ setBound(view, Bound.TOP, top)
+ setBound(view, Bound.RIGHT, right)
+ setBound(view, Bound.BOTTOM, bottom)
+ return
+ }
+
+ val startValues = mapOf(
+ Bound.LEFT to startLeft,
+ Bound.TOP to startTop,
+ Bound.RIGHT to startRight,
+ Bound.BOTTOM to startBottom
+ )
+ val endValues = mapOf(
+ Bound.LEFT to left,
+ Bound.TOP to top,
+ Bound.RIGHT to right,
+ 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)
+
+ if (boundsToAnimate.isNotEmpty()) {
+ startAnimation(
+ view,
+ boundsToAnimate,
+ startValues,
+ endValues,
+ interpolator,
+ duration,
+ ephemeral
+ )
+ }
+ }
+ }
+ }
+
+ 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)
+ }
+
+ view.addOnLayoutChangeListener(listener)
+ view.setTag(R.id.tag_layout_listener, listener)
+ if (view is ViewGroup) {
+ for (i in 0 until view.childCount) {
+ recursivelyAddListener(view.getChildAt(i), listener)
+ }
+ }
+ }
+
+ private fun getBound(view: View, bound: Bound): Int? {
+ return view.getTag(bound.overrideTag) as? Int
+ }
+
+ private fun setBound(view: View, bound: Bound, value: Int) {
+ view.setTag(bound.overrideTag, value)
+ bound.setValue(view, value)
+ }
+
+ /**
+ * 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.
+ */
+ private fun startAnimation(
+ view: View,
+ bounds: Set<Bound>,
+ startValues: Map<Bound, Int>,
+ endValues: Map<Bound, Int>,
+ interpolator: Interpolator,
+ duration: Long,
+ ephemeral: Boolean
+ ) {
+ val propertyValuesHolders = buildList {
+ bounds.forEach { bound ->
+ add(
+ PropertyValuesHolder.ofInt(
+ PROPERTIES[bound],
+ startValues.getValue(bound),
+ endValues.getValue(bound)
+ )
+ )
+ }
+ }.toTypedArray()
+
+ val animator = ObjectAnimator.ofPropertyValuesHolder(view, *propertyValuesHolders)
+ animator.interpolator = interpolator
+ animator.duration = duration
+ animator.addListener(object : AnimatorListenerAdapter() {
+ var cancelled = false
+
+ override fun onAnimationEnd(animation: Animator) {
+ view.setTag(R.id.tag_animator, null /* tag */)
+ bounds.forEach { view.setTag(it.overrideTag, null /* tag */) }
+
+ // When an animation is cancelled, a new one might be taking over. We shouldn't
+ // unregister the listener yet.
+ if (ephemeral && !cancelled) {
+ val listener = view.getTag(R.id.tag_layout_listener)
+ if (listener != null && listener is View.OnLayoutChangeListener) {
+ view.setTag(R.id.tag_layout_listener, null /* tag */)
+ view.removeOnLayoutChangeListener(listener)
+ }
+ }
+ }
+
+ override fun onAnimationCancel(animation: Animator?) {
+ cancelled = true
+ }
+ })
+
+ bounds.forEach { bound -> setBound(view, bound, startValues.getValue(bound)) }
+
+ view.setTag(R.id.tag_animator, animator)
+ animator.start()
+ }
+ }
+}
diff --git a/packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt b/packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt
index d8b050aa8e2c..46dad02ddb45 100644
--- a/packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt
+++ b/packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt
@@ -31,37 +31,134 @@ const val ACCENT1_CHROMA = 48.0f
const val GOOGLE_BLUE = 0xFF1b6ef3.toInt()
const val MIN_CHROMA = 5
-internal enum class ChromaStrategy {
- EQ, GTE
+internal interface Hue {
+ fun get(sourceColor: Cam): Double
+
+ /**
+ * Given a hue, and a mapping of hues to hue rotations, find which hues in the mapping the
+ * hue fall betweens, and use the hue rotation of the lower hue.
+ *
+ * @param sourceHue hue of source color
+ * @param hueAndRotations list of pairs, where the first item in a pair is a hue, and the
+ * second item in the pair is a hue rotation that should be applied
+ */
+ fun getHueRotation(sourceHue: Float, hueAndRotations: List<Pair<Int, Int>>): Double {
+ for (i in 0..hueAndRotations.size) {
+ val previousIndex = if (i == 0) hueAndRotations.size - 1 else i - 1
+ val thisHue = hueAndRotations[i].first
+ val previousHue = hueAndRotations[previousIndex].first
+ if (ColorScheme.angleIsBetween(sourceHue, thisHue, previousHue)) {
+ return ColorScheme.wrapDegreesDouble(sourceHue.toDouble() +
+ hueAndRotations[previousIndex].first)
+ }
+ }
+
+ // If this statement executes, something is wrong, there should have been a rotation
+ // found using the arrays.
+ return sourceHue.toDouble()
+ }
}
-internal enum class HueStrategy {
- SOURCE, ADD, SUBTRACT
+internal class HueSource : Hue {
+ override fun get(sourceColor: Cam): Double {
+ return sourceColor.hue.toDouble()
+ }
}
-internal class Chroma(val strategy: ChromaStrategy, val value: Double) {
- fun get(sourceChroma: Double): Double {
- return when (strategy) {
- ChromaStrategy.EQ -> value
- ChromaStrategy.GTE -> sourceChroma.coerceAtLeast(value)
- }
+internal class HueAdd(val amountDegrees: Double) : Hue {
+ override fun get(sourceColor: Cam): Double {
+ return ColorScheme.wrapDegreesDouble(sourceColor.hue.toDouble() + amountDegrees)
+ }
+}
+
+internal class HueSubtract(val amountDegrees: Double) : Hue {
+ override fun get(sourceColor: Cam): Double {
+ return ColorScheme.wrapDegreesDouble(sourceColor.hue.toDouble() - amountDegrees)
+ }
+}
+
+internal class HueVibrantSecondary() : Hue {
+ val hueToRotations = listOf(Pair(24, 15), Pair(53, 15), Pair(91, 15), Pair(123, 15),
+ Pair(141, 15), Pair(172, 15), Pair(198, 15), Pair(234, 18), Pair(272, 18),
+ Pair(302, 18), Pair(329, 30), Pair(354, 15))
+ override fun get(sourceColor: Cam): Double {
+ return getHueRotation(sourceColor.hue, hueToRotations)
+ }
+}
+
+internal class HueVibrantTertiary() : Hue {
+ val hueToRotations = listOf(Pair(24, 30), Pair(53, 30), Pair(91, 15), Pair(123, 30),
+ Pair(141, 27), Pair(172, 27), Pair(198, 30), Pair(234, 35), Pair(272, 30),
+ Pair(302, 30), Pair(329, 60), Pair(354, 30))
+ override fun get(sourceColor: Cam): Double {
+ return getHueRotation(sourceColor.hue, hueToRotations)
+ }
+}
+
+internal class HueExpressiveSecondary() : Hue {
+ val hueToRotations = listOf(Pair(24, 95), Pair(53, 45), Pair(91, 45), Pair(123, 20),
+ Pair(141, 45), Pair(172, 45), Pair(198, 15), Pair(234, 15),
+ Pair(272, 45), Pair(302, 45), Pair(329, 45), Pair(354, 45))
+ override fun get(sourceColor: Cam): Double {
+ return getHueRotation(sourceColor.hue, hueToRotations)
+ }
+}
+
+internal class HueExpressiveTertiary() : Hue {
+ val hueToRotations = listOf(Pair(24, 20), Pair(53, 20), Pair(91, 20), Pair(123, 45),
+ Pair(141, 20), Pair(172, 20), Pair(198, 90), Pair(234, 90), Pair(272, 20),
+ Pair(302, 20), Pair(329, 120), Pair(354, 120))
+ override fun get(sourceColor: Cam): Double {
+ return getHueRotation(sourceColor.hue, hueToRotations)
}
}
-internal class Hue(val strategy: HueStrategy = HueStrategy.SOURCE, val value: Double = 0.0) {
- fun get(sourceHue: Double): Double {
- return when (strategy) {
- HueStrategy.SOURCE -> sourceHue
- HueStrategy.ADD -> ColorScheme.wrapDegreesDouble(sourceHue + value)
- HueStrategy.SUBTRACT -> ColorScheme.wrapDegreesDouble(sourceHue - value)
+internal interface Chroma {
+ fun get(sourceColor: Cam): Double
+
+ /**
+ * Given a hue, and a mapping of hues to hue rotations, find which hues in the mapping the
+ * hue fall betweens, and use the hue rotation of the lower hue.
+ *
+ * @param sourceHue hue of source color
+ * @param hueAndChromas list of pairs, where the first item in a pair is a hue, and the
+ * second item in the pair is a chroma that should be applied
+ */
+ fun getSpecifiedChroma(sourceHue: Float, hueAndChromas: List<Pair<Int, Int>>): Double {
+ for (i in 0..hueAndChromas.size) {
+ val previousIndex = if (i == 0) hueAndChromas.size - 1 else i - 1
+ val thisHue = hueAndChromas[i].first
+ val previousHue = hueAndChromas[previousIndex].first
+ if (ColorScheme.angleIsBetween(sourceHue, thisHue, previousHue)) {
+ return hueAndChromas[i].second.toDouble()
+ }
}
+
+ // If this statement executes, something is wrong, there should have been a rotation
+ // found using the arrays.
+ return sourceHue.toDouble()
+ }
+}
+
+internal class ChromaConstant(val chroma: Double) : Chroma {
+ override fun get(sourceColor: Cam): Double {
+ return chroma
+ }
+}
+
+internal class ChromaExpressiveNeutral() : Chroma {
+ val hueToChromas = listOf(Pair(24, 8), Pair(53, 8), Pair(91, 8), Pair(123, 8),
+ Pair(141, 6), Pair(172, 6), Pair(198, 8), Pair(234, 8), Pair(272, 8),
+ Pair(302, 8), Pair(329, 8), Pair(354, 8))
+ override fun get(sourceColor: Cam): Double {
+ return getSpecifiedChroma(sourceColor.hue, hueToChromas)
}
}
-internal class TonalSpec(val hue: Hue = Hue(), val chroma: Chroma) {
+internal class TonalSpec(val hue: Hue = HueSource(), val chroma: Chroma) {
fun shades(sourceColor: Cam): List<Int> {
- val hue = hue.get(sourceColor.hue.toDouble())
- val chroma = chroma.get(sourceColor.chroma.toDouble())
+ val hue = hue.get(sourceColor)
+ val chroma = chroma.get(sourceColor)
return Shades.of(hue.toFloat(), chroma.toFloat()).toList()
}
}
@@ -76,46 +173,46 @@ internal class CoreSpec(
enum class Style(internal val coreSpec: CoreSpec) {
SPRITZ(CoreSpec(
- a1 = TonalSpec(chroma = Chroma(ChromaStrategy.EQ, 12.0)),
- a2 = TonalSpec(chroma = Chroma(ChromaStrategy.EQ, 8.0)),
- a3 = TonalSpec(chroma = Chroma(ChromaStrategy.EQ, 16.0)),
- n1 = TonalSpec(chroma = Chroma(ChromaStrategy.EQ, 4.0)),
- n2 = TonalSpec(chroma = Chroma(ChromaStrategy.EQ, 8.0))
+ a1 = TonalSpec(HueSource(), ChromaConstant(12.0)),
+ a2 = TonalSpec(HueSource(), ChromaConstant(8.0)),
+ a3 = TonalSpec(HueSource(), ChromaConstant(16.0)),
+ n1 = TonalSpec(HueSource(), ChromaConstant(2.0)),
+ n2 = TonalSpec(HueSource(), ChromaConstant(2.0))
)),
TONAL_SPOT(CoreSpec(
- a1 = TonalSpec(chroma = Chroma(ChromaStrategy.GTE, 32.0)),
- a2 = TonalSpec(chroma = Chroma(ChromaStrategy.EQ, 16.0)),
- a3 = TonalSpec(Hue(HueStrategy.ADD, 60.0), Chroma(ChromaStrategy.EQ, 24.0)),
- n1 = TonalSpec(chroma = Chroma(ChromaStrategy.EQ, 4.0)),
- n2 = TonalSpec(chroma = Chroma(ChromaStrategy.EQ, 8.0))
+ a1 = TonalSpec(HueSource(), ChromaConstant(36.0)),
+ a2 = TonalSpec(HueSource(), ChromaConstant(16.0)),
+ a3 = TonalSpec(HueAdd(60.0), ChromaConstant(24.0)),
+ n1 = TonalSpec(HueSource(), ChromaConstant(4.0)),
+ n2 = TonalSpec(HueSource(), ChromaConstant(8.0))
)),
VIBRANT(CoreSpec(
- a1 = TonalSpec(chroma = Chroma(ChromaStrategy.GTE, 48.0)),
- a2 = TonalSpec(Hue(HueStrategy.ADD, 15.0), Chroma(ChromaStrategy.EQ, 24.0)),
- a3 = TonalSpec(Hue(HueStrategy.ADD, 30.0), Chroma(ChromaStrategy.GTE, 32.0)),
- n1 = TonalSpec(chroma = Chroma(ChromaStrategy.EQ, 8.0)),
- n2 = TonalSpec(chroma = Chroma(ChromaStrategy.EQ, 16.0))
+ a1 = TonalSpec(HueSource(), ChromaConstant(48.0)),
+ a2 = TonalSpec(HueVibrantSecondary(), ChromaConstant(24.0)),
+ a3 = TonalSpec(HueVibrantTertiary(), ChromaConstant(32.0)),
+ n1 = TonalSpec(HueSource(), ChromaConstant(6.0)),
+ n2 = TonalSpec(HueSource(), ChromaConstant(12.0))
)),
EXPRESSIVE(CoreSpec(
- a1 = TonalSpec(Hue(HueStrategy.SUBTRACT, 60.0), Chroma(ChromaStrategy.GTE, 64.0)),
- a2 = TonalSpec(Hue(HueStrategy.SUBTRACT, 30.0), Chroma(ChromaStrategy.EQ, 24.0)),
- a3 = TonalSpec(chroma = Chroma(ChromaStrategy.GTE, 48.0)),
- n1 = TonalSpec(chroma = Chroma(ChromaStrategy.EQ, 12.0)),
- n2 = TonalSpec(chroma = Chroma(ChromaStrategy.EQ, 16.0))
+ a1 = TonalSpec(HueAdd(240.0), ChromaConstant(40.0)),
+ a2 = TonalSpec(HueExpressiveSecondary(), ChromaConstant(24.0)),
+ a3 = TonalSpec(HueExpressiveTertiary(), ChromaConstant(40.0)),
+ n1 = TonalSpec(HueAdd(15.0), ChromaExpressiveNeutral()),
+ n2 = TonalSpec(HueAdd(15.0), ChromaConstant(12.0))
)),
RAINBOW(CoreSpec(
- a1 = TonalSpec(chroma = Chroma(ChromaStrategy.GTE, 48.0)),
- a2 = TonalSpec(chroma = Chroma(ChromaStrategy.EQ, 16.0)),
- a3 = TonalSpec(Hue(HueStrategy.ADD, 60.0), Chroma(ChromaStrategy.EQ, 24.0)),
- n1 = TonalSpec(chroma = Chroma(ChromaStrategy.EQ, 0.0)),
- n2 = TonalSpec(chroma = Chroma(ChromaStrategy.EQ, 0.0))
+ a1 = TonalSpec(HueSource(), ChromaConstant(48.0)),
+ a2 = TonalSpec(HueSource(), ChromaConstant(16.0)),
+ a3 = TonalSpec(HueAdd(60.0), ChromaConstant(24.0)),
+ n1 = TonalSpec(HueSource(), ChromaConstant(0.0)),
+ n2 = TonalSpec(HueSource(), ChromaConstant(0.0))
)),
FRUIT_SALAD(CoreSpec(
- a1 = TonalSpec(Hue(HueStrategy.SUBTRACT, 50.0), Chroma(ChromaStrategy.GTE, 48.0)),
- a2 = TonalSpec(Hue(HueStrategy.SUBTRACT, 50.0), Chroma(ChromaStrategy.EQ, 36.0)),
- a3 = TonalSpec(chroma = Chroma(ChromaStrategy.EQ, 36.0)),
- n1 = TonalSpec(chroma = Chroma(ChromaStrategy.EQ, 10.0)),
- n2 = TonalSpec(chroma = Chroma(ChromaStrategy.EQ, 16.0))
+ a1 = TonalSpec(HueSubtract(50.0), ChromaConstant(48.0)),
+ a2 = TonalSpec(HueSubtract(50.0), ChromaConstant(36.0)),
+ a3 = TonalSpec(HueSource(), ChromaConstant(36.0)),
+ n1 = TonalSpec(HueSource(), ChromaConstant(10.0)),
+ n2 = TonalSpec(HueSource(), ChromaConstant(16.0))
)),
}
@@ -296,6 +393,13 @@ class ColorScheme(
return seeds
}
+ internal fun angleIsBetween(angle: Float, a: Int, b: Int): Boolean {
+ if (a < b) {
+ return a <= angle && angle <= b
+ }
+ return a <= angle || angle <= b
+ }
+
private fun wrapDegrees(degrees: Int): Int {
return when {
degrees < 0 -> {
diff --git a/packages/SystemUI/monet/src/com/android/systemui/monet/Shades.java b/packages/SystemUI/monet/src/com/android/systemui/monet/Shades.java
index aab3538e3c4c..c97b9601f743 100644
--- a/packages/SystemUI/monet/src/com/android/systemui/monet/Shades.java
+++ b/packages/SystemUI/monet/src/com/android/systemui/monet/Shades.java
@@ -59,9 +59,6 @@ public class Shades {
shades[1] = ColorUtils.CAMToColor(hue, Math.min(40f, chroma), 95);
for (int i = 2; i < 12; i++) {
float lStar = (i == 6) ? MIDDLE_LSTAR : 100 - 10 * (i - 1);
- if (lStar >= 90) {
- chroma = Math.min(40f, chroma);
- }
shades[i] = ColorUtils.CAMToColor(hue, chroma, lStar);
}
return shades;
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java
index 6d088f090bcd..1fec3314a13e 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java
@@ -17,6 +17,7 @@ package com.android.systemui.plugins;
import android.annotation.Nullable;
import android.app.PendingIntent;
import android.content.Intent;
+import android.os.UserHandle;
import android.view.View;
import com.android.systemui.animation.ActivityLaunchAnimator;
@@ -70,6 +71,9 @@ public interface ActivityStarter {
void startActivity(Intent intent, boolean dismissShade,
@Nullable ActivityLaunchAnimator.Controller animationController,
boolean showOverLockscreenWhenLocked);
+ void startActivity(Intent intent, boolean dismissShade,
+ @Nullable ActivityLaunchAnimator.Controller animationController,
+ boolean showOverLockscreenWhenLocked, UserHandle userHandle);
void startActivity(Intent intent, boolean onlyProvisioned, boolean dismissShade);
void startActivity(Intent intent, boolean dismissShade, Callback callback);
void postStartActivityDismissingKeyguard(Intent intent, int delay);
diff --git a/packages/SystemUI/proguard.flags b/packages/SystemUI/proguard.flags
index c97ebe8d5559..e74b6c78ec80 100644
--- a/packages/SystemUI/proguard.flags
+++ b/packages/SystemUI/proguard.flags
@@ -41,6 +41,14 @@
-keep,allowoptimization,allowaccessmodification class com.android.systemui.dagger.Dagger** { !synthetic *; }
-keep,allowoptimization,allowaccessmodification class com.android.systemui.tv.Dagger** { !synthetic *; }
+# Prevent optimization or access modification of any referenced code that may
+# conflict with code in the bootclasspath.
+# TODO(b/222468116): Resolve such collisions in the build system.
+-keepnames class android.**.nano.** { *; }
+-keepnames class com.android.**.nano.** { *; }
+-keepnames class com.android.internal.protolog.** { *; }
+-keepnames class android.hardware.common.** { *; }
+
# Allows proguard to make private and protected methods and fields public as
# part of optimization. This lets proguard inline trivial getter/setter methods.
-allowaccessmodification
diff --git a/packages/SystemUI/res-keyguard/drawable/kg_emergency_button_background.xml b/packages/SystemUI/res-keyguard/drawable/kg_emergency_button_background.xml
index b96c07ea53f0..07642736869c 100644
--- a/packages/SystemUI/res-keyguard/drawable/kg_emergency_button_background.xml
+++ b/packages/SystemUI/res-keyguard/drawable/kg_emergency_button_background.xml
@@ -15,10 +15,11 @@
~ limitations under the License.
-->
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:color="?attr/wallpaperTextColorSecondary">
<item android:id="@android:id/background">
<shape android:shape="rectangle">
- <solid android:color="?android:attr/colorAccent"/>
+ <solid android:color="?androidprv:attr/colorAccentTertiary"/>
<corners android:radius="24dp"/>
</shape>
</item>
diff --git a/packages/SystemUI/res-keyguard/drawable/media_squiggly_progress.xml b/packages/SystemUI/res-keyguard/drawable/media_squiggly_progress.xml
new file mode 100644
index 000000000000..9e61236aa7df
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/drawable/media_squiggly_progress.xml
@@ -0,0 +1,17 @@
+<?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.
+ -->
+<com.android.systemui.media.SquigglyProgress /> \ No newline at end of file
diff --git a/packages/SystemUI/res-keyguard/values-it/strings.xml b/packages/SystemUI/res-keyguard/values-it/strings.xml
index 06db7b7dfd60..f912a28d0342 100644
--- a/packages/SystemUI/res-keyguard/values-it/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-it/strings.xml
@@ -53,7 +53,7 @@
<string name="kg_wrong_pattern" msgid="5907301342430102842">"Sequenza errata"</string>
<string name="kg_wrong_password" msgid="4143127991071670512">"Password errata"</string>
<string name="kg_wrong_pin" msgid="4160978845968732624">"PIN errato"</string>
- <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Riprova fra # secondo.}one{Riprova fra # secondo.}other{Riprova fra # secondi.}}"</string>
+ <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Riprova fra # secondo.}other{Riprova fra # secondi.}}"</string>
<string name="kg_sim_pin_instructions" msgid="1942424305184242951">"Inserisci il PIN della SIM."</string>
<string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"Inserisci il PIN della SIM \"<xliff:g id="CARRIER">%1$s</xliff:g>\"."</string>
<string name="kg_sim_lock_esim_instructions" msgid="5577169988158738030">"<xliff:g id="PREVIOUS_MSG">%1$s</xliff:g> Disattiva la eSIM per usare il dispositivo senza servizio dati mobile."</string>
@@ -69,13 +69,13 @@
<string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"<xliff:g id="NUMBER_0">%1$d</xliff:g> tentativi errati di inserimento della sequenza di sblocco. \n\nRiprova tra <xliff:g id="NUMBER_1">%2$d</xliff:g> secondi."</string>
<string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Codice PIN della SIM errato. Devi contattare l\'operatore per sbloccare il dispositivo."</string>
<plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
- <item quantity="one">Incorrect SIM PIN code, you have <xliff:g id="NUMBER_1">%d</xliff:g> remaining attempts.</item>
<item quantity="other">Codice PIN della SIM errato. Hai ancora <xliff:g id="NUMBER_1">%d</xliff:g> tentativi a disposizione.</item>
+ <item quantity="one">Codice PIN della SIM errato. Hai ancora <xliff:g id="NUMBER_0">%d</xliff:g> tentativo a disposizione, dopodiché dovrai contattare l\'operatore per sbloccare il dispositivo.</item>
</plurals>
<string name="kg_password_wrong_puk_code_dead" msgid="3698285357028468617">"SIM inutilizzabile. Contatta il tuo operatore."</string>
<plurals name="kg_password_wrong_puk_code" formatted="false" msgid="3937306685604862886">
- <item quantity="one">Incorrect SIM PUK code, you have <xliff:g id="NUMBER_1">%d</xliff:g> remaining attempts before SIM becomes permanently unusable.</item>
<item quantity="other">Codice PUK della SIM errato. Hai ancora <xliff:g id="NUMBER_1">%d</xliff:g> tentativi a disposizione prima che la SIM diventi definitivamente inutilizzabile.</item>
+ <item quantity="one">Codice PUK della SIM errato. Hai ancora <xliff:g id="NUMBER_0">%d</xliff:g> tentativo a disposizione prima che la SIM diventi definitivamente inutilizzabile.</item>
</plurals>
<string name="kg_password_pin_failed" msgid="5136259126330604009">"Operazione con PIN della SIM non riuscita."</string>
<string name="kg_password_puk_failed" msgid="6778867411556937118">"Operazione con PUK della SIM non riuscita."</string>
@@ -92,12 +92,12 @@
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Non riconosciuto"</string>
<string name="kg_face_sensor_privacy_enabled" msgid="6513157891227284806">"Per utilizzare lo sblocco con il volto, attiva "<b>"l\'accesso alla fotocamera"</b>" in Impostazioni &gt; Privacy"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
- <item quantity="one">Enter SIM PIN. You have <xliff:g id="NUMBER_1">%d</xliff:g> remaining attempts.</item>
<item quantity="other">Inserisci il codice PIN della SIM. Hai ancora <xliff:g id="NUMBER_1">%d</xliff:g> tentativi a disposizione.</item>
+ <item quantity="one">Inserisci il codice PIN della SIM. Hai ancora <xliff:g id="NUMBER_0">%d</xliff:g> tentativo a disposizione, dopodiché dovrai contattare l\'operatore per sbloccare il dispositivo.</item>
</plurals>
<plurals name="kg_password_default_puk_message" formatted="false" msgid="571308542462946935">
- <item quantity="one">SIM is now disabled. Enter PUK code to continue. You have <xliff:g id="_NUMBER_1">%d</xliff:g> remaining attempts before SIM becomes permanently unusable. Contact carrier for details.</item>
<item quantity="other">La scheda SIM è ora disattivata. Inserisci il codice PUK per continuare. Hai ancora <xliff:g id="_NUMBER_1">%d</xliff:g> tentativi a disposizione prima che la SIM diventi definitivamente inutilizzabile. Per informazioni dettagliate, contatta l\'operatore.</item>
+ <item quantity="one">La scheda SIM è ora disattivata. Inserisci il codice PUK per continuare. Hai ancora <xliff:g id="_NUMBER_0">%d</xliff:g> tentativo a disposizione prima che la SIM diventi definitivamente inutilizzabile. Per informazioni dettagliate, contatta l\'operatore.</item>
</plurals>
<string name="clock_title_default" msgid="6342735240617459864">"Predefinito"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Bolla"</string>
diff --git a/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml b/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml
index c3486bbf62d9..a8d8f349ca1e 100644
--- a/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml
@@ -53,7 +53,7 @@
<string name="kg_wrong_pattern" msgid="5907301342430102842">"Padrão incorreto."</string>
<string name="kg_wrong_password" msgid="4143127991071670512">"Palavra-passe incorreta."</string>
<string name="kg_wrong_pin" msgid="4160978845968732624">"PIN incorreto"</string>
- <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Tente novamente dentro de # segundo.}one{Tente novamente dentro de # segundo(s).}other{Tente novamente dentro de # segundos.}}"</string>
+ <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Tente novamente dentro de # segundo.}other{Tente novamente dentro de # segundos.}}"</string>
<string name="kg_sim_pin_instructions" msgid="1942424305184242951">"Introduza o PIN do cartão SIM."</string>
<string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"Introduza o PIN do cartão SIM \"<xliff:g id="CARRIER">%1$s</xliff:g>\"."</string>
<string name="kg_sim_lock_esim_instructions" msgid="5577169988158738030">"<xliff:g id="PREVIOUS_MSG">%1$s</xliff:g> Desative o eSIM para utilizar o dispositivo sem serviço móvel."</string>
@@ -69,13 +69,13 @@
<string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Desenhou a sua padrão de desbloqueio incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. \n\nTente novamente dentro de <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string>
<string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Código PIN do cartão SIM incorreto. Tem de contactar o seu operador para desbloquear o dispositivo."</string>
<plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
- <item quantity="one">Código PIN do cartão SIM incorreto. Tem mais <xliff:g id="NUMBER_0">%d</xliff:g> tentativa antes de precisar de contactar o seu operador para desbloquear o dispositivo.</item>
<item quantity="other">Código PIN do cartão SIM incorreto. Tem mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas.</item>
+ <item quantity="one">Código PIN do cartão SIM incorreto. Tem mais <xliff:g id="NUMBER_0">%d</xliff:g> tentativa antes de precisar de contactar o seu operador para desbloquear o dispositivo.</item>
</plurals>
<string name="kg_password_wrong_puk_code_dead" msgid="3698285357028468617">"Cartão SIM inutilizável. Contacte o seu operador."</string>
<plurals name="kg_password_wrong_puk_code" formatted="false" msgid="3937306685604862886">
- <item quantity="one">Código PUK do cartão SIM incorreto. Tem mais <xliff:g id="NUMBER_0">%d</xliff:g> tentativa antes de o cartão SIM ficar permanentemente inutilizável.</item>
<item quantity="other">Código PUK do cartão SIM incorreto. Tem mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas antes de o cartão SIM ficar permanentemente inutilizável.</item>
+ <item quantity="one">Código PUK do cartão SIM incorreto. Tem mais <xliff:g id="NUMBER_0">%d</xliff:g> tentativa antes de o cartão SIM ficar permanentemente inutilizável.</item>
</plurals>
<string name="kg_password_pin_failed" msgid="5136259126330604009">"Falha ao introduzir o PIN do cartão SIM!"</string>
<string name="kg_password_puk_failed" msgid="6778867411556937118">"Falha ao introduzir o PUK do cartão SIM!"</string>
@@ -92,12 +92,12 @@
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Não reconhecido."</string>
<string name="kg_face_sensor_privacy_enabled" msgid="6513157891227284806">"Para utilizar o Desbloqueio facial, ative o "<b>"Acesso à câmara"</b>" em Definições &gt; Privacidade"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="7730152526369857818">
- <item quantity="one">Introduza o PIN do cartão SIM. Tem mais <xliff:g id="NUMBER_0">%d</xliff:g> tentativa antes de ser necessário contactar o operador para desbloquear o dispositivo.</item>
<item quantity="other">Introduza o PIN do cartão SIM. Tem mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas.</item>
+ <item quantity="one">Introduza o PIN do cartão SIM. Tem mais <xliff:g id="NUMBER_0">%d</xliff:g> tentativa antes de ser necessário contactar o operador para desbloquear o dispositivo.</item>
</plurals>
<plurals name="kg_password_default_puk_message" formatted="false" msgid="571308542462946935">
- <item quantity="one">O SIM encontra-se desativado. Introduza o código PUK para continuar. Tem mais <xliff:g id="_NUMBER_0">%d</xliff:g> tentativa antes de o cartão SIM ficar permanentemente inutilizável. Contacte o operador para obter mais detalhes.</item>
<item quantity="other">O SIM encontra-se desativado. Introduza o código PUK para continuar. Tem mais <xliff:g id="_NUMBER_1">%d</xliff:g> tentativas antes de o cartão SIM ficar permanentemente inutilizável. Contacte o operador para obter mais detalhes.</item>
+ <item quantity="one">O SIM encontra-se desativado. Introduza o código PUK para continuar. Tem mais <xliff:g id="_NUMBER_0">%d</xliff:g> tentativa antes de o cartão SIM ficar permanentemente inutilizável. Contacte o operador para obter mais detalhes.</item>
</plurals>
<string name="clock_title_default" msgid="6342735240617459864">"Predefinido"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Balão"</string>
diff --git a/packages/SystemUI/res-keyguard/values/dimens.xml b/packages/SystemUI/res-keyguard/values/dimens.xml
index 8d205c14144d..9a6f5edae5ec 100644
--- a/packages/SystemUI/res-keyguard/values/dimens.xml
+++ b/packages/SystemUI/res-keyguard/values/dimens.xml
@@ -129,4 +129,7 @@
<dimen name="user_switcher_icon_selected_width">8dp</dimen>
<dimen name="user_switcher_fullscreen_button_text_size">14sp</dimen>
<dimen name="user_switcher_fullscreen_button_padding">12dp</dimen>
+
+ <!-- Translation y for appear animation -->
+ <dimen name="keyguard_host_view_translation_y">80dp</dimen>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values/styles.xml b/packages/SystemUI/res-keyguard/values/styles.xml
index 637569830465..625ffd3aa3ec 100644
--- a/packages/SystemUI/res-keyguard/values/styles.xml
+++ b/packages/SystemUI/res-keyguard/values/styles.xml
@@ -17,13 +17,14 @@
*/
-->
-<resources xmlns:android="http://schemas.android.com/apk/res/android">
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
<!-- Keyguard PIN pad styles -->
<style name="Keyguard.TextView" parent="@android:style/Widget.DeviceDefault.TextView">
<item name="android:textSize">@dimen/kg_status_line_font_size</item>
</style>
<style name="Keyguard.TextView.EmergencyButton" parent="Theme.SystemUI">
- <item name="android:textColor">?android:attr/textColorPrimaryInverse</item>
+ <item name="android:textColor">?androidprv:attr/textColorOnAccent</item>
<item name="android:textSize">14dp</item>
<item name="android:background">@drawable/kg_emergency_button_background</item>
<item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
diff --git a/packages/SystemUI/res/color/kg_user_avatar_frame.xml b/packages/SystemUI/res/color/kg_user_avatar_frame.xml
index 174981e2a660..a143194f331d 100644
--- a/packages/SystemUI/res/color/kg_user_avatar_frame.xml
+++ b/packages/SystemUI/res/color/kg_user_avatar_frame.xml
@@ -18,6 +18,6 @@
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:state_activated="true"
- android:color="@color/kg_user_switcher_avatar_background" />
- <item android:color="@color/kg_user_switcher_avatar_background" />
+ android:color="@color/user_avatar_color_bg" />
+ <item android:color="@color/user_avatar_color_bg" />
</selector>
diff --git a/packages/SystemUI/res/drawable/ic_circular_unchecked.xml b/packages/SystemUI/res/drawable/ic_circular_unchecked.xml
index 9b43cf64f116..779ab816d925 100644
--- a/packages/SystemUI/res/drawable/ic_circular_unchecked.xml
+++ b/packages/SystemUI/res/drawable/ic_circular_unchecked.xml
@@ -4,6 +4,6 @@
android:viewportWidth="24"
android:viewportHeight="24">
<path
- android:fillColor="@color/media_dialog_inactive_item_main_content"
+ android:fillColor="@color/media_dialog_item_main_content"
android:pathData="M12,22q-2.075,0 -3.9,-0.788 -1.825,-0.787 -3.175,-2.137 -1.35,-1.35 -2.137,-3.175Q2,14.075 2,12t0.788,-3.9q0.787,-1.825 2.137,-3.175 1.35,-1.35 3.175,-2.137Q9.925,2 12,2t3.9,0.788q1.825,0.787 3.175,2.137 1.35,1.35 2.137,3.175Q22,9.925 22,12t-0.788,3.9q-0.787,1.825 -2.137,3.175 -1.35,1.35 -3.175,2.137Q14.075,22 12,22zM12,12zM12,20q3.325,0 5.663,-2.337Q20,15.325 20,12t-2.337,-5.662Q15.325,4 12,4T6.338,6.338Q4,8.675 4,12q0,3.325 2.338,5.663Q8.675,20 12,20z"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/media_output_status_check.xml b/packages/SystemUI/res/drawable/media_output_status_check.xml
index 1b750f8959b9..5fbc42b245b8 100644
--- a/packages/SystemUI/res/drawable/media_output_status_check.xml
+++ b/packages/SystemUI/res/drawable/media_output_status_check.xml
@@ -21,6 +21,6 @@
android:viewportHeight="24"
android:tint="?attr/colorControlNormal">
<path
- android:fillColor="@color/media_dialog_item_status"
+ android:fillColor="@color/media_dialog_item_main_content"
android:pathData="M9,16.2L4.8,12l-1.4,1.4L9,19 21,7l-1.4,-1.4L9,16.2z"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/media_output_status_failed.xml b/packages/SystemUI/res/drawable/media_output_status_failed.xml
index 05c635833441..0599e239a9ee 100644
--- a/packages/SystemUI/res/drawable/media_output_status_failed.xml
+++ b/packages/SystemUI/res/drawable/media_output_status_failed.xml
@@ -21,6 +21,6 @@
android:viewportHeight="24"
android:tint="?attr/colorControlNormal">
<path
- android:fillColor="@color/media_dialog_inactive_item_main_content"
+ android:fillColor="@color/media_dialog_item_main_content"
android:pathData="M11,7h2v2h-2zM11,11h2v6h-2zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8z"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/media_ttt_undo_background.xml b/packages/SystemUI/res/drawable/media_ttt_undo_background.xml
index ec74ee1fcbf1..3e2e4f055b14 100644
--- a/packages/SystemUI/res/drawable/media_ttt_undo_background.xml
+++ b/packages/SystemUI/res/drawable/media_ttt_undo_background.xml
@@ -14,9 +14,14 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-<shape
+<ripple
xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
- <solid android:color="?androidprv:attr/colorAccentPrimary" />
- <corners android:radius="24dp" />
-</shape>
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ android:color="?android:textColorPrimary">
+ <item android:id="@android:id/background">
+ <shape>
+ <solid android:color="?androidprv:attr/colorAccentPrimary"/>
+ <corners android:radius="24dp" />
+ </shape>
+ </item>
+</ripple>
diff --git a/packages/SystemUI/res/drawable/user_switcher_icon_large.xml b/packages/SystemUI/res/drawable/user_switcher_icon_large.xml
index b78b2216c9f9..d81b518d2a9f 100644
--- a/packages/SystemUI/res/drawable/user_switcher_icon_large.xml
+++ b/packages/SystemUI/res/drawable/user_switcher_icon_large.xml
@@ -27,7 +27,7 @@
</shape>
</item>
<!-- When an item is selected, this layer will show a ring around the icon -->
- <item>
+ <item android:id="@+id/ring">
<shape android:shape="oval">
<stroke
android:width="@dimen/user_switcher_icon_selected_width"
@@ -35,8 +35,8 @@
</shape>
</item>
<!-- Where the user drawable/bitmap will be placed -->
- <item
- android:drawable="@drawable/kg_bg_avatar"
+ <item android:id="@+id/user_avatar"
+ android:drawable="@drawable/user_avatar_bg"
android:width="@dimen/bouncer_user_switcher_icon_size"
android:height="@dimen/bouncer_user_switcher_icon_size"
android:top="@dimen/user_switcher_icon_large_margin"
diff --git a/packages/SystemUI/res/layout/clipboard_edit_text_activity.xml b/packages/SystemUI/res/layout/clipboard_edit_text_activity.xml
index 8f6753a095d0..da4088f6731d 100644
--- a/packages/SystemUI/res/layout/clipboard_edit_text_activity.xml
+++ b/packages/SystemUI/res/layout/clipboard_edit_text_activity.xml
@@ -36,6 +36,7 @@
android:tooltipText="@*android:string/share"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@+id/copy_button"
+ android:tint="?android:attr/textColorPrimary"
android:src="@drawable/ic_screenshot_share" />
<ScrollView
diff --git a/packages/SystemUI/res/layout/clipboard_overlay.xml b/packages/SystemUI/res/layout/clipboard_overlay.xml
index c58c00114262..27823009459c 100644
--- a/packages/SystemUI/res/layout/clipboard_overlay.xml
+++ b/packages/SystemUI/res/layout/clipboard_overlay.xml
@@ -26,7 +26,7 @@
android:layout_width="match_parent"
android:layout_gravity="bottom"
android:src="@drawable/overlay_actions_background_protection"/>
- <com.android.systemui.clipboardoverlay.DraggableConstraintLayout
+ <com.android.systemui.screenshot.DraggableConstraintLayout
android:id="@+id/clipboard_ui"
android:theme="@style/FloatingOverlay"
android:layout_width="match_parent"
@@ -146,5 +146,5 @@
android:layout_margin="@dimen/overlay_dismiss_button_margin"
android:src="@drawable/overlay_cancel"/>
</FrameLayout>
- </com.android.systemui.clipboardoverlay.DraggableConstraintLayout>
+ </com.android.systemui.screenshot.DraggableConstraintLayout>
</FrameLayout> \ No newline at end of file
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 91d81a2b0b2f..cb63300f819b 100644
--- a/packages/SystemUI/res/layout/dream_overlay_complication_clock_date.xml
+++ b/packages/SystemUI/res/layout/dream_overlay_complication_clock_date.xml
@@ -19,6 +19,7 @@
android:id="@+id/date_view"
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"
diff --git a/packages/SystemUI/res/layout/dream_overlay_complication_weather.xml b/packages/SystemUI/res/layout/dream_overlay_complication_weather.xml
index 3900ea56dda3..76fe58c29852 100644
--- a/packages/SystemUI/res/layout/dream_overlay_complication_weather.xml
+++ b/packages/SystemUI/res/layout/dream_overlay_complication_weather.xml
@@ -19,6 +19,7 @@
android:id="@+id/weather_view"
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"
diff --git a/packages/SystemUI/res/layout/dream_overlay_status_bar_view.xml b/packages/SystemUI/res/layout/dream_overlay_status_bar_view.xml
index 1cbc3c284874..d0f4903a3421 100644
--- a/packages/SystemUI/res/layout/dream_overlay_status_bar_view.xml
+++ b/packages/SystemUI/res/layout/dream_overlay_status_bar_view.xml
@@ -42,17 +42,6 @@
app:layout_constraintEnd_toEndOf="parent">
<com.android.systemui.statusbar.AlphaOptimizedImageView
- android:id="@+id/dream_overlay_assistant_guest_mode_enabled"
- android:layout_width="@dimen/dream_overlay_status_bar_icon_size"
- android:layout_height="match_parent"
- android:layout_marginEnd="@dimen/dream_overlay_status_icon_margin"
- android:src="@drawable/ic_account_circle"
- android:tint="@android:color/white"
- android:visibility="gone"
- android:contentDescription=
- "@string/dream_overlay_status_bar_assistant_guest_mode_enabled" />
-
- <com.android.systemui.statusbar.AlphaOptimizedImageView
android:id="@+id/dream_overlay_alarm_set"
android:layout_width="@dimen/dream_overlay_status_bar_icon_size"
android:layout_height="match_parent"
diff --git a/packages/SystemUI/res/layout/media_output_dialog.xml b/packages/SystemUI/res/layout/media_output_dialog.xml
index 51211a0c0d2a..05343e75b448 100644
--- a/packages/SystemUI/res/layout/media_output_dialog.xml
+++ b/packages/SystemUI/res/layout/media_output_dialog.xml
@@ -129,7 +129,7 @@
style="@style/Widget.Dialog.Button.BorderButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:text="@string/keyboard_key_media_stop"
+ android:text="@string/media_output_dialog_button_stop_casting"
android:visibility="gone"/>
<Space
diff --git a/packages/SystemUI/res/layout/media_output_list_item.xml b/packages/SystemUI/res/layout/media_output_list_item.xml
index 806804f2fc47..20747fad021b 100644
--- a/packages/SystemUI/res/layout/media_output_list_item.xml
+++ b/packages/SystemUI/res/layout/media_output_list_item.xml
@@ -62,41 +62,40 @@
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|start"
android:layout_marginStart="56dp"
+ android:layout_marginEnd="56dp"
android:ellipsize="end"
android:maxLines="1"
android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
android:textSize="16sp"/>
- <RelativeLayout
+ <LinearLayout
android:id="@+id/two_line_layout"
+ android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_gravity="center_vertical|start"
android:layout_height="48dp"
+ android:layout_marginEnd="56dp"
android:layout_marginStart="56dp">
<TextView
android:id="@+id/two_line_title"
- android:gravity="center_vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="1"
android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
- android:textColor="@color/media_dialog_inactive_item_main_content"
+ android:textColor="@color/media_dialog_item_main_content"
android:textSize="16sp"/>
<TextView
android:id="@+id/subtitle"
- android:layout_gravity="center_vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginTop="4dp"
- android:layout_alignParentBottom="true"
android:ellipsize="end"
android:maxLines="1"
- android:textColor="@color/media_dialog_inactive_item_main_content"
+ android:textColor="@color/media_dialog_item_main_content"
android:textSize="14sp"
android:fontFamily="@*android:string/config_bodyFontFamily"
android:visibility="gone"/>
- </RelativeLayout>
+ </LinearLayout>
<ProgressBar
android:id="@+id/volume_indeterminate_progress"
diff --git a/packages/SystemUI/res/layout/media_session_view.xml b/packages/SystemUI/res/layout/media_session_view.xml
index 978998d6ca2c..f030f3130be4 100644
--- a/packages/SystemUI/res/layout/media_session_view.xml
+++ b/packages/SystemUI/res/layout/media_session_view.xml
@@ -44,6 +44,7 @@
android:background="@drawable/qs_media_scrim"
/>
+ <!-- Guideline for output switcher -->
<androidx.constraintlayout.widget.Guideline
android:id="@+id/center_vertical_guideline"
android:layout_width="wrap_content"
@@ -51,6 +52,14 @@
android:orientation="vertical"
app:layout_constraintGuide_percent="0.6" />
+ <!-- Guideline for action buttons (collapsed view only) -->
+ <androidx.constraintlayout.widget.Guideline
+ android:id="@+id/action_button_guideline"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:orientation="vertical"
+ app:layout_constraintGuide_end="@dimen/qs_media_session_collapsed_guideline" />
+
<!-- App icon -->
<com.android.internal.widget.CachingIconView
android:id="@+id/icon"
@@ -118,15 +127,7 @@
android:singleLine="true"
android:textSize="16sp"
android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="20dp"
- android:layout_marginStart="@dimen/qs_media_padding"
- android:layout_marginEnd="@dimen/qs_media_padding"
- app:layout_constrainedWidth="true"
- app:layout_constraintTop_toBottomOf="@id/icon"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintEnd_toStartOf="@id/actionPlayPause"
- app:layout_constraintHorizontal_bias="0" />
+ android:layout_height="wrap_content" />
<!-- Artist name -->
<TextView
@@ -136,15 +137,7 @@
style="@style/MediaPlayer.Subtitle"
android:textSize="14sp"
android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginEnd="@dimen/qs_media_padding"
- app:layout_constrainedWidth="true"
- android:layout_marginTop="1dp"
- app:layout_constraintTop_toBottomOf="@id/header_title"
- app:layout_constraintStart_toStartOf="@id/header_title"
- app:layout_constraintEnd_toStartOf="@id/actionPlayPause"
- app:layout_constraintBottom_toBottomOf="@id/actionPlayPause"
- app:layout_constraintHorizontal_bias="0" />
+ android:layout_height="wrap_content" />
<ImageButton
android:id="@+id/actionPlayPause"
@@ -153,9 +146,33 @@
android:layout_height="48dp"
android:layout_marginStart="@dimen/qs_media_padding"
android:layout_marginEnd="@dimen/qs_media_padding"
- android:layout_marginTop="0dp"
- android:layout_marginBottom="0dp" />
+ />
+
+ <!-- See comment in media_session_collapsed.xml for how these barriers are used -->
+ <androidx.constraintlayout.widget.Barrier
+ android:id="@+id/media_action_barrier"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:orientation="vertical"
+ app:layout_constraintTop_toBottomOf="@id/header_title"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:barrierDirection="start"
+ app:constraint_referenced_ids="actionPrev,media_progress_bar,actionNext,action0,action1,action2,action3,action4"
+ />
+ <androidx.constraintlayout.widget.Barrier
+ android:id="@+id/media_action_barrier_end"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:orientation="vertical"
+ app:layout_constraintTop_toBottomOf="@id/media_seamless"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:barrierDirection="end"
+ app:constraint_referenced_ids="actionPrev,media_progress_bar,actionNext,action0,action1,action2,action3,action4"
+ app:layout_constraintStart_toStartOf="parent"
+ />
+ <!-- Button visibility will be controlled in code -->
<ImageButton
android:id="@+id/actionPrev"
style="@style/MediaPlayer.SessionAction"
@@ -163,10 +180,9 @@
android:layout_height="48dp"
android:layout_marginStart="4dp"
android:layout_marginEnd="0dp"
- android:layout_marginBottom="0dp"
+ android:layout_marginBottom="@dimen/qs_media_padding"
android:layout_marginTop="0dp"
- app:layout_constraintHorizontal_bias="1"
- app:layout_constraintHorizontal_chainStyle="packed" />
+ />
<!-- Seek Bar -->
<!-- As per Material Design on Bidirectionality, this is forced to LTR in code -->
@@ -174,12 +190,12 @@
android:id="@+id/media_progress_bar"
style="@style/MediaPlayer.ProgressBar"
android:layout_width="0dp"
- android:layout_height="wrap_content"
+ android:layout_height="48dp"
android:paddingTop="@dimen/qs_media_session_enabled_seekbar_vertical_padding"
android:paddingBottom="12dp"
android:maxHeight="@dimen/qs_media_enabled_seekbar_height"
android:splitTrack="false"
- android:layout_marginBottom="0dp"
+ android:layout_marginBottom="@dimen/qs_media_padding"
android:layout_marginTop="0dp"
android:layout_marginStart="0dp"
android:layout_marginEnd="0dp" />
@@ -191,29 +207,58 @@
android:layout_height="48dp"
android:layout_marginStart="0dp"
android:layout_marginEnd="@dimen/qs_media_action_spacing"
- android:layout_marginBottom="0dp"
+ android:layout_marginBottom="@dimen/qs_media_padding"
android:layout_marginTop="0dp" />
<ImageButton
- android:id="@+id/actionStart"
+ android:id="@+id/action0"
style="@style/MediaPlayer.SessionAction"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_marginStart="@dimen/qs_media_action_spacing"
android:layout_marginEnd="@dimen/qs_media_action_spacing"
- android:layout_marginBottom="0dp"
+ android:layout_marginBottom="@dimen/qs_media_padding"
+ android:layout_marginTop="0dp"/>
+
+ <ImageButton
+ android:id="@+id/action1"
+ style="@style/MediaPlayer.SessionAction"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:layout_marginStart="@dimen/qs_media_action_spacing"
+ android:layout_marginEnd="4dp"
+ android:layout_marginBottom="@dimen/qs_media_padding"
android:layout_marginTop="0dp" />
<ImageButton
- android:id="@+id/actionEnd"
+ android:id="@+id/action2"
style="@style/MediaPlayer.SessionAction"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_marginStart="@dimen/qs_media_action_spacing"
android:layout_marginEnd="4dp"
- android:layout_marginBottom="0dp"
- android:layout_marginTop="0dp"
- app:layout_constraintHorizontal_chainStyle="packed" />
+ android:layout_marginBottom="@dimen/qs_media_padding"
+ android:layout_marginTop="0dp" />
+
+ <ImageButton
+ android:id="@+id/action3"
+ style="@style/MediaPlayer.SessionAction"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:layout_marginStart="@dimen/qs_media_action_spacing"
+ android:layout_marginEnd="4dp"
+ android:layout_marginBottom="@dimen/qs_media_padding"
+ android:layout_marginTop="0dp" />
+
+ <ImageButton
+ android:id="@+id/action4"
+ style="@style/MediaPlayer.SessionAction"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:layout_marginStart="@dimen/qs_media_action_spacing"
+ android:layout_marginEnd="4dp"
+ android:layout_marginBottom="@dimen/qs_media_padding"
+ android:layout_marginTop="0dp" />
<!-- Long press menu -->
<TextView
diff --git a/packages/SystemUI/res/layout/ongoing_privacy_chip.xml b/packages/SystemUI/res/layout/ongoing_privacy_chip.xml
index 812277634d09..5aa608084510 100644
--- a/packages/SystemUI/res/layout/ongoing_privacy_chip.xml
+++ b/packages/SystemUI/res/layout/ongoing_privacy_chip.xml
@@ -22,7 +22,10 @@
android:layout_height="match_parent"
android:layout_width="wrap_content"
android:layout_gravity="center_vertical|end"
- android:focusable="true" >
+ android:focusable="true"
+ android:clipChildren="false"
+ android:clipToPadding="false"
+ >
<LinearLayout
android:id="@+id/icons_container"
diff --git a/packages/SystemUI/res/layout/screenshot_static.xml b/packages/SystemUI/res/layout/screenshot_static.xml
index 813bb6018801..8de80844d784 100644
--- a/packages/SystemUI/res/layout/screenshot_static.xml
+++ b/packages/SystemUI/res/layout/screenshot_static.xml
@@ -14,25 +14,25 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-<androidx.constraintlayout.widget.ConstraintLayout
+<com.android.systemui.screenshot.DraggableConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
- android:id="@+id/screenshot_actions_container_background"
+ android:id="@+id/actions_container_background"
android:visibility="gone"
android:layout_height="0dp"
android:layout_width="0dp"
android:elevation="1dp"
android:background="@drawable/action_chip_container_background"
android:layout_marginStart="@dimen/overlay_action_container_margin_horizontal"
- app:layout_constraintBottom_toBottomOf="@+id/screenshot_actions_container"
+ app:layout_constraintBottom_toBottomOf="@+id/actions_container"
app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toTopOf="@+id/screenshot_actions_container"
- app:layout_constraintEnd_toEndOf="@+id/screenshot_actions_container"/>
+ app:layout_constraintTop_toTopOf="@+id/actions_container"
+ app:layout_constraintEnd_toEndOf="@+id/actions_container"/>
<HorizontalScrollView
- android:id="@+id/screenshot_actions_container"
+ android:id="@+id/actions_container"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/overlay_action_container_margin_horizontal"
@@ -130,4 +130,4 @@
app:layout_constraintStart_toStartOf="@id/screenshot_preview"
app:layout_constraintTop_toTopOf="@id/screenshot_preview"
android:elevation="@dimen/overlay_preview_elevation"/>
-</androidx.constraintlayout.widget.ConstraintLayout>
+</com.android.systemui.screenshot.DraggableConstraintLayout>
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index e4706e263a0f..ef030baa967b 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -26,9 +26,6 @@
android:layout_height="match_parent"
android:background="@android:color/transparent">
- <include layout="@layout/communal_host_view"
- android:visibility="gone"/>
-
<ViewStub
android:id="@+id/keyguard_qs_user_switch_stub"
android:layout="@layout/keyguard_qs_user_switch"
diff --git a/packages/SystemUI/res/layout/status_bar_notification_section_header.xml b/packages/SystemUI/res/layout/status_bar_notification_section_header.xml
index e33f186dcbb7..c4d8d55f74e2 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_section_header.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_section_header.xml
@@ -21,8 +21,6 @@
android:layout_height="@dimen/notification_section_header_height"
android:paddingStart="4dp"
android:paddingEnd="4dp"
- android:focusable="true"
- android:clickable="true"
>
<LinearLayout
@@ -46,6 +44,7 @@
android:id="@+id/header_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:focusable="true"
android:forceHasOverlappingRendering="false"
android:text="@string/notification_section_header_gentle"
/>
@@ -57,6 +56,7 @@
android:layout_height="48dp"
android:src="@drawable/status_bar_notification_section_header_clear_btn"
android:contentDescription="@string/accessibility_notification_section_header_gentle_clear_all"
+ android:focusable="true"
android:scaleType="center"
android:tintMode="src_in"
android:visibility="gone"
diff --git a/packages/SystemUI/res/layout/system_event_animation_window.xml b/packages/SystemUI/res/layout/system_event_animation_window.xml
index c92dec9dd643..e6868b34df02 100644
--- a/packages/SystemUI/res/layout/system_event_animation_window.xml
+++ b/packages/SystemUI/res/layout/system_event_animation_window.xml
@@ -19,17 +19,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center_vertical|end"
- android:paddingTop="@dimen/status_bar_padding_top"
- android:paddingEnd="8dp"
+ android:clipChildren="false"
+ android:clipToPadding="false"
>
-
- <ImageView
- android:id="@+id/dot_view"
- android:layout_width="10dp"
- android:layout_height="10dp"
- android:layout_gravity="center_vertical|end"
- android:src="@drawable/system_animation_ongoing_dot"
- android:visibility="invisible"
- />
-
</FrameLayout> \ No newline at end of file
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 42955caf5ae9..8d09d7621042 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -20,14 +20,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4811759950673118541">"Stelsel-UI"</string>
- <string name="battery_low_title" msgid="6891106956328275225">"Battery kan binnekort afloop"</string>
+ <string name="battery_low_title" msgid="5319680173344341779">"Skakel Batterybespaarder aan?"</string>
+ <string name="battery_low_description" msgid="3282977755476423966">"Jy het <xliff:g id="PERCENTAGE">%s</xliff:g> batterykrag oor. Batterybespaarder skakel Donkertema aan, beperk agtergrondaktiwiteit en vertraag kennisgewings."</string>
+ <string name="battery_low_intro" msgid="5148725009653088790">"Batterybespaarder skakel Donkertema aan, beperk agtergrondaktiwiteit en vertraag kennisgewings."</string>
<string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> oor"</string>
<string name="invalid_charger_title" msgid="938685362320735167">"Kan nie deur USB laai nie"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"Gebruik die laaier wat jy saam met jou toestel gekry het"</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Skakel Batterybespaarder aan?"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Meer oor Batterybespaarder"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Skakel aan"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"Skakel Batterybespaarder aan"</string>
+ <string name="battery_saver_start_action" msgid="8353766979886287140">"Skakel aan"</string>
+ <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Nee, dankie"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Outodraai skerm"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"Gee <xliff:g id="APPLICATION">%1$s</xliff:g> toegang tot <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
<string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Laat <xliff:g id="APPLICATION">%1$s</xliff:g> toe om by <xliff:g id="USB_DEVICE">%2$s</xliff:g> in te gaan?\nOpneemtoestemming is nie aan hierdie program verleen nie, maar dit kan oudio deur hierdie USB-toestel vasvang."</string>
@@ -128,6 +131,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Gesig is gestaaf"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Bevestig"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Tik op Bevestig om te voltooi"</string>
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Ontsluit met jou gesig. Druk om voort te gaan."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Gestaaf"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Gebruik PIN"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Gebruik patroon"</string>
@@ -181,6 +185,7 @@
<string name="accessibility_desc_close" msgid="8293708213442107755">"Maak toe"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"volkome stilte"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"net wekkers"</string>
+ <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"Moenie Steur Nie."</string>
<string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"Bluetooth."</string>
<string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"Bluetooth aan."</string>
<string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"Wekker gestel vir <xliff:g id="TIME">%s</xliff:g>."</string>
@@ -205,6 +210,7 @@
<string name="dessert_case" msgid="9104973640704357717">"Nageregkas"</string>
<string name="start_dreams" msgid="9131802557946276718">"Sluimerskerm"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
+ <string name="quick_settings_dnd_label" msgid="7728690179108024338">"Moenie Steur Nie"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Geen saamgebinde toestelle beskikbaar nie"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> batterykrag"</string>
@@ -348,6 +354,7 @@
<string name="notification_section_header_alerting" msgid="5581175033680477651">"Kennisgewings"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Gesprekke"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Vee alle stil kennisgewings uit"</string>
+ <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Kennisgewings onderbreek deur Moenie Steur Nie"</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"Begin nou"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Geen kennisgewings nie"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Hierdie toestel word deur jou ouer bestuur"</string>
@@ -452,8 +459,8 @@
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Ontsluit om te gebruik"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Kon nie jou kaarte kry nie; probeer later weer"</string>
<string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Sluitskerminstellings"</string>
- <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR-kode"</string>
- <string name="qr_code_scanner_description" msgid="7937603775306661863">"Tik om te skandeer"</string>
+ <!-- no translation found for qr_code_scanner_title (5290201053875420785) -->
+ <skip />
<string name="status_bar_work" msgid="5238641949837091056">"Werkprofiel"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Vliegtuigmodus"</string>
<string name="zen_alarm_warning" msgid="7844303238486849503">"Jy sal nie jou volgende wekker <xliff:g id="WHEN">%1$s</xliff:g> hoor nie"</string>
@@ -491,6 +498,8 @@
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"&lt;b&gt;Status:&lt;/b&gt; Laer gegradeer"</string>
<string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"Word aan die bokant van gesprekskennisgewings en as \'n profielfoto op sluitskerm gewys"</string>
<string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"Word aan die bokant van gesprekskennisgewings en as \'n profielfoto op sluitskerm gewys, verskyn as \'n borrel"</string>
+ <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"Word aan die bokant van gesprekskennisgewings en as \'n profielfoto op sluitskerm gewys, onderbreek Moenie Steur Nie"</string>
+ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Word aan die bokant van gesprekskennisgewings en as \'n profielfoto op sluitskerm gewys, verskyn as \'n borrel, onderbreek Moenie Steur Nie"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioriteit"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> steun nie gesprekskenmerke nie"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Hierdie kennisgewings kan nie gewysig word nie."</string>
@@ -566,6 +575,7 @@
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"SMS"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"Musiek"</string>
<string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Kalender"</string>
+ <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Moenie Steur Nie"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"Volumeknoppieskortpad"</string>
<string name="battery" msgid="769686279459897127">"Battery"</string>
<string name="headset" msgid="4485892374984466437">"Kopstuk"</string>
@@ -684,6 +694,10 @@
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"Wi-Fi is af"</string>
<string name="bt_is_off" msgid="7436344904889461591">"Bluetooth is af"</string>
+ <string name="dnd_is_off" msgid="3185706903793094463">"Moenie Steur Nie is af"</string>
+ <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"\'n Outomatiese reël (<xliff:g id="ID_1">%s</xliff:g>) het Moenie Steur Nie aangeskakel."</string>
+ <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"\'n Program (<xliff:g id="ID_1">%s</xliff:g>) het Moenie Steur Nie aangeskakel."</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"\'n Outomatiese reël of program het Moenie Steur Nie aangeskakel."</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"Programme wat op die agtergrond loop"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"Tik vir besonderhede oor battery- en datagebruik"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Skakel mobiele data af?"</string>
@@ -708,6 +722,8 @@
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(werk)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"Oproep"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(deur <xliff:g id="APPLICATION_NAME_S_">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_label" msgid="3385241594101496292">"(<xliff:g id="ATTRIBUTION_LABEL">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_proxy_label" msgid="1111829599659403249">"(<xliff:g id="ATTRIBUTION_LABEL">%1$s</xliff:g> • <xliff:g id="PROXY_LABEL">%2$s</xliff:g>)"</string>
<string name="privacy_type_camera" msgid="7974051382167078332">"kamera"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"ligging"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofoon"</string>
@@ -806,6 +822,9 @@
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(ontkoppel)"</string>
<string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Kan nie wissel nie. Tik om weer te probeer."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Bind nuwe toestel saam"</string>
+ <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Maak die program oop om hierdie sessie uit te saai."</string>
+ <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Onbekende program"</string>
+ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Hou op uitsaai"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Bounommer"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Bounommer is na knipbord gekopieer."</string>
<string name="basic_status" msgid="2315371112182658176">"Maak gesprek oop"</string>
@@ -839,6 +858,7 @@
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Sien onlangse boodskappe, gemiste oproepe en statusopdaterings"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Gesprek"</string>
+ <string name="paused_by_dnd" msgid="7856941866433556428">"Onderbreek deur Moenie Steur nie"</string>
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> het \'n boodskap gestuur: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> het \'n prent gestuur"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> het \'n statusopdatering: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
@@ -877,8 +897,7 @@
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> aktiewe programme</item>
<item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> aktiewe program</item>
</plurals>
- <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
- <skip />
+ <string name="fgs_dot_content_description" msgid="2865071539464777240">"Nuwe inligting"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Aktiewe programme"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Stop"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Gestop"</string>
@@ -889,8 +908,12 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Wysig gekopieerde teks"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Wysig gekopieerde prent"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Stuur na toestel in die omtrek"</string>
- <!-- no translation found for add (81036585205287996) -->
- <skip />
- <!-- no translation found for manage_users (1823875311934643849) -->
- <skip />
+ <string name="add" msgid="81036585205287996">"Voeg by"</string>
+ <string name="manage_users" msgid="1823875311934643849">"Bestuur gebruikers"</string>
+ <string name="drag_split_not_supported" msgid="4326847447699729722">"Sleep na verdeelde skerm word nie vir hierdie kennisgewing gesteun nie."</string>
+ <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑fi onbeskikbaar"</string>
+ <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Prioriteitmodus"</string>
+ <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Wekker gestel"</string>
+ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Kamera en mikrofoon is af"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# kennisgewing}other{# kennisgewings}}"</string>
</resources>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 03ae0e41ff41..83c018494a92 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -20,14 +20,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4811759950673118541">"የስርዓት UI"</string>
- <string name="battery_low_title" msgid="6891106956328275225">"ባትሪ በቅርቡ ሊያልቅ ይችላል"</string>
+ <string name="battery_low_title" msgid="5319680173344341779">"ባትሪ ቆጣቢ ይብራ?"</string>
+ <string name="battery_low_description" msgid="3282977755476423966">"<xliff:g id="PERCENTAGE">%s</xliff:g> ቀሪ ባትሪ አለዎት። የባትሪ ኃይል ቆጣቢ ጠቆር ያለ ገጽታ ያበራል፣ የበስተጀርባ እንቅስቃሴን ይገድባል እና ማሳወቂያዎችን ያዘገያል።"</string>
+ <string name="battery_low_intro" msgid="5148725009653088790">"የባትሪ ኃይል ቆጣቢ ጠቆር ያለ ገጽታ ያበራል፣ የበስተጀርባ እንቅስቃሴን ይገድባል እና ማሳወቂያዎችን ያዘገያል።"</string>
<string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> ይቀራል"</string>
<string name="invalid_charger_title" msgid="938685362320735167">"በዩኤስቢ በኩል ኃይል መሙላት አይቻልም"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"ከእርስዎ መሣሪያ ጋር የመጣውን ኃይል መሙያ ይጠቀሙ"</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"ባትሪ ቆጣቢ ይብራ?"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"ስለ ባትሪ ቆጣቢ"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"አብራ"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"ባትሪ ቆጣቢን አብራ"</string>
+ <string name="battery_saver_start_action" msgid="8353766979886287140">"አብራ"</string>
+ <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"አይ፣ አመሰግናለሁ"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"ማያ በራስ ሰር አሽከርክር"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"<xliff:g id="APPLICATION">%1$s</xliff:g> <xliff:g id="USB_DEVICE">%2$s</xliff:g>ን እንዲደርስበት ይፈቀድለት?"</string>
<string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"<xliff:g id="APPLICATION">%1$s</xliff:g> <xliff:g id="USB_DEVICE">%2$s</xliff:g>ን እንዲደርስ ይፈቀድለት?\nይህ መተግበሪያ የመቅዳት ፈቃድ አልተሰጠውም፣ ነገር ግን በዩኤስቢ መሣሪያ በኩል ኦዲዮን መቅዳት ይችላል።"</string>
@@ -128,6 +131,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"መልክ ተረጋግጧል"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"ተረጋግጧል"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"ለማጠናቀቅ አረጋግጥን መታ ያድርጉ"</string>
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"በፊትዎ የተከፈተ። ለመቀጠል ይጫኑ።"</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"የተረጋገጠ"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"ፒን ይጠቀሙ"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"ሥርዓተ ጥለትን ተጠቀም"</string>
@@ -181,6 +185,7 @@
<string name="accessibility_desc_close" msgid="8293708213442107755">"ዝጋ"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"ሙሉ ለሙሉ ጸጥታ"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"ማንቂያዎች ብቻ"</string>
+ <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"አትረብሽ።"</string>
<string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"ብሉቱዝ።"</string>
<string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"ብሉቱዝ በርቷል።"</string>
<string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"ማንቂያ ለ<xliff:g id="TIME">%s</xliff:g> ተዋቅሯል።"</string>
@@ -205,6 +210,7 @@
<string name="dessert_case" msgid="9104973640704357717">"የማወራረጃ ምግቦች መያዣ"</string>
<string name="start_dreams" msgid="9131802557946276718">"የማያ ገጽ ማቆያ"</string>
<string name="ethernet_label" msgid="2203544727007463351">"ኤተርኔት"</string>
+ <string name="quick_settings_dnd_label" msgid="7728690179108024338">"አትረብሽ"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"ብሉቱዝ"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"ምንም የተጣመሩ መሣሪያዎች አይገኝም"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> ባትሪ"</string>
@@ -348,6 +354,7 @@
<string name="notification_section_header_alerting" msgid="5581175033680477651">"ማሳወቂያዎች"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"ውይይቶች"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"ሁሉንም ጸጥ ያሉ ማሳወቂያዎችን ያጽዱ"</string>
+ <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"ማሳወቂያዎች በአትረብሽ ባሉበት ቆመዋል"</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"አሁን ጀምር"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"ምንም ማሳወቂያ የለም"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"ይህ መሣሪያ በእርስዎ ወላጅ የሚተዳደር ነው።"</string>
@@ -452,8 +459,8 @@
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"ለማየት ይክፈቱ"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"የእርስዎን ካርዶች ማግኘት ላይ ችግር ነበር፣ እባክዎ ቆይተው እንደገና ይሞክሩ"</string>
<string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"የገጽ መቆለፊያ ቅንብሮች"</string>
- <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR ኮድ"</string>
- <string name="qr_code_scanner_description" msgid="7937603775306661863">"ለመቃኘት መታ ያድርጉ"</string>
+ <!-- no translation found for qr_code_scanner_title (5290201053875420785) -->
+ <skip />
<string name="status_bar_work" msgid="5238641949837091056">"የስራ መገለጫ"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"የአውሮፕላን ሁነታ"</string>
<string name="zen_alarm_warning" msgid="7844303238486849503">"የእርስዎን ቀጣይ ማንቂያ <xliff:g id="WHEN">%1$s</xliff:g> አይሰሙም"</string>
@@ -491,6 +498,8 @@
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"&lt;b&gt;ሁኔታ:&lt;/b&gt; ዝቅተኛ ደረጃ ተሰጥቶታል"</string>
<string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"በውይይት ማሳወቂያዎች አናት ላይ እና በማያ ገጽ መቆለፊያ ላይ እንደ መገለጫ ምስል ይታያል"</string>
<string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"በውይይት ማሳወቂያዎች አናት ላይ እና በማያ ገጽ መቆለፊያ ላይ እንደ መገለጫ ምስል ይታያል፣ እንደ አረፋ ሆኖ ይታያል"</string>
+ <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"በውይይት ማሳወቂያዎች አናት ላይ እና በማያ ገጽ መቆለፊያ ላይ እንደ መገለጫ ምስል ይታያል፣ አትረብሽን ያቋርጣል"</string>
+ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"በውይይት ማሳወቂያዎች አናት ላይ እና በማያ ገጽ መቆለፊያ ላይ እንደ መገለጫ ምስል ይታያል፣ እንደ አረፋ ሆኖ ይታያል፣ አትረብሽን ያቋርጣል"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"ቅድሚያ"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> የውይይት ባህሪያትን አይደግፍም"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"እነዚህ ማሳወቂያዎች ሊሻሻሉ አይችሉም።"</string>
@@ -566,6 +575,7 @@
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"ኤስኤምኤስ"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"ሙዚቃ"</string>
<string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"የቀን መቁጠሪያ"</string>
+ <string name="volume_and_do_not_disturb" msgid="502044092739382832">"አትረብሽ"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"የድምፅ አዝራሮች አቋራጭ"</string>
<string name="battery" msgid="769686279459897127">"ባትሪ"</string>
<string name="headset" msgid="4485892374984466437">"ጆሮ ማዳመጫ"</string>
@@ -684,6 +694,10 @@
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>፣ <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"Wi-Fi ጠፍቷል"</string>
<string name="bt_is_off" msgid="7436344904889461591">"ብሉቱዝ ጠፍቷል"</string>
+ <string name="dnd_is_off" msgid="3185706903793094463">"አትረብሽ ጠፍቷል"</string>
+ <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"አትረብሽ በአንድ ራስ-ሰር ደንብ (<xliff:g id="ID_1">%s</xliff:g>) በርቷል።"</string>
+ <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"አትረብሽ በአንድ መተግበሪያ (<xliff:g id="ID_1">%s</xliff:g>) በርቷል።"</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"አትረብሽ በአንድ ራስ-ሰር ደንብ ወይም መተግበሪያ በርቷል።"</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"በጀርባ ውስጥ የሚያሄዱ መተግበሪያዎች"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"በባትሪ እና ውሂብ አጠቃቀም ላይ ዝርዝሮችን ለማግኘት መታ ያድርጉ"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"የተንቀሳቃሽ ስልክ ውሂብ ይጥፋ?"</string>
@@ -708,6 +722,8 @@
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(ስራ)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"የስልክ ጥሪ"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(በ<xliff:g id="APPLICATION_NAME_S_">%s</xliff:g> በኩል)"</string>
+ <string name="ongoing_privacy_dialog_attribution_label" msgid="3385241594101496292">"(<xliff:g id="ATTRIBUTION_LABEL">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_proxy_label" msgid="1111829599659403249">"(<xliff:g id="ATTRIBUTION_LABEL">%1$s</xliff:g> • <xliff:g id="PROXY_LABEL">%2$s</xliff:g>)"</string>
<string name="privacy_type_camera" msgid="7974051382167078332">"ካሜራ"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"አካባቢ"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"ማይክሮፎን"</string>
@@ -806,6 +822,9 @@
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(ተቋርጧል)"</string>
<string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"መቀየር አይቻልም። እንደገና ለመሞከር መታ ያድርጉ።"</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"አዲስ መሣሪያ ያጣምሩ"</string>
+ <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"ይህን ክፍለ ጊዜ cast ለማድረግ፣ እባክዎ መተግበሪያውን ይክፈቱ።"</string>
+ <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"የማይታወቅ መተግበሪያ"</string>
+ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Cast ማድረግ አቁም"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"የግንብ ቁጥር"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"የገንባ ቁጥር ወደ ቅንጥብ ሰሌዳ ተቀድቷል።"</string>
<string name="basic_status" msgid="2315371112182658176">"ውይይት ይክፈቱ"</string>
@@ -839,6 +858,7 @@
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"የቅርብ ጊዜ መልዕክቶችን፣ ያመለጡ ጥሪዎች እና፣ የሁኔታ ዝመናዎችን ይመልከቱ"</string>
<string name="people_tile_title" msgid="6589377493334871272">"ውይይት"</string>
+ <string name="paused_by_dnd" msgid="7856941866433556428">"በአትረብሽ ባለበት ቆሟል"</string>
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> መልዕክት ልከዋል፦ <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> ምስል ልኳል"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> የሁኔታ ዝማኔ አለው፦ <xliff:g id="STATUS">%2$s</xliff:g>"</string>
@@ -877,8 +897,7 @@
<item quantity="one"><xliff:g id="COUNT_1">%s</xliff:g> ገቢር መተግበሪያዎች</item>
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> ገቢር መተግበሪያዎች</item>
</plurals>
- <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
- <skip />
+ <string name="fgs_dot_content_description" msgid="2865071539464777240">"አዲስ መረጃ"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"ገቢር መተግበሪያዎች"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"መቆሚያ"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"ቆሟል"</string>
@@ -889,8 +908,12 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"የተቀዳ ጽሁፍ አርትዕ ያድርጉ"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"የተቀዳ ምስል አርትዕ ያድርጉ"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"በአቅራቢያ ወዳለ መሳሪያ ይላኩ"</string>
- <!-- no translation found for add (81036585205287996) -->
- <skip />
- <!-- no translation found for manage_users (1823875311934643849) -->
- <skip />
+ <string name="add" msgid="81036585205287996">"አክል"</string>
+ <string name="manage_users" msgid="1823875311934643849">"ተጠቃሚዎችን ያስተዳድሩ"</string>
+ <string name="drag_split_not_supported" msgid="4326847447699729722">"ይህ ማሳወቂያ ወደ Splitscreen መጎተትን አይደግፍም።"</string>
+ <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi አይገኝም"</string>
+ <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"የቅድሚያ ሁነታ"</string>
+ <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"ማንቂያ ተቀናብሯል"</string>
+ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"ካሜራ እና ማይክሮፎን ጠፍተዋል"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# ማሳወቂያ}one{# ማሳወቂያዎች}other{# ማሳወቂያዎች}}"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 38dcb89cd56d..24e36fb5866f 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -20,14 +20,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4811759950673118541">"واجهة مستخدم النظام"</string>
- <string name="battery_low_title" msgid="6891106956328275225">"قد ينفد شحن البطارية قريبًا"</string>
+ <string name="battery_low_title" msgid="5319680173344341779">"هل تريد تفعيل ميزة \"توفير شحن البطارية\"؟"</string>
+ <string name="battery_low_description" msgid="3282977755476423966">"يتبقى لديك <xliff:g id="PERCENTAGE">%s</xliff:g> من شحن البطارية. يؤدي استخدام ميزة \"توفير شحن البطارية\" إلى تفعيل وضع \"المظهر الداكن\" وتقييد الأنشطة في الخلفية وتأخير الإشعارات."</string>
+ <string name="battery_low_intro" msgid="5148725009653088790">"يؤدي استخدام ميزة \"توفير شحن البطارية\" إلى تفعيل وضع \"المظهر الداكن\" وتقييد الأنشطة في الخلفية وتأخير الإشعارات."</string>
<string name="battery_low_percent_format" msgid="4276661262843170964">"متبقي <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="invalid_charger_title" msgid="938685362320735167">"‏يتعذّر الشحن باستخدام USB."</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"استخدم الشاحن المرفق بجهازك."</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"هل تريد تفعيل ميزة توفير شحن البطارية؟"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"لمحة عن ميزة \"توفير شحن البطارية\""</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"تفعيل"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"هل تريد تفعيل ميزة توفير شحن البطارية؟"</string>
+ <string name="battery_saver_start_action" msgid="8353766979886287140">"تفعيل"</string>
+ <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"لا، شكرًا"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"التدوير التلقائي للشاشة"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"هل تريد السماح لتطبيق <xliff:g id="APPLICATION">%1$s</xliff:g> بالدخول إلى <xliff:g id="USB_DEVICE">%2$s</xliff:g>؟"</string>
<string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"‏هل تريد السماح لتطبيق <xliff:g id="APPLICATION">%1$s</xliff:g> بالدخول إلى <xliff:g id="USB_DEVICE">%2$s</xliff:g>؟\nلم يتم منح هذا التطبيق إذن تسجيل، ولكن يمكنه تسجيل الصوت من خلال جهاز USB هذا."</string>
@@ -128,6 +131,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"تمّت مصادقة الوجه."</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"تمّ التأكيد."</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"يمكنك النقر على \"تأكيد\" لإكمال المهمة."</string>
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"تم فتح قفل الجهاز بالتعرف على وجهك. اضغط للمتابعة."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"مصادقة"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"استخدام رقم تعريف شخصي"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"استخدام نقش"</string>
@@ -181,6 +185,7 @@
<string name="accessibility_desc_close" msgid="8293708213442107755">"إغلاق"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"كتم الصوت تمامًا"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"المنبِّهات فقط"</string>
+ <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"عدم الإزعاج"</string>
<string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"البلوتوث."</string>
<string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"تفعيل البلوتوث."</string>
<string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"تم ضبط المنبّه على <xliff:g id="TIME">%s</xliff:g>."</string>
@@ -209,6 +214,7 @@
<string name="dessert_case" msgid="9104973640704357717">"حالة الحلويات"</string>
<string name="start_dreams" msgid="9131802557946276718">"شاشة الاستراحة"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
+ <string name="quick_settings_dnd_label" msgid="7728690179108024338">"عدم الإزعاج"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"بلوتوث"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"لا يتوفر أي أجهزة مقترنة"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"مستوى طاقة البطارية <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
@@ -360,6 +366,7 @@
<string name="notification_section_header_alerting" msgid="5581175033680477651">"الإشعارات"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"المحادثات"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"محو جميع الإشعارات الصامتة"</string>
+ <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"تم إيقاف الإشعارات مؤقتًا وفقًا لإعداد \"عدم الإزعاج\""</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"البدء الآن"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"ليس هناك أي اشعارات"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"يتولّى أحد الوالدين إدارة هذا الجهاز."</string>
@@ -464,8 +471,8 @@
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"فتح القفل للاستخدام"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"حدثت مشكلة أثناء الحصول على البطاقات، يُرجى إعادة المحاولة لاحقًا."</string>
<string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"إعدادات شاشة القفل"</string>
- <string name="qr_code_scanner_title" msgid="5660820608548306581">"رمز الاستجابة السريعة"</string>
- <string name="qr_code_scanner_description" msgid="7937603775306661863">"انقر للمسح ضوئيًا"</string>
+ <!-- no translation found for qr_code_scanner_title (5290201053875420785) -->
+ <skip />
<string name="status_bar_work" msgid="5238641949837091056">"الملف الشخصي للعمل"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"وضع الطيران"</string>
<string name="zen_alarm_warning" msgid="7844303238486849503">"لن تسمع المنبّه القادم في <xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -503,6 +510,8 @@
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"‏&lt;b&gt;الحالة:&lt;/b&gt; تم خفض الترتيب"</string>
<string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"تظهر في أعلى إشعارات المحادثات وكصورة ملف شخصي على شاشة القفل."</string>
<string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"تظهر في أعلى إشعارات المحادثات وكصورة ملف شخصي على شاشة القفل وتظهر على شكل فقاعة."</string>
+ <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"تظهر في أعلى إشعارات المحادثات وكصورة ملف شخصي على شاشة القفل، وتقاطع ميزة \"عدم الإزعاج\"."</string>
+ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"تظهر في أعلى إشعارات المحادثات وكصورة ملف شخصي على شاشة القفل وتظهر على شكل فقاعة لمقاطعة ميزة \"عدم الإزعاج\"."</string>
<string name="notification_priority_title" msgid="2079708866333537093">"الأولوية"</string>
<string name="no_shortcut" msgid="8257177117568230126">"لا يدعم تطبيق <xliff:g id="APP_NAME">%1$s</xliff:g> ميزات المحادثات."</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"يتعذّر تعديل هذه الإشعارات."</string>
@@ -586,6 +595,7 @@
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"‏الرسائل القصيرة SMS"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"الموسيقى"</string>
<string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"التقويم"</string>
+ <string name="volume_and_do_not_disturb" msgid="502044092739382832">"عدم الإزعاج"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"اختصار أزرار مستوى الصوت"</string>
<string name="battery" msgid="769686279459897127">"البطارية"</string>
<string name="headset" msgid="4485892374984466437">"سماعة الرأس"</string>
@@ -704,6 +714,10 @@
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>، <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"‏تم إيقاف شبكة Wi-Fi"</string>
<string name="bt_is_off" msgid="7436344904889461591">"تم إيقاف البلوتوث."</string>
+ <string name="dnd_is_off" msgid="3185706903793094463">"تم إيقاف وضع \"عدم الإزعاج\""</string>
+ <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"تم تفعيل وضع \"عدم الإزعاج\" بواسطة قاعدة تلقائية (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"تم تفعيل وضع \"عدم الإزعاج\" بواسطة تطبيق (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"تم تفعيل وضع \"عدم الإزعاج\" بواسطة قاعدة تلقائية أو تطبيق."</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"التطبيقات التي تعمل في الخلفية"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"انقر للحصول على تفاصيل حول البطارية واستخدام البيانات"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"هل تريد إيقاف بيانات الجوّال؟"</string>
@@ -728,6 +742,8 @@
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(العمل)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"المكالمات الهاتفية"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(من خلال <xliff:g id="APPLICATION_NAME_S_">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_label" msgid="3385241594101496292">"(<xliff:g id="ATTRIBUTION_LABEL">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_proxy_label" msgid="1111829599659403249">"(<xliff:g id="ATTRIBUTION_LABEL">%1$s</xliff:g> • <xliff:g id="PROXY_LABEL">%2$s</xliff:g>)"</string>
<string name="privacy_type_camera" msgid="7974051382167078332">"الكاميرا"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"الموقع"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"الميكروفون"</string>
@@ -830,6 +846,9 @@
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(غير متّصل)"</string>
<string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"لا يمكن التبديل. انقر لإعادة المحاولة."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"إقران جهاز جديد"</string>
+ <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"لبث هذه الجلسة، يُرجى فتح التطبيق"</string>
+ <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"تطبيق غير معروف"</string>
+ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"إيقاف البث"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"رقم الإصدار"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"تم نسخ رقم الإصدار إلى الحافظة."</string>
<string name="basic_status" msgid="2315371112182658176">"محادثة مفتوحة"</string>
@@ -863,6 +882,7 @@
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"+<xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="people_tile_description" msgid="8154966188085545556">"عرض أحدث الرسائل والمكالمات الفائتة والتغييرات في الحالة"</string>
<string name="people_tile_title" msgid="6589377493334871272">"محادثة"</string>
+ <string name="paused_by_dnd" msgid="7856941866433556428">"تم إيقاف الإشعار مؤقتًا من خلال ميزة \"عدم الإزعاج\""</string>
<string name="new_notification_text_content_description" msgid="2915029960094389291">"تم إرسال رسالة من <xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"تم إرسال صورة من <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="new_status_content_description" msgid="6046637888641308327">"تم تعديل حالة <xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
@@ -905,8 +925,7 @@
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> تطبيق نشط</item>
<item quantity="one">تطبيق واحد (<xliff:g id="COUNT_0">%s</xliff:g>) نشط</item>
</plurals>
- <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
- <skip />
+ <string name="fgs_dot_content_description" msgid="2865071539464777240">"معلومات جديدة"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"# تطبيق نشط"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"إيقاف"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"متوقّف"</string>
@@ -914,14 +933,15 @@
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"تم النسخ."</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"من <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"إغلاق واجهة مستخدم النسخ"</string>
- <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
- <skip />
- <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
- <skip />
- <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
- <skip />
- <!-- no translation found for add (81036585205287996) -->
- <skip />
- <!-- no translation found for manage_users (1823875311934643849) -->
- <skip />
+ <string name="clipboard_edit_text_description" msgid="805254383912962103">"تعديل النص المنسوخ"</string>
+ <string name="clipboard_edit_image_description" msgid="8904857948976041306">"تعديل الصورة المنسوخة"</string>
+ <string name="clipboard_send_nearby_description" msgid="4629769637846717650">"الإرسال إلى جهاز مجاور"</string>
+ <string name="add" msgid="81036585205287996">"إضافة"</string>
+ <string name="manage_users" msgid="1823875311934643849">"إدارة المستخدمين"</string>
+ <string name="drag_split_not_supported" msgid="4326847447699729722">"لا يتيح هذا الإشعار السحب لتقسيم الشاشة."</string>
+ <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"‏شبكة Wi‑Fi غير متاحة"</string>
+ <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"وضع الأولوية"</string>
+ <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"تم ضبط المنبه."</string>
+ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"الكاميرا والميكروفون غير مفعّلين."</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{إشعار واحد}zero{# إشعار}two{إشعاران}few{# إشعارات}many{# إشعارًا}other{# إشعار}}"</string>
</resources>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index 8d8a0fb32d96..7bb97a78d214 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -20,14 +20,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4811759950673118541">"ছিষ্টেম ইউআই"</string>
- <string name="battery_low_title" msgid="6891106956328275225">"বেটাৰী অতি সোনকালে শেষ হ\'ব পাৰে"</string>
+ <string name="battery_low_title" msgid="5319680173344341779">"বেটাৰী সঞ্চয়কাৰী অন কৰিবনে?"</string>
+ <string name="battery_low_description" msgid="3282977755476423966">"আপোনাৰ <xliff:g id="PERCENTAGE">%s</xliff:g> বেটাৰী বাকী আছে। বেটাৰী সঞ্চয়কাৰীয়ে গাঢ় ৰঙৰ থীম অন কৰে, নেপথ্যৰ কাৰ্যকলাপ সীমাবদ্ধ কৰে আৰু জাননী পলম কৰে।"</string>
+ <string name="battery_low_intro" msgid="5148725009653088790">"বেটাৰী সঞ্চয়কাৰীয়ে গাঢ় ৰঙৰ থীম অন কৰে, নেপথ্যৰ কাৰ্যকলাপ সীমাবদ্ধ কৰে আৰু জাননী পলম কৰে।"</string>
<string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> বাকী আছে"</string>
<string name="invalid_charger_title" msgid="938685362320735167">"ইউএছবি জৰিয়তে চ্চাৰ্জ কৰিব নোৱাৰি"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"আপোনাৰ ডিভাইচৰ লগত পোৱা চ্চাৰ্জাৰটো ব্যৱহাৰ কৰক।"</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"বেটাৰী সঞ্চয়কাৰী অন কৰেনে?"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"বেটাৰী সঞ্চয়কাৰীৰ বিষয়ে"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"অন কৰক"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"বেটাৰী সঞ্চয়কাৰী অন কৰক"</string>
+ <string name="battery_saver_start_action" msgid="8353766979886287140">"অন কৰক"</string>
+ <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"নালাগে, ধন্যবাদ"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"স্বয়ং-ঘূৰ্ণন স্ক্ৰীন"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"<xliff:g id="USB_DEVICE">%2$s</xliff:g>ত প্ৰৱেশ কৰিবলৈ <xliff:g id="APPLICATION">%1$s</xliff:g>ক অনুমতি দিবনে?"</string>
<string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"<xliff:g id="APPLICATION">%1$s</xliff:g>ক <xliff:g id="USB_DEVICE">%2$s</xliff:g> এক্সেছ কৰিবলৈ অনুমতি দিবনে?\nএই এপ্‌টোক ৰেকর্ড কৰাৰ অনুমতি দিয়া হোৱা নাই কিন্তু ই এই ইউএছবি ডিভাইচটোৰ জৰিয়তে অডিঅ\' ৰেকর্ড কৰিব পাৰে।"</string>
@@ -128,6 +131,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"মুখমণ্ডলৰ বিশ্বাসযোগ্যতা প্ৰমাণীকৰণ কৰা হ’ল"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"নিশ্চিত কৰিলে"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"সম্পূৰ্ণ কৰিবলৈ নিশ্চিত কৰক-ত টিপক"</string>
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"আপোনাৰ মুখাৱয়বৰ দ্বাৰা আনলক কৰা হৈছে। অব্যাহত ৰাখিবলৈ দবাওক।"</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"বিশ্বাসযোগ্যতা প্ৰমাণীকৰণ কৰা হ’ল"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"পিন ব্যৱহাৰ কৰক"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"আৰ্হি ব্যৱহাৰ কৰক"</string>
@@ -181,6 +185,7 @@
<string name="accessibility_desc_close" msgid="8293708213442107755">"বন্ধ কৰক"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"সম্পূৰ্ণ নিৰৱতা"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"কেৱল এলাৰ্মবোৰৰ বাবে"</string>
+ <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"অসুবিধা নিদিব"</string>
<string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"ব্লুটুথ।"</string>
<string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"ব্লুটুথ অন হৈ আছে।"</string>
<string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"<xliff:g id="TIME">%s</xliff:g>ৰ বাবে এলাৰ্ম ছেট কৰা হৈছে।"</string>
@@ -205,6 +210,7 @@
<string name="dessert_case" msgid="9104973640704357717">"মিষ্টান্ন ভাণ্ডাৰ"</string>
<string name="start_dreams" msgid="9131802557946276718">"স্ক্ৰীন ছেভাৰ"</string>
<string name="ethernet_label" msgid="2203544727007463351">"ইথাৰনেট"</string>
+ <string name="quick_settings_dnd_label" msgid="7728690179108024338">"অসুবিধা নিদিব"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"ব্লুটুথ"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"কোনো যোৰা লগোৱা ডিভাইচ উপলব্ধ নহয়।"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"বেটাৰী <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
@@ -348,6 +354,7 @@
<string name="notification_section_header_alerting" msgid="5581175033680477651">"জাননীসমূহ"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"বাৰ্তালাপ"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"আটাইবোৰ নীৰৱ জাননী মচক"</string>
+ <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"অসুবিধা নিদিব-ই জাননী পজ কৰিছে"</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"এতিয়াই আৰম্ভ কৰক"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"কোনো জাননী নাই"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"এই ডিভাইচটো আপোনাৰ অভিভাৱকে পৰিচালনা কৰে"</string>
@@ -452,8 +459,8 @@
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"ব্যৱহাৰ কৰিবলৈ আনলক কৰক"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"আপোনাৰ কাৰ্ড লাভ কৰোঁতে এটা সমস্যা হৈছে, অনুগ্ৰহ কৰি পাছত পুনৰ চেষ্টা কৰক"</string>
<string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"লক স্ক্ৰীনৰ ছেটিং"</string>
- <string name="qr_code_scanner_title" msgid="5660820608548306581">"কিউআৰ ক\'ড"</string>
- <string name="qr_code_scanner_description" msgid="7937603775306661863">"স্কেন কৰিবলৈ টিপক"</string>
+ <!-- no translation found for qr_code_scanner_title (5290201053875420785) -->
+ <skip />
<string name="status_bar_work" msgid="5238641949837091056">"কৰ্মস্থানৰ প্ৰ\'ফাইল"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"এয়াৰপ্লেইন ম\'ড"</string>
<string name="zen_alarm_warning" msgid="7844303238486849503">"আপুনি আপোনাৰ পিছৰটো এলাৰ্ম <xliff:g id="WHEN">%1$s</xliff:g> বজাত শুনা নাপাব"</string>
@@ -491,6 +498,8 @@
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"&lt;b&gt;স্থিতি:&lt;/b&gt; স্থান তললৈ কৰা হৈছে"</string>
<string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"বাৰ্তালাপৰ জাননীৰ শীৰ্ষত আৰু প্ৰ’ফাইল চিত্ৰ হিচাপে লক স্ক্ৰীনত দেখুৱায়"</string>
<string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"বাৰ্তালাপৰ জাননীৰ শীৰ্ষত আৰু প্ৰ’ফাইল চিত্ৰ হিচাপে লক স্ক্ৰীনত দেখুৱায়, এটা বাবল হিচাপে দেখা পোৱা যায়"</string>
+ <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"বাৰ্তালাপৰ জাননীৰ শীৰ্ষত আৰু প্ৰ’ফাইল চিত্ৰ হিচাপে লক স্ক্ৰীনত দেখুৱায়, অসুবিধা নিদিব ম’ডত ব্যাঘাত জন্মায়"</string>
+ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"বাৰ্তালাপৰ জাননীৰ শীৰ্ষত আৰু প্ৰ’ফাইল চিত্ৰ হিচাপে লক স্ক্ৰীনত দেখুৱায়, এটা বাবল হিচাপে দেখা পোৱা যায়, অসুবিধা নিদিব ম’ডত ব্যাঘাত জন্মায়"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"অগ্ৰাধিকাৰ"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g>এ বাৰ্তালাপৰ সুবিধাসমূহ সমৰ্থন নকৰে"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"এই জাননীসমূহ সংশোধন কৰিব নোৱাৰি।"</string>
@@ -566,6 +575,7 @@
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"এছএমএছ"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"সংগীত"</string>
<string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Calendar"</string>
+ <string name="volume_and_do_not_disturb" msgid="502044092739382832">"অসুবিধা নিদিব"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"ভলিউম বুটামসমূহৰ শ্বৰ্টকাট"</string>
<string name="battery" msgid="769686279459897127">"বেটাৰী"</string>
<string name="headset" msgid="4485892374984466437">"হেডছেট"</string>
@@ -684,6 +694,10 @@
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"ৱাই-ফাই অফ অৱস্থাত আছে"</string>
<string name="bt_is_off" msgid="7436344904889461591">"ব্লুটুথ অফ অৱস্থাত আছে"</string>
+ <string name="dnd_is_off" msgid="3185706903793094463">"অসুবিধা নিদিব অফ অৱস্থাত আছে"</string>
+ <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"অসুবিধা নিদিব-ক এটা স্বয়ংক্ৰিয় নিয়ম (<xliff:g id="ID_1">%s</xliff:g>)এ অন কৰিলে।"</string>
+ <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"অসুবিধা নিদিব-ক কোনো এপ্ (<xliff:g id="ID_1">%s</xliff:g>)এ অন কৰিলে।"</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"অসুবিধা নিদিব-ক এটা স্বয়ংক্ৰিয় নিয়ম বা এপে অন কৰিলে।"</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"নেপথ্যত চলি থকা এপসমূহ"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"বেটাৰী আৰু ডেটাৰ ব্যৱহাৰৰ বিষয়ে সবিশেষ জানিবলৈ টিপক"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"ম’বাইল ডেটা অফ কৰিবনে?"</string>
@@ -708,6 +722,8 @@
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(কৰ্মস্থান)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"ফ’ন কল"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(<xliff:g id="APPLICATION_NAME_S_">%s</xliff:g>ৰ জৰিয়তে)"</string>
+ <string name="ongoing_privacy_dialog_attribution_label" msgid="3385241594101496292">"(<xliff:g id="ATTRIBUTION_LABEL">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_proxy_label" msgid="1111829599659403249">"(<xliff:g id="ATTRIBUTION_LABEL">%1$s</xliff:g> • <xliff:g id="PROXY_LABEL">%2$s</xliff:g>)"</string>
<string name="privacy_type_camera" msgid="7974051382167078332">"Camera"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"অৱস্থান"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"মাইক্ৰ\'ফ\'ন"</string>
@@ -806,6 +822,9 @@
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(সংযোগ বিচ্ছিন্ন কৰা হৈছে)"</string>
<string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"সলনি কৰিব নোৱাৰি। আকৌ চেষ্টা কৰিবলৈ টিপক।"</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"নতুন ডিভাইচ পেয়াৰ কৰক"</string>
+ <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"এই ছেশ্বনটো কাষ্ট কৰিবলৈ, অনুগ্ৰহ কৰি এপ্‌টো খোলক"</string>
+ <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"অজ্ঞাত এপ্"</string>
+ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"কাষ্ট বন্ধ কৰক"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"বিল্ডৰ নম্বৰ"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"ক্লিপব’ৰ্ডলৈ বিল্ডৰ নম্বৰ প্ৰতিলিপি কৰা হ’ল।"</string>
<string name="basic_status" msgid="2315371112182658176">"বাৰ্তালাপ খোলক"</string>
@@ -839,6 +858,7 @@
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"শেহতীয়া বাৰ্তা, মিছড্‌ কল আৰু স্থিতিৰ আপডে’ট চাওক"</string>
<string name="people_tile_title" msgid="6589377493334871272">"বাৰ্তালাপ"</string>
+ <string name="paused_by_dnd" msgid="7856941866433556428">"অসুবিধা নিদিব সুবিধাটোৱে পজ কৰিছে"</string>
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g>এ এটা বাৰ্তা পঠিয়াইছে: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g>এ এখন প্ৰতিচ্ছবি পঠিয়াইছে"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g>ৰ এটা স্থিতিৰ আপডে’ট আছে: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
@@ -877,8 +897,7 @@
<item quantity="one"><xliff:g id="COUNT_1">%s</xliff:g> টা সক্ৰিয় এপ্‌</item>
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> টা সক্ৰিয় এপ্‌</item>
</plurals>
- <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
- <skip />
+ <string name="fgs_dot_content_description" msgid="2865071539464777240">"নতুন তথ্য"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"সক্ৰিয় এপ্‌"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"বন্ধ কৰক"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"বন্ধ হ’ল"</string>
@@ -889,8 +908,12 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"প্ৰতিলিপি কৰা পাঠ সম্পাদনা কৰক"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"প্ৰতিলিপি কৰা প্ৰতিচ্ছবি সম্পাদনা কৰক"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"নিকটৱৰ্তী ডিভাইচলৈ পঠাওক"</string>
- <!-- no translation found for add (81036585205287996) -->
- <skip />
- <!-- no translation found for manage_users (1823875311934643849) -->
- <skip />
+ <string name="add" msgid="81036585205287996">"যোগ দিয়ক"</string>
+ <string name="manage_users" msgid="1823875311934643849">"ব্যৱহাৰকাৰী পৰিচালনা কৰক"</string>
+ <string name="drag_split_not_supported" msgid="4326847447699729722">"এই জাননীটোৱে টানি আনি এৰাৰ পৰা বিভাজিত স্ক্ৰীন সমৰ্থন নকৰে।"</string>
+ <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"ৱাই-ফাই উপলব্ধ নহয়"</string>
+ <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"অগ্ৰাধিকাৰ ম’ড"</string>
+ <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"এলাৰ্ম ছেট কৰা হ’ল"</string>
+ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"কেমেৰা আৰু মাইক অফ হৈ আছে"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# টা জাননী}one{# টা জাননী}other{# টা জাননী}}"</string>
</resources>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index 1fc28a88d390..a796a201834a 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -20,14 +20,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4811759950673118541">"Sistemin İstifadə İnterfeysi"</string>
- <string name="battery_low_title" msgid="6891106956328275225">"Batareya tezliklə bitə bilər"</string>
+ <string name="battery_low_title" msgid="5319680173344341779">"Enerjiyə Qənaət aktiv edilsin?"</string>
+ <string name="battery_low_description" msgid="3282977755476423966">"<xliff:g id="PERCENTAGE">%s</xliff:g> enerji qalıb. Enerjiyə Qənaət rejimi Tünd temanı aktivləşdirir, arxa fon fəaliyyətini məhdudlaşdırır və bildirişləri gecikdirir."</string>
+ <string name="battery_low_intro" msgid="5148725009653088790">"Enerjiyə Qənaət rejimi Tünd temanı aktivləşdirir, arxa fon fəaliyyətini məhdudlaşdırır və bildirişləri gecikdirir."</string>
<string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> qalır"</string>
<string name="invalid_charger_title" msgid="938685362320735167">"USB vasitəsilə enerji yığa bilməz"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"Cihazla verilən adapterdən istifadə edin"</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Batareya Qənaəti aktiv edilsin?"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Enerjiyə Qənaət Haqqında"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Aktivləşdirin"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"Batareya Qənaətini aktiv edin"</string>
+ <string name="battery_saver_start_action" msgid="8353766979886287140">"Aktiv edin"</string>
+ <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Xeyr, təşəkkür"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Ekranın avtomatik dönməsi"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"<xliff:g id="APPLICATION">%1$s</xliff:g> tətbiqinə <xliff:g id="USB_DEVICE">%2$s</xliff:g> cihazına giriş icazəsi verilsin?"</string>
<string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"<xliff:g id="APPLICATION">%1$s</xliff:g> tətbiqinə <xliff:g id="USB_DEVICE">%2$s</xliff:g> cihazına giriş icazəsi verilsin?\nBu tətbiqə qeydə almaq icazəsi verilməyib lakin, bu USB vasitəsilə səs yaza bilər."</string>
@@ -128,6 +131,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Üz doğrulandı"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Təsdiqləndi"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Tamamlamaq üçün \"Təsdiq edin\" seçiminə toxunun"</string>
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Üzünüzlə kiliddən çıxarılıb. Davam etmək üçün basın."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Doğrulandı"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"PIN istifadə edin"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Model istifadə edin"</string>
@@ -181,6 +185,7 @@
<string name="accessibility_desc_close" msgid="8293708213442107755">"Qapadın"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"tam sakitlik"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"bildirişlər"</string>
+ <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"Narahat Etməyin."</string>
<string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"Bluetooth."</string>
<string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"Bluetooth aktiv."</string>
<string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"Alarm <xliff:g id="TIME">%s</xliff:g> üçün qurulub."</string>
@@ -205,6 +210,7 @@
<string name="dessert_case" msgid="9104973640704357717">"Desert Qabı"</string>
<string name="start_dreams" msgid="9131802557946276718">"Ekran qoruyucu"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
+ <string name="quick_settings_dnd_label" msgid="7728690179108024338">"Narahat etməyin"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Heç bir cütlənmiş cihaz əlçatan deyil"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> batareya"</string>
@@ -348,6 +354,7 @@
<string name="notification_section_header_alerting" msgid="5581175033680477651">"Bildirişlər"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Söhbətlər"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Səssiz bildirişlərin hamısını silin"</string>
+ <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Bildirişlər \"Narahat Etməyin\" rejimi tərəfindən dayandırıldı"</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"İndi başlayın"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Heç bir bildiriş yoxdur"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Bu cihaz valideyniniz tərəfindən idarə olunur"</string>
@@ -452,8 +459,7 @@
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"İstifadə etmək üçün kiliddən çıxarın"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Kartların əldə edilməsində problem oldu, sonra yenidən cəhd edin"</string>
<string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Kilid ekranı ayarları"</string>
- <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR kodu"</string>
- <string name="qr_code_scanner_description" msgid="7937603775306661863">"Skanlamaq üçün toxunun"</string>
+ <string name="qr_code_scanner_title" msgid="5290201053875420785">"QR kodu skanlayın"</string>
<string name="status_bar_work" msgid="5238641949837091056">"İş profili"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Təyyarə rejimi"</string>
<string name="zen_alarm_warning" msgid="7844303238486849503">"<xliff:g id="WHEN">%1$s</xliff:g> zaman növbəti xəbərdarlığınızı eşitməyəcəksiniz"</string>
@@ -491,6 +497,8 @@
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"&lt;b&gt;Status:&lt;/b&gt; Aşağı sıraya keçirilib"</string>
<string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"Söhbət bildirişlərinin yuxarısında və kilid ekranında profil şəkli kimi göstərilir"</string>
<string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"Söhbət bildirişlərinin yuxarısında və kilid ekranında profil şəkli kimi göstərilir, baloncuq kimi görünür"</string>
+ <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"Söhbət bildirişlərinin yuxarısında və kilid ekranında profil şəkli kimi göstərilir, Narahat Etməyin rejimini kəsir"</string>
+ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Söhbət bildirişlərinin yuxarısında və kilid ekranında profil şəkli kimi göstərilir, baloncuq kimi görünür, Narahat Etməyin rejimini kəsir"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritet"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> söhbət funksiyalarını dəstəkləmir"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Bu bildirişlər dəyişdirilə bilməz."</string>
@@ -566,6 +574,7 @@
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"SMS"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"Musiqi"</string>
<string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Təqvim"</string>
+ <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Narahat Etməyin"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"Səs düymələri qısayolu"</string>
<string name="battery" msgid="769686279459897127">"Batareya"</string>
<string name="headset" msgid="4485892374984466437">"Qulaqlıq"</string>
@@ -684,6 +693,10 @@
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"Wi-Fi deaktivdir"</string>
<string name="bt_is_off" msgid="7436344904889461591">"Bluetooth deaktivdir"</string>
+ <string name="dnd_is_off" msgid="3185706903793094463">"\"Narahat Etməyin\" deaktivdir"</string>
+ <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"\"Narahat etməyin\" rejimi (<xliff:g id="ID_1">%s</xliff:g>) avtomatik qaydası tərəfindən aktiv edildi."</string>
+ <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"\"Narahat etməyin\" rejimi (<xliff:g id="ID_1">%s</xliff:g>) tətbiqi tərəfindən aktiv edildi."</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"\"Narahat etməyin\" rejimi avtomatik qayda və ya tətbiq tərəfindən aktiv edildi."</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"Arxa fonda işləyən tətbiqlər"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"Batareya və data istifadəsi haqqında ətraflı məlumat üçün klikləyin"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Mobil data söndürülsün?"</string>
@@ -708,6 +721,8 @@
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(iş)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"Telefon zəngi"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(<xliff:g id="APPLICATION_NAME_S_">%s</xliff:g> vasitəsilə)"</string>
+ <string name="ongoing_privacy_dialog_attribution_label" msgid="3385241594101496292">"(<xliff:g id="ATTRIBUTION_LABEL">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_proxy_label" msgid="1111829599659403249">"(<xliff:g id="ATTRIBUTION_LABEL">%1$s</xliff:g> • <xliff:g id="PROXY_LABEL">%2$s</xliff:g>)"</string>
<string name="privacy_type_camera" msgid="7974051382167078332">"kamera"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"məkan"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofon"</string>
@@ -806,6 +821,9 @@
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(bağlantı kəsildi)"</string>
<string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Dəyişmək olmur. Yenidən cəhd etmək üçün toxunun."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Cihaz əlavə edin"</string>
+ <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Bu sessiyanı yayımlamaq üçün tətbiqi açın."</string>
+ <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Naməlum tətbiq"</string>
+ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Yayımı dayandırın"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Montaj nömrəsi"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Versiya nömrəsi mübadilə buferinə kopyalandı."</string>
<string name="basic_status" msgid="2315371112182658176">"Açıq söhbət"</string>
@@ -839,6 +857,7 @@
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Son mesajlar, buraxılmış zənglər və status güncəlləmələrinə baxın"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Söhbət"</string>
+ <string name="paused_by_dnd" msgid="7856941866433556428">"\"Narahat Etməyin\" rejimini tərəfindən durdurulub"</string>
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> mesaj göndərdi: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> şəkil göndərdi"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> status güncəlləməsi edib: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
@@ -877,8 +896,7 @@
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> aktiv tətbiq</item>
<item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> aktiv tətbiq</item>
</plurals>
- <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
- <skip />
+ <string name="fgs_dot_content_description" msgid="2865071539464777240">"Yeni məlumat"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Aktiv tətbiqlər"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Dayandırın"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Dayandırılıb"</string>
@@ -886,14 +904,15 @@
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Kopyalandı"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Mənbə: <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"UI kopyalanmasını qapadın"</string>
- <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
- <skip />
- <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
- <skip />
- <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
- <skip />
- <!-- no translation found for add (81036585205287996) -->
- <skip />
- <!-- no translation found for manage_users (1823875311934643849) -->
- <skip />
+ <string name="clipboard_edit_text_description" msgid="805254383912962103">"Kopyalanmış mətni redaktə edin"</string>
+ <string name="clipboard_edit_image_description" msgid="8904857948976041306">"Kopyalanmış şəkli redaktə edin"</string>
+ <string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Yaxınlıqdakı cihaza göndərin"</string>
+ <string name="add" msgid="81036585205287996">"Əlavə edin"</string>
+ <string name="manage_users" msgid="1823875311934643849">"İstifadəçiləri idarə edin"</string>
+ <string name="drag_split_not_supported" msgid="4326847447699729722">"Bu bildiriş Ayrılmış ekrana sürüşdürməyi dəstəkləmir."</string>
+ <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi əlçatan deyil"</string>
+ <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Prioritet rejimi"</string>
+ <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Siqnal ayarlanıb"</string>
+ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Kamera və mikrofon deaktivdir"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# bildiriş}other{# bildiriş}}"</string>
</resources>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index 555b477770a4..cd6b9cc147b5 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -20,14 +20,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4811759950673118541">"UI sistema"</string>
- <string name="battery_low_title" msgid="6891106956328275225">"Baterija će se možda uskoro isprazniti"</string>
+ <string name="battery_low_title" msgid="5319680173344341779">"Želite li da uključite Uštedu baterije?"</string>
+ <string name="battery_low_description" msgid="3282977755476423966">"Preostali nivo napunjenosti baterije je <xliff:g id="PERCENTAGE">%s</xliff:g>. Ušteda baterije uključuje Tamnu temu, ograničava aktivnosti u pozadini i odlaže obaveštenja."</string>
+ <string name="battery_low_intro" msgid="5148725009653088790">"Ušteda baterije uključuje Tamnu temu, ograničava aktivnosti u pozadini i odlaže obaveštenja."</string>
<string name="battery_low_percent_format" msgid="4276661262843170964">"Još <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="invalid_charger_title" msgid="938685362320735167">"Punjenje preko USB-a nije uspelo"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"Koristite punjač koji ste dobili uz uređaj"</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Želite da uključite Uštedu baterije?"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"O Uštedi baterije"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Uključi"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"Uključi Uštedu baterije"</string>
+ <string name="battery_saver_start_action" msgid="8353766979886287140">"Uključi"</string>
+ <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Ne, hvala"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Automatsko rotiranje ekrana"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"Želite li da dozvolite da <xliff:g id="APPLICATION">%1$s</xliff:g> pristupa uređaju <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
<string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Želite li da dozvolite da <xliff:g id="APPLICATION">%1$s</xliff:g> pristupa uređaju <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nOva aplikacija nema dozvolu za snimanje, ali bi mogla da snima zvuk pomoću ovog USB uređaja."</string>
@@ -128,6 +131,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Lice je potvrđeno"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Potvrđeno"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Dodirnite Potvrdi da biste završili"</string>
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Otključali ste licem. Pritisnite da biste nastavili."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Identitet je potvrđen"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Koristite PIN"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Koristite šablon"</string>
@@ -181,6 +185,7 @@
<string name="accessibility_desc_close" msgid="8293708213442107755">"Zatvori"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"potpuna tišina"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"samo alarmi"</string>
+ <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"Ne uznemiravaj."</string>
<string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"Bluetooth."</string>
<string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"Bluetooth je uključen."</string>
<string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"Alarm je podešen za <xliff:g id="TIME">%s</xliff:g>."</string>
@@ -206,6 +211,7 @@
<string name="dessert_case" msgid="9104973640704357717">"Vitrina sa poslasticama"</string>
<string name="start_dreams" msgid="9131802557946276718">"Čuvar ekrana"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Eternet"</string>
+ <string name="quick_settings_dnd_label" msgid="7728690179108024338">"Ne uznemiravaj"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Nije dostupan nijedan upareni uređaj"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Nivo baterije je <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
@@ -351,6 +357,7 @@
<string name="notification_section_header_alerting" msgid="5581175033680477651">"Obaveštenja"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Konverzacije"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Obrišite sva nečujna obaveštenja"</string>
+ <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Obaveštenja su pauzirana režimom Ne uznemiravaj"</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"Započni"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Nema obaveštenja"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Ovim uređajem upravlja roditelj"</string>
@@ -455,8 +462,7 @@
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Otključaj radi korišćenja"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Došlo je do problema pri preuzimanju kartica. Probajte ponovo kasnije"</string>
<string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Podešavanja zaključanog ekrana"</string>
- <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR kôd"</string>
- <string name="qr_code_scanner_description" msgid="7937603775306661863">"Dodirnite da biste skenirali"</string>
+ <string name="qr_code_scanner_title" msgid="5290201053875420785">"Skenirajte QR kôd"</string>
<string name="status_bar_work" msgid="5238641949837091056">"Poslovni profil"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Režim rada u avionu"</string>
<string name="zen_alarm_warning" msgid="7844303238486849503">"Nećete čuti sledeći alarm u <xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -494,6 +500,8 @@
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"&lt;b&gt;Status:&lt;/b&gt; Rangirano niže"</string>
<string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"Prikazuje se u vrhu obaveštenja o konverzacijama i kao slika profila na zaključanom ekranu"</string>
<string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"Prikazuje se u vrhu obaveštenja o konverzacijama i kao slika profila na zaključanom ekranu, pojavljuje se kao oblačić"</string>
+ <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"Prikazuje se u vrhu obaveštenja o konverzacijama i kao slika profila na zaključanom ekranu, prekida režim Ne uznemiravaj"</string>
+ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Prikazuje se u vrhu obaveštenja o konverzacijama i kao slika profila na zaključanom ekranu, pojavljuje se kao oblačić, prekida režim Ne uznemiravaj"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritet"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> ne podržava funkcije konverzacije"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Ova obaveštenja ne mogu da se menjaju."</string>
@@ -571,6 +579,7 @@
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"SMS"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"Muzika"</string>
<string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Kalendar"</string>
+ <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Ne uznemiravaj"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"Prečica za dugmad za jačinu zvuka"</string>
<string name="battery" msgid="769686279459897127">"Baterija"</string>
<string name="headset" msgid="4485892374984466437">"Naglavne slušalice"</string>
@@ -689,6 +698,10 @@
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"WiFi je isključen"</string>
<string name="bt_is_off" msgid="7436344904889461591">"Bluetooth je isključen"</string>
+ <string name="dnd_is_off" msgid="3185706903793094463">"Režim Ne uznemiravaj je isključen"</string>
+ <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"Automatsko pravilo (<xliff:g id="ID_1">%s</xliff:g>) je uključilo režim Ne uznemiravaj."</string>
+ <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"Aplikacija (<xliff:g id="ID_1">%s</xliff:g>) je uključila režim Ne uznemiravaj."</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"Automatsko pravilo ili aplikacija su uključili režim Ne uznemiravaj."</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"Aplikacije pokrenute u pozadini"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"Dodirnite za detalje o bateriji i potrošnji podataka"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Želite da isključite mobilne podatke?"</string>
@@ -713,6 +726,8 @@
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(posao)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"Telefonski poziv"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(preko: <xliff:g id="APPLICATION_NAME_S_">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_label" msgid="3385241594101496292">"(<xliff:g id="ATTRIBUTION_LABEL">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_proxy_label" msgid="1111829599659403249">"(<xliff:g id="ATTRIBUTION_LABEL">%1$s</xliff:g> • <xliff:g id="PROXY_LABEL">%2$s</xliff:g>)"</string>
<string name="privacy_type_camera" msgid="7974051382167078332">"kameru"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"lokaciju"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofon"</string>
@@ -812,6 +827,9 @@
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(veza je prekinuta)"</string>
<string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Prebacivanje nije uspelo. Probajte ponovo."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Upari novi uređaj"</string>
+ <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Da biste prebacivali ovu sesiju, otvorite aplikaciju."</string>
+ <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Nepoznata aplikacija"</string>
+ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Zaustavi prebacivanje"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Broj verzije"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Broj verzije je kopiran u privremenu memoriju."</string>
<string name="basic_status" msgid="2315371112182658176">"Otvorite konverzaciju"</string>
@@ -845,6 +863,7 @@
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Pogledajte nedavne poruke, propuštene pozive i ažuriranja statusa"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Konverzacija"</string>
+ <string name="paused_by_dnd" msgid="7856941866433556428">"Pauzirano režimom Ne uznemiravaj"</string>
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> je poslao/la poruku: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> šalje sliku"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> ima ažuriranje statusa: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
@@ -884,8 +903,7 @@
<item quantity="few"><xliff:g id="COUNT_1">%s</xliff:g> aktivne aplikacije</item>
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> aktivnih aplikacija</item>
</plurals>
- <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
- <skip />
+ <string name="fgs_dot_content_description" msgid="2865071539464777240">"Nove informacije"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Aktivne aplikacije"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Zaustavi"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Zaustavljeno"</string>
@@ -893,14 +911,15 @@
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Kopirano je"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Iz: <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Odbaci kopiranje korisničkog interfejsa"</string>
- <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
- <skip />
- <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
- <skip />
- <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
- <skip />
- <!-- no translation found for add (81036585205287996) -->
- <skip />
- <!-- no translation found for manage_users (1823875311934643849) -->
- <skip />
+ <string name="clipboard_edit_text_description" msgid="805254383912962103">"Izmenite kopirani tekst"</string>
+ <string name="clipboard_edit_image_description" msgid="8904857948976041306">"Izmenite kopiranu sliku"</string>
+ <string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Pošalji na uređaj u blizini"</string>
+ <string name="add" msgid="81036585205287996">"Dodaj"</string>
+ <string name="manage_users" msgid="1823875311934643849">"Upravljajte korisnicima"</string>
+ <string name="drag_split_not_supported" msgid="4326847447699729722">"Ovo obaveštenje ne podržava prevlačenje na podeljeni ekran."</string>
+ <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"WiFi nije dostupan"</string>
+ <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Prioritetni režim"</string>
+ <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarm je podešen"</string>
+ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Kamera i mikrofon su isključeni"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# obaveštenje}one{# obaveštenje}few{# obaveštenja}other{# obaveštenja}}"</string>
</resources>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index 744600740be6..0380a764e179 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -20,14 +20,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4811759950673118541">"Інтэрфейс сістэмы"</string>
- <string name="battery_low_title" msgid="6891106956328275225">"Акумулятар хутка разрадзіцца"</string>
+ <string name="battery_low_title" msgid="5319680173344341779">"Уключыць рэжым энергазберажэння?"</string>
+ <string name="battery_low_description" msgid="3282977755476423966">"Засталося <xliff:g id="PERCENTAGE">%s</xliff:g> зараду акумулятара. Рэжым энергазберажэння ўключае цёмную тэму, абмяжоўвае дзеянні ў фонавым рэжыме і затрымлівае апавяшчэнні."</string>
+ <string name="battery_low_intro" msgid="5148725009653088790">"Рэжым энергазберажэння ўключае цёмную тэму, абмяжоўвае дзеянні ў фонавым рэжыме і затрымлівае апавяшчэнні."</string>
<string name="battery_low_percent_format" msgid="4276661262843170964">"Засталося <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="invalid_charger_title" msgid="938685362320735167">"Не ўдалося выканаць зарадку праз USB"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"Выкарыстоўвайце зараднае прыстасаванне з камплекта прылады"</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Уключыць рэжым эканоміі зараду?"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Інфармацыя пра рэжым эканоміі зараду"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Уключыць"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"Уключыць рэжым эканоміі зараду"</string>
+ <string name="battery_saver_start_action" msgid="8353766979886287140">"Уключыць"</string>
+ <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Не, дзякуй"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Аўтаматычны паварот экрана"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"Дазволіць праграме <xliff:g id="APPLICATION">%1$s</xliff:g> доступ да прылады <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
<string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Даць праграме \"<xliff:g id="APPLICATION">%1$s</xliff:g>\" доступ да прылады \"<xliff:g id="USB_DEVICE">%2$s</xliff:g>\"?\nУ гэтай праграмы няма дазволу на запіс, аднак яна зможа запісваць аўдыя праз гэту прыладу USB."</string>
@@ -128,6 +131,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Твар распазнаны"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Пацверджана"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Націсніце \"Пацвердзіць\", каб завяршыць"</string>
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Разблакіравана распазнаваннем твару. Націсніце для працягу."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Распазнана"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Увесці PIN-код"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Выкарыстаць узор разблакіроўкі"</string>
@@ -181,6 +185,7 @@
<string name="accessibility_desc_close" msgid="8293708213442107755">"Закрыць"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"поўная цішыня"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"толькі будзільнікі"</string>
+ <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"Не турбаваць."</string>
<string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"Bluetooth."</string>
<string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"Bluetooth уключаны."</string>
<string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"Наладжаны будзiльнiк: <xliff:g id="TIME">%s</xliff:g>."</string>
@@ -207,6 +212,7 @@
<string name="dessert_case" msgid="9104973640704357717">"Вітрына з дэсертамі"</string>
<string name="start_dreams" msgid="9131802557946276718">"Экранная застаўка"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
+ <string name="quick_settings_dnd_label" msgid="7728690179108024338">"Не турбаваць"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Няма даступных спалучаных прылад"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Узровень зараду: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
@@ -354,6 +360,7 @@
<string name="notification_section_header_alerting" msgid="5581175033680477651">"Апавяшчэнні"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Размовы"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Выдаліць усе апавяшчэнні без гуку"</string>
+ <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Паказ апавяшчэнняў прыпынены ў рэжыме \"Не турбаваць\""</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"Пачаць зараз"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Апавяшчэнняў няма"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Гэта прылада знаходзіцца пад кантролем бацькоў"</string>
@@ -458,8 +465,8 @@
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Разблакіраваць для выкарыстання"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Узнікла праблема з загрузкай вашых карт. Паўтарыце спробу пазней"</string>
<string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Налады экрана блакіроўкі"</string>
- <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR-код"</string>
- <string name="qr_code_scanner_description" msgid="7937603775306661863">"Націсніце, каб адсканіраваць"</string>
+ <!-- no translation found for qr_code_scanner_title (5290201053875420785) -->
+ <skip />
<string name="status_bar_work" msgid="5238641949837091056">"Працоўны профіль"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Рэжым палёту"</string>
<string name="zen_alarm_warning" msgid="7844303238486849503">"Вы не пачуеце наступны будзільнік <xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -497,6 +504,8 @@
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"&lt;b&gt;Стан:&lt;/b&gt; Ацэнена як няважнае"</string>
<string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"З\'яўляецца ўверсе раздзела размоў і паказвае на экране блакіроўкі відарыс профілю"</string>
<string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"З\'яўляецца ўверсе раздзела размоў як усплывальнае апавяшчэнне, якое паказвае на экране блакіроўкі відарыс профілю"</string>
+ <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"З\'яўляецца ўверсе раздзела размоў, перарывае рэжым \"Не турбаваць\" і паказвае на экране блакіроўкі відарыс профілю"</string>
+ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"З\'яўляецца ўверсе раздзела размоў як усплывальнае апавяшчэнне, якое перарывае рэжым \"Не турбаваць\" і паказвае на экране блакіроўкі відарыс профілю"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Прыярытэт"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> не падтрымлівае функцыі размовы"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Гэтыя апавяшчэнні нельга змяніць."</string>
@@ -576,6 +585,7 @@
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"SMS-паведамленні"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"Музыка"</string>
<string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Каляндар"</string>
+ <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Не турбаваць"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"Доступ праз кнопкі рэгулявання гучнасці"</string>
<string name="battery" msgid="769686279459897127">"Акумулятар"</string>
<string name="headset" msgid="4485892374984466437">"Гарнітура"</string>
@@ -694,6 +704,10 @@
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"Wi-Fi выключаны"</string>
<string name="bt_is_off" msgid="7436344904889461591">"Bluetooth выключаны"</string>
+ <string name="dnd_is_off" msgid="3185706903793094463">"Рэжым \"Не турбаваць\" выключаны"</string>
+ <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"Рэжым \"Не турбаваць\" быў уключаны аўтаматычным правілам (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"Рэжым \"Не турбаваць\" быў уключаны праграмай (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"Рэжым \"Не турбаваць\" быў уключаны аўтаматычным правілам ці праграмай."</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"Праграмы, якія працуюць у фонавым рэжыме"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"Дакраніцеся, каб даведацца пра выкарыстанне трафіка і акумулятара"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Выключыць мабільную перадачу даных?"</string>
@@ -718,6 +732,8 @@
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(працоўная)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"Тэлефонны выклік"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(праз праграму \"<xliff:g id="APPLICATION_NAME_S_">%s</xliff:g>\")"</string>
+ <string name="ongoing_privacy_dialog_attribution_label" msgid="3385241594101496292">"(<xliff:g id="ATTRIBUTION_LABEL">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_proxy_label" msgid="1111829599659403249">"(<xliff:g id="ATTRIBUTION_LABEL">%1$s</xliff:g> • <xliff:g id="PROXY_LABEL">%2$s</xliff:g>)"</string>
<string name="privacy_type_camera" msgid="7974051382167078332">"камера"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"геалакацыя"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"мікрафон"</string>
@@ -818,6 +834,9 @@
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(адключана)"</string>
<string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Не ўдалося пераключыцца. Дакраніцеся, каб паўтарыць спробу."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Спалучыць з новай прыладай"</string>
+ <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Для трансляцыі гэтага сеанса адкрыйце праграму."</string>
+ <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Невядомая праграма"</string>
+ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Спыніць трансляцыю"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Нумар зборкі"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Нумар зборкі скапіраваны ў буфер абмену."</string>
<string name="basic_status" msgid="2315371112182658176">"Адкрытая размова"</string>
@@ -851,6 +870,7 @@
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Глядзець нядаўнія паведамленні, прапушчаныя выклікі і абнаўленні стану"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Размова"</string>
+ <string name="paused_by_dnd" msgid="7856941866433556428">"Прыпынена функцыяй \"Не турбаваць\""</string>
<string name="new_notification_text_content_description" msgid="2915029960094389291">"Карыстальнік <xliff:g id="NAME">%1$s</xliff:g> прыслаў паведамленне: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"Карыстальнік <xliff:g id="NAME">%1$s</xliff:g> адправіў відарыс"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"Карыстальнік <xliff:g id="NAME">%1$s</xliff:g> абнавіў стан: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
@@ -891,8 +911,7 @@
<item quantity="many"><xliff:g id="COUNT_1">%s</xliff:g> актыўных праграм</item>
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> актыўнай праграмы</item>
</plurals>
- <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
- <skip />
+ <string name="fgs_dot_content_description" msgid="2865071539464777240">"Новая інфармацыя"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Актыўныя праграмы"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Спыніць"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Спынена"</string>
@@ -900,14 +919,15 @@
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Скапіравана"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"З праграмы \"<xliff:g id="APPNAME">%1$s</xliff:g>\""</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Закрыць інтэрфейс капіравання"</string>
- <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
- <skip />
- <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
- <skip />
- <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
- <skip />
- <!-- no translation found for add (81036585205287996) -->
- <skip />
- <!-- no translation found for manage_users (1823875311934643849) -->
- <skip />
+ <string name="clipboard_edit_text_description" msgid="805254383912962103">"Змяніць скапіраваны тэкст"</string>
+ <string name="clipboard_edit_image_description" msgid="8904857948976041306">"Змяніць скапіраваны відарыс"</string>
+ <string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Адправіць на прыладу паблізу"</string>
+ <string name="add" msgid="81036585205287996">"Дадаць"</string>
+ <string name="manage_users" msgid="1823875311934643849">"Кіраванне карыстальнікамі"</string>
+ <string name="drag_split_not_supported" msgid="4326847447699729722">"Гэта апавяшчэнне нельга перацягнуць на падзелены экран."</string>
+ <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Сетка Wi‑Fi недаступная"</string>
+ <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Прыярытэтны рэжым"</string>
+ <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Будзільнік зададзены"</string>
+ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Камера і мікрафон выключаны"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# апавяшчэнне}one{# апавяшчэнне}few{# апавяшчэнні}many{# апавяшчэнняў}other{# апавяшчэння}}"</string>
</resources>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index f7a1ad65b0f0..f56e57d4a6cf 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -20,14 +20,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4811759950673118541">"Системен ПИ"</string>
- <string name="battery_low_title" msgid="6891106956328275225">"Батерията може скоро да се изтощи"</string>
+ <string name="battery_low_title" msgid="5319680173344341779">"Да се включи ли режимът за запазване на батерията?"</string>
+ <string name="battery_low_description" msgid="3282977755476423966">"Оставащ заряд на батерията: <xliff:g id="PERCENTAGE">%s</xliff:g>. Режимът за запазване на батерията включва тъмната тема, ограничава активността на заден план и отлага известията."</string>
+ <string name="battery_low_intro" msgid="5148725009653088790">"Режимът за запазване на батерията включва тъмната тема, ограничава активността на заден план и отлага известията."</string>
<string name="battery_low_percent_format" msgid="4276661262843170964">"Остава/т <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="invalid_charger_title" msgid="938685362320735167">"Зареждането през USB не е възможно"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"Използвайте оригиналното зарядно устройство"</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Да се включи ли режимът за запазване на батерията?"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Всичко за режима за запазване на батерията"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Включване"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"Включване на режима за запазване на батерията"</string>
+ <string name="battery_saver_start_action" msgid="8353766979886287140">"Включване"</string>
+ <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Не, благодаря"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Авт. завъртане на екрана"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"Да се разреши ли на <xliff:g id="APPLICATION">%1$s</xliff:g> достъп до <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
<string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Наистина ли искате да разрешите на <xliff:g id="APPLICATION">%1$s</xliff:g> достъп до <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nНа приложението не е предоставено разрешение за записване, но е възможно да запише звук чрез това USB устройство."</string>
@@ -111,7 +114,7 @@
<string name="accessibility_phone_button" msgid="4256353121703100427">"Телефон"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Гласова помощ"</string>
<string name="accessibility_wallet_button" msgid="1458258783460555507">"Портфейл"</string>
- <string name="accessibility_qr_code_scanner_button" msgid="7521277927692910795">"Инструмент за сканиране на QR кодове"</string>
+ <string name="accessibility_qr_code_scanner_button" msgid="7521277927692910795">"Скенер за QR кодове"</string>
<string name="accessibility_unlock_button" msgid="122785427241471085">"Отключване"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"Устройството е заключено"</string>
<string name="accessibility_scanning_face" msgid="3093828357921541387">"Извършва се сканиране на лице"</string>
@@ -128,6 +131,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Лицето е удостоверено"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Потвърдено"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Докоснете „Потвърждаване“ за завършване"</string>
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Отключено чрез лицето ви. Натиснете, за да продължите."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Удостоверено"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Използване на ПИН"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Използване на фигура"</string>
@@ -181,6 +185,7 @@
<string name="accessibility_desc_close" msgid="8293708213442107755">"Затваряне"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"пълна тишина"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"само будилници"</string>
+ <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"Не безпокойте."</string>
<string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"Bluetooth."</string>
<string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"Функцията за Bluetooth е включена."</string>
<string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"Будилникът е навит за <xliff:g id="TIME">%s</xliff:g>."</string>
@@ -205,6 +210,7 @@
<string name="dessert_case" msgid="9104973640704357717">"Витрина с десерти"</string>
<string name="start_dreams" msgid="9131802557946276718">"Скрийнсейвър"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
+ <string name="quick_settings_dnd_label" msgid="7728690179108024338">"Не безпокойте"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Няма налични сдвоени устройства"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Батерия: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
@@ -348,6 +354,7 @@
<string name="notification_section_header_alerting" msgid="5581175033680477651">"Известия"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Разговори"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Изчистване на всички беззвучни известия"</string>
+ <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Известията са поставени на пауза от режима „Не безпокойте“"</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"Стартиране сега"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Няма известия"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Това устройство се управлява от родителя ви"</string>
@@ -452,8 +459,8 @@
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Отключване с цел използване"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"При извличането на картите ви възникна проблем. Моля, опитайте отново по-късно"</string>
<string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Настройки за заключения екран"</string>
- <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR код"</string>
- <string name="qr_code_scanner_description" msgid="7937603775306661863">"Докоснете за сканиране"</string>
+ <!-- no translation found for qr_code_scanner_title (5290201053875420785) -->
+ <skip />
<string name="status_bar_work" msgid="5238641949837091056">"Потребителски профил в Work"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Самолетен режим"</string>
<string name="zen_alarm_warning" msgid="7844303238486849503">"Няма да чуете следващия си будилник в <xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -491,6 +498,8 @@
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"&lt;b&gt;Състояние:&lt;/b&gt; Класирано по-ниско"</string>
<string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"Показва се в горната част на известията за разговори и като снимка на потребителския профил на заключения екран"</string>
<string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"Показва се в горната част на известията за разговори и като снимка на потребителския профил на заключения екран, изглежда като балонче"</string>
+ <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"Показва се в горната част на известията за разговори и като снимка на потребителския профил на заключения екран, прекъсва режима „Не безпокойте“"</string>
+ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Показва се в горната част на известията за разговори и като снимка на потребителския профил на заключения екран, изглежда като балонче, прекъсва режима „Не безпокойте“"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Приоритет"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> не поддържа функциите за разговор"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Тези известия не могат да бъдат променяни."</string>
@@ -566,6 +575,7 @@
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"SMS"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"Музика"</string>
<string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Календар"</string>
+ <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Не безпокойте"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"Пряк път към бутоните за силата на звука"</string>
<string name="battery" msgid="769686279459897127">"Батерия"</string>
<string name="headset" msgid="4485892374984466437">"Слушалки"</string>
@@ -684,6 +694,10 @@
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"Функцията за Wi‑Fi е изключена"</string>
<string name="bt_is_off" msgid="7436344904889461591">"Функцията за Bluetooth е изключена"</string>
+ <string name="dnd_is_off" msgid="3185706903793094463">"Режимът „Не безпокойте“ е изключен"</string>
+ <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"Режимът „Не безпокойте“ бе включен от автоматично правило (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"Режимът „Не безпокойте“ бе включен от приложение (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"Режимът „Не безпокойте“ бе включен от автоматично правило или от приложение."</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"Приложения, работещи на заден план"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"Докоснете за информация относно използването на батерията и преноса на данни"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Да се изключат ли мобилните данни?"</string>
@@ -708,6 +722,8 @@
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(служебно)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"Телефонно обаждане"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(чрез <xliff:g id="APPLICATION_NAME_S_">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_label" msgid="3385241594101496292">"(<xliff:g id="ATTRIBUTION_LABEL">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_proxy_label" msgid="1111829599659403249">"(<xliff:g id="ATTRIBUTION_LABEL">%1$s</xliff:g> • <xliff:g id="PROXY_LABEL">%2$s</xliff:g>)"</string>
<string name="privacy_type_camera" msgid="7974051382167078332">"камерата"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"местополож."</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"микрофона"</string>
@@ -806,6 +822,9 @@
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(връзката е прекратена)"</string>
<string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Не може да се превключи. Докоснете за нов опит."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Сдвояване на ново устройство"</string>
+ <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"За да предавате тази сесия, моля, отворете приложението."</string>
+ <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Неизвестно приложение"</string>
+ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Спиране на предаването"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Номер на компилацията"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Номерът на компилацията е копиран в буферната памет."</string>
<string name="basic_status" msgid="2315371112182658176">"Отворен разговор"</string>
@@ -839,6 +858,7 @@
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"Над <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Преглеждайте скорошни съобщения, пропуснати обаждания и информация за състоянието"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Разговор"</string>
+ <string name="paused_by_dnd" msgid="7856941866433556428">"Поставено на пауза от режима „Не безпокойте“"</string>
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> изпрати съобщение: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> изпрати изображение"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> има актуализация на състоянието: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
@@ -877,8 +897,7 @@
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> активни приложения</item>
<item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> активно приложение</item>
</plurals>
- <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
- <skip />
+ <string name="fgs_dot_content_description" msgid="2865071539464777240">"Нова информация"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Активни приложения"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Спиране"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Спряно"</string>
@@ -886,14 +905,15 @@
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Копирано"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"От <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Отхвърляне на ПИ за копиране"</string>
- <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
- <skip />
- <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
- <skip />
- <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
- <skip />
- <!-- no translation found for add (81036585205287996) -->
- <skip />
- <!-- no translation found for manage_users (1823875311934643849) -->
- <skip />
+ <string name="clipboard_edit_text_description" msgid="805254383912962103">"Редактиране на копирания текст"</string>
+ <string name="clipboard_edit_image_description" msgid="8904857948976041306">"Редактиране на копираното изображение"</string>
+ <string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Изпращане до устройство в близост"</string>
+ <string name="add" msgid="81036585205287996">"Добавяне"</string>
+ <string name="manage_users" msgid="1823875311934643849">"Управление на потребителите"</string>
+ <string name="drag_split_not_supported" msgid="4326847447699729722">"Това известие не поддържа плъзгане за разделяне на екрана."</string>
+ <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi не е налице"</string>
+ <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Приоритетен режим"</string>
+ <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Будилникът е зададен"</string>
+ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Камерата и микрофонът са изключени"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# известие}other{# известия}}"</string>
</resources>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index 36a5bc48b2b4..2730b4cc3ebf 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -20,14 +20,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4811759950673118541">"সিস্টেম UI"</string>
- <string name="battery_low_title" msgid="6891106956328275225">"চার্জ শীঘ্রই শেষ হয়ে যেতে পারে"</string>
+ <string name="battery_low_title" msgid="5319680173344341779">"\'ব্যাটারি সেভার\' চালু করতে চান?"</string>
+ <string name="battery_low_description" msgid="3282977755476423966">"আপনার আর <xliff:g id="PERCENTAGE">%s</xliff:g> ব্যাটারি আছে। ব্যাটারি সেভার ডার্ক থিম চালু করে, ব্যাকগ্রাউন্ড অ্যাক্টিভিটি সীমিত করে এবং বিজ্ঞপ্তিতে দেরি করে।"</string>
+ <string name="battery_low_intro" msgid="5148725009653088790">"ব্যাটারি সেভার ডার্ক থিম চালু করে, ব্যাকগ্রাউন্ড অ্যাক্টিভিটি সীমিত করে এবং বিজ্ঞপ্তিতে দেরি করে।"</string>
<string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> অবশিষ্ট আছে"</string>
<string name="invalid_charger_title" msgid="938685362320735167">"ইউএসবি দিয়ে চার্জ করা যাবে না"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"ডিভাইসের সাথে যে চার্জারটি পেয়েছেন, সেটি ব্যবহার করুন"</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"ব্যাটারি সেভার চালু করবেন?"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"ব্যাটারি সেভার সম্পর্কে"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"চালু করুন"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"ব্যাটারি সেভার চালু করুন"</string>
+ <string name="battery_saver_start_action" msgid="8353766979886287140">"চালু করুন"</string>
+ <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"না থাক"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"অটো-রোটেট স্ক্রিন"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"<xliff:g id="APPLICATION">%1$s</xliff:g> কে <xliff:g id="USB_DEVICE">%2$s</xliff:g> অ্যাক্সেস করতে দেবেন?"</string>
<string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> অ্যাক্সেস করতে <xliff:g id="APPLICATION">%1$s</xliff:g>-কে কি অনুমতি দেবেন?\nএই অ্যাপকে রেকর্ড করার অনুমতি দেওয়া হয়নি কিন্তু USB ডিভাইসের মাধ্যমে সেটি অডিও রেকর্ড করতে পারে।"</string>
@@ -128,6 +131,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"ফেস যাচাই করা হয়েছে"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"কনফার্ম করা হয়েছে"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"সম্পূর্ণ করতে \'কনফার্ম করুন\' বোতামে ট্যাপ করুন"</string>
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"আপনার মুখ মাধ্যমে আনলক করা হয়েছে। চালিয়ে যেতে প্রেস করুন।"</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"প্রমাণীকৃত"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"পিন ব্যবহার করুন"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"প্যাটার্ন ব্যবহার করুন"</string>
@@ -181,6 +185,7 @@
<string name="accessibility_desc_close" msgid="8293708213442107755">"বন্ধ করুন"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"সম্পূর্ণ নীরব"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"শুধুমাত্র অ্যালার্ম"</string>
+ <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"বিরক্ত করবে না।"</string>
<string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"ব্লুটুথ"</string>
<string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"ব্লুটুথ চালু আছে।"</string>
<string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"<xliff:g id="TIME">%s</xliff:g> এ অ্যালার্ম সেট করা হয়েছে৷"</string>
@@ -205,6 +210,7 @@
<string name="dessert_case" msgid="9104973640704357717">"ডেজার্ট কেস"</string>
<string name="start_dreams" msgid="9131802557946276718">"স্ক্রিন সেভার"</string>
<string name="ethernet_label" msgid="2203544727007463351">"ইথারনেট"</string>
+ <string name="quick_settings_dnd_label" msgid="7728690179108024338">"বিরক্ত করবে না"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"ব্লুটুথ"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"চেনা কোনও ডিভাইস নেই"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"চার্জ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
@@ -348,6 +354,7 @@
<string name="notification_section_header_alerting" msgid="5581175033680477651">"বিজ্ঞপ্তি"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"কথোপকথন"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"সব নীরব বিজ্ঞপ্তি মুছুন"</string>
+ <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"\'বিরক্ত করবে না\' দিয়ে বিজ্ঞপ্তি পজ করা হয়েছে"</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"এখন শুরু করুন"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"কোনো বিজ্ঞপ্তি নেই"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"আপনার অভিভাবক এই ডিভাইস ম্যানেজ করেন"</string>
@@ -452,8 +459,8 @@
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"ব্যবহার করতে আনলক করুন"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"আপনার কার্ড সংক্রান্ত তথ্য পেতে সমস্যা হয়েছে, পরে আবার চেষ্টা করুন"</string>
<string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"লক স্ক্রিন সেটিংস"</string>
- <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR কোড"</string>
- <string name="qr_code_scanner_description" msgid="7937603775306661863">"স্ক্যান করতে ট্যাপ করুন"</string>
+ <!-- no translation found for qr_code_scanner_title (5290201053875420785) -->
+ <skip />
<string name="status_bar_work" msgid="5238641949837091056">"কাজের প্রোফাইল"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"বিমান মোড"</string>
<string name="zen_alarm_warning" msgid="7844303238486849503">"আপনি আপনার পরবর্তী <xliff:g id="WHEN">%1$s</xliff:g> অ্যালার্ম শুনতে পাবেন না"</string>
@@ -491,6 +498,8 @@
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"&lt;b&gt;স্ট্যাটাস:&lt;/b&gt; র‍্যাঙ্ক কমে গেছে"</string>
<string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"কথোপকথনের বিজ্ঞপ্তির উপরের দিকে এবং প্রোফাইল ছবি হিসেবে লক স্ক্রিনে দেখানো হয়"</string>
<string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"কথোপকথনের বিজ্ঞপ্তির উপরের দিকে এবং প্রোফাইল ছবি হিসেবে লক স্ক্রিনে দেখানো হয়, বাবল হিসেবেও এটি দেখা যায়"</string>
+ <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"কথোপকথনের বিজ্ঞপ্তির উপরের দিকে এবং প্রোফাইল ছবি হিসেবে লক স্ক্রিনে দেখানো হয় এবং এর ফলে \'বিরক্ত করবে না\' মোডে কাজ করতে অসুবিধা হয়"</string>
+ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"কথোপকথনের বিজ্ঞপ্তির উপরের দিকে এবং প্রোফাইল ছবি হিসেবে লক স্ক্রিনে দেখানো হয়, বাবল হিসেবেও এটি দেখা যায় এবং এর ফলে \'বিরক্ত করবে না\' মোডে কাজ করতে অসুবিধা হয়"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"অগ্রাধিকার"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g>-এ কথোপকথন ফিচার কাজ করে না"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"এই বিজ্ঞপ্তিগুলি পরিবর্তন করা যাবে না।"</string>
@@ -566,6 +575,7 @@
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"SMS"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"সংগীত"</string>
<string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Calendar"</string>
+ <string name="volume_and_do_not_disturb" msgid="502044092739382832">"বিরক্ত করবে না"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"ভলিউম বোতামের শর্টকাট"</string>
<string name="battery" msgid="769686279459897127">"ব্যাটারি"</string>
<string name="headset" msgid="4485892374984466437">"হেডসেট"</string>
@@ -684,6 +694,10 @@
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"ওয়াই ফাই বন্ধ আছে"</string>
<string name="bt_is_off" msgid="7436344904889461591">"ব্লুটুথ বন্ধ আছে"</string>
+ <string name="dnd_is_off" msgid="3185706903793094463">"বিরক্ত করবে না বিকল্পটি বন্ধ আছে"</string>
+ <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"বিরক্ত করবে না বিকল্পটি একটি স্বয়ংক্রিয় নিয়ম <xliff:g id="ID_1">%s</xliff:g> এর দ্বারা চালু করা হয়েছে।"</string>
+ <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"বিরক্ত করবে না বিকল্পটি একটি অ্যাপ <xliff:g id="ID_1">%s</xliff:g> এর দ্বারা চালু করা হয়েছে।"</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"বিরক্ত করবে না বিকল্পটি একটি স্বয়ংক্রিয় নিয়ম বা অ্যাপের দ্বারা চালু করা হয়েছে।"</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"পটভূমিতে অ্যাপ চালু আছে"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"ব্যাটারি এবং ডেটার ব্যবহারের বিশদ বিবরণের জন্য ট্যাপ করুন"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"মোবাইল ডেটা বন্ধ করবেন?"</string>
@@ -708,6 +722,8 @@
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(অফিস)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"ফোন কল"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(<xliff:g id="APPLICATION_NAME_S_">%s</xliff:g>-এর সাহায্যে)"</string>
+ <string name="ongoing_privacy_dialog_attribution_label" msgid="3385241594101496292">"(<xliff:g id="ATTRIBUTION_LABEL">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_proxy_label" msgid="1111829599659403249">"(<xliff:g id="ATTRIBUTION_LABEL">%1$s</xliff:g> • <xliff:g id="PROXY_LABEL">%2$s</xliff:g>)"</string>
<string name="privacy_type_camera" msgid="7974051382167078332">"ক্যামেরা"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"লোকেশন"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"মাইক্রোফোন"</string>
@@ -806,6 +822,9 @@
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(ডিসকানেক্ট হয়ে গেছে)"</string>
<string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"পাল্টানো যাচ্ছে না। আবার চেষ্টা করতে ট্যাপ করুন।"</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"নতুন ডিভাইস পেয়ার করুন"</string>
+ <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"এই সেশন কাস্ট করার জন্য, অ্যাপ খুলুন।"</string>
+ <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"অজানা অ্যাপ"</string>
+ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"কাস্ট করা বন্ধ করুন"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"বিল্ড নম্বর"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"বিল্ড নম্বর ক্লিপবোর্ডে কপি করা হয়েছে।"</string>
<string name="basic_status" msgid="2315371112182658176">"খোলা কথোপকথন"</string>
@@ -839,6 +858,7 @@
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"সাম্প্রতিক মেসেজ, মিসড কল এবং স্ট্যাটাস সংক্রান্ত আপডেট দেখুন"</string>
<string name="people_tile_title" msgid="6589377493334871272">"কথোপকথন"</string>
+ <string name="paused_by_dnd" msgid="7856941866433556428">"\'বিরক্ত করবে না\' মোডের মাধ্যমে পজ করা আছে"</string>
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> একটি মেসেজ পাঠিয়েছেন: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> একটি ছবি পাঠিয়েছেন"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> একটি স্ট্যাটাস আপডেট করেছেন: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
@@ -877,8 +897,7 @@
<item quantity="one"><xliff:g id="COUNT_1">%s</xliff:g>টি অ্যাক্টিভ অ্যাপ</item>
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g>টি অ্যাক্টিভ অ্যাপ</item>
</plurals>
- <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
- <skip />
+ <string name="fgs_dot_content_description" msgid="2865071539464777240">"নতুন তথ্য"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"অ্যাক্টিভ অ্যাপ"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"বন্ধ করুন"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"থামানো হয়েছে"</string>
@@ -889,8 +908,12 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"কপি করা টেক্সট এডিট করুন"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"কপি করা ছবি এডিট করুন"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"আশেপাশের ডিভাইসে পাঠান"</string>
- <!-- no translation found for add (81036585205287996) -->
- <skip />
- <!-- no translation found for manage_users (1823875311934643849) -->
- <skip />
+ <string name="add" msgid="81036585205287996">"যোগ করুন"</string>
+ <string name="manage_users" msgid="1823875311934643849">"ব্যবহারকারীদের ম্যানেজ করুন"</string>
+ <string name="drag_split_not_supported" msgid="4326847447699729722">"স্প্লিটস্ক্রিন মোডে এই বিজ্ঞপ্তি টেনে আনা যাবে না।"</string>
+ <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"ওয়াই-ফাই উপলভ্য নেই"</string>
+ <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"প্রায়োরিটি মোড"</string>
+ <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"অ্যালার্ম সেট করা হয়েছে"</string>
+ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"ক্যামেরা ও মাইক্রোফোন বন্ধ আছে"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{#টি বিজ্ঞপ্তি}one{#টি বিজ্ঞপ্তি}other{#টি বিজ্ঞপ্তি}}"</string>
</resources>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index 1545c43aafbd..00973eee5674 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -20,14 +20,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4811759950673118541">"Sistemski UI"</string>
- <string name="battery_low_title" msgid="6891106956328275225">"Baterija će se uskoro isprazniti"</string>
+ <string name="battery_low_title" msgid="5319680173344341779">"Uključiti Uštedu baterije?"</string>
+ <string name="battery_low_description" msgid="3282977755476423966">"Preostalo vam je još <xliff:g id="PERCENTAGE">%s</xliff:g> baterije. Ušteda baterije uključuje tamnu temu, ograničava aktivnost u pozadini i odgađa obavještenja."</string>
+ <string name="battery_low_intro" msgid="5148725009653088790">"Ušteda baterije uključuje tamnu temu, ograničava aktivnost u pozadini i odgađa obavještenja."</string>
<string name="battery_low_percent_format" msgid="4276661262843170964">"Preostalo <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="invalid_charger_title" msgid="938685362320735167">"Punjenje putem USB-a nije moguće"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"Koristite punjač koji ste dobili uz uređaj"</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Uključiti Uštedu baterije?"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Informacije o Uštedi baterije"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Uključi"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"Uključi Uštedu baterije"</string>
+ <string name="battery_saver_start_action" msgid="8353766979886287140">"Uključi"</string>
+ <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Ne, hvala"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Automatsko rotiranje ekrana"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"Dozvoliti aplikaciji <xliff:g id="APPLICATION">%1$s</xliff:g> pristup uređaju: <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
<string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Dozvoliti aplikaciji <xliff:g id="APPLICATION">%1$s</xliff:g> pristup uređaju <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nOvoj aplikaciji nije dato odobrenje za snimanje, ali može snimati zvuk putem ovog USB uređaja."</string>
@@ -111,7 +114,7 @@
<string name="accessibility_phone_button" msgid="4256353121703100427">"Telefon"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Glasovna pomoć"</string>
<string name="accessibility_wallet_button" msgid="1458258783460555507">"Novčanik"</string>
- <string name="accessibility_qr_code_scanner_button" msgid="7521277927692910795">"Skener QR kôda"</string>
+ <string name="accessibility_qr_code_scanner_button" msgid="7521277927692910795">"Skener QR koda"</string>
<string name="accessibility_unlock_button" msgid="122785427241471085">"Otključaj"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"Uređaj je zaključan"</string>
<string name="accessibility_scanning_face" msgid="3093828357921541387">"Skeniranje lica"</string>
@@ -128,6 +131,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Lice je provjereno"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Potvrđeno"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Dodirnite Potvrdi da završite"</string>
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Otključano vašim licem. Pritisnite da nastavite."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Autentificirano"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Koristi PIN"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Koristi uzorak"</string>
@@ -181,6 +185,7 @@
<string name="accessibility_desc_close" msgid="8293708213442107755">"Zatvori"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"potpuna tišina"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"samo alarmi"</string>
+ <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"Ne ometaj."</string>
<string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"Bluetooth."</string>
<string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"Bluetooth uključen."</string>
<string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"Alarm je podešen na <xliff:g id="TIME">%s</xliff:g>."</string>
@@ -206,6 +211,7 @@
<string name="dessert_case" msgid="9104973640704357717">"Slika sa desertima"</string>
<string name="start_dreams" msgid="9131802557946276718">"Čuvar ekrana"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
+ <string name="quick_settings_dnd_label" msgid="7728690179108024338">"Ne ometaj"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Nema dostupnih uparenih uređaja"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> baterije"</string>
@@ -351,6 +357,7 @@
<string name="notification_section_header_alerting" msgid="5581175033680477651">"Obavještenja"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Razgovori"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Obriši sva nečujna obavještenja"</string>
+ <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Obavještenja su pauzirana načinom rada Ne ometaj"</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"Započni odmah"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Nema obavještenja"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Ovim uređajem upravlja tvoj roditelj"</string>
@@ -455,8 +462,7 @@
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Otključajte da koristite"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Došlo je do problema prilikom preuzimanja vaših kartica. Pokušajte ponovo kasnije"</string>
<string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Postavke zaključavanja ekrana"</string>
- <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR kôd"</string>
- <string name="qr_code_scanner_description" msgid="7937603775306661863">"Dodirnite da skenirate"</string>
+ <string name="qr_code_scanner_title" msgid="5290201053875420785">"Skeniraj QR kôd"</string>
<string name="status_bar_work" msgid="5238641949837091056">"Profil za posao"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Način rada u avionu"</string>
<string name="zen_alarm_warning" msgid="7844303238486849503">"Nećete čuti sljedeći alarm u <xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -494,6 +500,8 @@
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"&lt;b&gt;Status:&lt;/b&gt; je rangiran niže"</string>
<string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"Prikazuje se na vrhu obavještenja u razgovorima i kao slika profila na zaključanom ekranu"</string>
<string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"Prikazuje se na vrhu obavještenja u razgovorima i kao slika profila na zaključanom ekranu, izgleda kao oblačić"</string>
+ <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"Prikazuje se na vrhu obavještenja u razgovorima i kao slika profila na zaključanom ekranu, prekida funkciju Ne ometaj"</string>
+ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Prikazuje se na vrhu obavještenja u razgovorima i kao slika profila na zaključanom ekranu, izgleda kao oblačić, prekida funkciju Ne ometaj"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritetno"</string>
<string name="no_shortcut" msgid="8257177117568230126">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> ne podržava funkcije razgovora"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Ta obavještenja se ne mogu izmijeniti."</string>
@@ -571,6 +579,7 @@
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"SMS"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"Muzika"</string>
<string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Kalendar"</string>
+ <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Ne ometaj"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"Prečica za dugmad za Jačinu zvuka"</string>
<string name="battery" msgid="769686279459897127">"Baterija"</string>
<string name="headset" msgid="4485892374984466437">"Slušalice s mikrofonom"</string>
@@ -689,10 +698,14 @@
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"WiFi veza je isključena"</string>
<string name="bt_is_off" msgid="7436344904889461591">"Bluetooth je isključen"</string>
+ <string name="dnd_is_off" msgid="3185706903793094463">"Način rada Ne ometaj je isključen"</string>
+ <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"Opciju Ne ometaju uključilo je automatsko pravilo (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"Način rada Ne ometaj uključila je aplikacija <xliff:g id="ID_1">%s</xliff:g>."</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"Način rada Ne ometaj uključilo je automatsko pravilo ili aplikacija."</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"Aplikacije koje rade u pozadini"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"Dodirnite za detalje o potrošnji baterije i prijenosa podataka"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Isključiti prijenos podataka na mobilnoj mreži?"</string>
- <string name="mobile_data_disable_message" msgid="8604966027899770415">"Nećete imati pristup podacima ni internetu putem mobilnog operatera <xliff:g id="CARRIER">%s</xliff:g>. Internet će biti dostupan samo putem WiFi mreže."</string>
+ <string name="mobile_data_disable_message" msgid="8604966027899770415">"Nećete imati pristup podacima ni internetu putem mobilnog operatera <xliff:g id="CARRIER">%s</xliff:g>. Internet će biti dostupan samo putem WiFi-ja."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"vaš operater"</string>
<string name="touch_filtered_warning" msgid="8119511393338714836">"Postavke ne mogu potvrditi vaš odgovor jer aplikacija zaklanja zahtjev za odobrenje."</string>
<string name="slice_permission_title" msgid="3262615140094151017">"Dozvoliti aplikaciji <xliff:g id="APP_0">%1$s</xliff:g> da prikazuje isječke aplikacije <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
@@ -713,6 +726,8 @@
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(posao)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"Telefonski poziv"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(putem aplikacije <xliff:g id="APPLICATION_NAME_S_">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_label" msgid="3385241594101496292">"(<xliff:g id="ATTRIBUTION_LABEL">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_proxy_label" msgid="1111829599659403249">"(<xliff:g id="ATTRIBUTION_LABEL">%1$s</xliff:g> • <xliff:g id="PROXY_LABEL">%2$s</xliff:g>)"</string>
<string name="privacy_type_camera" msgid="7974051382167078332">"kameru"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"lokaciju"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofon"</string>
@@ -812,6 +827,9 @@
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(veza je prekinuta)"</string>
<string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Nije moguće prebaciti. Dodirnite da pokušate ponovo."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Uparite novi uređaj"</string>
+ <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Da emitirate ovu sesiju, otvorite aplikaciju."</string>
+ <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Nepoznata aplikacija"</string>
+ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Zaustavi emitiranje"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Broj verzije"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Broj verzije je kopiran u međumemoriju."</string>
<string name="basic_status" msgid="2315371112182658176">"Otvoreni razgovor"</string>
@@ -845,6 +863,7 @@
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Pregledajte nedavne poruke, propuštene pozive i ažuriranja statusa"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Razgovor"</string>
+ <string name="paused_by_dnd" msgid="7856941866433556428">"Pauzirala je funkcija Ne ometaj"</string>
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> je poslao/la poruku: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> je poslao/la sliku"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> je ažurirao/la status: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
@@ -884,8 +903,7 @@
<item quantity="few"><xliff:g id="COUNT_1">%s</xliff:g> aktivne aplikacije</item>
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> aktivnih aplikacija</item>
</plurals>
- <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
- <skip />
+ <string name="fgs_dot_content_description" msgid="2865071539464777240">"Nove informacije"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Aktivne aplikacije"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Zaustavi"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Zaustavljeno"</string>
@@ -896,8 +914,12 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Uredi kopirani tekst"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Uredi kopiranu sliku"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Pošalji na uređaj u blizini"</string>
- <!-- no translation found for add (81036585205287996) -->
- <skip />
- <!-- no translation found for manage_users (1823875311934643849) -->
- <skip />
+ <string name="add" msgid="81036585205287996">"Dodaj"</string>
+ <string name="manage_users" msgid="1823875311934643849">"Upravljajte korisnicima"</string>
+ <string name="drag_split_not_supported" msgid="4326847447699729722">"Ovo obavještenje ne podržava prevlačenje na podijeljeni ekran."</string>
+ <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"WiFi je nedostupan"</string>
+ <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Način rada Prioriteti"</string>
+ <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarm je postavljen"</string>
+ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Kamera i mikrofon su isključeni"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# obavještenje}one{# obavještenje}few{# obavještenja}other{# obavještenja}}"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 621f5f9a5383..975f4e0f1f53 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -20,14 +20,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4811759950673118541">"IU del sistema"</string>
- <string name="battery_low_title" msgid="6891106956328275225">"És possible que la bateria s\'esgoti aviat"</string>
+ <string name="battery_low_title" msgid="5319680173344341779">"Vols activar Estalvi de bateria?"</string>
+ <string name="battery_low_description" msgid="3282977755476423966">"Et queda un <xliff:g id="PERCENTAGE">%s</xliff:g> de bateria. Estalvi de bateria activa el tema fosc, restringeix l\'activitat en segon pla i endarrereix les notificacions."</string>
+ <string name="battery_low_intro" msgid="5148725009653088790">"Estalvi de bateria activa el tema fosc, restringeix l\'activitat en segon pla i endarrereix les notificacions."</string>
<string name="battery_low_percent_format" msgid="4276661262843170964">"Queda un <xliff:g id="PERCENTAGE">%s</xliff:g>."</string>
<string name="invalid_charger_title" msgid="938685362320735167">"No es pot carregar per USB"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"Fes servir el carregador original del dispositiu"</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Vols activar la funció Estalvi de bateria?"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Sobre la funció Estalvi de bateria"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Activa"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"Activa la funció Estalvi de bateria"</string>
+ <string name="battery_saver_start_action" msgid="8353766979886287140">"Activa"</string>
+ <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"No, gràcies"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Gira la pantalla automàticament"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"Vols permetre que <xliff:g id="APPLICATION">%1$s</xliff:g> accedeixi a <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
<string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Vols permetre que <xliff:g id="APPLICATION">%1$s</xliff:g> accedeixi a <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nAquesta aplicació no té permís de gravació, però pot capturar àudio a través d\'aquest dispositiu USB."</string>
@@ -128,6 +131,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Cara autenticada"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Confirmat"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Toca Confirma per completar"</string>
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"S\'ha desbloquejat amb la cara. Prem per continuar."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Autenticat"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Utilitza el PIN"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Utilitza el patró"</string>
@@ -181,6 +185,7 @@
<string name="accessibility_desc_close" msgid="8293708213442107755">"Tanca"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"silenci total"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"només alarmes"</string>
+ <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"No molestis."</string>
<string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"Bluetooth."</string>
<string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"Bluetooth activat."</string>
<string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"S\'ha configurat l\'alarma (<xliff:g id="TIME">%s</xliff:g>)."</string>
@@ -205,6 +210,7 @@
<string name="dessert_case" msgid="9104973640704357717">"Capsa de postres"</string>
<string name="start_dreams" msgid="9131802557946276718">"Estalvi de pantalla"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
+ <string name="quick_settings_dnd_label" msgid="7728690179108024338">"No molestis"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"No hi ha dispositius vinculats disponibles"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> de bateria"</string>
@@ -348,6 +354,7 @@
<string name="notification_section_header_alerting" msgid="5581175033680477651">"Notificacions"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Converses"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Esborra totes les notificacions silencioses"</string>
+ <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Notificacions pausades pel mode No molestis"</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"Comença ara"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"No hi ha cap notificació"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Els teus pares gestionen aquest dispositiu"</string>
@@ -452,8 +459,8 @@
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Desbloqueja per utilitzar"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Hi ha hagut un problema en obtenir les teves targetes; torna-ho a provar més tard"</string>
<string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Configuració de la pantalla de bloqueig"</string>
- <string name="qr_code_scanner_title" msgid="5660820608548306581">"Codi QR"</string>
- <string name="qr_code_scanner_description" msgid="7937603775306661863">"Toca per escanejar"</string>
+ <!-- no translation found for qr_code_scanner_title (5290201053875420785) -->
+ <skip />
<string name="status_bar_work" msgid="5238641949837091056">"Perfil de treball"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Mode d\'avió"</string>
<string name="zen_alarm_warning" msgid="7844303238486849503">"<xliff:g id="WHEN">%1$s</xliff:g> no sentiràs la pròxima alarma"</string>
@@ -491,6 +498,8 @@
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"&lt;b&gt;Estat&lt;/b&gt;: s\'ha classificat amb un nivell inferior"</string>
<string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"Es mostra a la part superior de les notificacions de les converses i com a foto de perfil a la pantalla de bloqueig"</string>
<string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"Es mostra a la part superior de les notificacions de les converses i com a foto de perfil a la pantalla de bloqueig, apareix com una bombolla"</string>
+ <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"Es mostra a la part superior de les notificacions de les converses i com a foto de perfil a la pantalla de bloqueig, interromp el mode No molestis"</string>
+ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Es mostra a la part superior de les notificacions de les converses i com a foto de perfil a la pantalla de bloqueig, apareix com una bombolla, interromp el mode No molestis"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritat"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> no admet les funcions de converses"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Aquestes notificacions no es poden modificar."</string>
@@ -566,6 +575,7 @@
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"SMS"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"Música"</string>
<string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Calendar"</string>
+ <string name="volume_and_do_not_disturb" msgid="502044092739382832">"No molestis"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"Drecera per als botons de volum"</string>
<string name="battery" msgid="769686279459897127">"Bateria"</string>
<string name="headset" msgid="4485892374984466437">"Auriculars"</string>
@@ -684,6 +694,10 @@
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"La Wi-Fi està desactivada"</string>
<string name="bt_is_off" msgid="7436344904889461591">"El Bluetooth està desactivat"</string>
+ <string name="dnd_is_off" msgid="3185706903793094463">"El mode No molestis està desactivat"</string>
+ <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"Una regla automàtica (<xliff:g id="ID_1">%s</xliff:g>) ha activat el mode No molestis."</string>
+ <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"Una aplicació (<xliff:g id="ID_1">%s</xliff:g>) ha activat el mode No molestis."</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"Una regla automàtica o una aplicació han activat el mode No molestis."</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"Aplicacions que s\'estan executant en segon pla"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"Toca per obtenir informació sobre l\'ús de dades i de bateria"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Vols desactivar les dades mòbils?"</string>
@@ -708,6 +722,8 @@
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(feina)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"Trucada"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(a través de: <xliff:g id="APPLICATION_NAME_S_">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_label" msgid="3385241594101496292">"(<xliff:g id="ATTRIBUTION_LABEL">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_proxy_label" msgid="1111829599659403249">"(<xliff:g id="ATTRIBUTION_LABEL">%1$s</xliff:g> • <xliff:g id="PROXY_LABEL">%2$s</xliff:g>)"</string>
<string name="privacy_type_camera" msgid="7974051382167078332">"càmera"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"ubicació"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"micròfon"</string>
@@ -806,6 +822,9 @@
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(desconnectat)"</string>
<string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"No es pot canviar. Torna-ho a provar."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Vincula un dispositiu nou"</string>
+ <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Per emetre aquesta sessió, obre l\'aplicació."</string>
+ <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Aplicació desconeguda"</string>
+ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Atura l\'emissió"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Número de compilació"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"El número de compilació s\'ha copiat al porta-retalls."</string>
<string name="basic_status" msgid="2315371112182658176">"Conversa oberta"</string>
@@ -839,6 +858,7 @@
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Consulta els missatges recents, les trucades perdudes i les actualitzacions d\'estat"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Conversa"</string>
+ <string name="paused_by_dnd" msgid="7856941866433556428">"Posat en pausa pel mode No molestis"</string>
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> ha enviat un missatge: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> ha enviat una imatge"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> té una actualització d\'estat: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
@@ -877,8 +897,7 @@
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> aplicacions actives</item>
<item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> aplicació activa</item>
</plurals>
- <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
- <skip />
+ <string name="fgs_dot_content_description" msgid="2865071539464777240">"Informació nova"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Aplicacions actives"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Atura"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Aturada"</string>
@@ -886,14 +905,15 @@
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"S\'ha copiat"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"De: <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Ignora la IU de còpia"</string>
- <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
- <skip />
- <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
- <skip />
- <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
- <skip />
- <!-- no translation found for add (81036585205287996) -->
- <skip />
- <!-- no translation found for manage_users (1823875311934643849) -->
- <skip />
+ <string name="clipboard_edit_text_description" msgid="805254383912962103">"Edita el text que has copiat"</string>
+ <string name="clipboard_edit_image_description" msgid="8904857948976041306">"Edita la imatge que has copiat"</string>
+ <string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Envia a un dispositiu proper"</string>
+ <string name="add" msgid="81036585205287996">"Afegeix"</string>
+ <string name="manage_users" msgid="1823875311934643849">"Gestiona els usuaris"</string>
+ <string name="drag_split_not_supported" msgid="4326847447699729722">"Aquesta notificació no es pot arrossegar a la pantalla dividida."</string>
+ <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi no disponible"</string>
+ <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Mode Prioritat"</string>
+ <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarma definida"</string>
+ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Càmera i micròfon desactivats"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notificació}other{# notificacions}}"</string>
</resources>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index ba976883136f..ee9a04fe2dd6 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -20,14 +20,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4811759950673118541">"UI systému"</string>
- <string name="battery_low_title" msgid="6891106956328275225">"Baterie se brzy vybije"</string>
+ <string name="battery_low_title" msgid="5319680173344341779">"Zapnout spořič baterie?"</string>
+ <string name="battery_low_description" msgid="3282977755476423966">"Zbývá <xliff:g id="PERCENTAGE">%s</xliff:g> baterie. Spořič baterie zapne tmavý motiv, omezí aktivitu na pozadí a pozdrží oznámení."</string>
+ <string name="battery_low_intro" msgid="5148725009653088790">"Spořič baterie zapne tmavý motiv, omezí aktivitu na pozadí a pozdrží oznámení."</string>
<string name="battery_low_percent_format" msgid="4276661262843170964">"Zbývá <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="invalid_charger_title" msgid="938685362320735167">"Nabíjení přes USB nefunguje"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"Používejte originální nabíječku, která byla dodána spolu se zařízením."</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Zapnout spořič baterie?"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Informace o spořiči baterie"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Zapnout"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"Zapnout spořič baterie"</string>
+ <string name="battery_saver_start_action" msgid="8353766979886287140">"Zapnout"</string>
+ <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Ne, díky"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Automatické otočení obrazovky"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"Povolit aplikaci <xliff:g id="APPLICATION">%1$s</xliff:g> přístup k zařízení <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
<string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Povolit aplikaci <xliff:g id="APPLICATION">%1$s</xliff:g> přístup k zařízení <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nTato aplikace nemá oprávnění k nahrávání, ale může zaznamenávat zvuk prostřednictvím tohoto zařízení USB."</string>
@@ -128,6 +131,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Obličej byl ověřen"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Potvrzeno"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Ověření dokončíte klepnutím na Potvrdit"</string>
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Odemyká se obličejem. Pokračujte stisknutím."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Ověřeno"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Použít kód PIN"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Použít gesto"</string>
@@ -181,6 +185,7 @@
<string name="accessibility_desc_close" msgid="8293708213442107755">"Zavřít"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"úplné ticho"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"pouze budíky"</string>
+ <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"Nerušit."</string>
<string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"Bluetooth."</string>
<string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"Rozhraní Bluetooth je zapnuto."</string>
<string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"Budík je nastaven na <xliff:g id="TIME">%s</xliff:g>."</string>
@@ -207,6 +212,7 @@
<string name="dessert_case" msgid="9104973640704357717">"Pult se sladkostmi"</string>
<string name="start_dreams" msgid="9131802557946276718">"Spořič obrazovky"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
+ <string name="quick_settings_dnd_label" msgid="7728690179108024338">"Nerušit"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Nejsou dostupná žádná spárovaná zařízení"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Baterie: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
@@ -354,6 +360,7 @@
<string name="notification_section_header_alerting" msgid="5581175033680477651">"Oznámení"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Konverzace"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Vymazat všechna tichá oznámení"</string>
+ <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Oznámení jsou pozastavena režimem Nerušit"</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"Spustit"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Žádná oznámení"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Toto zařízení spravuje rodič"</string>
@@ -458,8 +465,8 @@
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Odemknout a použít"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Při načítání karet došlo k problému, zkuste to později"</string>
<string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Nastavení obrazovky uzamčení"</string>
- <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR kód"</string>
- <string name="qr_code_scanner_description" msgid="7937603775306661863">"Klepnutím naskenujete kód"</string>
+ <!-- no translation found for qr_code_scanner_title (5290201053875420785) -->
+ <skip />
<string name="status_bar_work" msgid="5238641949837091056">"Pracovní profil"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Režim Letadlo"</string>
<string name="zen_alarm_warning" msgid="7844303238486849503">"Svůj další budík <xliff:g id="WHEN">%1$s</xliff:g> neuslyšíte"</string>
@@ -497,6 +504,8 @@
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"&lt;b&gt;Stav:&lt;/b&gt; zařazeno níže"</string>
<string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"Zobrazuje se v horní části sekce konverzací a na obrazovce uzamčení se objevuje jako profilová fotka"</string>
<string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"Zobrazuje se v horní části sekce konverzací a na obrazovce uzamčení se objevuje jako profilová fotka, má podobu bubliny"</string>
+ <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"Zobrazuje se v horní části sekce konverzací a na obrazovce uzamčení se objevuje jako profilová fotka, deaktivuje režim Nerušit"</string>
+ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Zobrazuje se v horní části sekce konverzací a na obrazovce uzamčení se objevuje jako profilová fotka, má podobu bubliny a deaktivuje režim Nerušit"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Priorita"</string>
<string name="no_shortcut" msgid="8257177117568230126">"Aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> funkce konverzace nepodporuje"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Tato oznámení nelze upravit."</string>
@@ -576,6 +585,7 @@
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"SMS"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"Hudba"</string>
<string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Kalendář"</string>
+ <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Nerušit"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"Zkratka tlačítek hlasitosti"</string>
<string name="battery" msgid="769686279459897127">"Baterie"</string>
<string name="headset" msgid="4485892374984466437">"Sluchátka"</string>
@@ -694,6 +704,10 @@
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"Wi-Fi je vypnuta"</string>
<string name="bt_is_off" msgid="7436344904889461591">"Bluetooth je vypnuto"</string>
+ <string name="dnd_is_off" msgid="3185706903793094463">"Režim Nerušit je vypnut"</string>
+ <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"Režim Nerušit byl zapnut automatickým pravidlem (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"Režim Nerušit byl zapnut aplikací (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"Režim Nerušit byl zapnut automatickým pravidlem nebo aplikací."</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"Aplikace běžící na pozadí"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"Klepnutím zobrazíte podrobnosti o využití baterie a dat"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Vypnout mobilní data?"</string>
@@ -718,6 +732,8 @@
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(práce)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"Telefonní hovor"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(prostřednictvím aplikace <xliff:g id="APPLICATION_NAME_S_">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_label" msgid="3385241594101496292">"(<xliff:g id="ATTRIBUTION_LABEL">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_proxy_label" msgid="1111829599659403249">"(<xliff:g id="ATTRIBUTION_LABEL">%1$s</xliff:g> • <xliff:g id="PROXY_LABEL">%2$s</xliff:g>)"</string>
<string name="privacy_type_camera" msgid="7974051382167078332">"fotoaparát"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"poloha"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofon"</string>
@@ -818,6 +834,9 @@
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(odpojeno)"</string>
<string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Nelze přepnout. Klepnutím opakujte akci."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Spárovat nové zařízení"</string>
+ <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Pokud chcete odesílat relaci, otevřete aplikaci."</string>
+ <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Neznámá aplikace"</string>
+ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Zastavit odesílání"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Číslo sestavení"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Číslo sestavení bylo zkopírováno do schránky."</string>
<string name="basic_status" msgid="2315371112182658176">"Otevřít konverzaci"</string>
@@ -851,6 +870,7 @@
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Zobrazit poslední zprávy, zmeškané hovory a aktualizace stavu"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Konverzace"</string>
+ <string name="paused_by_dnd" msgid="7856941866433556428">"Pozastaveno funkcí Nerušit"</string>
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> posílá zprávu: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> posílá obrázek"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> má aktualizaci stavu: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
@@ -891,8 +911,7 @@
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> aktivních aplikací</item>
<item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> aktivních aplikací</item>
</plurals>
- <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
- <skip />
+ <string name="fgs_dot_content_description" msgid="2865071539464777240">"Nové informace"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Aktivní aplikace"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Konec"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Zastaveno"</string>
@@ -900,14 +919,15 @@
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Zkopírováno"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Z aplikace <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Zavřít uživatelské rozhraní kopírování"</string>
- <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
- <skip />
- <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
- <skip />
- <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
- <skip />
- <!-- no translation found for add (81036585205287996) -->
- <skip />
- <!-- no translation found for manage_users (1823875311934643849) -->
- <skip />
+ <string name="clipboard_edit_text_description" msgid="805254383912962103">"Upravit zkopírovaný text"</string>
+ <string name="clipboard_edit_image_description" msgid="8904857948976041306">"Upravit zkopírovaný obrázek"</string>
+ <string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Odeslat do zařízení v okolí"</string>
+ <string name="add" msgid="81036585205287996">"Přidat"</string>
+ <string name="manage_users" msgid="1823875311934643849">"Správa uživatelů"</string>
+ <string name="drag_split_not_supported" msgid="4326847447699729722">"Toto oznámení nepodporuje přetažení na rozdělenou obrazovku."</string>
+ <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Síť Wi‑Fi není k dispozici"</string>
+ <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Prioritní režim"</string>
+ <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Je nastaven budík"</string>
+ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Fotoaparát a mikrofon jsou vypnuté"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# oznámení}few{# oznámení}many{# oznámení}other{# oznámení}}"</string>
</resources>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index bbcb9bc0b530..43027b833267 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -20,14 +20,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4811759950673118541">"System-UI"</string>
- <string name="battery_low_title" msgid="6891106956328275225">"Enheden løber muligvis snart tør for batteri"</string>
+ <string name="battery_low_title" msgid="5319680173344341779">"Vil du aktivere Batterisparefunktion?"</string>
+ <string name="battery_low_description" msgid="3282977755476423966">"Du har <xliff:g id="PERCENTAGE">%s</xliff:g> batteri tilbage. Batterisparefunktion aktiverer Mørkt tema, begrænser aktivitet i baggrunden og udskyder notifikationer."</string>
+ <string name="battery_low_intro" msgid="5148725009653088790">"Batterisparefunktion aktiverer Mørkt tema, begrænser aktivitet i baggrunden og udskyder notifikationer."</string>
<string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> tilbage"</string>
<string name="invalid_charger_title" msgid="938685362320735167">"Enheden kan ikke oplades via USB"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"Brug den oplader, der fulgte med din enhed"</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Vil du aktivere Batterisparefunktion?"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Om Batterisparefunktion"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Aktivér"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"Aktivér batterisparefunktion"</string>
+ <string name="battery_saver_start_action" msgid="8353766979886287140">"Aktivér"</string>
+ <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Nej tak"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Roter skærm automatisk"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"Vil du give <xliff:g id="APPLICATION">%1$s</xliff:g> adgang til <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
<string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Vil du give <xliff:g id="APPLICATION">%1$s</xliff:g> adgang til <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nDenne app har ikke fået tilladelse til at optage, men optager muligvis lyd via denne USB-enhed."</string>
@@ -128,6 +131,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Ansigtet er godkendt"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Bekræftet"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Tryk på Bekræft for at udføre"</string>
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Låst op med ansigtsgenkendelse. Tryk for at fortsætte."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Godkendt"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Brug pinkode"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Brug mønster"</string>
@@ -181,6 +185,7 @@
<string name="accessibility_desc_close" msgid="8293708213442107755">"Luk"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"total stilhed"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"kun alarmer"</string>
+ <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"Forstyr ikke."</string>
<string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"Bluetooth."</string>
<string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"Bluetooth er slået til."</string>
<string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"Alarmen er indstillet til <xliff:g id="TIME">%s</xliff:g>."</string>
@@ -205,6 +210,7 @@
<string name="dessert_case" msgid="9104973640704357717">"Dessertcase"</string>
<string name="start_dreams" msgid="9131802557946276718">"Pauseskærm"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
+ <string name="quick_settings_dnd_label" msgid="7728690179108024338">"Forstyr ikke"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Der er ingen tilgængelige parrede enheder"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> batteri"</string>
@@ -348,6 +354,7 @@
<string name="notification_section_header_alerting" msgid="5581175033680477651">"Notifikationer"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Samtaler"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Ryd alle lydløse notifikationer"</string>
+ <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Notifikationer er sat på pause af Forstyr ikke"</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"Start nu"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Ingen notifikationer"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Denne enhed administreres af din forælder"</string>
@@ -452,8 +459,8 @@
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Lås op for at bruge"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Dine kort kunne ikke hentes. Prøv igen senere."</string>
<string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Lås skærmindstillinger"</string>
- <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR-kode"</string>
- <string name="qr_code_scanner_description" msgid="7937603775306661863">"Tryk for at scanne"</string>
+ <!-- no translation found for qr_code_scanner_title (5290201053875420785) -->
+ <skip />
<string name="status_bar_work" msgid="5238641949837091056">"Arbejdsprofil"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Flytilstand"</string>
<string name="zen_alarm_warning" msgid="7844303238486849503">"Du vil ikke kunne høre din næste alarm <xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -491,6 +498,8 @@
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"&lt;b&gt;Status:&lt;/b&gt; Placeret lavere"</string>
<string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"Vises øverst i samtalenotifikationer og som et profilbillede på låseskærmen"</string>
<string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"Vises øverst i samtalenotifikationer og som et profilbillede på låseskærmen. Vises som en boble"</string>
+ <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"Vises øverst i samtalenotifikationer og som et profilbillede på låseskærmen. Afbryder Forstyr ikke"</string>
+ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Vises øverst i samtalenotifikationer og som et profilbillede på låseskærmen. Vises som en boble, der afbryder Forstyr ikke"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritet"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> understøtter ikke samtalefunktioner"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Disse notifikationer kan ikke redigeres."</string>
@@ -566,6 +575,7 @@
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"Sms"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"Musik"</string>
<string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Kalender"</string>
+ <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Forstyr ikke"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"Genvej til lydstyrkeknapper"</string>
<string name="battery" msgid="769686279459897127">"Batteri"</string>
<string name="headset" msgid="4485892374984466437">"Headset"</string>
@@ -684,6 +694,10 @@
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"Wi-Fi er slået fra"</string>
<string name="bt_is_off" msgid="7436344904889461591">"Bluetooth er slået fra"</string>
+ <string name="dnd_is_off" msgid="3185706903793094463">"Forstyr ikke er slået fra"</string>
+ <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"Tilstanden Forstyr ikke blev aktiveret af en automatisk regel (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"Tilstanden Forstyr ikke blev aktiveret af en app (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"Tilstanden Forstyr ikke blev aktiveret af en automatisk regel eller en app."</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"Apps, der kører i baggrunden"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"Tryk for at se info om batteri- og dataforbrug"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Vil du deaktivere mobildata?"</string>
@@ -708,6 +722,8 @@
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(arbejde)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"Telefonopkald"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(via <xliff:g id="APPLICATION_NAME_S_">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_label" msgid="3385241594101496292">"(<xliff:g id="ATTRIBUTION_LABEL">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_proxy_label" msgid="1111829599659403249">"(<xliff:g id="ATTRIBUTION_LABEL">%1$s</xliff:g> • <xliff:g id="PROXY_LABEL">%2$s</xliff:g>)"</string>
<string name="privacy_type_camera" msgid="7974051382167078332">"kameraet"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"lokation"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofonen"</string>
@@ -806,6 +822,9 @@
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(afbrudt)"</string>
<string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Det var ikke muligt at skifte. Tryk for at prøve igen."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Par ny enhed"</string>
+ <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Åbn appen for at caste denne session."</string>
+ <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Ukendt app"</string>
+ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Stop med at caste"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Buildnummer"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Buildnummeret blev kopieret til udklipsholderen."</string>
<string name="basic_status" msgid="2315371112182658176">"Åben samtale"</string>
@@ -839,6 +858,7 @@
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Se dine seneste beskeder, mistede opkald og statusopdateringer"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Samtale"</string>
+ <string name="paused_by_dnd" msgid="7856941866433556428">"Sat på pause af Forstyr ikke"</string>
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> har sendt en besked: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> har sendt et billede"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> har opdateret sin status: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
@@ -877,8 +897,7 @@
<item quantity="one"><xliff:g id="COUNT_1">%s</xliff:g> aktiv app</item>
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> aktive apps</item>
</plurals>
- <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
- <skip />
+ <string name="fgs_dot_content_description" msgid="2865071539464777240">"Nye oplysninger"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Aktive apps"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Stop"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Stoppet"</string>
@@ -886,14 +905,15 @@
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Kopieret"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Fra <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Luk brugerfladen for kopi"</string>
- <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
- <skip />
- <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
- <skip />
- <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
- <skip />
- <!-- no translation found for add (81036585205287996) -->
- <skip />
- <!-- no translation found for manage_users (1823875311934643849) -->
- <skip />
+ <string name="clipboard_edit_text_description" msgid="805254383912962103">"Rediger kopieret tekst"</string>
+ <string name="clipboard_edit_image_description" msgid="8904857948976041306">"Rediger kopieret billede"</string>
+ <string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Send til enhed i nærheden"</string>
+ <string name="add" msgid="81036585205287996">"Tilføj"</string>
+ <string name="manage_users" msgid="1823875311934643849">"Administrer brugere"</string>
+ <string name="drag_split_not_supported" msgid="4326847447699729722">"Denne notifikation kan ikke trækkes til en opdelt skærm."</string>
+ <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Ingen tilgængelig Wi-Fi-forbindelse"</string>
+ <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Tilstanden Prioritet"</string>
+ <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarmen er indstillet"</string>
+ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Kamera og mikrofon er slået fra"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notifikation}one{# notifikation}other{# notifikationer}}"</string>
</resources>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 2b9f725e24e4..60bcecb93d8b 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -20,14 +20,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4811759950673118541">"System-UI"</string>
- <string name="battery_low_title" msgid="6891106956328275225">"Der Akku ist fast leer"</string>
+ <string name="battery_low_title" msgid="5319680173344341779">"Energiesparmodus aktivieren?"</string>
+ <string name="battery_low_description" msgid="3282977755476423966">"Dein Akkustand beträgt <xliff:g id="PERCENTAGE">%s</xliff:g>. Im Energiesparmodus wird das dunkle Design aktiviert und es werden Hintergrundaktivitäten eingeschränkt sowie Benachrichtigungen verzögert empfangen."</string>
+ <string name="battery_low_intro" msgid="5148725009653088790">"Im Energiesparmodus wird das dunkle Design aktiviert und es werden Hintergrundaktivitäten eingeschränkt sowie Benachrichtigungen verzögert empfangen."</string>
<string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> verbleibend"</string>
<string name="invalid_charger_title" msgid="938685362320735167">"Aufladen über USB nicht möglich"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"Verwende das mit dem Gerät gelieferte Ladegerät"</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Energiesparmodus aktivieren?"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Über den Energiesparmodus"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Aktivieren"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"Energiesparmodus aktivieren"</string>
+ <string name="battery_saver_start_action" msgid="8353766979886287140">"Aktivieren"</string>
+ <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Nein danke"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Bildschirm automatisch drehen"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"<xliff:g id="APPLICATION">%1$s</xliff:g> den Zugriff auf <xliff:g id="USB_DEVICE">%2$s</xliff:g> gewähren?"</string>
<string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"<xliff:g id="APPLICATION">%1$s</xliff:g> den Zugriff auf <xliff:g id="USB_DEVICE">%2$s</xliff:g> gewähren?\nDiese App hat noch nicht die Berechtigung zum Aufnehmen erhalten, könnte jedoch Audio über dieses USB-Gerät aufnehmen."</string>
@@ -128,6 +131,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Gesicht authentifiziert"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Bestätigt"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Zum Abschließen auf \"Bestätigen\" tippen"</string>
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Mit dem Gesicht entsperrt. Drücken, um fortzufahren."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Authentifiziert"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"PIN verwenden"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Muster verwenden"</string>
@@ -181,6 +185,7 @@
<string name="accessibility_desc_close" msgid="8293708213442107755">"Schließen"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"lautlos"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"nur Weckrufe"</string>
+ <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"Bitte nicht stören."</string>
<string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"Bluetooth."</string>
<string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"Bluetooth aktiviert"</string>
<string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"Wecker gestellt für <xliff:g id="TIME">%s</xliff:g>"</string>
@@ -205,6 +210,7 @@
<string name="dessert_case" msgid="9104973640704357717">"Dessertbehälter"</string>
<string name="start_dreams" msgid="9131802557946276718">"Bildschirmschoner"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
+ <string name="quick_settings_dnd_label" msgid="7728690179108024338">"Bitte nicht stören"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Keine gekoppelten Geräte verfügbar"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Akkustand: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
@@ -348,6 +354,7 @@
<string name="notification_section_header_alerting" msgid="5581175033680477651">"Benachrichtigungen"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Unterhaltungen"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Alle lautlosen Benachrichtigungen löschen"</string>
+ <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Benachrichtigungen durch „Bitte nicht stören“ pausiert"</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"Jetzt starten"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Keine Benachrichtigungen"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Dieses Gerät wird von deinen Eltern verwaltet"</string>
@@ -452,8 +459,8 @@
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Zum Verwenden entsperren"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Beim Abrufen deiner Karten ist ein Fehler aufgetreten – bitte versuch es später noch einmal"</string>
<string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Einstellungen für den Sperrbildschirm"</string>
- <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR-Code"</string>
- <string name="qr_code_scanner_description" msgid="7937603775306661863">"Zum Scannen tippen"</string>
+ <!-- no translation found for qr_code_scanner_title (5290201053875420785) -->
+ <skip />
<string name="status_bar_work" msgid="5238641949837091056">"Arbeitsprofil"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Flugmodus"</string>
<string name="zen_alarm_warning" msgid="7844303238486849503">"Lautloser Weckruf <xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -491,6 +498,8 @@
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"&lt;b&gt;Status&lt;/b&gt;: niedriger eingestuft"</string>
<string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"Wird oben im Bereich „Unterhaltungen“ sowie als Profilbild auf dem Sperrbildschirm angezeigt"</string>
<string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"Wird oben im Bereich „Unterhaltungen“ sowie als Profilbild auf dem Sperrbildschirm angezeigt, erscheint als Bubble"</string>
+ <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"Wird oben im Bereich „Unterhaltungen“ sowie als Profilbild auf dem Sperrbildschirm angezeigt, unterbricht „Bitte nicht stören“"</string>
+ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Wird oben im Bereich „Unterhaltungen“ sowie als Profilbild auf dem Sperrbildschirm angezeigt, erscheint als Bubble, unterbricht „Bitte nicht stören“"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Priorität"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> unterstützt keine Funktionen für Unterhaltungen"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Diese Benachrichtigungen können nicht geändert werden."</string>
@@ -566,6 +575,7 @@
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"SMS"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"Musik"</string>
<string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Kalender"</string>
+ <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Bitte nicht stören"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"Tastenkombination für Lautstärketasten"</string>
<string name="battery" msgid="769686279459897127">"Akku"</string>
<string name="headset" msgid="4485892374984466437">"Headset"</string>
@@ -673,7 +683,7 @@
<string name="notification_channel_general" msgid="4384774889645929705">"Nachrichten"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"Speicher"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Hinweise"</string>
- <string name="instant_apps" msgid="8337185853050247304">"Instant-Apps"</string>
+ <string name="instant_apps" msgid="8337185853050247304">"Instant Apps"</string>
<string name="instant_apps_title" msgid="8942706782103036910">"<xliff:g id="APP">%1$s</xliff:g> wird ausgeführt"</string>
<string name="instant_apps_message" msgid="6112428971833011754">"App wurde geöffnet, ohne vorher installiert zu werden."</string>
<string name="instant_apps_message_with_help" msgid="1816952263531203932">"App wurde geöffnet, ohne vorher installiert zu werden. Tippe, um weitere Informationen zu erhalten."</string>
@@ -684,6 +694,10 @@
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"WLAN ist deaktiviert"</string>
<string name="bt_is_off" msgid="7436344904889461591">"Bluetooth ist deaktiviert"</string>
+ <string name="dnd_is_off" msgid="3185706903793094463">"„Bitte nicht stören“ ist deaktiviert"</string>
+ <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"„Bitte nicht stören“ wurde von einer automatischen Regel aktiviert (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"„Bitte nicht stören“ wurde von einer App aktiviert (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"„Bitte nicht stören“ wurde von einer automatischen Regel oder einer App aktiviert."</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"Apps, die im Hintergrund ausgeführt werden"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"Für Details zur Akku- und Datennutzung tippen"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Mobile Daten deaktivieren?"</string>
@@ -708,6 +722,8 @@
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(geschäftlich)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"Telefonanruf"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(über <xliff:g id="APPLICATION_NAME_S_">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_label" msgid="3385241594101496292">"(<xliff:g id="ATTRIBUTION_LABEL">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_proxy_label" msgid="1111829599659403249">"(<xliff:g id="ATTRIBUTION_LABEL">%1$s</xliff:g> • <xliff:g id="PROXY_LABEL">%2$s</xliff:g>)"</string>
<string name="privacy_type_camera" msgid="7974051382167078332">"Kamera"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"Standort"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"Mikrofon"</string>
@@ -806,6 +822,9 @@
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(nicht verbunden)"</string>
<string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Wechseln nicht möglich. Tippe, um es noch einmal zu versuchen."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Neues Gerät koppeln"</string>
+ <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Öffne zum Streamen dieser Sitzung die App."</string>
+ <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Unbekannte App"</string>
+ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Streaming beenden"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Build-Nummer"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Build-Nummer in Zwischenablage kopiert."</string>
<string name="basic_status" msgid="2315371112182658176">"Offene Unterhaltung"</string>
@@ -839,6 +858,7 @@
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Letzte Nachrichten, verpasste Anrufe und Statusaktualisierungen ansehen"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Unterhaltung"</string>
+ <string name="paused_by_dnd" msgid="7856941866433556428">"Durch „Bitte nicht stören“ pausiert"</string>
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> hat eine Nachricht gesendet: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> hat ein Bild gesendet"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> hat den Status aktualisiert: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
@@ -877,8 +897,7 @@
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> aktive Apps</item>
<item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> aktive App</item>
</plurals>
- <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
- <skip />
+ <string name="fgs_dot_content_description" msgid="2865071539464777240">"Neue Informationen"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Aktive Apps"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Beenden"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Beendet"</string>
@@ -886,14 +905,15 @@
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Kopiert"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Von <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Kopieren-Benutzeroberfläche schließen"</string>
- <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
- <skip />
- <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
- <skip />
- <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
- <skip />
- <!-- no translation found for add (81036585205287996) -->
- <skip />
- <!-- no translation found for manage_users (1823875311934643849) -->
- <skip />
+ <string name="clipboard_edit_text_description" msgid="805254383912962103">"Kopierten Text bearbeiten"</string>
+ <string name="clipboard_edit_image_description" msgid="8904857948976041306">"Kopiertes Bild bearbeiten"</string>
+ <string name="clipboard_send_nearby_description" msgid="4629769637846717650">"An Gerät in der Nähe senden"</string>
+ <string name="add" msgid="81036585205287996">"Hinzufügen"</string>
+ <string name="manage_users" msgid="1823875311934643849">"Nutzer verwalten"</string>
+ <string name="drag_split_not_supported" msgid="4326847447699729722">"Diese Benachrichtigung lässt sich nicht auf einen geteilten Bildschirm ziehen."</string>
+ <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"WLAN nicht verfügbar"</string>
+ <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Prioritätsmodus"</string>
+ <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Wecker gestellt"</string>
+ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Kamera und Mikrofon ausgeschaltet"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# Benachrichtigung}other{# Benachrichtigungen}}"</string>
</resources>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 609674929af5..17a54c2ad7c9 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -20,14 +20,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4811759950673118541">"UI συστήματ."</string>
- <string name="battery_low_title" msgid="6891106956328275225">"Η μπαταρία μπορεί να εξαντληθεί σύντομα"</string>
+ <string name="battery_low_title" msgid="5319680173344341779">"Ενεργοποίηση Εξοικονόμησης μπαταρίας;"</string>
+ <string name="battery_low_description" msgid="3282977755476423966">"Απομένει <xliff:g id="PERCENTAGE">%s</xliff:g> μπαταρία. Η Εξοικονόμηση μπαταρίας ενεργοποιεί το Σκούρο θέμα, περιορίζει τη δραστηριότητα στο παρασκήνιο και καθυστερεί τις ειδοποιήσεις."</string>
+ <string name="battery_low_intro" msgid="5148725009653088790">"Η Εξοικονόμηση μπαταρίας ενεργοποιεί το Σκούρο θέμα, περιορίζει τη δραστηριότητα στο παρασκήνιο και καθυστερεί τις ειδοποιήσεις."</string>
<string name="battery_low_percent_format" msgid="4276661262843170964">"Απομένουν <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="invalid_charger_title" msgid="938685362320735167">"Δεν είναι δυνατή η φόρτιση μέσω USB"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"Χρησιμοποιήστε τον φορτιστή που συνοδεύει τη συσκευή σας"</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Να ενεργοποιηθεί η Εξοικονόμηση μπαταρίας;"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Σχετικά με την Εξοικονόμηση μπαταρίας"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Ενεργοποίηση"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"Ενεργοποίηση Εξοικονόμησης μπαταρίας"</string>
+ <string name="battery_saver_start_action" msgid="8353766979886287140">"Ενεργοποίηση"</string>
+ <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Όχι, ευχαριστώ"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Αυτόματη περιστροφή οθόνης"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"Να επιτρέπεται η πρόσβαση της εφαρμογής <xliff:g id="APPLICATION">%1$s</xliff:g> στη συσκευή <xliff:g id="USB_DEVICE">%2$s</xliff:g>;"</string>
<string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Να επιτρέπεται στην εφαρμογή <xliff:g id="APPLICATION">%1$s</xliff:g> να έχει πρόσβαση στη συσκευή <xliff:g id="USB_DEVICE">%2$s</xliff:g>;\nΔεν έχει εκχωρηθεί άδεια εγγραφής σε αυτήν την εφαρμογή, αλλά μέσω αυτής της συσκευής USB θα μπορεί να εγγράφει ήχο."</string>
@@ -128,6 +131,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Έγινε έλεγχος ταυτότητας προσώπου"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Επιβεβαιώθηκε"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Πατήστε Επιβεβαίωση για ολοκλήρωση"</string>
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Ξεκλειδώθηκε με το πρόσωπό σας. Πατήστε για συνέχεια."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Ολοκληρώθηκε ο έλεγχος ταυτότητας"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Χρήση PIN"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Χρήση μοτίβου"</string>
@@ -181,6 +185,7 @@
<string name="accessibility_desc_close" msgid="8293708213442107755">"Κλείσιμο"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"πλήρης σίγαση"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"μόνο ξυπνητήρια"</string>
+ <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"Μην ενοχλείτε."</string>
<string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"Bluetooth."</string>
<string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"Ενεργό Bluetooth."</string>
<string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"Το ξυπνητήρι έχει οριστεί στις <xliff:g id="TIME">%s</xliff:g>."</string>
@@ -205,6 +210,7 @@
<string name="dessert_case" msgid="9104973640704357717">"Επιδόρπιο"</string>
<string name="start_dreams" msgid="9131802557946276718">"Προφύλαξη οθόνης"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
+ <string name="quick_settings_dnd_label" msgid="7728690179108024338">"Μην ενοχλείτε"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Δεν υπάρχουν διαθέσιμες συσκευές σε σύζευξη"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Μπαταρία <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
@@ -348,6 +354,7 @@
<string name="notification_section_header_alerting" msgid="5581175033680477651">"Ειδοποιήσεις"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Συζητήσεις"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Διαγραφή όλων των ειδοποιήσεων σε σίγαση"</string>
+ <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Οι ειδοποιήσεις τέθηκαν σε παύση από τη λειτουργία \"Μην ενοχλείτε\""</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"Έναρξη τώρα"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Δεν υπάρχουν ειδοποιήσεις"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Αυτή η συσκευή είναι διαχειριζόμενη από τον γονέα σου"</string>
@@ -452,8 +459,8 @@
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Ξεκλείδωμα για χρήση"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Παρουσιάστηκε πρόβλημα με τη λήψη των καρτών σας. Δοκιμάστε ξανά αργότερα"</string>
<string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Ρυθμίσεις κλειδώματος οθόνης"</string>
- <string name="qr_code_scanner_title" msgid="5660820608548306581">"Κωδικός QR"</string>
- <string name="qr_code_scanner_description" msgid="7937603775306661863">"Πατήστε για σάρωση"</string>
+ <!-- no translation found for qr_code_scanner_title (5290201053875420785) -->
+ <skip />
<string name="status_bar_work" msgid="5238641949837091056">"Προφίλ εργασίας"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Λειτουργία πτήσης"</string>
<string name="zen_alarm_warning" msgid="7844303238486849503">"Δεν θα ακούσετε το επόμενο ξυπνητήρι σας <xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -491,6 +498,8 @@
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"&lt;b&gt;Κατάσταση:&lt;/b&gt; Κατατάχθηκε χαμηλότερα"</string>
<string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"Εμφανίζεται στην κορυφή των ειδοποιήσεων συζήτησης και ως φωτογραφία προφίλ στην οθόνη κλειδώματος"</string>
<string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"Εμφανίζεται στην κορυφή των ειδοποιήσεων συζήτησης και ως φωτογραφία προφίλ στην οθόνη κλειδώματος, εμφανίζεται ως συννεφάκι"</string>
+ <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"Εμφανίζεται στην κορυφή των ειδοποιήσεων συζήτησης και ως φωτογραφία προφίλ στην οθόνη κλειδώματος, διακόπτει τη λειτουργία Μην ενοχλείτε"</string>
+ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Εμφανίζεται στην κορυφή των ειδοποιήσεων συζήτησης και ως φωτογραφία προφίλ στην οθόνη κλειδώματος, εμφανίζεται ως συννεφάκι, διακόπτει τη λειτουργία Μην ενοχλείτε"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Προτεραιότητα"</string>
<string name="no_shortcut" msgid="8257177117568230126">"Η εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> δεν υποστηρίζει τις λειτουργίες συζήτησης"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Δεν είναι δυνατή η τροποποίηση αυτών των ειδοποιήσεων"</string>
@@ -566,6 +575,7 @@
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"SMS"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"Μουσική"</string>
<string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Ημερολόγιο"</string>
+ <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Μην ενοχλείτε"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"Συντόμευση κουμπιών έντασης ήχου"</string>
<string name="battery" msgid="769686279459897127">"Μπαταρία"</string>
<string name="headset" msgid="4485892374984466437">"Ακουστικά"</string>
@@ -684,6 +694,10 @@
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"Το Wi-Fi είναι ανενεργό"</string>
<string name="bt_is_off" msgid="7436344904889461591">"Το Bluetooth είναι ανενεργό"</string>
+ <string name="dnd_is_off" msgid="3185706903793094463">"Η λειτουργία \"Μην ενοχλείτε\" είναι ανενεργή"</string>
+ <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"Η λειτουργία \"Μην ενοχλείτε\" ενεργοποιήθηκε από έναν αυτόματο κανόνα (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"Η λειτουργία \"Μην ενοχλείτε\" ενεργοποιήθηκε από μια εφαρμογή (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"Η λειτουργία \"Μην ενοχλείτε\" ενεργοποιήθηκε από έναν αυτόματο κανόνα ή μια εφαρμογή."</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"Εφαρμογές που εκτελούνται στο παρασκήνιο"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"Πατήστε για λεπτομέρειες σχετικά με τη χρήση μπαταρίας και δεδομένων"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Απενεργοποίηση δεδομένων κινητής τηλεφωνίας;"</string>
@@ -708,6 +722,8 @@
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(εργασία)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"Τηλεφωνική κλήση"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(μέσω <xliff:g id="APPLICATION_NAME_S_">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_label" msgid="3385241594101496292">"(<xliff:g id="ATTRIBUTION_LABEL">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_proxy_label" msgid="1111829599659403249">"(<xliff:g id="ATTRIBUTION_LABEL">%1$s</xliff:g> • <xliff:g id="PROXY_LABEL">%2$s</xliff:g>)"</string>
<string name="privacy_type_camera" msgid="7974051382167078332">"κάμερα"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"τοποθεσία"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"μικρόφωνο"</string>
@@ -806,6 +822,9 @@
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(αποσυνδέθηκε)"</string>
<string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Δεν είναι δυνατή η εναλλαγή. Πατήστε για επανάληψη."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Σύζευξη νέας συσκευής"</string>
+ <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Για μετάδοση της περιόδου σύνδεσης, ανοίξτε την εφαρμογή."</string>
+ <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Άγνωστη εφαρμογή"</string>
+ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Διακοπή μετάδοσης"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Αριθμός έκδοσης"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Ο αριθμός έκδοσης αντιγράφηκε στο πρόχειρο."</string>
<string name="basic_status" msgid="2315371112182658176">"Άνοιγμα συνομιλίας"</string>
@@ -839,6 +858,7 @@
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Δείτε πρόσφατα μηνύματα, αναπάντητες κλήσεις και ενημερώσεις κατάστασης"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Συνομιλία"</string>
+ <string name="paused_by_dnd" msgid="7856941866433556428">"Σε παύση από τη λειτουργία Μην ενοχλείτε"</string>
<string name="new_notification_text_content_description" msgid="2915029960094389291">"Ο χρήστης <xliff:g id="NAME">%1$s</xliff:g> έστειλε ένα μήνυμα: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"Ο χρήστης <xliff:g id="NAME">%1$s</xliff:g> έστειλε μια εικόνα"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"Ο χρήστης <xliff:g id="NAME">%1$s</xliff:g> έχει μια ενημέρωση κατάστασης: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
@@ -877,8 +897,7 @@
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> ενεργές εφαρμογές</item>
<item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> ενεργή εφαρμογή</item>
</plurals>
- <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
- <skip />
+ <string name="fgs_dot_content_description" msgid="2865071539464777240">"Νέες πληροφορίες"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Ενεργές εφαρμογές"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Διακοπή"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Διακόπηκε"</string>
@@ -886,14 +905,15 @@
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Αντιγράφηκε"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Από <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Παράβλεψη διεπαφής χρήστη αντιγραφής"</string>
- <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
- <skip />
- <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
- <skip />
- <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
- <skip />
- <!-- no translation found for add (81036585205287996) -->
- <skip />
- <!-- no translation found for manage_users (1823875311934643849) -->
- <skip />
+ <string name="clipboard_edit_text_description" msgid="805254383912962103">"Επεξεργασία αντιγραμμένου κειμένου"</string>
+ <string name="clipboard_edit_image_description" msgid="8904857948976041306">"Επεξεργασία αντιγραμμένης εικόνας"</string>
+ <string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Αποστολή σε κοντινή συσκευή"</string>
+ <string name="add" msgid="81036585205287996">"Προσθήκη"</string>
+ <string name="manage_users" msgid="1823875311934643849">"Διαχείριση χρηστών"</string>
+ <string name="drag_split_not_supported" msgid="4326847447699729722">"Αυτή η ειδοποίηση δεν υποστηρίζει τη μεταφορά με σύρσιμο για χρήση του διαχωρισμού οθόνης."</string>
+ <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Το Wi‑Fi δεν είναι διαθέσιμο"</string>
+ <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Λειτουργία προτεραιότητας"</string>
+ <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Το ξυπνητήρι ρυθμίστηκε"</string>
+ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Η κάμερα και το μικρόφωνο έχουν απενεργοποιηθεί"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# ειδοποίηση}other{# ειδοποιήσεις}}"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index f6dc3145bc9c..5544a9597fae 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -20,14 +20,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4811759950673118541">"System UI"</string>
- <string name="battery_low_title" msgid="6891106956328275225">"Battery may run out soon"</string>
+ <string name="battery_low_title" msgid="5319680173344341779">"Turn on Battery Saver?"</string>
+ <string name="battery_low_description" msgid="3282977755476423966">"You have <xliff:g id="PERCENTAGE">%s</xliff:g> battery left. Battery Saver turns on Dark theme, restricts background activity and delays notifications."</string>
+ <string name="battery_low_intro" msgid="5148725009653088790">"Battery Saver turns on Dark theme, restricts background activity and delays notifications."</string>
<string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> remaining"</string>
<string name="invalid_charger_title" msgid="938685362320735167">"Can\'t charge via USB"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"Use the charger that came with your device"</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Turn on Battery Saver?"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"About Battery Saver"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Turn on"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"Turn on Battery Saver"</string>
+ <string name="battery_saver_start_action" msgid="8353766979886287140">"Turn on"</string>
+ <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"No thanks"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Auto-rotate screen"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"Allow <xliff:g id="APPLICATION">%1$s</xliff:g> to access <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
<string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Allow <xliff:g id="APPLICATION">%1$s</xliff:g> to access <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nThis app has not been granted record permission but could capture audio through this USB device."</string>
@@ -128,6 +131,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Face authenticated"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Confirmed"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Tap Confirm to complete"</string>
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Unlocked by your face. Press to continue."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Authenticated"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Use PIN"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Use pattern"</string>
@@ -181,6 +185,7 @@
<string name="accessibility_desc_close" msgid="8293708213442107755">"Close"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"total silence"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"alarms only"</string>
+ <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"Do Not Disturb."</string>
<string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"Bluetooth"</string>
<string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"Bluetooth on."</string>
<string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"Alarm set for <xliff:g id="TIME">%s</xliff:g>."</string>
@@ -205,6 +210,7 @@
<string name="dessert_case" msgid="9104973640704357717">"Dessert Case"</string>
<string name="start_dreams" msgid="9131802557946276718">"Screen saver"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
+ <string name="quick_settings_dnd_label" msgid="7728690179108024338">"Do Not Disturb"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"No paired devices available"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> battery"</string>
@@ -348,6 +354,7 @@
<string name="notification_section_header_alerting" msgid="5581175033680477651">"Notifications"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Conversations"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Clear all silent notifications"</string>
+ <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Notifications paused by Do Not Disturb"</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"Start now"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"No notifications"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"This device is managed by your parent"</string>
@@ -452,8 +459,7 @@
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Unlock to use"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"There was a problem getting your cards. Please try again later."</string>
<string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Lock screen settings"</string>
- <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR code"</string>
- <string name="qr_code_scanner_description" msgid="7937603775306661863">"Tap to scan"</string>
+ <string name="qr_code_scanner_title" msgid="5290201053875420785">"Scan QR code"</string>
<string name="status_bar_work" msgid="5238641949837091056">"Work profile"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Aeroplane mode"</string>
<string name="zen_alarm_warning" msgid="7844303238486849503">"You won\'t hear your next alarm <xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -491,6 +497,8 @@
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"&lt;b&gt;Status:&lt;/b&gt; ranked lower"</string>
<string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"Shows at the top of conversation notifications and as a profile picture on lock screen"</string>
<string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"Shows at the top of conversation notifications and as a profile picture on lock screen, appears as a bubble"</string>
+ <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"Shows at the top of conversation notifications and as a profile picture on lock screen, interrupts Do Not Disturb"</string>
+ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Shows at the top of conversation notifications and as a profile picture on lock screen, appears as a bubble, interrupts Do Not Disturb"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Priority"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> doesn’t support conversation features"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"These notifications can\'t be modified."</string>
@@ -566,6 +574,7 @@
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"SMS"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"Music"</string>
<string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Calendar"</string>
+ <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Do Not Disturb"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"Volume buttons shortcut"</string>
<string name="battery" msgid="769686279459897127">"Battery"</string>
<string name="headset" msgid="4485892374984466437">"Headset"</string>
@@ -684,6 +693,10 @@
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"Wi-Fi is off"</string>
<string name="bt_is_off" msgid="7436344904889461591">"Bluetooth is off"</string>
+ <string name="dnd_is_off" msgid="3185706903793094463">"Do Not Disturb is off"</string>
+ <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"Do Not Disturb was turned on by an automatic rule (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"Do Not Disturb was turned on by an app (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"Do Not Disturb was turned on by an automatic rule or app."</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"Apps running in background"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"Tap for details on battery and data usage"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Turn off mobile data?"</string>
@@ -708,6 +721,8 @@
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(work)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"Phone call"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(through <xliff:g id="APPLICATION_NAME_S_">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_label" msgid="3385241594101496292">"(<xliff:g id="ATTRIBUTION_LABEL">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_proxy_label" msgid="1111829599659403249">"(<xliff:g id="ATTRIBUTION_LABEL">%1$s</xliff:g> • <xliff:g id="PROXY_LABEL">%2$s</xliff:g>)"</string>
<string name="privacy_type_camera" msgid="7974051382167078332">"camera"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"location"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"microphone"</string>
@@ -806,6 +821,9 @@
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(disconnected)"</string>
<string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Can\'t switch. Tap to try again."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Pair new device"</string>
+ <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"To cast this session, please open the app."</string>
+ <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Unknown app"</string>
+ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Stop casting"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Build number"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Build number copied to clipboard."</string>
<string name="basic_status" msgid="2315371112182658176">"Open conversation"</string>
@@ -839,6 +857,7 @@
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"See recent messages, missed calls and status updates"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Conversation"</string>
+ <string name="paused_by_dnd" msgid="7856941866433556428">"Paused by Do Not Disturb"</string>
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> sent a message: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> sent an image"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> has a status update: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
@@ -877,8 +896,7 @@
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> active apps</item>
<item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> active app</item>
</plurals>
- <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
- <skip />
+ <string name="fgs_dot_content_description" msgid="2865071539464777240">"New information"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Active apps"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Stop"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Stopped"</string>
@@ -889,8 +907,12 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Edit copied text"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Edit copied image"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Send to nearby device"</string>
- <!-- no translation found for add (81036585205287996) -->
- <skip />
- <!-- no translation found for manage_users (1823875311934643849) -->
- <skip />
+ <string name="add" msgid="81036585205287996">"Add"</string>
+ <string name="manage_users" msgid="1823875311934643849">"Manage users"</string>
+ <string name="drag_split_not_supported" msgid="4326847447699729722">"This notification does not support dragging to Split screen."</string>
+ <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi unavailable"</string>
+ <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Priority mode"</string>
+ <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarm set"</string>
+ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Camera and mic are off"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notification}other{# notifications}}"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index 0b4e00945337..9a204eb5d296 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -20,14 +20,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4811759950673118541">"System UI"</string>
- <string name="battery_low_title" msgid="6891106956328275225">"Battery may run out soon"</string>
+ <string name="battery_low_title" msgid="5319680173344341779">"Turn on Battery Saver?"</string>
+ <string name="battery_low_description" msgid="3282977755476423966">"You have <xliff:g id="PERCENTAGE">%s</xliff:g> battery left. Battery Saver turns on Dark theme, restricts background activity and delays notifications."</string>
+ <string name="battery_low_intro" msgid="5148725009653088790">"Battery Saver turns on Dark theme, restricts background activity and delays notifications."</string>
<string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> remaining"</string>
<string name="invalid_charger_title" msgid="938685362320735167">"Can\'t charge via USB"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"Use the charger that came with your device"</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Turn on Battery Saver?"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"About Battery Saver"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Turn on"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"Turn on Battery Saver"</string>
+ <string name="battery_saver_start_action" msgid="8353766979886287140">"Turn on"</string>
+ <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"No thanks"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Auto-rotate screen"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"Allow <xliff:g id="APPLICATION">%1$s</xliff:g> to access <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
<string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Allow <xliff:g id="APPLICATION">%1$s</xliff:g> to access <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nThis app has not been granted record permission but could capture audio through this USB device."</string>
@@ -128,6 +131,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Face authenticated"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Confirmed"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Tap Confirm to complete"</string>
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Unlocked by your face. Press to continue."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Authenticated"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Use PIN"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Use pattern"</string>
@@ -181,6 +185,7 @@
<string name="accessibility_desc_close" msgid="8293708213442107755">"Close"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"total silence"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"alarms only"</string>
+ <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"Do Not Disturb."</string>
<string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"Bluetooth"</string>
<string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"Bluetooth on."</string>
<string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"Alarm set for <xliff:g id="TIME">%s</xliff:g>."</string>
@@ -205,6 +210,7 @@
<string name="dessert_case" msgid="9104973640704357717">"Dessert Case"</string>
<string name="start_dreams" msgid="9131802557946276718">"Screen saver"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
+ <string name="quick_settings_dnd_label" msgid="7728690179108024338">"Do Not Disturb"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"No paired devices available"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> battery"</string>
@@ -348,6 +354,7 @@
<string name="notification_section_header_alerting" msgid="5581175033680477651">"Notifications"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Conversations"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Clear all silent notifications"</string>
+ <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Notifications paused by Do Not Disturb"</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"Start now"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"No notifications"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"This device is managed by your parent"</string>
@@ -452,8 +459,7 @@
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Unlock to use"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"There was a problem getting your cards. Please try again later."</string>
<string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Lock screen settings"</string>
- <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR code"</string>
- <string name="qr_code_scanner_description" msgid="7937603775306661863">"Tap to scan"</string>
+ <string name="qr_code_scanner_title" msgid="5290201053875420785">"Scan QR code"</string>
<string name="status_bar_work" msgid="5238641949837091056">"Work profile"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Airplane mode"</string>
<string name="zen_alarm_warning" msgid="7844303238486849503">"You won\'t hear your next alarm <xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -491,6 +497,8 @@
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"&lt;b&gt;Status:&lt;/b&gt; ranked lower"</string>
<string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"Shows at the top of conversation notifications and as a profile picture on lock screen"</string>
<string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"Shows at the top of conversation notifications and as a profile picture on lock screen, appears as a bubble"</string>
+ <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"Shows at the top of conversation notifications and as a profile picture on lock screen, interrupts Do Not Disturb"</string>
+ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Shows at the top of conversation notifications and as a profile picture on lock screen, appears as a bubble, interrupts Do Not Disturb"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Priority"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> doesn’t support conversation features"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"These notifications can\'t be modified."</string>
@@ -566,6 +574,7 @@
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"SMS"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"Music"</string>
<string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Calendar"</string>
+ <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Do Not Disturb"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"Volume buttons shortcut"</string>
<string name="battery" msgid="769686279459897127">"Battery"</string>
<string name="headset" msgid="4485892374984466437">"Headset"</string>
@@ -684,6 +693,10 @@
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"Wi-Fi is off"</string>
<string name="bt_is_off" msgid="7436344904889461591">"Bluetooth is off"</string>
+ <string name="dnd_is_off" msgid="3185706903793094463">"Do Not Disturb is off"</string>
+ <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"Do Not Disturb was turned on by an automatic rule (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"Do Not Disturb was turned on by an app (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"Do Not Disturb was turned on by an automatic rule or app."</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"Apps running in background"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"Tap for details on battery and data usage"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Turn off mobile data?"</string>
@@ -708,6 +721,8 @@
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(work)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"Phone call"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(through <xliff:g id="APPLICATION_NAME_S_">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_label" msgid="3385241594101496292">"(<xliff:g id="ATTRIBUTION_LABEL">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_proxy_label" msgid="1111829599659403249">"(<xliff:g id="ATTRIBUTION_LABEL">%1$s</xliff:g> • <xliff:g id="PROXY_LABEL">%2$s</xliff:g>)"</string>
<string name="privacy_type_camera" msgid="7974051382167078332">"camera"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"location"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"microphone"</string>
@@ -806,6 +821,9 @@
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(disconnected)"</string>
<string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Can\'t switch. Tap to try again."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Pair new device"</string>
+ <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"To cast this session, please open the app."</string>
+ <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Unknown app"</string>
+ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Stop casting"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Build number"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Build number copied to clipboard."</string>
<string name="basic_status" msgid="2315371112182658176">"Open conversation"</string>
@@ -839,6 +857,7 @@
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"See recent messages, missed calls and status updates"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Conversation"</string>
+ <string name="paused_by_dnd" msgid="7856941866433556428">"Paused by Do Not Disturb"</string>
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> sent a message: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> sent an image"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> has a status update: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
@@ -877,8 +896,7 @@
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> active apps</item>
<item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> active app</item>
</plurals>
- <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
- <skip />
+ <string name="fgs_dot_content_description" msgid="2865071539464777240">"New information"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Active apps"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Stop"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Stopped"</string>
@@ -889,8 +907,12 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Edit copied text"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Edit copied image"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Send to nearby device"</string>
- <!-- no translation found for add (81036585205287996) -->
- <skip />
- <!-- no translation found for manage_users (1823875311934643849) -->
- <skip />
+ <string name="add" msgid="81036585205287996">"Add"</string>
+ <string name="manage_users" msgid="1823875311934643849">"Manage users"</string>
+ <string name="drag_split_not_supported" msgid="4326847447699729722">"This notification does not support dragging to Split screen."</string>
+ <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi unavailable"</string>
+ <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Priority mode"</string>
+ <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarm set"</string>
+ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Camera and mic are off"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notification}other{# notifications}}"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index f6dc3145bc9c..5544a9597fae 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -20,14 +20,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4811759950673118541">"System UI"</string>
- <string name="battery_low_title" msgid="6891106956328275225">"Battery may run out soon"</string>
+ <string name="battery_low_title" msgid="5319680173344341779">"Turn on Battery Saver?"</string>
+ <string name="battery_low_description" msgid="3282977755476423966">"You have <xliff:g id="PERCENTAGE">%s</xliff:g> battery left. Battery Saver turns on Dark theme, restricts background activity and delays notifications."</string>
+ <string name="battery_low_intro" msgid="5148725009653088790">"Battery Saver turns on Dark theme, restricts background activity and delays notifications."</string>
<string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> remaining"</string>
<string name="invalid_charger_title" msgid="938685362320735167">"Can\'t charge via USB"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"Use the charger that came with your device"</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Turn on Battery Saver?"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"About Battery Saver"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Turn on"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"Turn on Battery Saver"</string>
+ <string name="battery_saver_start_action" msgid="8353766979886287140">"Turn on"</string>
+ <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"No thanks"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Auto-rotate screen"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"Allow <xliff:g id="APPLICATION">%1$s</xliff:g> to access <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
<string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Allow <xliff:g id="APPLICATION">%1$s</xliff:g> to access <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nThis app has not been granted record permission but could capture audio through this USB device."</string>
@@ -128,6 +131,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Face authenticated"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Confirmed"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Tap Confirm to complete"</string>
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Unlocked by your face. Press to continue."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Authenticated"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Use PIN"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Use pattern"</string>
@@ -181,6 +185,7 @@
<string name="accessibility_desc_close" msgid="8293708213442107755">"Close"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"total silence"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"alarms only"</string>
+ <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"Do Not Disturb."</string>
<string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"Bluetooth"</string>
<string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"Bluetooth on."</string>
<string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"Alarm set for <xliff:g id="TIME">%s</xliff:g>."</string>
@@ -205,6 +210,7 @@
<string name="dessert_case" msgid="9104973640704357717">"Dessert Case"</string>
<string name="start_dreams" msgid="9131802557946276718">"Screen saver"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
+ <string name="quick_settings_dnd_label" msgid="7728690179108024338">"Do Not Disturb"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"No paired devices available"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> battery"</string>
@@ -348,6 +354,7 @@
<string name="notification_section_header_alerting" msgid="5581175033680477651">"Notifications"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Conversations"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Clear all silent notifications"</string>
+ <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Notifications paused by Do Not Disturb"</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"Start now"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"No notifications"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"This device is managed by your parent"</string>
@@ -452,8 +459,7 @@
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Unlock to use"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"There was a problem getting your cards. Please try again later."</string>
<string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Lock screen settings"</string>
- <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR code"</string>
- <string name="qr_code_scanner_description" msgid="7937603775306661863">"Tap to scan"</string>
+ <string name="qr_code_scanner_title" msgid="5290201053875420785">"Scan QR code"</string>
<string name="status_bar_work" msgid="5238641949837091056">"Work profile"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Aeroplane mode"</string>
<string name="zen_alarm_warning" msgid="7844303238486849503">"You won\'t hear your next alarm <xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -491,6 +497,8 @@
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"&lt;b&gt;Status:&lt;/b&gt; ranked lower"</string>
<string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"Shows at the top of conversation notifications and as a profile picture on lock screen"</string>
<string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"Shows at the top of conversation notifications and as a profile picture on lock screen, appears as a bubble"</string>
+ <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"Shows at the top of conversation notifications and as a profile picture on lock screen, interrupts Do Not Disturb"</string>
+ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Shows at the top of conversation notifications and as a profile picture on lock screen, appears as a bubble, interrupts Do Not Disturb"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Priority"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> doesn’t support conversation features"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"These notifications can\'t be modified."</string>
@@ -566,6 +574,7 @@
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"SMS"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"Music"</string>
<string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Calendar"</string>
+ <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Do Not Disturb"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"Volume buttons shortcut"</string>
<string name="battery" msgid="769686279459897127">"Battery"</string>
<string name="headset" msgid="4485892374984466437">"Headset"</string>
@@ -684,6 +693,10 @@
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"Wi-Fi is off"</string>
<string name="bt_is_off" msgid="7436344904889461591">"Bluetooth is off"</string>
+ <string name="dnd_is_off" msgid="3185706903793094463">"Do Not Disturb is off"</string>
+ <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"Do Not Disturb was turned on by an automatic rule (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"Do Not Disturb was turned on by an app (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"Do Not Disturb was turned on by an automatic rule or app."</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"Apps running in background"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"Tap for details on battery and data usage"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Turn off mobile data?"</string>
@@ -708,6 +721,8 @@
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(work)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"Phone call"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(through <xliff:g id="APPLICATION_NAME_S_">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_label" msgid="3385241594101496292">"(<xliff:g id="ATTRIBUTION_LABEL">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_proxy_label" msgid="1111829599659403249">"(<xliff:g id="ATTRIBUTION_LABEL">%1$s</xliff:g> • <xliff:g id="PROXY_LABEL">%2$s</xliff:g>)"</string>
<string name="privacy_type_camera" msgid="7974051382167078332">"camera"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"location"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"microphone"</string>
@@ -806,6 +821,9 @@
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(disconnected)"</string>
<string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Can\'t switch. Tap to try again."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Pair new device"</string>
+ <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"To cast this session, please open the app."</string>
+ <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Unknown app"</string>
+ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Stop casting"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Build number"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Build number copied to clipboard."</string>
<string name="basic_status" msgid="2315371112182658176">"Open conversation"</string>
@@ -839,6 +857,7 @@
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"See recent messages, missed calls and status updates"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Conversation"</string>
+ <string name="paused_by_dnd" msgid="7856941866433556428">"Paused by Do Not Disturb"</string>
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> sent a message: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> sent an image"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> has a status update: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
@@ -877,8 +896,7 @@
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> active apps</item>
<item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> active app</item>
</plurals>
- <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
- <skip />
+ <string name="fgs_dot_content_description" msgid="2865071539464777240">"New information"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Active apps"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Stop"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Stopped"</string>
@@ -889,8 +907,12 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Edit copied text"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Edit copied image"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Send to nearby device"</string>
- <!-- no translation found for add (81036585205287996) -->
- <skip />
- <!-- no translation found for manage_users (1823875311934643849) -->
- <skip />
+ <string name="add" msgid="81036585205287996">"Add"</string>
+ <string name="manage_users" msgid="1823875311934643849">"Manage users"</string>
+ <string name="drag_split_not_supported" msgid="4326847447699729722">"This notification does not support dragging to Split screen."</string>
+ <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi unavailable"</string>
+ <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Priority mode"</string>
+ <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarm set"</string>
+ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Camera and mic are off"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notification}other{# notifications}}"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index f6dc3145bc9c..5544a9597fae 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -20,14 +20,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4811759950673118541">"System UI"</string>
- <string name="battery_low_title" msgid="6891106956328275225">"Battery may run out soon"</string>
+ <string name="battery_low_title" msgid="5319680173344341779">"Turn on Battery Saver?"</string>
+ <string name="battery_low_description" msgid="3282977755476423966">"You have <xliff:g id="PERCENTAGE">%s</xliff:g> battery left. Battery Saver turns on Dark theme, restricts background activity and delays notifications."</string>
+ <string name="battery_low_intro" msgid="5148725009653088790">"Battery Saver turns on Dark theme, restricts background activity and delays notifications."</string>
<string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> remaining"</string>
<string name="invalid_charger_title" msgid="938685362320735167">"Can\'t charge via USB"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"Use the charger that came with your device"</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Turn on Battery Saver?"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"About Battery Saver"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Turn on"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"Turn on Battery Saver"</string>
+ <string name="battery_saver_start_action" msgid="8353766979886287140">"Turn on"</string>
+ <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"No thanks"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Auto-rotate screen"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"Allow <xliff:g id="APPLICATION">%1$s</xliff:g> to access <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
<string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Allow <xliff:g id="APPLICATION">%1$s</xliff:g> to access <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nThis app has not been granted record permission but could capture audio through this USB device."</string>
@@ -128,6 +131,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Face authenticated"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Confirmed"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Tap Confirm to complete"</string>
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Unlocked by your face. Press to continue."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Authenticated"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Use PIN"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Use pattern"</string>
@@ -181,6 +185,7 @@
<string name="accessibility_desc_close" msgid="8293708213442107755">"Close"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"total silence"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"alarms only"</string>
+ <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"Do Not Disturb."</string>
<string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"Bluetooth"</string>
<string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"Bluetooth on."</string>
<string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"Alarm set for <xliff:g id="TIME">%s</xliff:g>."</string>
@@ -205,6 +210,7 @@
<string name="dessert_case" msgid="9104973640704357717">"Dessert Case"</string>
<string name="start_dreams" msgid="9131802557946276718">"Screen saver"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
+ <string name="quick_settings_dnd_label" msgid="7728690179108024338">"Do Not Disturb"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"No paired devices available"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> battery"</string>
@@ -348,6 +354,7 @@
<string name="notification_section_header_alerting" msgid="5581175033680477651">"Notifications"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Conversations"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Clear all silent notifications"</string>
+ <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Notifications paused by Do Not Disturb"</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"Start now"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"No notifications"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"This device is managed by your parent"</string>
@@ -452,8 +459,7 @@
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Unlock to use"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"There was a problem getting your cards. Please try again later."</string>
<string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Lock screen settings"</string>
- <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR code"</string>
- <string name="qr_code_scanner_description" msgid="7937603775306661863">"Tap to scan"</string>
+ <string name="qr_code_scanner_title" msgid="5290201053875420785">"Scan QR code"</string>
<string name="status_bar_work" msgid="5238641949837091056">"Work profile"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Aeroplane mode"</string>
<string name="zen_alarm_warning" msgid="7844303238486849503">"You won\'t hear your next alarm <xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -491,6 +497,8 @@
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"&lt;b&gt;Status:&lt;/b&gt; ranked lower"</string>
<string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"Shows at the top of conversation notifications and as a profile picture on lock screen"</string>
<string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"Shows at the top of conversation notifications and as a profile picture on lock screen, appears as a bubble"</string>
+ <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"Shows at the top of conversation notifications and as a profile picture on lock screen, interrupts Do Not Disturb"</string>
+ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Shows at the top of conversation notifications and as a profile picture on lock screen, appears as a bubble, interrupts Do Not Disturb"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Priority"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> doesn’t support conversation features"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"These notifications can\'t be modified."</string>
@@ -566,6 +574,7 @@
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"SMS"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"Music"</string>
<string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Calendar"</string>
+ <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Do Not Disturb"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"Volume buttons shortcut"</string>
<string name="battery" msgid="769686279459897127">"Battery"</string>
<string name="headset" msgid="4485892374984466437">"Headset"</string>
@@ -684,6 +693,10 @@
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"Wi-Fi is off"</string>
<string name="bt_is_off" msgid="7436344904889461591">"Bluetooth is off"</string>
+ <string name="dnd_is_off" msgid="3185706903793094463">"Do Not Disturb is off"</string>
+ <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"Do Not Disturb was turned on by an automatic rule (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"Do Not Disturb was turned on by an app (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"Do Not Disturb was turned on by an automatic rule or app."</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"Apps running in background"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"Tap for details on battery and data usage"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Turn off mobile data?"</string>
@@ -708,6 +721,8 @@
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(work)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"Phone call"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(through <xliff:g id="APPLICATION_NAME_S_">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_label" msgid="3385241594101496292">"(<xliff:g id="ATTRIBUTION_LABEL">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_proxy_label" msgid="1111829599659403249">"(<xliff:g id="ATTRIBUTION_LABEL">%1$s</xliff:g> • <xliff:g id="PROXY_LABEL">%2$s</xliff:g>)"</string>
<string name="privacy_type_camera" msgid="7974051382167078332">"camera"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"location"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"microphone"</string>
@@ -806,6 +821,9 @@
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(disconnected)"</string>
<string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Can\'t switch. Tap to try again."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Pair new device"</string>
+ <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"To cast this session, please open the app."</string>
+ <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Unknown app"</string>
+ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Stop casting"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Build number"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Build number copied to clipboard."</string>
<string name="basic_status" msgid="2315371112182658176">"Open conversation"</string>
@@ -839,6 +857,7 @@
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"See recent messages, missed calls and status updates"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Conversation"</string>
+ <string name="paused_by_dnd" msgid="7856941866433556428">"Paused by Do Not Disturb"</string>
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> sent a message: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> sent an image"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> has a status update: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
@@ -877,8 +896,7 @@
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> active apps</item>
<item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> active app</item>
</plurals>
- <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
- <skip />
+ <string name="fgs_dot_content_description" msgid="2865071539464777240">"New information"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Active apps"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Stop"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Stopped"</string>
@@ -889,8 +907,12 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Edit copied text"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Edit copied image"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Send to nearby device"</string>
- <!-- no translation found for add (81036585205287996) -->
- <skip />
- <!-- no translation found for manage_users (1823875311934643849) -->
- <skip />
+ <string name="add" msgid="81036585205287996">"Add"</string>
+ <string name="manage_users" msgid="1823875311934643849">"Manage users"</string>
+ <string name="drag_split_not_supported" msgid="4326847447699729722">"This notification does not support dragging to Split screen."</string>
+ <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi unavailable"</string>
+ <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Priority mode"</string>
+ <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarm set"</string>
+ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Camera and mic are off"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notification}other{# notifications}}"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index 18d87f3f6208..052f175280ff 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -20,14 +20,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4811759950673118541">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‏‎‏‏‎‎‎‏‏‎‏‏‎‎‏‏‏‎‎‎‏‎‏‏‏‎‎‏‏‎‏‏‎‎‎‏‎‏‎‎‏‎‏‎‎‎‎‏‎‏‎‏‎‎‏‏‎‏‎System UI‎‏‎‎‏‎"</string>
- <string name="battery_low_title" msgid="6891106956328275225">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‏‏‏‎‏‎‎‎‏‎‎‎‏‎‎‎‎‏‎‏‎‎‎‏‎‎‎‎‏‎‎‎‎‏‎‎‏‎‏‎‏‏‏‎‎‎‏‏‎‏‎‎‎‏‏‎‎‏‎Battery may run out soon‎‏‎‎‏‎"</string>
+ <string name="battery_low_title" msgid="5319680173344341779">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‎‏‏‏‎‏‎‎‏‏‎‏‎‎‏‏‎‎‏‏‏‎‏‏‏‎‏‏‎‎‏‎‏‎‏‏‏‎‎‎‎‎‏‎‏‏‏‏‏‏‎‎‎‏‎‎‏‏‎Turn on Battery Saver?‎‏‎‎‏‎"</string>
+ <string name="battery_low_description" msgid="3282977755476423966">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‎‏‏‎‎‎‏‏‏‏‎‏‏‏‏‎‏‎‏‏‎‏‏‏‏‏‏‏‏‎‏‎‎‎‏‎‏‎‏‏‏‎‎‏‏‏‎‏‎‏‎‎‎‏‏‏‏‎‎You have ‎‏‎‎‏‏‎<xliff:g id="PERCENTAGE">%s</xliff:g>‎‏‎‎‏‏‏‎ battery left. Battery Saver turns on Dark theme, restricts background activity, and delays notifications.‎‏‎‎‏‎"</string>
+ <string name="battery_low_intro" msgid="5148725009653088790">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‏‏‎‏‏‏‎‎‏‏‏‏‏‏‎‎‏‎‎‎‎‏‏‏‎‏‏‏‏‏‏‏‏‎‏‎‎‎‏‎‏‎‏‏‎‎‎‎‏‎‎‎‎‏‎‏‏‎‎Battery Saver turns on Dark theme, restricts background activity, and delays notifications.‎‏‎‎‏‎"</string>
<string name="battery_low_percent_format" msgid="4276661262843170964">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‏‏‎‏‎‏‏‎‎‏‏‏‎‎‎‎‎‎‏‏‎‎‎‎‏‎‏‎‎‎‎‏‎‎‎‏‏‏‎‎‎‎‏‏‎‏‎‎‎‎‏‎‎‏‎‏‎‎‎‎‏‎‎‏‏‎<xliff:g id="PERCENTAGE">%s</xliff:g>‎‏‎‎‏‏‏‎ remaining‎‏‎‎‏‎"</string>
<string name="invalid_charger_title" msgid="938685362320735167">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‎‏‎‎‎‎‎‏‏‎‏‏‏‎‎‎‎‏‎‏‎‏‏‏‎‏‎‎‎‏‏‎‎‎‏‏‏‏‏‏‎‎‎‏‏‏‏‎‏‏‏‎‏‏‏‏‏‏‎Can\'t charge via USB‎‏‎‎‏‎"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‎‎‏‏‏‎‏‏‎‏‏‏‎‎‏‏‎‎‎‏‎‎‏‎‏‏‏‏‏‏‎‎‏‎‎‎‏‎‏‎‏‏‏‏‎‎‏‎‏‎‏‏‏‏‎‎‏‎Use the charger that came with your device‎‏‎‎‏‎"</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‎‏‎‎‏‎‎‎‏‏‏‎‎‏‏‎‎‎‏‎‎‎‏‏‏‏‎‎‏‏‏‎‎‎‎‎‎‎‎‏‏‏‎‏‎‏‎‏‏‏‏‎‏‏‎‏‎‏‎Turn on Battery Saver?‎‏‎‎‏‎"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‏‏‏‏‏‎‏‎‎‎‏‎‎‎‎‎‏‏‎‎‏‏‎‏‏‏‏‎‎‎‎‏‎‎‎‎‎‏‎‎‏‏‏‎‏‎‏‎‏‏‏‏‏‎‏‎‎‏‎About Battery Saver‎‏‎‎‏‎"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‎‏‏‏‏‏‏‎‎‏‎‏‎‎‎‏‎‎‎‏‏‎‏‎‎‏‎‏‎‎‏‎‎‎‏‏‎‏‏‏‏‏‎‎‎‏‏‎‎‏‏‏‏‎‏‏‏‎‎Turn on‎‏‎‎‏‎"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‏‏‎‎‏‏‎‎‎‎‎‏‏‎‏‎‏‎‎‎‏‏‏‎‎‏‎‏‏‎‎‎‎‏‎‎‎‎‏‏‎‎‏‎‏‎‎‎‏‏‏‏‏‏‎‎‎‏‎Turn on Battery Saver‎‏‎‎‏‎"</string>
+ <string name="battery_saver_start_action" msgid="8353766979886287140">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‏‏‎‏‏‏‎‏‎‎‎‏‎‏‎‏‏‎‎‏‏‏‎‏‏‎‏‏‏‎‎‏‎‎‎‎‎‏‎‏‎‎‎‏‎‎‏‎‎‏‎‎‏‎‎‎Turn on‎‏‎‎‏‎"</string>
+ <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‏‏‏‏‏‎‏‎‎‏‎‎‏‏‎‎‏‏‏‏‏‏‏‎‎‎‎‏‎‏‎‏‏‏‎‏‏‎‏‎‏‏‎‏‏‏‎‏‎‏‏‎‎‏‎‎‏‎‎No thanks‎‏‎‎‏‎"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‎‎‏‎‏‏‎‏‏‎‏‎‏‏‎‏‎‎‎‏‎‎‎‎‏‏‎‏‎‏‏‏‎‏‎‏‎‎‎‏‏‎‎‏‎‏‏‏‏‎‏‏‏‎‎‎Auto-rotate screen‎‏‎‎‏‎"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‎‏‎‏‎‎‎‏‎‎‎‎‏‏‏‎‏‏‏‎‎‏‎‎‎‎‏‏‏‎‏‏‎‏‎‎‎‏‏‎‏‎‎‏‎‎‏‏‎‎‎‏‎‎‏‏‎‎‎Allow ‎‏‎‎‏‏‎<xliff:g id="APPLICATION">%1$s</xliff:g>‎‏‎‎‏‏‏‎ to access ‎‏‎‎‏‏‎<xliff:g id="USB_DEVICE">%2$s</xliff:g>‎‏‎‎‏‏‏‎?‎‏‎‎‏‎"</string>
<string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‎‎‎‎‎‏‎‏‏‏‎‏‎‏‏‎‏‎‏‎‎‏‏‏‎‎‎‎‏‏‏‏‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‏‎‏‎‏‎‏‎‎‎‎Allow ‎‏‎‎‏‏‎<xliff:g id="APPLICATION">%1$s</xliff:g>‎‏‎‎‏‏‏‎ to access ‎‏‎‎‏‏‎<xliff:g id="USB_DEVICE">%2$s</xliff:g>‎‏‎‎‏‏‏‎?‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎This app has not been granted record permission but could capture audio through this USB device.‎‏‎‎‏‎"</string>
@@ -128,6 +131,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‏‏‎‎‎‏‏‏‎‏‏‏‎‎‎‏‏‏‎‏‏‎‎‎‏‎‏‎‏‎‏‏‏‎‎‎‎‎‎‏‏‎‎‎‏‏‏‎‎‏‎‎‏‏‏‎‎‎‎Face authenticated‎‏‎‎‏‎"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‎‏‏‏‏‎‎‎‏‎‏‎‏‎‎‎‎‎‏‏‏‎‎‎‏‏‏‎‎‎‎‏‏‏‎‎‎‎‎‎‏‏‏‎‏‏‎‏‎‏‎‎‏‎‏‎‏‎‎Confirmed‎‏‎‎‏‎"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‏‎‏‎‏‎‏‏‎‏‎‏‏‎‏‏‎‏‏‏‎‎‏‏‏‏‏‎‎‎‏‎‏‎‏‏‎‏‎‏‏‎‎‎‎‏‎‏‏‏‏‏‎‎Tap Confirm to complete‎‏‎‎‏‎"</string>
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‏‎‎‎‏‎‏‏‎‎‏‏‏‎‎‎‎‏‎‏‏‏‏‏‎‎‎‎‏‏‏‎‎‏‏‏‎‏‏‎‎‎‎‎‎‏‎‏‏‏‏‏‎‏‎‏‏‎‎Unlocked by your face. Press to continue.‎‏‎‎‏‎"</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‎‏‏‏‎‏‎‎‏‎‏‏‎‎‏‎‎‎‏‎‎‏‏‏‏‎‏‏‎‏‏‎‏‏‎‎‎‎‏‎‏‎‏‏‏‎‏‎‎‎‏‎‏‎‎‏‎‎‎Authenticated‎‏‎‎‏‎"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‎‎‎‏‎‏‏‏‏‎‏‎‎‎‏‏‎‎‏‎‎‏‎‎‏‎‎‎‎‏‎‏‏‎‏‎‎‏‏‏‎‏‏‏‎‏‏‏‎‏‏‎‎‎‎‏‎‏‎Use PIN‎‏‎‎‏‎"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‎‎‎‏‎‎‎‏‎‏‎‏‎‎‎‏‏‏‏‏‎‏‏‎‎‎‎‏‎‏‎‏‏‏‏‏‏‏‎‎‏‎‎‎‏‏‎‏‎‏‎‏‏‏‎‏‎‎Use pattern‎‏‎‎‏‎"</string>
@@ -181,6 +185,7 @@
<string name="accessibility_desc_close" msgid="8293708213442107755">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‏‏‎‎‎‏‏‎‎‏‎‎‏‎‏‎‏‏‏‎‏‎‏‏‎‏‏‎‎‏‏‏‎‎‏‏‏‏‎‏‎‎‏‏‎‏‏‎‎‏‎‏‏‎‏‎‏‏‎Close‎‏‎‎‏‎"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‎‎‏‏‏‎‎‏‏‎‏‏‏‏‏‏‏‎‎‏‎‎‎‎‎‏‏‎‏‎‎‎‎‏‎‏‏‎‎‎‎‎‎‎‎‎‏‎‏‎‏‎‏‏‎‏‏‏‎total silence‎‏‎‎‏‎"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‏‎‏‏‎‏‏‎‎‏‎‏‏‎‏‏‎‎‎‎‏‎‎‏‏‎‏‎‏‏‎‎‎‏‎‏‏‎‏‏‎‎‏‎‎‏‏‏‎‏‏‏‏‎‏‏‏‎‎alarms only‎‏‎‎‏‎"</string>
+ <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‏‏‎‎‎‎‏‏‏‎‎‏‏‏‏‎‏‏‎‎‏‏‎‎‎‏‏‏‏‎‏‎‏‎‎‎‏‏‏‎‏‎‎‎‎‏‏‏‎‏‏‎‏‏‏‏‏‎Do Not Disturb.‎‏‎‎‏‎"</string>
<string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‏‎‏‎‎‎‎‎‎‏‎‎‏‏‏‏‎‎‎‏‏‎‎‎‏‎‏‎‏‎‎‏‎‎‏‎‏‏‏‎‎‏‏‎‏‎‎‏‏‏‎‎‏‏‎‎‏‏‎Bluetooth.‎‏‎‎‏‎"</string>
<string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‎‏‎‎‎‎‎‎‎‎‎‎‎‏‏‎‏‎‏‏‏‏‏‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‎‎‏‎‏‏‏‎‏‏‎‏‏‎‏‏‏‏‎‏‎Bluetooth on.‎‏‎‎‏‎"</string>
<string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‏‏‏‎‏‏‏‏‏‎‏‏‎‎‎‎‎‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‎‏‏‏‏‎‎‏‎‏‎‏‎‏‏‎‎‏‎‏‎‏‎‏‎‎Alarm set for ‎‏‎‎‏‏‎<xliff:g id="TIME">%s</xliff:g>‎‏‎‎‏‏‏‎.‎‏‎‎‏‎"</string>
@@ -205,6 +210,7 @@
<string name="dessert_case" msgid="9104973640704357717">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‎‏‏‎‏‏‎‏‎‏‏‏‎‏‎‏‎‎‏‎‎‏‎‎‏‏‎‏‏‏‎‏‏‏‏‎‏‎‎‏‏‏‎‏‎‏‎‏‎‏‎‏‎‏‎Dessert Case‎‏‎‎‏‎"</string>
<string name="start_dreams" msgid="9131802557946276718">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‎‏‏‏‎‏‎‏‎‏‎‏‏‏‎‎‎‎‎‏‎‏‏‎‏‎‎‏‎‎‏‎‏‏‎‎‏‎‎‎‎‏‎‏‎‏‏‎‏‏‎‏‏‏‎‎Screen saver‎‏‎‎‏‎"</string>
<string name="ethernet_label" msgid="2203544727007463351">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‏‎‏‎‎‏‎‏‎‎‏‎‎‏‎‎‎‎‎‏‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‏‏‏‎‎‎‎‎‏‏‏‏‎‏‏‎‏‏‏‎Ethernet‎‏‎‎‏‎"</string>
+ <string name="quick_settings_dnd_label" msgid="7728690179108024338">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‏‏‎‏‎‎‎‎‎‏‏‏‎‏‎‎‏‎‏‏‎‎‎‏‎‏‎‎‎‎‎‎‎‎‏‏‎‎‏‎‎‎‏‎‏‏‎‎‎‎‎‎‎‏‎‎‏‎‎Do Not Disturb‎‏‎‎‏‎"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‎‏‎‏‏‎‎‏‏‏‏‎‏‎‏‎‎‎‎‎‎‏‏‎‎‎‎‏‏‎‏‏‎‏‎‎‎‎‎‏‏‎‏‎‏‎‎‏‏‏‏‎‎‎‏‎‎‏‎Bluetooth‎‏‎‎‏‎"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‏‏‏‏‏‏‎‎‎‎‎‏‏‏‏‎‏‏‎‏‏‎‎‎‏‎‎‎‎‎‏‎‎‎‏‎‏‏‏‏‎‏‏‎‎‎‎‏‏‎‏‎‎‏‎‎‏‎‎No paired devices available‎‏‎‎‏‎"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‏‎‎‎‎‎‏‎‎‏‏‎‎‏‎‎‏‎‏‎‎‏‏‏‏‎‏‎‏‏‏‏‎‏‏‏‏‏‎‎‎‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‎‏‎‎‏‎‎‏‏‎<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>‎‏‎‎‏‏‏‎ battery‎‏‎‎‏‎"</string>
@@ -348,6 +354,7 @@
<string name="notification_section_header_alerting" msgid="5581175033680477651">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‎‏‎‏‏‏‎‏‎‎‎‏‎‏‎‎‎‏‎‎‎‏‏‏‏‏‎‏‏‎‏‏‏‏‏‏‎‎‏‏‎‏‏‎‏‏‏‏‎‏‏‏‎‏‎‎‏‏‎Notifications‎‏‎‎‏‎"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‏‏‎‏‏‎‎‏‏‏‏‎‏‏‏‏‏‎‎‏‎‏‏‎‎‎‏‎‎‎‏‏‎‎‎‏‎‎‏‎‎‎‎‎‏‏‎‎‎‎‏‎‏‏‏‏‎‏‎Conversations‎‏‎‎‏‎"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‏‎‎‎‎‏‎‎‎‏‏‏‎‏‏‎‎‏‏‎‏‏‎‎‏‎‎‏‎‎‏‎‎‎‏‎‏‏‎‏‏‎‏‎‏‏‎‎‎‏‎‎‎‏‏‏‏‏‎Clear all silent notifications‎‏‎‎‏‎"</string>
+ <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‎‏‏‎‎‎‏‏‎‏‎‏‏‏‎‏‎‏‏‏‎‏‎‎‎‎‎‏‏‎‏‎‏‎‎‏‎‏‏‎‎‎‎‎‏‎‏‎‏‏‎‎‏‎‏‎‏‎‎Notifications paused by Do Not Disturb‎‏‎‎‏‎"</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‏‎‎‏‏‏‎‎‎‏‏‏‎‎‏‎‎‎‎‏‏‏‎‎‏‎‎‎‏‎‏‎‎‏‏‏‎‏‎‎‏‎‎‏‏‏‎‏‎‏‏‏‎‎‏‎‎‎‎Start now‎‏‎‎‏‎"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‎‎‎‎‎‎‎‎‏‎‏‏‏‎‏‏‏‎‏‏‎‎‏‎‎‎‏‏‏‎‏‎‎‎‏‎‎‏‏‎‎‏‎‏‎‏‎‎‏‎‎‎‏‎‎‏‎‎‎No notifications‎‏‎‎‏‎"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‎‏‎‏‎‏‎‏‏‎‏‏‎‎‏‏‎‏‎‏‎‏‏‏‎‎‎‏‎‎‏‏‏‎‏‎‏‏‎‏‎‏‎‏‏‎‏‎‎‎‏‏‏‏‎‎‎‎‎This device is managed by your parent‎‏‎‎‏‎"</string>
@@ -452,8 +459,7 @@
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‏‏‏‏‎‏‎‏‎‎‎‏‎‏‏‎‏‏‎‎‎‏‎‏‎‏‎‏‏‎‎‎‎‎‎‏‏‎‎‏‏‏‎‏‎‏‏‏‏‎‏‎‎‎‏‎‏‎‎Unlock to use‎‏‎‎‏‎"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‎‏‏‏‎‎‏‎‎‏‏‏‎‎‎‏‏‎‎‏‏‏‏‎‎‎‎‏‏‏‏‎‎‏‎‏‏‎‎‎‎‎‎‎‎‎‏‎‎‎‏‏‎‎‏‏‎‏‏‎There was a problem getting your cards, please try again later‎‏‎‎‏‎"</string>
<string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‎‏‎‎‎‏‏‏‎‏‎‏‏‎‏‏‎‏‏‎‎‎‎‏‎‏‎‎‏‎‏‎‎‏‎‎‎‏‎‏‎‎‏‏‎‎‎‏‏‏‏‏‎‏‎‎‏‎‎Lock screen settings‎‏‎‎‏‎"</string>
- <string name="qr_code_scanner_title" msgid="5660820608548306581">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‏‎‏‎‎‎‏‏‏‏‎‏‎‎‎‏‏‎‎‏‎‏‏‎‎‏‏‏‏‎‎‏‎‏‏‎‏‏‏‎‏‏‎‏‏‏‏‏‏‎‏‎‎‏‎‏‎‏‎QR code‎‏‎‎‏‎"</string>
- <string name="qr_code_scanner_description" msgid="7937603775306661863">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‏‎‎‎‏‎‏‎‎‎‎‎‎‎‏‎‎‎‏‎‎‏‎‏‎‎‎‎‎‏‎‎‏‎‏‏‏‏‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‎Tap to scan‎‏‎‎‏‎"</string>
+ <string name="qr_code_scanner_title" msgid="5290201053875420785">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‎‏‎‏‏‎‏‎‏‎‏‎‎‏‎‎‎‏‏‏‎‏‎‏‎‎‎‏‏‎‏‏‏‎‏‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‎‎‎‏‎Scan QR code‎‏‎‎‏‎"</string>
<string name="status_bar_work" msgid="5238641949837091056">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‎‎‏‎‏‏‎‎‏‏‎‏‏‎‎‏‎‏‎‎‎‏‏‎‎‏‎‎‎‎‏‏‎‏‎‏‏‏‏‏‏‏‏‏‏‎‎‎‎‎‏‏‏‏‎‎‎‎‎Work profile‎‏‎‎‏‎"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‏‏‎‏‎‎‏‎‏‎‎‎‎‎‏‏‎‏‎‎‏‏‏‏‎‏‏‏‏‏‏‎‏‏‏‎‏‎‏‏‏‏‏‏‏‏‏‏‎‎‎‏‎‏‎‎‎‏‎Airplane mode‎‏‎‎‏‎"</string>
<string name="zen_alarm_warning" msgid="7844303238486849503">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‎‎‏‏‎‏‏‏‎‎‏‎‎‏‎‎‎‎‎‎‏‏‏‏‎‎‎‎‎‎‏‎‎‎‎‏‏‏‎‏‎‎‎‏‏‏‎‏‏‏‏‏‎‏‏‏‏‏‎You won\'t hear your next alarm ‎‏‎‎‏‏‎<xliff:g id="WHEN">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
@@ -491,6 +497,8 @@
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‏‎‏‏‎‏‎‏‎‎‎‎‏‏‎‎‏‎‏‎‎‎‎‎‎‏‏‎‏‎‎‎‏‎‏‎‏‏‏‏‏‎‎‏‏‏‎‎‎‎‎‎‏‎‏‎‎‎&lt;b&gt;Status:&lt;/b&gt; Ranked Lower‎‏‎‎‏‎"</string>
<string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‎‎‏‎‏‎‎‏‎‏‏‏‎‏‎‎‏‎‎‏‏‎‎‎‏‎‎‎‏‎‎‎‎‏‏‏‎‎‎‏‏‎‏‎‎‏‏‏‏‏‎‏‎‎‎‎‏‎‎Shows at the top of conversation notifications and as a profile picture on lock screen‎‏‎‎‏‎"</string>
<string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‎‏‏‎‏‏‎‎‏‏‎‎‏‎‏‏‎‏‎‏‏‏‎‏‏‏‎‎‏‏‏‏‎‎‏‎‏‏‏‎‎‎‏‎‏‎‎‏‏‎‎‎‎‏‎‎‎‎‎Shows at the top of conversation notifications and as a profile picture on lock screen, appears as a bubble‎‏‎‎‏‎"</string>
+ <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‎‎‏‎‎‎‎‎‎‎‎‎‏‏‏‏‎‏‎‏‏‏‎‏‎‏‎‏‏‏‏‎‎‏‎‏‎‏‎‎‎‏‎‎‎‎‎‎‏‎‏‏‏‏‏‎‎‏‎Shows at the top of conversation notifications and as a profile picture on lock screen, interrupts Do Not Disturb‎‏‎‎‏‎"</string>
+ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‏‏‎‏‎‎‎‎‎‎‎‎‏‎‎‎‎‏‎‏‏‎‏‏‎‎‏‏‎‏‏‎‎‏‎‏‎‎‏‎‏‎‎‎‏‎‏‎‎‏‎‎‎‏‏‏‎‏‎Shows at the top of conversation notifications and as a profile picture on lock screen, appears as a bubble, interrupts Do Not Disturb‎‏‎‎‏‎"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‎‎‏‏‎‏‏‏‎‎‏‎‎‏‏‏‎‎‎‎‏‏‎‎‎‏‏‏‏‏‎‏‏‎‎‎‎‎‏‎‏‎‎‏‏‏‎‎‏‏‎‏‎‎‎‏‎‏‎Priority‎‏‎‎‏‎"</string>
<string name="no_shortcut" msgid="8257177117568230126">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‏‎‏‎‎‏‎‏‏‏‎‏‏‎‎‎‏‎‏‏‎‏‎‏‏‏‎‎‎‎‏‏‎‎‎‎‏‎‎‎‏‏‎‏‏‎‎‎‏‎‏‏‏‎‏‏‏‎‎‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎ doesn’t support conversation features‎‏‎‎‏‎"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‎‎‏‏‎‎‎‏‎‎‏‏‏‎‎‎‏‎‏‎‎‏‏‎‏‏‏‎‎‎‎‎‎‎‏‏‎‎‏‏‏‏‏‏‏‏‎‎‏‎‏‏‎‏‎‏‎‎‎These notifications can\'t be modified.‎‏‎‎‏‎"</string>
@@ -566,6 +574,7 @@
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‏‏‏‏‏‎‏‏‏‎‏‎‎‏‏‎‏‏‏‏‎‏‏‎‎‎‎‏‏‎‎‎‏‏‏‏‏‏‏‎‎‏‏‏‎‎‎‎‎‏‎‎‏‎‏‏‏‎‎SMS‎‏‎‎‏‎"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‎‏‎‏‎‏‏‎‎‎‎‏‏‎‎‎‏‏‏‎‎‎‎‎‎‎‏‎‎‏‏‎‎‏‎‎‎‎‏‏‎‎‎‎‏‎‎‏‏‏‎‏‏‏‏‎‎‏‎Music‎‏‎‎‏‎"</string>
<string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‏‎‏‎‏‏‎‎‏‎‏‎‎‏‎‎‎‏‏‎‎‎‎‎‏‏‎‎‎‎‏‏‏‎‎‏‎‎‎‎‎‎‎‏‎‎‏‎‎‎‎‎‏‎‏‏‎‏‎Calendar‎‏‎‎‏‎"</string>
+ <string name="volume_and_do_not_disturb" msgid="502044092739382832">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‏‎‏‏‏‏‎‏‏‏‏‎‎‏‏‏‏‎‎‏‏‏‎‎‎‏‎‏‎‎‎‎‎‏‎‏‎‏‎‎‎‎‎‏‏‎‏‏‏‎‎‎‏‏‎‎‎‎‎Do Not Disturb‎‏‎‎‏‎"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‎‏‏‎‏‎‏‎‎‎‎‎‎‏‏‎‎‎‎‎‏‏‎‏‏‏‎‎‏‎‏‎‏‎‎‎‏‎‎‎‎‎‎‎‎‏‏‏‎‎‏‏‏‎‏‏‎‏‎Volume buttons shortcut‎‏‎‎‏‎"</string>
<string name="battery" msgid="769686279459897127">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‏‎‏‎‏‎‏‏‏‎‎‏‏‏‏‎‎‏‏‎‎‏‎‏‏‏‏‏‎‏‏‎‏‏‏‎‏‏‎‎‏‎‏‏‏‏‏‏‏‏‎‎‏‎‎‏‏‏‎Battery‎‏‎‎‏‎"</string>
<string name="headset" msgid="4485892374984466437">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‏‎‎‏‎‎‎‎‎‏‎‎‎‏‎‏‏‏‎‏‎‏‏‎‎‏‎‎‎‎‎‏‏‏‏‎‎‏‎‏‎‏‎‎‏‎‎‎‎‎‎‎‎‎‎‏‎‏‎Headset‎‏‎‎‏‎"</string>
@@ -684,6 +693,10 @@
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‎‏‎‏‏‏‎‏‎‎‎‎‎‏‎‎‏‏‏‏‎‏‎‏‏‏‏‎‎‎‎‏‏‏‏‎‏‎‎‎‏‎‎‎‎‎‏‏‏‏‎‏‏‏‎‎‎‏‎‎‏‏‎<xliff:g id="CARRIER_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎, ‎‏‎‎‏‏‎<xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‏‎‏‏‎‎‏‎‏‏‏‎‏‏‎‎‏‎‎‏‎‎‎‏‏‎‏‏‎‏‎‎‎‏‎‏‎‎‏‏‏‏‎‎‎‎‎‎‏‎‏‎‏‏‏‏‏‏‎Wi-Fi is off‎‏‎‎‏‎"</string>
<string name="bt_is_off" msgid="7436344904889461591">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‏‏‎‎‏‏‎‎‏‏‎‎‏‏‎‏‎‎‎‏‎‎‏‎‏‎‏‎‏‎‎‎‏‏‎‎‏‏‏‎‎‎‏‏‏‎‏‎‏‏‎‏‎‏‎‏‏‏‎Bluetooth is off‎‏‎‎‏‎"</string>
+ <string name="dnd_is_off" msgid="3185706903793094463">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‎‎‎‎‏‏‎‏‎‏‏‏‏‎‎‏‏‏‏‎‎‎‏‏‎‎‏‏‏‎‎‏‏‏‎‎‎‏‏‎‎‎‏‏‎‎‏‏‏‏‎‎‏‏‏‏‏‏‎Do Not Disturb is off‎‏‎‎‏‎"</string>
+ <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‎‏‎‎‎‏‎‎‎‎‏‎‎‎‎‎‏‎‏‎‏‏‏‏‏‏‏‏‏‎‏‏‎‎‏‏‎‏‏‎‏‏‎‏‎‏‏‎‏‏‏‎‏‏‏‎‎‎‎Do Not Disturb was turned on by an automatic rule (‎‏‎‎‏‏‎<xliff:g id="ID_1">%s</xliff:g>‎‏‎‎‏‏‏‎).‎‏‎‎‏‎"</string>
+ <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‏‏‏‏‏‎‎‏‏‎‎‏‎‎‎‏‏‎‏‎‎‎‎‎‏‏‏‎‏‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‏‏‏‎‏‏‏‏‎‏‎‏‎‎‎Do Not Disturb was turned on by an app (‎‏‎‎‏‏‎<xliff:g id="ID_1">%s</xliff:g>‎‏‎‎‏‏‏‎).‎‏‎‎‏‎"</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‏‏‎‎‎‏‏‏‎‎‎‏‏‎‏‏‏‎‎‏‎‏‎‎‎‎‏‎‏‏‎‏‏‏‎‏‏‏‏‎‏‏‎‏‎‎‏‏‎‎‎‏‏‎‏‎‎‎Do Not Disturb was turned on by an automatic rule or app.‎‏‎‎‏‎"</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‏‏‎‏‎‎‏‎‏‏‎‏‏‎‎‏‏‏‎‎‎‏‏‏‎‎‏‏‎‏‎‎‏‎‎‏‎‎‏‏‎‎‏‏‏‏‎‏‎‎‏‏‏‏‏‏‎‏‎Apps running in background‎‏‎‎‏‎"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‎‏‏‏‎‎‎‎‏‏‏‎‏‏‏‏‏‏‎‏‎‎‎‎‎‎‎‏‎‏‏‏‏‏‏‏‏‏‏‎‏‎‏‎‎‏‏‏‎‏‏‏‎‏‏‎‎‏‎Tap for details on battery and data usage‎‏‎‎‏‎"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‏‎‎‏‏‏‏‎‎‏‏‎‎‎‏‏‎‏‏‎‎‏‏‎‏‏‏‏‏‎‎‎‏‏‏‏‏‎‎‏‏‎‎‎‏‏‎‎‎‎‏‏‏‏‏‏‏‎‎Turn off mobile data?‎‏‎‎‏‎"</string>
@@ -708,6 +721,8 @@
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‎‏‏‎‏‎‏‏‎‏‏‏‏‎‏‎‏‎‎‏‎‎‏‎‎‎‏‏‏‎‎‏‎‎‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‏‎‏‏‎‏‎(work)‎‏‎‎‏‎"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‏‎‎‏‎‎‎‏‏‎‎‏‎‏‎‏‏‏‏‏‎‎‎‎‎‎‎‏‏‎‎‏‏‎‏‎‏‏‎‏‏‎‎‏‎‎‏‏‏‏‏‏‎‎‎‎‏‎‎Phone call‎‏‎‎‏‎"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‎‏‏‏‎‎‎‎‏‏‏‎‎‏‎‏‎‏‏‏‎‎‏‎‎‏‎‏‏‏‎‎‏‏‎‏‎‏‏‏‎‏‏‎‎‏‏‏‎‏‏‏‏‎‏‎‏‎‎(through ‎‏‎‎‏‏‎<xliff:g id="APPLICATION_NAME_S_">%s</xliff:g>‎‏‎‎‏‏‏‎)‎‏‎‎‏‎"</string>
+ <string name="ongoing_privacy_dialog_attribution_label" msgid="3385241594101496292">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‏‎‏‏‏‏‏‎‏‎‏‏‎‎‏‎‏‏‎‏‎‎‏‎‏‏‎‏‎‎‎‏‏‏‎‏‎‎‏‎‏‏‏‏‏‏‏‎‎‏‏‏‏‎‎‏‎‎‎(‎‏‎‎‏‏‎<xliff:g id="ATTRIBUTION_LABEL">%s</xliff:g>‎‏‎‎‏‏‏‎)‎‏‎‎‏‎"</string>
+ <string name="ongoing_privacy_dialog_attribution_proxy_label" msgid="1111829599659403249">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‏‎‏‏‎‏‏‏‎‎‎‎‎‎‎‏‏‎‎‏‎‎‎‎‏‎‏‎‏‎‎‏‎‎‏‏‏‎‏‏‎‏‎‏‎‎‏‏‏‏‏‏‏‎‎‎‏‎(‎‏‎‎‏‏‎<xliff:g id="ATTRIBUTION_LABEL">%1$s</xliff:g>‎‏‎‎‏‏‏‎ • ‎‏‎‎‏‏‎<xliff:g id="PROXY_LABEL">%2$s</xliff:g>‎‏‎‎‏‏‏‎)‎‏‎‎‏‎"</string>
<string name="privacy_type_camera" msgid="7974051382167078332">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‏‎‏‎‏‎‏‎‎‏‏‎‎‎‎‏‎‏‎‏‏‏‏‎‏‏‏‏‎‏‎‏‏‎‏‏‎‎‏‎‎‎‎‎‎‎‎‏‎‏‏‎‏‏‏‏‎‎‎camera‎‏‎‎‏‎"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‏‎‏‏‏‎‎‏‏‏‎‏‏‏‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‎‏‎‎‎‏‏‏‏‏‏‎‎‏‎‏‏‏‎‎‎‏‏‏‏‎location‎‏‎‎‏‎"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‎‏‏‎‎‎‏‎‎‏‏‏‎‎‏‎‏‏‏‎‏‎‏‎‏‎‏‎‏‎‏‎‎‏‎‏‎‎‎‎‎‎‎‏‎‎‏‎‎‏‏‎‎‎microphone‎‏‎‎‏‎"</string>
@@ -806,6 +821,9 @@
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‏‎‎‏‏‎‎‏‏‎‏‎‎‎‏‏‏‏‏‏‎‏‏‏‏‏‎‏‎‏‏‎‏‏‏‎‎‎‎‎‎‏‎‏‏‎‏‎‎‎‏‎‎‏‎‎‎‏‎(disconnected)‎‏‎‎‏‎"</string>
<string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‏‎‏‏‎‎‎‎‎‏‏‏‎‏‎‎‎‎‎‏‎‎‎‏‏‎‏‎‏‎‎‏‏‏‏‎‎‎‏‎‏‏‎‏‎‎‎‎‎‏‎‏‏‏‏‎‏‏‎Can\'t switch. Tap to try again.‎‏‎‎‏‎"</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‎‏‏‎‎‏‎‏‎‏‏‎‎‏‏‎‎‎‏‎‏‎‎‏‎‎‏‏‏‎‏‏‎‏‎‎‏‏‎‎Pair new device‎‏‎‎‏‎"</string>
+ <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‎‏‎‎‏‏‎‎‏‎‎‏‏‏‎‏‏‎‎‏‎‏‎‎‏‎‎‏‎‏‎‏‎‏‏‏‏‎‎‏‏‎‏‎‎‎‎‏‏‎‎‎‎‏‎‎‏‏‎To cast this session, please open the app.‎‏‎‎‏‎"</string>
+ <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‏‎‎‎‎‏‏‏‎‎‏‎‏‎‏‏‎‎‎‏‏‎‎‎‏‎‏‎‎‎‎‏‏‏‎‎‎‏‎‎‏‏‏‏‏‏‏‎‏‏‏‎‎‏‎‎‎‎Unknown app‎‏‎‎‏‎"</string>
+ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‏‏‎‏‎‏‎‏‎‏‏‏‎‎‎‎‎‏‏‏‎‏‎‎‎‏‏‏‏‏‎‎‏‎‎‏‎‏‏‎‏‎‏‎‏‎‎‎‎‎‏‎‎‏‎‏‎‏‎Stop casting‎‏‎‎‏‎"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‏‎‎‏‎‎‏‎‎‎‎‎‎‏‏‏‎‎‎‎‎‎‏‎‎‏‏‎‏‏‏‏‏‏‎‏‏‏‏‏‏‎‎‎‎‏‏‏‏‎‎‎‎‏‎‎‏‎‎Build number‎‏‎‎‏‎"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‎‎‎‎‏‎‏‏‏‎‎‏‎‎‏‎‏‎‏‎‎‎‎‏‏‏‎‎‏‎‎‎‎‎‎‎‏‏‏‎‎‏‎‏‏‏‏‎‎‎‎‏‎‎‎‏‏‎‎Build number copied to clipboard.‎‏‎‎‏‎"</string>
<string name="basic_status" msgid="2315371112182658176">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‎‎‎‏‎‎‎‎‏‏‏‎‏‏‎‎‏‏‏‎‎‎‎‏‎‎‏‎‏‏‎‎‎‏‏‎‏‏‎‎‏‎‎‏‏‎‏‎‎‏‎‎‎‎‎‎‎‎Open conversation‎‏‎‎‏‎"</string>
@@ -839,6 +857,7 @@
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‎‎‏‏‏‏‎‏‎‎‎‎‎‏‏‏‏‎‏‏‏‏‎‎‎‎‎‎‎‏‏‏‏‏‎‏‏‎‏‏‏‏‏‎‎‎‏‏‏‎‎‎‎‏‏‎‏‏‎‎‏‎‎‏‏‎<xliff:g id="NUMBER">%d</xliff:g>‎‏‎‎‏‏‏‎+‎‏‎‎‏‎"</string>
<string name="people_tile_description" msgid="8154966188085545556">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‎‏‎‎‏‎‏‏‎‎‎‏‎‎‎‎‏‎‏‎‎‎‏‎‏‎‏‎‎‎‏‏‎‎‎‎‏‎‏‎‎‏‎‎‎‎‏‎‏‎‎‏‎‏‎‏‎‎‎See recent messages, missed calls, and status updates‎‏‎‎‏‎"</string>
<string name="people_tile_title" msgid="6589377493334871272">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‏‏‎‏‏‏‎‎‏‎‎‎‏‎‏‎‏‏‏‏‏‎‏‎‏‏‎‎‎‎‏‏‎‏‎‎‏‎‏‏‎‏‏‏‎‎‏‏‎‎‏‏‏‎‏‎‎‎‎Conversation‎‏‎‎‏‎"</string>
+ <string name="paused_by_dnd" msgid="7856941866433556428">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‎‏‎‎‎‎‏‎‎‏‎‏‏‏‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‎‏‎‎‏‏‎‏‎‏‎‏‎‏‎‏‎‏‏‏‏‏‏‎‎‏‏‎‎‎Paused by Do Not Disturb‎‏‎‎‏‎"</string>
<string name="new_notification_text_content_description" msgid="2915029960094389291">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‎‎‎‏‏‏‎‏‎‎‎‏‎‎‎‏‎‎‎‏‎‎‏‏‎‏‏‏‏‎‎‎‎‏‎‎‎‎‏‏‎‎‎‎‎‏‎‏‎‎‎‎‏‎‏‎‏‏‎‎‏‎‎‏‏‎<xliff:g id="NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎ sent a message: ‎‏‎‎‏‏‎<xliff:g id="NOTIFICATION">%2$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‏‏‏‎‎‎‎‎‏‎‎‏‏‏‏‎‏‎‏‎‏‎‎‎‎‏‏‎‏‎‎‏‎‏‏‏‎‏‎‎‏‏‎‏‎‎‎‎‏‎‏‏‎‎‎‎‏‏‎‎‏‎‎‏‏‎<xliff:g id="NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎ sent an image‎‏‎‎‏‎"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‏‏‏‏‏‎‏‎‎‏‏‏‏‏‏‎‎‏‎‎‎‏‏‏‏‏‏‎‎‎‏‏‎‏‏‏‏‎‎‎‏‎‎‎‎‏‎‏‏‎‏‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎<xliff:g id="NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎ has a status update: ‎‏‎‎‏‏‎<xliff:g id="STATUS">%2$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
@@ -890,4 +909,10 @@
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‎‎‎‏‎‎‎‎‎‎‎‎‏‏‏‏‏‎‏‏‏‏‎‏‎‎‏‎‏‏‏‏‏‏‏‎‏‏‏‏‏‎‎‎‎‏‎‏‎‎‏‏‎‏‎‎‏‎‎Send to nearby device‎‏‎‎‏‎"</string>
<string name="add" msgid="81036585205287996">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‎‏‏‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‎‎‏‎‏‏‎‎‎‎‏‎‎‏‎‏‎‏‏‏‏‏‎‎‎‏‏‎‎‏‏‎‎‎‎‏‏‏‏‎‎‎Add‎‏‎‎‏‎"</string>
<string name="manage_users" msgid="1823875311934643849">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‏‎‏‎‎‏‏‏‏‏‎‏‏‎‏‎‎‏‏‏‎‏‏‏‎‏‏‎‏‎‎‏‎‎‏‏‏‏‎‎‎‎‎‎‏‏‏‏‎‏‎‎‎‏‎‎‏‎Manage users‎‏‎‎‏‎"</string>
+ <string name="drag_split_not_supported" msgid="4326847447699729722">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‎‎‎‎‎‎‏‏‎‎‎‎‎‎‏‏‎‎‏‏‎‏‎‏‎‎‎‎‏‏‏‏‎‏‎‏‏‏‎‎‏‎‏‎‏‎‏‏‎‏‎‎‏‏‏‎‏‎‎This notification does not support dragging to Splitscreen.‎‏‎‎‏‎"</string>
+ <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‏‎‎‏‏‎‏‎‎‎‏‏‎‎‏‏‎‎‏‎‏‎‎‏‏‎‏‏‏‎‎‎‎‏‏‏‎‏‎‏‏‎‎‏‏‎‏‎‏‏‏‎‏‏‏‏‏‎‎Wi‑Fi unavailable‎‏‎‎‏‎"</string>
+ <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‏‏‎‏‎‏‎‏‎‏‏‏‎‎‎‏‎‏‏‎‎‎‏‎‏‎‎‎‏‏‏‎‎‎‏‏‎‏‎‏‏‎‎‏‎‎‏‏‏‏‎‎‏‎‎‎‏‏‎Priority mode‎‏‎‎‏‎"</string>
+ <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‏‏‏‏‎‏‏‏‎‏‎‏‎‏‏‎‎‏‎‏‎‏‎‎‎‎‎‎‎‎‎‏‏‎‎‏‎‎‏‏‏‎‎‎‏‎‎‏‎‏‎‎‏‎‎‏‏‎‎Alarm set‎‏‎‎‏‎"</string>
+ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‎‎‎‏‏‎‎‏‏‎‏‎‏‎‎‏‎‎‎‏‎‏‎‎‏‎‎‎‎‏‏‎‏‎‏‎‎‏‏‎‎‎‎‎‏‏‏‎‏‎‎‎‎‎‎‎‎‏‎Camera and mic are off‎‏‎‎‏‎"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‎‎‎‏‎‎‏‎‏‎‎‏‏‎‎‎‏‏‏‎‏‎‏‎‎‎‎‏‏‏‎‏‎‎‏‏‏‎‎‎‎‏‎‎‎‏‎‏‏‏‏‏‏‎‏‏‏‏‎# notification‎‏‎‎‏‎}other{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‎‎‎‏‎‎‏‎‏‎‎‏‏‎‎‎‏‏‏‎‏‎‏‎‎‎‎‏‏‏‎‏‎‎‏‏‏‎‎‎‎‏‎‎‎‏‎‏‏‏‏‏‏‎‏‏‏‏‎# notifications‎‏‎‎‏‎}}"</string>
</resources>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 3f1cc42f880b..57996ee26e6f 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -20,14 +20,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4811759950673118541">"IU del sistema"</string>
- <string name="battery_low_title" msgid="6891106956328275225">"Es posible que pronto se agote la batería"</string>
+ <string name="battery_low_title" msgid="5319680173344341779">"¿Quieres activar el Ahorro de batería?"</string>
+ <string name="battery_low_description" msgid="3282977755476423966">"Tienes <xliff:g id="PERCENTAGE">%s</xliff:g> de batería restante. El Ahorro de batería activa el Tema oscuro, restringe la actividad en segundo plano y retrasa las notificaciones."</string>
+ <string name="battery_low_intro" msgid="5148725009653088790">"El Ahorro de batería activa el Tema oscuro, restringe la actividad en segundo plano y retrasa las notificaciones."</string>
<string name="battery_low_percent_format" msgid="4276661262843170964">"Queda un <xliff:g id="PERCENTAGE">%s</xliff:g> de batería."</string>
<string name="invalid_charger_title" msgid="938685362320735167">"No se puede cargar mediante USB"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"Usa el cargador que se incluyó con el dispositivo"</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"¿Deseas activar Ahorro de batería?"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Acerca del Ahorro de batería"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Activar"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"Activar el Ahorro de batería"</string>
+ <string name="battery_saver_start_action" msgid="8353766979886287140">"Activar"</string>
+ <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"No, gracias"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Girar la pantalla automáticamente"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"¿Deseas permitir que <xliff:g id="APPLICATION">%1$s</xliff:g> acceda a <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
<string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"¿Quieres permitir que <xliff:g id="APPLICATION">%1$s</xliff:g> acceda a <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nLa app no tiene permiso para grabar, pero podría capturar audio mediante este dispositivo USB."</string>
@@ -128,6 +131,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Se autenticó el rostro"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Confirmado"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Presiona Confirmar para completar"</string>
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Disp. desbloqueado con rostro. Presiona para continuar."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Autenticado"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Usar PIN"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Usar patrón"</string>
@@ -181,6 +185,7 @@
<string name="accessibility_desc_close" msgid="8293708213442107755">"Cerrar"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"silencio total"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"solo alarmas"</string>
+ <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"No interrumpir."</string>
<string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"Bluetooth"</string>
<string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"Bluetooth activado"</string>
<string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"Alarma: <xliff:g id="TIME">%s</xliff:g>"</string>
@@ -205,6 +210,7 @@
<string name="dessert_case" msgid="9104973640704357717">"Caja para postres"</string>
<string name="start_dreams" msgid="9131802557946276718">"Protector pantalla"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
+ <string name="quick_settings_dnd_label" msgid="7728690179108024338">"No interrumpir"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"No hay dispositivos sincronizados disponibles"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> de batería"</string>
@@ -348,6 +354,7 @@
<string name="notification_section_header_alerting" msgid="5581175033680477651">"Notificaciones"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Conversaciones"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Borrar todas las notificaciones silenciosas"</string>
+ <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Notificaciones pausadas por el modo \"No interrumpir\""</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"Comenzar ahora"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"No hay notificaciones"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Tu padre o madre administra este dispositivo"</string>
@@ -452,8 +459,8 @@
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Desbloquear para usar"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Ocurrió un problema al obtener las tarjetas; vuelve a intentarlo más tarde"</string>
<string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Configuración de pantalla de bloqueo"</string>
- <string name="qr_code_scanner_title" msgid="5660820608548306581">"Código QR"</string>
- <string name="qr_code_scanner_description" msgid="7937603775306661863">"Presiona para escanear"</string>
+ <!-- no translation found for qr_code_scanner_title (5290201053875420785) -->
+ <skip />
<string name="status_bar_work" msgid="5238641949837091056">"Perfil de trabajo"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Modo de avión"</string>
<string name="zen_alarm_warning" msgid="7844303238486849503">"No oirás la próxima alarma a la(s) <xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -491,6 +498,8 @@
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"&lt;b&gt;Estado:&lt;/b&gt; Se clasificó en una posición inferior"</string>
<string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"Aparece como foto de perfil en la parte superior de las notificaciones de conversación, en la pantalla de bloqueo"</string>
<string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"Aparece en forma de burbuja y como foto de perfil en la parte superior de las notificaciones de conversación, en la pantalla de bloqueo"</string>
+ <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"Aparece como foto de perfil en la parte superior de las notificaciones de conversación, en la pantalla de bloqueo, y detiene el modo No interrumpir"</string>
+ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Aparece en forma de burbuja y como foto de perfil en la parte superior de las notificaciones de conversación, en la pantalla de bloqueo, y detiene el modo No interrumpir"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritaria"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> no admite funciones de conversación"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"No se pueden modificar estas notificaciones."</string>
@@ -566,6 +575,7 @@
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"SMS"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"Música"</string>
<string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Calendario"</string>
+ <string name="volume_and_do_not_disturb" msgid="502044092739382832">"No interrumpir"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"Combinación de teclas de botones de volumen"</string>
<string name="battery" msgid="769686279459897127">"Batería"</string>
<string name="headset" msgid="4485892374984466437">"Auriculares"</string>
@@ -684,6 +694,10 @@
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"Wi-Fi desactivado"</string>
<string name="bt_is_off" msgid="7436344904889461591">"Bluetooth desactivado"</string>
+ <string name="dnd_is_off" msgid="3185706903793094463">"No interrumpir desactivado"</string>
+ <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"Se activó el modo No interrumpir con una regla automática (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"Se activó el modo No interrumpir con una app (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"Se activó el modo No interrumpir con una app o regla automática."</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"Apps que se ejecutan en segundo plano"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"Presiona para obtener información sobre el uso de datos y de la batería"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"¿Deseas desactivar los datos móviles?"</string>
@@ -708,6 +722,8 @@
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(trabajo)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"Llamada telefónica"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(a través de <xliff:g id="APPLICATION_NAME_S_">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_label" msgid="3385241594101496292">"(<xliff:g id="ATTRIBUTION_LABEL">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_proxy_label" msgid="1111829599659403249">"(<xliff:g id="ATTRIBUTION_LABEL">%1$s</xliff:g> • <xliff:g id="PROXY_LABEL">%2$s</xliff:g>)"</string>
<string name="privacy_type_camera" msgid="7974051382167078332">"cámara"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"ubicación"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"micrófono"</string>
@@ -806,6 +822,9 @@
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(desconectado)"</string>
<string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"No se pudo conectar. Presiona para volver a intentarlo."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Vincular dispositivo nuevo"</string>
+ <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Para transmitir esta sesión, abre la app"</string>
+ <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"App desconocida"</string>
+ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Detener transmisión"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Número de compilación"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Se copió el número de compilación en el portapapeles."</string>
<string name="basic_status" msgid="2315371112182658176">"Conversación abierta"</string>
@@ -839,6 +858,7 @@
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g> o más"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Consulta mensajes recientes, llamadas perdidas y actualizaciones de estado"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Conversación"</string>
+ <string name="paused_by_dnd" msgid="7856941866433556428">"Se detuvo por el modo No interrumpir"</string>
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> envió un mensaje: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> envió una imagen"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> actualizó su estado: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
@@ -877,8 +897,7 @@
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> apps activas</item>
<item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> app activa</item>
</plurals>
- <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
- <skip />
+ <string name="fgs_dot_content_description" msgid="2865071539464777240">"Nueva información"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Apps activas"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Detener"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Detenida"</string>
@@ -886,14 +905,15 @@
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Se copió"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"De <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Descartar la copia de la IU"</string>
- <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
- <skip />
- <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
- <skip />
- <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
- <skip />
- <!-- no translation found for add (81036585205287996) -->
- <skip />
- <!-- no translation found for manage_users (1823875311934643849) -->
- <skip />
+ <string name="clipboard_edit_text_description" msgid="805254383912962103">"Editar el texto copiado"</string>
+ <string name="clipboard_edit_image_description" msgid="8904857948976041306">"Editar la imagen copiada"</string>
+ <string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Enviar a dispositivos cercanos"</string>
+ <string name="add" msgid="81036585205287996">"Agregar"</string>
+ <string name="manage_users" msgid="1823875311934643849">"Administrar usuarios"</string>
+ <string name="drag_split_not_supported" msgid="4326847447699729722">"Esta notificación no admite arrastrar entre pantallas divididas."</string>
+ <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"La red Wi-Fi no está disponible"</string>
+ <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Modo prioridad"</string>
+ <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Se estableció la alarma"</string>
+ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"La cámara y el micrófono están apagados"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notificación}other{# notificaciones}}"</string>
</resources>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index b84ed6512bdb..f4a8cf7f673e 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -20,14 +20,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4811759950673118541">"UI del sistema"</string>
- <string name="battery_low_title" msgid="6891106956328275225">"Puede que te quedes sin batería pronto"</string>
+ <string name="battery_low_title" msgid="5319680173344341779">"¿Activar Ahorro de batería?"</string>
+ <string name="battery_low_description" msgid="3282977755476423966">"Te queda un <xliff:g id="PERCENTAGE">%s</xliff:g> de batería. Ahorro de batería activa el tema oscuro, restringe la actividad en segundo plano y retrasa las notificaciones."</string>
+ <string name="battery_low_intro" msgid="5148725009653088790">"Ahorro de batería activa el tema oscuro, restringe la actividad en segundo plano y retrasa las notificaciones."</string>
<string name="battery_low_percent_format" msgid="4276661262843170964">"Queda un <xliff:g id="PERCENTAGE">%s</xliff:g> de batería"</string>
<string name="invalid_charger_title" msgid="938685362320735167">"No se puede cargar por USB"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"Utiliza el cargador original incluido con el dispositivo"</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"¿Activar Ahorro de batería?"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Información de Ahorro de batería"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Activar"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"Activar Ahorro de batería"</string>
+ <string name="battery_saver_start_action" msgid="8353766979886287140">"Activar"</string>
+ <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"No, gracias"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Girar pantalla automáticamente"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"¿Permitir que <xliff:g id="APPLICATION">%1$s</xliff:g> acceda a <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
<string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"¿Quieres que <xliff:g id="APPLICATION">%1$s</xliff:g> pueda acceder a <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nEsta aplicación no tiene permisos para grabar, pero podría captar audio a través de este dispositivo USB."</string>
@@ -128,6 +131,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Cara autenticada"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Confirmada"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Toca Confirmar para completar la acción"</string>
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Desbloqueada con la cara. Pulsa para continuar."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Se ha autenticado"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Usar PIN"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Usar patrón"</string>
@@ -181,6 +185,7 @@
<string name="accessibility_desc_close" msgid="8293708213442107755">"Cerrar"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"silencio total"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"solo alarmas"</string>
+ <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"No molestar."</string>
<string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"Bluetooth."</string>
<string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"Bluetooth activado."</string>
<string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"La alarma sonará a la(s) <xliff:g id="TIME">%s</xliff:g>."</string>
@@ -205,6 +210,7 @@
<string name="dessert_case" msgid="9104973640704357717">"Caja para postres"</string>
<string name="start_dreams" msgid="9131802557946276718">"Salvapantallas"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
+ <string name="quick_settings_dnd_label" msgid="7728690179108024338">"No molestar"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"No hay dispositivos vinculados disponibles"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> de batería"</string>
@@ -348,6 +354,7 @@
<string name="notification_section_header_alerting" msgid="5581175033680477651">"Notificaciones"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Conversaciones"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Borrar todas las notificaciones silenciosas"</string>
+ <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Notificaciones pausadas por el modo No molestar"</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"Empezar ahora"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"No hay notificaciones"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Este dispositivo lo gestionan tu padre o tu madre"</string>
@@ -452,8 +459,8 @@
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Desbloquear para usar"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Se ha producido un problema al obtener tus tarjetas. Inténtalo de nuevo más tarde."</string>
<string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Ajustes de pantalla de bloqueo"</string>
- <string name="qr_code_scanner_title" msgid="5660820608548306581">"Código QR"</string>
- <string name="qr_code_scanner_description" msgid="7937603775306661863">"Toca para escanear"</string>
+ <!-- no translation found for qr_code_scanner_title (5290201053875420785) -->
+ <skip />
<string name="status_bar_work" msgid="5238641949837091056">"Perfil de trabajo"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Modo avión"</string>
<string name="zen_alarm_warning" msgid="7844303238486849503">"No oirás la próxima alarma (<xliff:g id="WHEN">%1$s</xliff:g>)"</string>
@@ -491,6 +498,8 @@
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"&lt;b&gt;Estado:&lt;/b&gt; posición más baja"</string>
<string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"Se muestra encima de las notificaciones de conversaciones y como imagen de perfil en la pantalla de bloqueo"</string>
<string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"Se muestra encima de las notificaciones de conversaciones y como imagen de perfil en la pantalla de bloqueo, y aparece como burbuja"</string>
+ <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"Se muestra encima de las notificaciones de conversaciones y como imagen de perfil en la pantalla de bloqueo, e interrumpe el modo No molestar"</string>
+ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Se muestra encima de las notificaciones de conversaciones y como imagen de perfil en la pantalla de bloqueo, aparece como burbuja e interrumpe el modo No molestar"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioridad"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> no admite funciones de conversación"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Estas notificaciones no se pueden modificar."</string>
@@ -566,6 +575,7 @@
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"SMS"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"Música"</string>
<string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Calendario"</string>
+ <string name="volume_and_do_not_disturb" msgid="502044092739382832">"No molestar"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"Combinación de teclas para los botones de volumen"</string>
<string name="battery" msgid="769686279459897127">"Batería"</string>
<string name="headset" msgid="4485892374984466437">"Auriculares"</string>
@@ -684,6 +694,10 @@
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"Wi-Fi desactivado"</string>
<string name="bt_is_off" msgid="7436344904889461591">"Bluetooth desactivado"</string>
+ <string name="dnd_is_off" msgid="3185706903793094463">"No molestar está desactivado"</string>
+ <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"Una regla automática (<xliff:g id="ID_1">%s</xliff:g>) ha activado No molestar."</string>
+ <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"Una aplicación (<xliff:g id="ID_1">%s</xliff:g>) ha activado No molestar."</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"Una aplicación o una regla automática han activado No molestar."</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"Aplicaciones que se están ejecutando en segundo plano"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"Toca para ver información detallada sobre el uso de datos y de la batería"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"¿Desactivar datos móviles?"</string>
@@ -708,6 +722,8 @@
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(trabajo)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"Llamada telefónica"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(a través de <xliff:g id="APPLICATION_NAME_S_">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_label" msgid="3385241594101496292">"(<xliff:g id="ATTRIBUTION_LABEL">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_proxy_label" msgid="1111829599659403249">"(<xliff:g id="ATTRIBUTION_LABEL">%1$s</xliff:g> • <xliff:g id="PROXY_LABEL">%2$s</xliff:g>)"</string>
<string name="privacy_type_camera" msgid="7974051382167078332">"cámara"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"ubicación"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"micrófono"</string>
@@ -806,6 +822,9 @@
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(desconectado)"</string>
<string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"No se puede cambiar. Toca para volver a intentarlo."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Emparejar nuevo dispositivo"</string>
+ <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Para enviar esta sesión, abre la aplicación."</string>
+ <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Aplicación desconocida"</string>
+ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Dejar de enviar contenido"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Número de compilación"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Número de compilación copiado en el portapapeles."</string>
<string name="basic_status" msgid="2315371112182658176">"Conversación abierta"</string>
@@ -839,6 +858,7 @@
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Consulta los mensajes recientes, las llamadas perdidas y los cambios de estado"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Conversación"</string>
+ <string name="paused_by_dnd" msgid="7856941866433556428">"Pausado por No molestar"</string>
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> ha enviado un mensaje: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> ha enviado una imagen"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> ha cambiado su estado: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
@@ -877,8 +897,7 @@
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> aplicaciones activas</item>
<item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> aplicación activa</item>
</plurals>
- <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
- <skip />
+ <string name="fgs_dot_content_description" msgid="2865071539464777240">"Información nueva"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Aplicaciones activas"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Detener"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Detenida"</string>
@@ -886,14 +905,15 @@
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Copiado"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"<xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Cerrar la interfaz de copia"</string>
- <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
- <skip />
- <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
- <skip />
- <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
- <skip />
- <!-- no translation found for add (81036585205287996) -->
- <skip />
- <!-- no translation found for manage_users (1823875311934643849) -->
- <skip />
+ <string name="clipboard_edit_text_description" msgid="805254383912962103">"Editar texto copiado"</string>
+ <string name="clipboard_edit_image_description" msgid="8904857948976041306">"Editar imagen copiada"</string>
+ <string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Enviar a dispositivo cercano"</string>
+ <string name="add" msgid="81036585205287996">"Añadir"</string>
+ <string name="manage_users" msgid="1823875311934643849">"Gestionar usuarios"</string>
+ <string name="drag_split_not_supported" msgid="4326847447699729722">"Esta notificación no se puede arrastrar a la pantalla dividida."</string>
+ <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi no disponible"</string>
+ <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Modo prioritario"</string>
+ <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarma añadida"</string>
+ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"La cámara y el micrófono están desactivados"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notificación}other{# notificaciones}}"</string>
</resources>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index 91250c384eb3..b6d266c394aa 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -20,14 +20,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4811759950673118541">"Süsteemi UI"</string>
- <string name="battery_low_title" msgid="6891106956328275225">"Aku võib peagi tühjaks saada"</string>
+ <string name="battery_low_title" msgid="5319680173344341779">"Kas lülitada akusäästja sisse?"</string>
+ <string name="battery_low_description" msgid="3282977755476423966">"Teil on jäänud <xliff:g id="PERCENTAGE">%s</xliff:g> akutoidet. Akusäästja lülitab sisse tumeda teema, piirab taustategevusi ja viivitab märguannete saatmisega."</string>
+ <string name="battery_low_intro" msgid="5148725009653088790">"Akusäästja lülitab sisse tumeda teema, piirab taustategevusi ja viivitab märguannete saatmisega."</string>
<string name="battery_low_percent_format" msgid="4276661262843170964">"Jäänud on <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="invalid_charger_title" msgid="938685362320735167">"Ei saa USB kaudu laadida"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"Kasutage seadmega kaasas olnud laadijat"</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Kas lülitada akusäästja sisse?"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Teave akusäästja kohta"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Lülita sisse"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"Akusäästja sisselülitamine"</string>
+ <string name="battery_saver_start_action" msgid="8353766979886287140">"Lülita sisse"</string>
+ <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Tänan, ei"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Kuva automaatne pööramine"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"Kas lubada rakendusele <xliff:g id="APPLICATION">%1$s</xliff:g> juurdepääs seadmele <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
<string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Kas lubada rakendusel <xliff:g id="APPLICATION">%1$s</xliff:g> seadmele <xliff:g id="USB_DEVICE">%2$s</xliff:g> juurde pääseda?\nSellele rakendusele pole antud salvestamise luba, kuid see saab heli jäädvustada selle USB-seadme kaudu."</string>
@@ -128,6 +131,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Nägu on autenditud"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Kinnitatud"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Lõpuleviimiseks puudutage nuppu Kinnita"</string>
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Avati teie näoga. Vajutage jätkamiseks."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Autenditud"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Kasuta PIN-koodi"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Kasuta mustrit"</string>
@@ -181,6 +185,7 @@
<string name="accessibility_desc_close" msgid="8293708213442107755">"Sulgemine"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"täielik vaikus"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"ainult alarmid"</string>
+ <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"Mitte segada."</string>
<string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"Bluetooth."</string>
<string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"Bluetooth on sees."</string>
<string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"Määratud äratus: <xliff:g id="TIME">%s</xliff:g>"</string>
@@ -205,6 +210,7 @@
<string name="dessert_case" msgid="9104973640704357717">"Maiustusekorv"</string>
<string name="start_dreams" msgid="9131802557946276718">"Ekraanisäästja"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
+ <string name="quick_settings_dnd_label" msgid="7728690179108024338">"Mitte segada"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Ühtegi seotud seadet pole saadaval"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> akut"</string>
@@ -348,6 +354,7 @@
<string name="notification_section_header_alerting" msgid="5581175033680477651">"Märguanded"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Vestlused"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Kustuta kõik hääletud märguanded"</string>
+ <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Režiim Mitte segada peatas märguanded"</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"Alusta kohe"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Märguandeid pole"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Seda seadet haldab sinu vanem"</string>
@@ -452,8 +459,8 @@
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Avage kasutamiseks"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Teie kaartide hankimisel ilmnes probleem, proovige hiljem uuesti"</string>
<string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Lukustuskuva seaded"</string>
- <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR-kood"</string>
- <string name="qr_code_scanner_description" msgid="7937603775306661863">"Skannimiseks puudutamine"</string>
+ <!-- no translation found for qr_code_scanner_title (5290201053875420785) -->
+ <skip />
<string name="status_bar_work" msgid="5238641949837091056">"Tööprofiil"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Lennukirežiim"</string>
<string name="zen_alarm_warning" msgid="7844303238486849503">"Te ei kuule järgmist äratust kell <xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -491,6 +498,8 @@
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"&lt;b&gt;Olek:&lt;/b&gt; määrati madalam prioriteet"</string>
<string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"Kuvatakse vestluste märguannete ülaosas ja profiilipildina lukustuskuval"</string>
<string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"Kuvatakse mullina vestluste märguannete ülaosas ja profiilipildina lukustuskuval"</string>
+ <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"Kuvatakse vestluste märguannete ülaosas ja profiilipildina lukustuskuval ning katkestab režiimi Mitte segada"</string>
+ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Kuvatakse mullina vestluste märguannete ülaosas ja profiilipildina lukustuskuval ning katkestab režiimi Mitte segada"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioriteetne"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> ei toeta vestlusfunktsioone"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Neid märguandeid ei saa muuta."</string>
@@ -566,6 +575,7 @@
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"SMS"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"Muusika"</string>
<string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Kalender"</string>
+ <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Mitte segada"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"Helitugevuse nuppude otsetee"</string>
<string name="battery" msgid="769686279459897127">"Aku"</string>
<string name="headset" msgid="4485892374984466437">"Peakomplekt"</string>
@@ -684,6 +694,10 @@
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"WiFi on välja lülitatud"</string>
<string name="bt_is_off" msgid="7436344904889461591">"Bluetooth on välja lülitatud"</string>
+ <string name="dnd_is_off" msgid="3185706903793094463">"Funktsioon Mitte segada on välja lülitatud"</string>
+ <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"Automaatne reegel (<xliff:g id="ID_1">%s</xliff:g>) lülitas funktsiooni Mitte segada sisse."</string>
+ <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"Rakendus (<xliff:g id="ID_1">%s</xliff:g>) lülitas funktsiooni Mitte segada sisse."</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"Automaatne reegel või rakendus lülitas funktsiooni Mitte segada sisse."</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"Rakendusi käitatakse taustal"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"Aku ja andmekasutuse üksikasjade nägemiseks puudutage"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Kas lülitada mobiilne andmeside välja?"</string>
@@ -708,6 +722,8 @@
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(töö)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"Telefonikõne"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(rakenduse <xliff:g id="APPLICATION_NAME_S_">%s</xliff:g> kaudu)"</string>
+ <string name="ongoing_privacy_dialog_attribution_label" msgid="3385241594101496292">"(<xliff:g id="ATTRIBUTION_LABEL">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_proxy_label" msgid="1111829599659403249">"(<xliff:g id="ATTRIBUTION_LABEL">%1$s</xliff:g> • <xliff:g id="PROXY_LABEL">%2$s</xliff:g>)"</string>
<string name="privacy_type_camera" msgid="7974051382167078332">"kaamera"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"asukoht"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofon"</string>
@@ -806,6 +822,9 @@
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(ühendus on katkestatud)"</string>
<string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Ei saa lülitada. Puudutage uuesti proovimiseks."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Uue seadme sidumine"</string>
+ <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Selle seansi ülekandmiseks avage rakendus."</string>
+ <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Tundmatu rakendus"</string>
+ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Lõpeta ülekanne"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Järgunumber"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Järgunumber kopeeriti lõikelauale."</string>
<string name="basic_status" msgid="2315371112182658176">"Avage vestlus"</string>
@@ -839,6 +858,7 @@
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Vaadake hiljutisi sõnumeid, vastamata kõnesid ja olekuvärskendusi"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Vestlus"</string>
+ <string name="paused_by_dnd" msgid="7856941866433556428">"Peatas režiim Mitte segada"</string>
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> saatis sõnumi: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> saatis pildi"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> värskendas olekut: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
@@ -877,8 +897,7 @@
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> aktiivset rakendust</item>
<item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> aktiivne rakendus</item>
</plurals>
- <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
- <skip />
+ <string name="fgs_dot_content_description" msgid="2865071539464777240">"Uus teave"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Aktiivsed rakendused"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Peata"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Peatatud"</string>
@@ -886,14 +905,15 @@
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Kopeeritud"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Rakendusest <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Koopiast loobumise kasutajaliides"</string>
- <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
- <skip />
- <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
- <skip />
- <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
- <skip />
- <!-- no translation found for add (81036585205287996) -->
- <skip />
- <!-- no translation found for manage_users (1823875311934643849) -->
- <skip />
+ <string name="clipboard_edit_text_description" msgid="805254383912962103">"Muuda kopeeritud teksti"</string>
+ <string name="clipboard_edit_image_description" msgid="8904857948976041306">"Muuda kopeeritud pilti"</string>
+ <string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Saada läheduses olevasse seadmesse"</string>
+ <string name="add" msgid="81036585205287996">"Lisa"</string>
+ <string name="manage_users" msgid="1823875311934643849">"Kasutajate haldamine"</string>
+ <string name="drag_split_not_supported" msgid="4326847447699729722">"See märguanne ei toeta jagatud ekraanikuvale lohistamist."</string>
+ <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"WiFi pole saadaval"</string>
+ <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Režiim Prioriteetne"</string>
+ <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarm on määratud"</string>
+ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Kaamera ja mikrofon on välja lülitatud"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# märguanne}other{# märguannet}}"</string>
</resources>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index b531794dc7a9..768c2020e5b6 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -20,14 +20,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4811759950673118541">"Sistemaren interfazea"</string>
- <string name="battery_low_title" msgid="6891106956328275225">"Laster agortuko da bateria"</string>
+ <string name="battery_low_title" msgid="5319680173344341779">"Bateria-aurrezlea aktibatu nahi duzu?"</string>
+ <string name="battery_low_description" msgid="3282977755476423966">"Bateriaren <xliff:g id="PERCENTAGE">%s</xliff:g> gelditzen zaizu. Bateria-aurrezleak gai iluna aktibatzen du, atzeko planoko jarduerak murrizten, eta jakinarazpenak atzeratzen."</string>
+ <string name="battery_low_intro" msgid="5148725009653088790">"Bateria-aurrezleak gai iluna aktibatzen du, atzeko planoko jarduerak murrizten, eta jakinarazpenak atzeratzen."</string>
<string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> gelditzen da"</string>
<string name="invalid_charger_title" msgid="938685362320735167">"Ezin da USB bidez kargatu"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"Erabili gailuaren kargagailua"</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Bateria-aurrezlea aktibatu nahi duzu?"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Bateria-aurrezleari buruz"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Aktibatu"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"Aktibatu bateria-aurrezlea"</string>
+ <string name="battery_saver_start_action" msgid="8353766979886287140">"Aktibatu"</string>
+ <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Ez, eskerrik asko"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Biratu pantaila automatikoki"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> atzitzeko baimena eman nahi diozu <xliff:g id="APPLICATION">%1$s</xliff:g> aplikazioari?"</string>
<string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> erabiltzeko baimena eman nahi diozu <xliff:g id="APPLICATION">%1$s</xliff:g> aplikazioari?\nAplikazioak ez du grabatzeko baimenik, baina baliteke USB bidezko gailu horren bidez audioa grabatzea."</string>
@@ -128,6 +131,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Autentifikatu da aurpegia"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Berretsita"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Amaitzeko, sakatu \"Berretsi\""</string>
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Aurpegiaren bidez desblokeatu da. Sakatu aurrera egiteko."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Autentifikatuta"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Erabili PINa"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Erabili eredua"</string>
@@ -181,6 +185,7 @@
<string name="accessibility_desc_close" msgid="8293708213442107755">"Itxi"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"isiltasun osoa"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"alarmak soilik"</string>
+ <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"Ez molestatzeko modua."</string>
<string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"Bluetooth-a."</string>
<string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"Bluetooth bidezko konexioa aktibatuta dago."</string>
<string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"Alarma ordu honetarako ezarri da: <xliff:g id="TIME">%s</xliff:g>."</string>
@@ -189,7 +194,7 @@
<string name="accessibility_casting_turned_off" msgid="1387906158563374962">"Pantaila igortzeari utzi zaio."</string>
<string name="accessibility_brightness" msgid="5391187016177823721">"Bistaratu distira"</string>
<string name="data_usage_disabled_dialog_mobile_title" msgid="2286843518689837719">"Datu-konexioa pausatu egin da"</string>
- <string name="data_usage_disabled_dialog_title" msgid="9131615296036724838">"Datuen erabilera pausatu da"</string>
+ <string name="data_usage_disabled_dialog_title" msgid="9131615296036724838">"Datu-erabilera pausatu da"</string>
<string name="data_usage_disabled_dialog" msgid="7933201635215099780">"Iritsi zara ezarri zenuen datu-mugara. Datu-konexioa erabiltzeari utzi diozu.\n\nDatu-konexioa erabiltzeari berrekiten badiozu, baliteke zerbait ordaindu behar izatea datuak erabiltzeagatik."</string>
<string name="data_usage_disabled_dialog_enable" msgid="2796648546086408937">"Jarraitu erabiltzen"</string>
<string name="accessibility_location_active" msgid="2845747916764660369">"Aplikazioen kokapen-eskaerak aktibo daude"</string>
@@ -205,6 +210,7 @@
<string name="dessert_case" msgid="9104973640704357717">"Postreen kutxa"</string>
<string name="start_dreams" msgid="9131802557946276718">"Pantaila-babeslea"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
+ <string name="quick_settings_dnd_label" msgid="7728690179108024338">"Ez molestatzeko modua"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth-a"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Ez dago parekatutako gailurik erabilgarri"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Bateria: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
@@ -252,7 +258,7 @@
<string name="quick_settings_flashlight_label" msgid="4904634272006284185">"Linterna"</string>
<string name="quick_settings_flashlight_camera_in_use" msgid="4820591564526512571">"Kamera abian da"</string>
<string name="quick_settings_cellular_detail_title" msgid="792977203299358893">"Datu-konexioa"</string>
- <string name="quick_settings_cellular_detail_data_usage" msgid="6105969068871138427">"Datuen erabilera"</string>
+ <string name="quick_settings_cellular_detail_data_usage" msgid="6105969068871138427">"Datu-erabilera"</string>
<string name="quick_settings_cellular_detail_remaining_data" msgid="1136599216568805644">"Geratzen diren datuak"</string>
<string name="quick_settings_cellular_detail_over_limit" msgid="4561921367680636235">"Mugaren gainetik"</string>
<string name="quick_settings_cellular_detail_data_used" msgid="6798849610647988987">"<xliff:g id="DATA_USED">%s</xliff:g> erabilita"</string>
@@ -348,6 +354,7 @@
<string name="notification_section_header_alerting" msgid="5581175033680477651">"Jakinarazpenak"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Elkarrizketak"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Garbitu soinurik gabeko jakinarazpen guztiak"</string>
+ <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Ez molestatzeko moduak pausatu egin ditu jakinarazpenak"</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"Hasi"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Ez dago jakinarazpenik"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Zure gurasoak kudeatzen du gailua"</string>
@@ -452,8 +459,8 @@
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Desblokeatu erabiltzeko"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Arazo bat izan da txartelak eskuratzean. Saiatu berriro geroago."</string>
<string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Pantaila blokeatuaren ezarpenak"</string>
- <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR kodea"</string>
- <string name="qr_code_scanner_description" msgid="7937603775306661863">"Sakatu eskaneatzeko"</string>
+ <!-- no translation found for qr_code_scanner_title (5290201053875420785) -->
+ <skip />
<string name="status_bar_work" msgid="5238641949837091056">"Work profila"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Hegaldi modua"</string>
<string name="zen_alarm_warning" msgid="7844303238486849503">"Ez duzu entzungo hurrengo alarma (<xliff:g id="WHEN">%1$s</xliff:g>)"</string>
@@ -491,6 +498,8 @@
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"Mailaz jaitsi da &lt;b&gt;egoera:&lt;/b&gt;"</string>
<string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"Elkarrizketen jakinarazpenen goialdean eta profileko argazki gisa agertzen da pantaila blokeatuan"</string>
<string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"Elkarrizketen jakinarazpenen goialdean eta profileko argazki gisa agertzen da pantaila blokeatuan, burbuila batean"</string>
+ <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"Elkarrizketen jakinarazpenen goialdean eta profileko argazki gisa agertzen da pantaila blokeatuan, eta ez molestatzeko modua eteten du"</string>
+ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Elkarrizketen jakinarazpenen goialdean eta profileko argazki gisa agertzen da pantaila blokeatuan, burbuila batean, eta ez molestatzeko modua eteten du"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Lehentasuna"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioak ez ditu onartzen elkarrizketetarako eginbideak"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Jakinarazpen horiek ezin dira aldatu."</string>
@@ -566,6 +575,7 @@
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"SMSak"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"Musika"</string>
<string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Calendar"</string>
+ <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Ez molestatzeko modua"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"Bolumen-botoietarako lasterbidea"</string>
<string name="battery" msgid="769686279459897127">"Bateria"</string>
<string name="headset" msgid="4485892374984466437">"Mikrofonodun entzungailua"</string>
@@ -684,8 +694,12 @@
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g> (<xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>)"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"Wi-Fi konexioa desaktibatuta dago"</string>
<string name="bt_is_off" msgid="7436344904889461591">"Bluetooth bidezko konexioa desaktibatuta dago"</string>
+ <string name="dnd_is_off" msgid="3185706903793094463">"Ez molestatzeko modua desaktibatuta dago"</string>
+ <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"Ez molestatzeko modua aktibatu du arau automatiko batek (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"Ez molestatzeko modua aktibatu du aplikazio batek (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"Ez molestatzeko modua aktibatu du arau automatiko edo aplikazio batek."</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"Aplikazioak abian dira atzeko planoan"</string>
- <string name="running_foreground_services_msg" msgid="3009459259222695385">"Sakatu bateria eta datuen erabilerari buruzko xehetasunak ikusteko"</string>
+ <string name="running_foreground_services_msg" msgid="3009459259222695385">"Sakatu bateria eta datu-erabilerari buruzko xehetasunak ikusteko"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Datu-konexioa desaktibatu nahi duzu?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"<xliff:g id="CARRIER">%s</xliff:g> erabilita ezingo dituzu erabili datuak edo Internet. Wifi-sare baten bidez soilik konektatu ahal izango zara Internetera."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"Zure operadorea"</string>
@@ -708,6 +722,8 @@
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(lanekoa)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"Telefono-deia"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(<xliff:g id="APPLICATION_NAME_S_">%s</xliff:g> aplikazioaren bidez)"</string>
+ <string name="ongoing_privacy_dialog_attribution_label" msgid="3385241594101496292">"(<xliff:g id="ATTRIBUTION_LABEL">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_proxy_label" msgid="1111829599659403249">"(<xliff:g id="ATTRIBUTION_LABEL">%1$s</xliff:g> • <xliff:g id="PROXY_LABEL">%2$s</xliff:g>)"</string>
<string name="privacy_type_camera" msgid="7974051382167078332">"kamera"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"kokapena"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofonoa"</string>
@@ -806,6 +822,9 @@
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(deskonektatuta)"</string>
<string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Ezin da aldatu. Berriro saiatzeko, sakatu hau."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Parekatu beste gailu batekin"</string>
+ <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Saioa ireki nahi baduzu, ireki aplikazioa."</string>
+ <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Aplikazio ezezaguna"</string>
+ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Utzi igortzeari"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Konpilazio-zenbakia"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Kopiatu da konpilazio-zenbakia arbelean."</string>
<string name="basic_status" msgid="2315371112182658176">"Elkarrizketa irekia"</string>
@@ -839,6 +858,7 @@
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Ikusi azken mezuak, dei galduak eta egoerari buruzko informazio eguneratua"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Elkarrizketa"</string>
+ <string name="paused_by_dnd" msgid="7856941866433556428">"Ez molestatzeko moduak pausatu du"</string>
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> erabiltzaileak mezu bat bidali du: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> erabiltzaileak irudi bat bidali du"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> erabiltzaileak egoera eguneratu du: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
@@ -877,8 +897,7 @@
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> aplikazio aktibo</item>
<item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> aplikazio aktibo</item>
</plurals>
- <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
- <skip />
+ <string name="fgs_dot_content_description" msgid="2865071539464777240">"Informazio berria"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Aktibo dauden aplikazioak"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Gelditu"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Geldituta"</string>
@@ -886,14 +905,15 @@
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Kopiatu da"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Jatorria: <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Kopiatutako UIa baztertzeko botoia"</string>
- <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
- <skip />
- <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
- <skip />
- <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
- <skip />
- <!-- no translation found for add (81036585205287996) -->
- <skip />
- <!-- no translation found for manage_users (1823875311934643849) -->
- <skip />
+ <string name="clipboard_edit_text_description" msgid="805254383912962103">"Editatu kopiatutako testua"</string>
+ <string name="clipboard_edit_image_description" msgid="8904857948976041306">"Editatu kopiatutako irudia"</string>
+ <string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Bidali inguruko gailu batera"</string>
+ <string name="add" msgid="81036585205287996">"Gehitu"</string>
+ <string name="manage_users" msgid="1823875311934643849">"Kudeatu erabiltzaileak"</string>
+ <string name="drag_split_not_supported" msgid="4326847447699729722">"Jakinarazpen hau ezin da arrastatu pantaila zatitura."</string>
+ <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wifi-konexioa ez dago erabilgarri"</string>
+ <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Lehentasun modua"</string>
+ <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarma ezarrita dago"</string>
+ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Kamera eta mikrofonoa desaktibatuta daude"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# jakinarazpen}other{# jakinarazpen}}"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 642a82635396..3e76c46241f8 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -20,14 +20,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4811759950673118541">"میانای کاربر سیستم"</string>
- <string name="battery_low_title" msgid="6891106956328275225">"ممکن است باتری به‌زودی تمام شود"</string>
+ <string name="battery_low_title" msgid="5319680173344341779">"«بهینه‌سازی باتری» روشن شود؟"</string>
+ <string name="battery_low_description" msgid="3282977755476423966">"<xliff:g id="PERCENTAGE">%s</xliff:g> از باتری‌تان باقی مانده است. «بهینه‌سازی باتری» زمینه تیره را روشن می‌کند، فعالیت‌های پس‌زمینه را محدود می‌کند، و اعلان‌ها را به‌تأخیر می‌اندازد."</string>
+ <string name="battery_low_intro" msgid="5148725009653088790">"«بهینه‌سازی باتری» زمینه تیره را روشن می‌کند، فعالیت‌های پس‌زمینه را محدود می‌کند، و اعلان‌ها را به‌تأخیر می‌اندازد."</string>
<string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> باقی مانده است"</string>
<string name="invalid_charger_title" msgid="938685362320735167">"‏ازطریق USB شارژ نمی‌شود"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"از شارژر ارائه‌شده با دستگاه استفاده کنید"</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"«بهینه‌سازی باتری» روشن شود؟"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"درباره «بهینه‌سازی باتری»"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"روشن کردن"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"«بهینه‌سازی باتری» را روشن کنید"</string>
+ <string name="battery_saver_start_action" msgid="8353766979886287140">"روشن کردن"</string>
+ <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"نه متشکرم"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"چرخش خودکار صفحه"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"به <xliff:g id="APPLICATION">%1$s</xliff:g> برای دسترسی به <xliff:g id="USB_DEVICE">%2$s</xliff:g> اجازه داده شود؟"</string>
<string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"‏به <xliff:g id="APPLICATION">%1$s</xliff:g> اجازه می‌دهید به <xliff:g id="USB_DEVICE">%2$s</xliff:g>دسترسی داشته باشد؟\nمجوز ضبط به این برنامه داده نشده است اما می‌تواند صدا را ازطریق این دستگاه USB ضبط کند."</string>
@@ -111,7 +114,7 @@
<string name="accessibility_phone_button" msgid="4256353121703100427">"تلفن"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"دستیار صوتی"</string>
<string name="accessibility_wallet_button" msgid="1458258783460555507">"Wallet"</string>
- <string name="accessibility_qr_code_scanner_button" msgid="7521277927692910795">"اسکنر رمزینه پاسخ‌سریع"</string>
+ <string name="accessibility_qr_code_scanner_button" msgid="7521277927692910795">"کدخوان پاسخ‌سریع"</string>
<string name="accessibility_unlock_button" msgid="122785427241471085">"باز کردن قفل"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"دستگاه قفل است"</string>
<string name="accessibility_scanning_face" msgid="3093828357921541387">"درحال اسکن کردن چهره"</string>
@@ -128,6 +131,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"چهره اصالت‌سنجی شد"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"تأیید شد"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"برای تکمیل، روی تأیید ضربه بزنید"</string>
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"قفل با چهره‌تان باز شد. برای ادامه دادن، فشار دهید."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"راستی‌آزمایی‌شده"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"استفاده از پین"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"استفاده از الگو"</string>
@@ -181,6 +185,7 @@
<string name="accessibility_desc_close" msgid="8293708213442107755">"بستن"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"سکوت کامل"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"فقط زنگ ساعت"</string>
+ <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"مزاحم نشوید."</string>
<string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"بلوتوث."</string>
<string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"بلوتوث روشن است."</string>
<string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"زنگ برای <xliff:g id="TIME">%s</xliff:g> تنظیم شد."</string>
@@ -205,6 +210,7 @@
<string name="dessert_case" msgid="9104973640704357717">"ویترین دسر"</string>
<string name="start_dreams" msgid="9131802557946276718">"محافظ صفحه"</string>
<string name="ethernet_label" msgid="2203544727007463351">"اترنت"</string>
+ <string name="quick_settings_dnd_label" msgid="7728690179108024338">"مزاحم نشوید"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"بلوتوث"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"هیچ دستگاه مرتبط شده‌ای موجود نیست"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"شارژ باتری <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
@@ -264,7 +270,7 @@
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"تا طلوع"</string>
<string name="quick_settings_night_secondary_label_on_at" msgid="3584738542293528235">"ساعت <xliff:g id="TIME">%s</xliff:g> روشن می‌شود"</string>
<string name="quick_settings_secondary_label_until" msgid="1883981263191927372">"تا <xliff:g id="TIME">%s</xliff:g>"</string>
- <string name="quick_settings_ui_mode_night_label" msgid="1398928270610780470">"طرح زمینه تیره"</string>
+ <string name="quick_settings_ui_mode_night_label" msgid="1398928270610780470">"زمینه تیره"</string>
<string name="quick_settings_dark_mode_secondary_label_battery_saver" msgid="4990712734503013251">"بهینه‌سازی باتری"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at_sunset" msgid="6017379738102015710">"غروب روشن می‌شود"</string>
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"تا طلوع آفتاب"</string>
@@ -348,6 +354,7 @@
<string name="notification_section_header_alerting" msgid="5581175033680477651">"اعلان‌ها"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"مکالمه‌ها"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"پاک کردن همه اعلان‌های بی‌صدا"</string>
+ <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"اعلان‌ها توسط «مزاحم نشوید» موقتاً متوقف شدند"</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"اکنون شروع کنید"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"اعلانی موجود نیست"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"این دستگاه را ولی‌تان مدیریت می‌کند"</string>
@@ -452,8 +459,8 @@
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"برای استفاده، قفل را باز کنید"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"هنگام دریافت کارت‌ها مشکلی پیش آمد، لطفاً بعداً دوباره امتحان کنید"</string>
<string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"تنظیمات صفحه قفل"</string>
- <string name="qr_code_scanner_title" msgid="5660820608548306581">"رمزینه پاسخ‌سریع"</string>
- <string name="qr_code_scanner_description" msgid="7937603775306661863">"برای اسکن کردن، ضربه بزنید"</string>
+ <!-- no translation found for qr_code_scanner_title (5290201053875420785) -->
+ <skip />
<string name="status_bar_work" msgid="5238641949837091056">"نمایه کاری"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"حالت هواپیما"</string>
<string name="zen_alarm_warning" msgid="7844303238486849503">"در ساعت <xliff:g id="WHEN">%1$s</xliff:g>، دیگر صدای زنگ ساعت را نمی‌شنوید"</string>
@@ -491,6 +498,8 @@
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"‏&lt;b&gt;وضعیت:&lt;/b&gt; در رده‌بندی پایین‌تری قرار گرفت"</string>
<string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"در بالای اعلان‌های مکالمه و به‌صورت عکس نمایه در صفحه قفل نشان داده می‌شود"</string>
<string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"در بالای اعلان‌های مکالمه و به‌صورت عکس نمایه در صفحه قفل نشان داده می‌شود، به‌صورت حبابک ظاهر می‌شود"</string>
+ <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"در بالای اعلان‌های مکالمه و به‌صورت عکس نمایه در صفحه قفل نشان داده می‌شود، در حالت «مزاحم نشوید» وقفه ایجاد می‌کند"</string>
+ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"در بالای اعلان‌های مکالمه و به‌صورت عکس نمایه در صفحه قفل نشان داده می‌شود، به‌صورت حبابک ظاهر می‌شود، در حالت «مزاحم نشوید» وقفه ایجاد می‌کند"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"اولویت"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> از ویژگی‌های مکالمه پشتیبانی نمی‌کند"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"این اعلان‌ها قابل اصلاح نیستند."</string>
@@ -566,6 +575,7 @@
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"پیامک"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"موسیقی"</string>
<string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"تقویم"</string>
+ <string name="volume_and_do_not_disturb" msgid="502044092739382832">"مزاحم نشوید"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"میان‌بر دکمه‌های صدا"</string>
<string name="battery" msgid="769686279459897127">"باتری"</string>
<string name="headset" msgid="4485892374984466437">"هدست"</string>
@@ -684,6 +694,10 @@
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>، <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"‏Wi-Fi خاموش است"</string>
<string name="bt_is_off" msgid="7436344904889461591">"بلوتوث خاموش است"</string>
+ <string name="dnd_is_off" msgid="3185706903793094463">"«مزاحم نشوید» خاموش است"</string>
+ <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"قانون خودکاری (<xliff:g id="ID_1">%s</xliff:g>) «مزاحم نشوید» را روشن کرد."</string>
+ <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"برنامه‌ای (<xliff:g id="ID_1">%s</xliff:g>) «مزاحم نشوید» را روشن کرد."</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"برنامه یا قانون خودکاری، «مزاحم نشوید» را روشن کرد."</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"برنامه‌هایی که در پس‌زمینه اجرا می‌شوند"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"برای جزئیات مربوط به مصرف باتری و داده، ضربه بزنید"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"داده تلفن همراه خاموش شود؟"</string>
@@ -708,6 +722,8 @@
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(کاری)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"تماس تلفنی"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(ازطریق <xliff:g id="APPLICATION_NAME_S_">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_label" msgid="3385241594101496292">"(<xliff:g id="ATTRIBUTION_LABEL">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_proxy_label" msgid="1111829599659403249">"(<xliff:g id="ATTRIBUTION_LABEL">%1$s</xliff:g> • <xliff:g id="PROXY_LABEL">%2$s</xliff:g>)"</string>
<string name="privacy_type_camera" msgid="7974051382167078332">"دوربین"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"مکان"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"میکروفون"</string>
@@ -806,6 +822,9 @@
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(اتصال قطع شد)"</string>
<string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"عوض نمی‌شود. برای تلاش مجدد ضربه بزنید."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"مرتبط کردن دستگاه جدید"</string>
+ <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"برای ارسال محتوای این جلسه، لطفاً برنامه را باز کنید."</string>
+ <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"برنامه ناشناس"</string>
+ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"توقف ارسال محتوا"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"شماره ساخت"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"شماره ساخت در بریده‌دان کپی شد."</string>
<string name="basic_status" msgid="2315371112182658176">"باز کردن مکالمه"</string>
@@ -839,6 +858,7 @@
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"بیش‌از <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="people_tile_description" msgid="8154966188085545556">"دیدن به‌روزرسانی‌های وضعیت، تماس‌های بی‌پاسخ، و پیام‌های اخیر"</string>
<string name="people_tile_title" msgid="6589377493334871272">"مکالمه"</string>
+ <string name="paused_by_dnd" msgid="7856941866433556428">"با «مزاحم نشوید» موقتاً متوقف شده است"</string>
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> پیامی ارسال کرد: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> تصویری ارسال کرد"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> وضعیتش را به‌روزرسانی کرد: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
@@ -877,8 +897,7 @@
<item quantity="one"><xliff:g id="COUNT_1">%s</xliff:g> برنامه فعال</item>
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> برنامه فعال</item>
</plurals>
- <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
- <skip />
+ <string name="fgs_dot_content_description" msgid="2865071539464777240">"اطلاعات جدید"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"برنامه‌های فعال"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"توقف"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"متوقف شد"</string>
@@ -886,14 +905,15 @@
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"کپی شد"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"از <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"رد کردن رابط کاربری کپی کردن"</string>
- <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
- <skip />
- <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
- <skip />
- <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
- <skip />
- <!-- no translation found for add (81036585205287996) -->
- <skip />
- <!-- no translation found for manage_users (1823875311934643849) -->
- <skip />
+ <string name="clipboard_edit_text_description" msgid="805254383912962103">"ویرایش نوشتار کپی‌شده"</string>
+ <string name="clipboard_edit_image_description" msgid="8904857948976041306">"ویرایش تصویر کپی‌شده"</string>
+ <string name="clipboard_send_nearby_description" msgid="4629769637846717650">"ارسال به دستگاهی در اطراف"</string>
+ <string name="add" msgid="81036585205287996">"افزودن"</string>
+ <string name="manage_users" msgid="1823875311934643849">"مدیریت کاربران"</string>
+ <string name="drag_split_not_supported" msgid="4326847447699729722">"این اعلان از تنظیم کشیدن برای دو نیمه کردن صفحه پشتیبانی نمی‌کند."</string>
+ <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"‏Wi‑Fi دردسترس نیست"</string>
+ <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"حالت اولویت"</string>
+ <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"زنگ ساعت تنظیم شد"</string>
+ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"دوربین و میکروفون خاموش هستند"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# اعلان}one{# اعلان}other{# اعلان}}"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index a9c11bce0360..3257d8b87385 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -20,14 +20,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4811759950673118541">"Käyttöliitt."</string>
- <string name="battery_low_title" msgid="6891106956328275225">"Akku voi loppua pian"</string>
+ <string name="battery_low_title" msgid="5319680173344341779">"Laitetaanko virransäästö päälle?"</string>
+ <string name="battery_low_description" msgid="3282977755476423966">"Akkua jäljellä <xliff:g id="PERCENTAGE">%s</xliff:g>. Virransäästö laittaa tumman teeman päälle, rajoittaa taustatoimintoja ja viivästyttää ilmoituksia."</string>
+ <string name="battery_low_intro" msgid="5148725009653088790">"Virransäästö laittaa tumman teeman päälle, rajoittaa taustatoimintoja ja viivästyttää ilmoituksia."</string>
<string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> jäljellä"</string>
<string name="invalid_charger_title" msgid="938685362320735167">"Lataaminen USB:llä ei onnistu"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"Käytä laitteesi mukana tullutta laturia"</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Otetaanko virransäästö käyttöön?"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Tietoa virransäästöstä"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Ota käyttöön"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"Ota virransäästö käyttöön"</string>
+ <string name="battery_saver_start_action" msgid="8353766979886287140">"Laita päälle"</string>
+ <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Ei kiitos"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Näytön automaattinen kääntö"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"Saako <xliff:g id="APPLICATION">%1$s</xliff:g> käyttöoikeuden (<xliff:g id="USB_DEVICE">%2$s</xliff:g>)?"</string>
<string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Saako <xliff:g id="APPLICATION">%1$s</xliff:g> tämän pääsyoikeuden: <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nSovellus ei ole saanut tallennuslupaa, mutta voi tallentaa ääntä tämän USB-laitteen avulla."</string>
@@ -128,6 +131,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Kasvot tunnistettu"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Vahvistettu"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Valitse lopuksi Vahvista"</string>
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Lukitus avattu kasvojen avulla. Jatka painamalla."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Todennettu"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Käytä PIN-koodia"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Käytä kuviota"</string>
@@ -181,6 +185,7 @@
<string name="accessibility_desc_close" msgid="8293708213442107755">"Sulje"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"hiljennä kaikki"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"vain herätykset"</string>
+ <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"Älä häiritse."</string>
<string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"Bluetooth"</string>
<string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"Bluetooth on päällä."</string>
<string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"Hälytys asetettu, aika: <xliff:g id="TIME">%s</xliff:g>."</string>
@@ -205,6 +210,7 @@
<string name="dessert_case" msgid="9104973640704357717">"Jälkiruokavitriini"</string>
<string name="start_dreams" msgid="9131802557946276718">"Näytönsäästäjä"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
+ <string name="quick_settings_dnd_label" msgid="7728690179108024338">"Älä häiritse"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Laitepareja ei ole käytettävissä"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Akun taso <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
@@ -348,6 +354,7 @@
<string name="notification_section_header_alerting" msgid="5581175033680477651">"Ilmoitukset"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Keskustelut"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Tyhjennä kaikki hiljaiset ilmoitukset"</string>
+ <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Älä häiritse ‑tila keskeytti ilmoitukset"</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"Aloita nyt"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Ei ilmoituksia"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Vanhempasi ylläpitää tätä laitetta"</string>
@@ -452,8 +459,8 @@
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Avaa lukitus ja käytä"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Korttien noutamisessa oli ongelma, yritä myöhemmin uudelleen"</string>
<string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Lukitusnäytön asetukset"</string>
- <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR-koodi"</string>
- <string name="qr_code_scanner_description" msgid="7937603775306661863">"Skannaa napauttamalla"</string>
+ <!-- no translation found for qr_code_scanner_title (5290201053875420785) -->
+ <skip />
<string name="status_bar_work" msgid="5238641949837091056">"Työprofiili"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Lentokonetila"</string>
<string name="zen_alarm_warning" msgid="7844303238486849503">"Et kuule seuraavaa hälytystäsi (<xliff:g id="WHEN">%1$s</xliff:g>)."</string>
@@ -491,6 +498,8 @@
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"&lt;b&gt;Tila:&lt;/b&gt; valittu vähemmän tärkeäksi"</string>
<string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"Näkyy keskusteluilmoitusten yläosassa ja profiilikuvana lukitusnäytöllä"</string>
<string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"Näkyy keskusteluilmoitusten yläosassa ja profiilikuvana lukitusnäytöllä, näkyy kuplana"</string>
+ <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"Näkyy keskusteluilmoitusten yläosassa ja profiilikuvana lukitusnäytöllä, keskeyttää Älä häiritse ‑tilan"</string>
+ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Näkyy keskusteluilmoitusten yläosassa ja profiilikuvana lukitusnäytöllä, näkyy kuplana, keskeyttää Älä häiritse ‑tilan"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Tärkeä"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> ei tue keskusteluominaisuuksia"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Näitä ilmoituksia ei voi muokata"</string>
@@ -566,6 +575,7 @@
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"Tekstiviesti"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"Musiikki"</string>
<string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Kalenteri"</string>
+ <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Älä häiritse"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"Äänenvoimakkuuspainikkeiden pikanäppäin"</string>
<string name="battery" msgid="769686279459897127">"Akku"</string>
<string name="headset" msgid="4485892374984466437">"Kuulokemikrofoni"</string>
@@ -679,11 +689,15 @@
<string name="instant_apps_message_with_help" msgid="1816952263531203932">"Sovellus avattiin ilman asennusta. Katso lisätietoja napauttamalla."</string>
<string name="app_info" msgid="5153758994129963243">"Sovelluksen tiedot"</string>
<string name="go_to_web" msgid="636673528981366511">"Siirry selaimeen"</string>
- <string name="mobile_data" msgid="4564407557775397216">"Mobiilitiedonsiirto"</string>
+ <string name="mobile_data" msgid="4564407557775397216">"Mobiilidata"</string>
<string name="mobile_data_text_format" msgid="6806501540022589786">"<xliff:g id="ID_1">%1$s</xliff:g> – <xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"Wi-Fi on pois päältä"</string>
<string name="bt_is_off" msgid="7436344904889461591">"Bluetooth ei ole käytössä"</string>
+ <string name="dnd_is_off" msgid="3185706903793094463">"Älä häiritse ‑tila on pois päältä"</string>
+ <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"Automaattinen sääntö otti käyttöön Älä häiritse ‑tilan (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"Sovellus otti käyttöön Älä häiritse ‑tilan (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"Automaattinen sääntö tai sovellus otti käyttöön Älä häiritse ‑tilan."</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"Sovelluksia käynnissä taustalla"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"Katso lisätietoja akun ja datan käytöstä napauttamalla"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Laitetaanko mobiilidata pois päältä?"</string>
@@ -708,6 +722,8 @@
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(työ)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"Puhelu"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(kautta: <xliff:g id="APPLICATION_NAME_S_">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_label" msgid="3385241594101496292">"(<xliff:g id="ATTRIBUTION_LABEL">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_proxy_label" msgid="1111829599659403249">"(<xliff:g id="ATTRIBUTION_LABEL">%1$s</xliff:g> • <xliff:g id="PROXY_LABEL">%2$s</xliff:g>)"</string>
<string name="privacy_type_camera" msgid="7974051382167078332">"kamera"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"sijainti"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofoni"</string>
@@ -806,6 +822,9 @@
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(yhteys katkaistu)"</string>
<string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Vaihtaminen ei onnistunut. Yritä uudelleen."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Muodosta uusi laitepari"</string>
+ <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Jos haluat striimata tämän käyttökerran, avaa sovellus."</string>
+ <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Tuntematon sovellus"</string>
+ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Lopeta striimaus"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Koontiversion numero"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Koontiversion numero kopioitu leikepöydälle"</string>
<string name="basic_status" msgid="2315371112182658176">"Avaa keskustelu"</string>
@@ -839,6 +858,7 @@
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"Yli <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Katso viimeaikaiset viestit, vastaamattomat puhelut ja tilapäivitykset"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Keskustelu"</string>
+ <string name="paused_by_dnd" msgid="7856941866433556428">"Älä häiritse ‑tilan keskeyttämä"</string>
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> lähetti viestin: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> lähetti kuvan"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> on päivittänyt tilansa: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
@@ -877,8 +897,7 @@
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> aktiivista sovellusta</item>
<item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> aktiivinen sovellus</item>
</plurals>
- <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
- <skip />
+ <string name="fgs_dot_content_description" msgid="2865071539464777240">"Uutta tietoa"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Aktiiviset sovellukset"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Lopeta"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Pysäytetty"</string>
@@ -886,14 +905,15 @@
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Kopioitu"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Lähde: <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Hylkää kopioitu UI"</string>
- <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
- <skip />
- <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
- <skip />
- <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
- <skip />
- <!-- no translation found for add (81036585205287996) -->
- <skip />
- <!-- no translation found for manage_users (1823875311934643849) -->
- <skip />
+ <string name="clipboard_edit_text_description" msgid="805254383912962103">"Muokkaa kopioitua tekstiä"</string>
+ <string name="clipboard_edit_image_description" msgid="8904857948976041306">"Muokkaa kopioitua kuvaa"</string>
+ <string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Lähetä lähellä olevaan laitteeseen"</string>
+ <string name="add" msgid="81036585205287996">"Lisää"</string>
+ <string name="manage_users" msgid="1823875311934643849">"Ylläpidä käyttäjiä"</string>
+ <string name="drag_split_not_supported" msgid="4326847447699729722">"Ilmoitus ei tue jaetulle näytölle vetämistä."</string>
+ <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi ei ole saatavilla"</string>
+ <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Tärkeät-tila"</string>
+ <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Hälytys asetettu"</string>
+ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Kamera ja mikrofoni ovat pois päältä"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# ilmoitus}other{# ilmoitusta}}"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 3ee8efa56019..e91e55dd4d37 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -20,14 +20,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4811759950673118541">"IU système"</string>
- <string name="battery_low_title" msgid="6891106956328275225">"La pile sera bientôt épuisée"</string>
+ <string name="battery_low_title" msgid="5319680173344341779">"Activer l\'économiseur de pile?"</string>
+ <string name="battery_low_description" msgid="3282977755476423966">"Il vous reste <xliff:g id="PERCENTAGE">%s</xliff:g> d\'autonomie. L\'économiseur de pile active le thème sombre, limite l\'activité en arrière-plan et retarde les notifications."</string>
+ <string name="battery_low_intro" msgid="5148725009653088790">"L\'économiseur de pile active le thème sombre, limite l\'activité en arrière-plan et retarde les notifications."</string>
<string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> restants"</string>
<string name="invalid_charger_title" msgid="938685362320735167">"Impossible de charger l\'appareil par USB"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"Servez-vous du chargeur fourni avec votre appareil"</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Activer l\'économiseur de pile?"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"À propos du mode Économiseur de pile"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Activer"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"Activer l\'économiseur de pile"</string>
+ <string name="battery_saver_start_action" msgid="8353766979886287140">"Activer"</string>
+ <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Non merci"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Rotation auto de l\'écran"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"Autoriser <xliff:g id="APPLICATION">%1$s</xliff:g> à accéder à <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
<string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Autorisé <xliff:g id="APPLICATION">%1$s</xliff:g> à accéder à <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nCette application n\'a pas été autorisée à effectuer des enregistrements, mais elle pourrait enregistrer du contenu audio par l\'intermédiaire de cet appareil USB."</string>
@@ -128,6 +131,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Visage authentifié"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Confirmé"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Touchez Confirmer pour terminer"</string>
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Déverrouillé par votre visage. Appuyez pour continuer."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Authentifié"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Utiliser un NIP"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Utiliser un schéma"</string>
@@ -181,6 +185,7 @@
<string name="accessibility_desc_close" msgid="8293708213442107755">"Fermer"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"aucune interruption"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"alarmes seulement"</string>
+ <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"Ne pas déranger."</string>
<string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"Bluetooth."</string>
<string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"Bluetooth activé."</string>
<string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"Alarme réglée sur <xliff:g id="TIME">%s</xliff:g>"</string>
@@ -205,6 +210,7 @@
<string name="dessert_case" msgid="9104973640704357717">"Vitrine des desserts"</string>
<string name="start_dreams" msgid="9131802557946276718">"Écran de veille"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
+ <string name="quick_settings_dnd_label" msgid="7728690179108024338">"Ne pas déranger"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Aucun des appareils associés n\'est disponible"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Pile : <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
@@ -348,6 +354,7 @@
<string name="notification_section_header_alerting" msgid="5581175033680477651">"Notifications"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Conversations"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Effacer toutes les notifications silencieuses"</string>
+ <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Les notifications sont suspendues par le mode Ne pas déranger"</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"Commencer"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Aucune notification"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Cet appareil est géré par ton parent"</string>
@@ -452,8 +459,8 @@
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Déverrouiller pour utiliser"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Un problème est survenu lors de la récupération de vos cartes, veuillez réessayer plus tard"</string>
<string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Paramètres de l\'écran de verrouillage"</string>
- <string name="qr_code_scanner_title" msgid="5660820608548306581">"Code QR"</string>
- <string name="qr_code_scanner_description" msgid="7937603775306661863">"Touchez pour numériser"</string>
+ <!-- no translation found for qr_code_scanner_title (5290201053875420785) -->
+ <skip />
<string name="status_bar_work" msgid="5238641949837091056">"Profil professionnel"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Mode Avion"</string>
<string name="zen_alarm_warning" msgid="7844303238486849503">"Vous n\'entendrez pas votre prochaine alarme à <xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -491,6 +498,8 @@
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"&lt;b&gt;État :&lt;/b&gt; abaissé d\'un niveau"</string>
<string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"S\'affiche dans le haut des notifications de conversation et comme photo de profil à l\'écran de verrouillage"</string>
<string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"S\'affiche dans le haut des notifications de conversation et comme photo de profil à l\'écran de verrouillage, s\'affiche comme bulle"</string>
+ <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"S\'affiche dans le haut des notifications de conversation et comme photo de profil à l\'écran de verrouillage, interrompt le mode Ne pas déranger"</string>
+ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"S\'affiche dans le haut des notifications de conversation et comme photo de profil à l\'écran de verrouillage, s\'affiche comme bulle, interrompt le mode Ne pas déranger"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritaire"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> ne prend pas en charge les fonctionnalités de conversation"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Ces notifications ne peuvent pas être modifiées"</string>
@@ -566,6 +575,7 @@
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"Message texte"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"Musique"</string>
<string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Agenda"</string>
+ <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Ne pas déranger"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"Raccourci des boutons de volume"</string>
<string name="battery" msgid="769686279459897127">"Pile"</string>
<string name="headset" msgid="4485892374984466437">"Écouteurs"</string>
@@ -684,6 +694,10 @@
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"Le Wi-Fi est désactivé"</string>
<string name="bt_is_off" msgid="7436344904889461591">"Le Bluetooth est désactivé"</string>
+ <string name="dnd_is_off" msgid="3185706903793094463">"Le mode Ne pas déranger est désactivé"</string>
+ <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"Le mode Ne pas déranger a été activé par une règle automatique (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"Le mode Ne pas déranger a été activé par une application (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"Le mode Ne pas déranger a été activé par une règle automatique ou une application."</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"Applications qui fonctionnent en arrière-plan"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"Touchez pour afficher des détails sur l\'utilisation de la pile et des données"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Désactiver les données cellulaires?"</string>
@@ -708,6 +722,8 @@
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(travail)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"Appel téléphonique"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(par l\'intermédiaire de <xliff:g id="APPLICATION_NAME_S_">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_label" msgid="3385241594101496292">"(<xliff:g id="ATTRIBUTION_LABEL">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_proxy_label" msgid="1111829599659403249">"(<xliff:g id="ATTRIBUTION_LABEL">%1$s</xliff:g> • <xliff:g id="PROXY_LABEL">%2$s</xliff:g>)"</string>
<string name="privacy_type_camera" msgid="7974051382167078332">"appareil photo"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"position"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"microphone"</string>
@@ -806,6 +822,9 @@
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(déconnecté)"</string>
<string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Changement impossible. Touchez pour réessayer."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Associer un autre appareil"</string>
+ <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Pour diffuser cette session, veuillez ouvrir l\'application."</string>
+ <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Application inconnue"</string>
+ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Arrêter la diffusion"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Numéro de version"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Le numéro de version a été copié dans le presse-papiers."</string>
<string name="basic_status" msgid="2315371112182658176">"Ouvrir la conversation"</string>
@@ -839,6 +858,7 @@
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Affichez les messages récents, les appels manqués et les mises à jour d\'état"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Conversation"</string>
+ <string name="paused_by_dnd" msgid="7856941866433556428">"Interrompue par la fonctionnalité Ne pas déranger"</string>
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> a envoyé un message : <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> a envoyé une image"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> a mis à jour son état : <xliff:g id="STATUS">%2$s</xliff:g>"</string>
@@ -877,8 +897,7 @@
<item quantity="one"><xliff:g id="COUNT_1">%s</xliff:g> application active</item>
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> applications actives</item>
</plurals>
- <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
- <skip />
+ <string name="fgs_dot_content_description" msgid="2865071539464777240">"Nouvelle information"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Applications actives"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Arrêter"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Arrêtée"</string>
@@ -886,14 +905,15 @@
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Copié"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"À partir de <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Ignorer la copie de l\'IU"</string>
- <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
- <skip />
- <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
- <skip />
- <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
- <skip />
- <!-- no translation found for add (81036585205287996) -->
- <skip />
- <!-- no translation found for manage_users (1823875311934643849) -->
- <skip />
+ <string name="clipboard_edit_text_description" msgid="805254383912962103">"Modifier le texte copié"</string>
+ <string name="clipboard_edit_image_description" msgid="8904857948976041306">"Modifier l\'image copiée"</string>
+ <string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Envoyer à un appareil à proximité"</string>
+ <string name="add" msgid="81036585205287996">"Ajouter"</string>
+ <string name="manage_users" msgid="1823875311934643849">"Gérer les utilisateurs"</string>
+ <string name="drag_split_not_supported" msgid="4326847447699729722">"Cette notification ne prend pas en charge le partage d\'écran par glissement."</string>
+ <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi-Fi non disponible"</string>
+ <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Mode priorité"</string>
+ <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"L\'alarme a été réglée"</string>
+ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"L\'appareil photo et le micro sont désactivés"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notification}one{# notification}other{# notifications}}"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 0af35baae386..33194aae5042 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -20,14 +20,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4811759950673118541">"Interface"</string>
- <string name="battery_low_title" msgid="6891106956328275225">"La batterie est bientôt épuisée"</string>
+ <string name="battery_low_title" msgid="5319680173344341779">"Activer l\'économiseur de batterie ?"</string>
+ <string name="battery_low_description" msgid="3282977755476423966">"Il vous reste <xliff:g id="PERCENTAGE">%s</xliff:g> de batterie. L\'économiseur de batterie active le thème sombre, limite les activités en arrière-plan et retarde les notifications."</string>
+ <string name="battery_low_intro" msgid="5148725009653088790">"L\'économiseur de batterie active le thème sombre, limite les activités en arrière-plan et retarde les notifications."</string>
<string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> restants"</string>
<string name="invalid_charger_title" msgid="938685362320735167">"Impossible de recharger via USB"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"Utiliser le chargeur d\'origine fourni avec votre appareil"</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Activer l\'économiseur de batterie ?"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"À propos de l\'économiseur de batterie"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Activer"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"Activer l\'économiseur de batterie"</string>
+ <string name="battery_saver_start_action" msgid="8353766979886287140">"Activer"</string>
+ <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Non, merci"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Rotation automatique de l\'écran"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"Autoriser <xliff:g id="APPLICATION">%1$s</xliff:g> à accéder à <xliff:g id="USB_DEVICE">%2$s</xliff:g> ?"</string>
<string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Autoriser <xliff:g id="APPLICATION">%1$s</xliff:g> à accéder à <xliff:g id="USB_DEVICE">%2$s</xliff:g> ?\nCette application n\'a pas été autorisée à effectuer des enregistrements, mais elle pourrait enregistrer du contenu audio via ce périphérique USB."</string>
@@ -128,6 +131,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Visage authentifié"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Confirmé"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Appuyez sur \"Confirmer\" pour terminer"</string>
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Déverrouillé par votre visage. Appuyez pour continuer."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Authentifié"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Utiliser un code PIN"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Utiliser un schéma"</string>
@@ -181,6 +185,7 @@
<string name="accessibility_desc_close" msgid="8293708213442107755">"Fermer"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"aucune interruption"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"alarmes uniquement"</string>
+ <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"Ne pas déranger."</string>
<string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"Bluetooth."</string>
<string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"Bluetooth activé."</string>
<string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"Alarme réglée sur <xliff:g id="TIME">%s</xliff:g>"</string>
@@ -205,6 +210,7 @@
<string name="dessert_case" msgid="9104973640704357717">"Vitrine des desserts"</string>
<string name="start_dreams" msgid="9131802557946276718">"Économiseur d\'écran"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
+ <string name="quick_settings_dnd_label" msgid="7728690179108024338">"Ne pas déranger"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Aucun appareil associé disponible."</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> de batterie"</string>
@@ -348,6 +354,7 @@
<string name="notification_section_header_alerting" msgid="5581175033680477651">"Notifications"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Conversations"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Effacer toutes les notifications silencieuses"</string>
+ <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Notifications suspendues par le mode Ne pas déranger"</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"Commencer"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Aucune notification"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Cet appareil est géré par tes parents"</string>
@@ -452,8 +459,8 @@
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Déverrouiller pour utiliser"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Problème de récupération de vos cartes. Réessayez plus tard"</string>
<string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Paramètres de l\'écran de verrouillage"</string>
- <string name="qr_code_scanner_title" msgid="5660820608548306581">"Code QR"</string>
- <string name="qr_code_scanner_description" msgid="7937603775306661863">"Appuyer pour scanner"</string>
+ <!-- no translation found for qr_code_scanner_title (5290201053875420785) -->
+ <skip />
<string name="status_bar_work" msgid="5238641949837091056">"Profil professionnel"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Mode Avion"</string>
<string name="zen_alarm_warning" msgid="7844303238486849503">"Vous n\'entendrez pas votre prochaine alarme <xliff:g id="WHEN">%1$s</xliff:g>."</string>
@@ -491,6 +498,8 @@
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"&lt;b&gt;État ::&lt;/b&gt; Abaissée d\'un niveau"</string>
<string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"S\'affiche en haut des notifications de conversation et en tant que photo de profil sur l\'écran de verrouillage"</string>
<string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"S\'affiche en haut des notifications de conversation et en tant que photo de profil sur l\'écran de verrouillage, apparaît sous forme de bulle"</string>
+ <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"S\'affiche en haut des notifications de conversation et en tant que photo de profil sur l\'écran de verrouillage, interrompt le mode Ne pas déranger"</string>
+ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"S\'affiche en haut des notifications de conversation et en tant que photo de profil sur l\'écran de verrouillage, apparaît sous forme de bulle, interrompt le mode Ne pas déranger"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritaire"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> n\'est pas compatible avec les fonctionnalités de conversation"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Impossible de modifier ces notifications."</string>
@@ -566,6 +575,7 @@
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"SMS"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"Musique"</string>
<string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Agenda"</string>
+ <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Ne pas déranger"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"Raccourci des boutons de volume"</string>
<string name="battery" msgid="769686279459897127">"Batterie"</string>
<string name="headset" msgid="4485892374984466437">"Casque"</string>
@@ -684,6 +694,10 @@
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"Wi-Fi désactivé"</string>
<string name="bt_is_off" msgid="7436344904889461591">"Bluetooth désactivé"</string>
+ <string name="dnd_is_off" msgid="3185706903793094463">"Mode \"Ne pas déranger\" désactivé"</string>
+ <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"Le mode \"Ne pas déranger\" a été activé par une règle automatique (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"Le mode \"Ne pas déranger\" a été activé par une application (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"Le mode \"Ne pas déranger\" a été activé par une règle automatique ou une application."</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"Applications en cours d\'exécution en arrière-plan"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"Appuyer pour obtenir des informations sur l\'utilisation de la batterie et des données"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Désactiver les données mobiles ?"</string>
@@ -708,6 +722,8 @@
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(travail)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"Appel téléphonique"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(via <xliff:g id="APPLICATION_NAME_S_">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_label" msgid="3385241594101496292">"(<xliff:g id="ATTRIBUTION_LABEL">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_proxy_label" msgid="1111829599659403249">"(<xliff:g id="ATTRIBUTION_LABEL">%1$s</xliff:g> • <xliff:g id="PROXY_LABEL">%2$s</xliff:g>)"</string>
<string name="privacy_type_camera" msgid="7974051382167078332">"l\'appareil photo"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"la position"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"le micro"</string>
@@ -806,6 +822,9 @@
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(déconnecté)"</string>
<string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Impossible de changer. Appuyez pour réessayer."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Associer un nouvel appareil"</string>
+ <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Pour caster cette session, veuillez ouvrir l\'appli."</string>
+ <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Appli inconnue"</string>
+ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Arrêter la diffusion"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Numéro de build"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Numéro de build copié dans le presse-papiers."</string>
<string name="basic_status" msgid="2315371112182658176">"Conversation ouverte"</string>
@@ -839,6 +858,7 @@
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"+ de <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Voir les messages récents, les appels manqués et les notifications d\'état"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Conversation"</string>
+ <string name="paused_by_dnd" msgid="7856941866433556428">"Mise en pause par Ne pas déranger"</string>
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> a envoyé un message : <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> a envoyé une image"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> a mis à jour son statut : <xliff:g id="STATUS">%2$s</xliff:g>"</string>
@@ -877,8 +897,7 @@
<item quantity="one"><xliff:g id="COUNT_1">%s</xliff:g> appli active</item>
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> applis actives</item>
</plurals>
- <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
- <skip />
+ <string name="fgs_dot_content_description" msgid="2865071539464777240">"Nouvelles informations"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Applis actives"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Arrêter"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Arrêtée"</string>
@@ -886,14 +905,15 @@
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Copié"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"De <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Désactiver l\'interface de copie"</string>
- <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
- <skip />
- <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
- <skip />
- <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
- <skip />
- <!-- no translation found for add (81036585205287996) -->
- <skip />
- <!-- no translation found for manage_users (1823875311934643849) -->
- <skip />
+ <string name="clipboard_edit_text_description" msgid="805254383912962103">"Modifier le texte copié"</string>
+ <string name="clipboard_edit_image_description" msgid="8904857948976041306">"Modifier l\'image copiée"</string>
+ <string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Envoyer à un appareil à proximité"</string>
+ <string name="add" msgid="81036585205287996">"Ajouter"</string>
+ <string name="manage_users" msgid="1823875311934643849">"Gérer les utilisateurs"</string>
+ <string name="drag_split_not_supported" msgid="4326847447699729722">"Impossible de faire glisser cette notification vers l\'écran partagé."</string>
+ <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi non disponible"</string>
+ <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Mode Prioritaire"</string>
+ <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarme réglée"</string>
+ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Appareil photo et micro désactivés"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notification}one{# notification}other{# notifications}}"</string>
</resources>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index 81efcb54769b..52a55e7ab7fa 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -20,14 +20,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4811759950673118541">"IU do sistema"</string>
- <string name="battery_low_title" msgid="6891106956328275225">"A batería pode esgotarse en breve"</string>
+ <string name="battery_low_title" msgid="5319680173344341779">"Queres activar a función Aforro de batería?"</string>
+ <string name="battery_low_description" msgid="3282977755476423966">"Quédache un <xliff:g id="PERCENTAGE">%s</xliff:g> de batería. Coa función Aforro de batería, actívase o tema escuro, restrínxese a actividade en segundo plano e atrásanse as notificacións."</string>
+ <string name="battery_low_intro" msgid="5148725009653088790">"Coa función Aforro de batería, actívase o tema escuro, restrínxese a actividade en segundo plano e atrásanse as notificacións."</string>
<string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> restante"</string>
<string name="invalid_charger_title" msgid="938685362320735167">"Non se puido realizar a carga por USB"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"Utiliza o cargador que incluía o dispositivo"</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Queres activar a función Aforro de batería?"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Acerca de Aforro de batería"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Activar"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"Activar a función Aforro de batería"</string>
+ <string name="battery_saver_start_action" msgid="8353766979886287140">"Activar"</string>
+ <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Non, grazas"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Xirar pantalla automaticamente"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"Queres permitir que <xliff:g id="APPLICATION">%1$s</xliff:g> acceda a <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
<string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Queres permitir que a aplicación <xliff:g id="APPLICATION">%1$s</xliff:g> acceda ao dispositivo (<xliff:g id="USB_DEVICE">%2$s</xliff:g>)?\nEsta aplicación non está autorizada para realizar gravacións, pero pode capturar audio a través deste dispositivo USB."</string>
@@ -128,6 +131,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Autenticouse a cara"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Confirmada"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Toca Confirmar para completar o proceso"</string>
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Desbloqueouse coa túa cara. Preme para continuar."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Autenticado"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Usar PIN"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Usar padrón"</string>
@@ -181,6 +185,7 @@
<string name="accessibility_desc_close" msgid="8293708213442107755">"Pechar"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"silencio total"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"só alarmas"</string>
+ <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"Modo Non molestar."</string>
<string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"Bluetooth."</string>
<string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"Bluetooth activado."</string>
<string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"Alarma definida para as <xliff:g id="TIME">%s</xliff:g>"</string>
@@ -205,6 +210,7 @@
<string name="dessert_case" msgid="9104973640704357717">"Caixa de sobremesa"</string>
<string name="start_dreams" msgid="9131802557946276718">"Protector pantalla"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
+ <string name="quick_settings_dnd_label" msgid="7728690179108024338">"Non molestar"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Non hai dispositivos vinculados dispoñibles"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> de batería"</string>
@@ -348,6 +354,7 @@
<string name="notification_section_header_alerting" msgid="5581175033680477651">"Notificacións"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Conversas"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Borra todas as notificacións silenciadas"</string>
+ <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"O modo Non molestar puxo en pausa as notificacións"</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"Iniciar agora"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Non hai notificacións"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"O teu pai ou nai xestiona este dispositivo"</string>
@@ -452,8 +459,8 @@
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Desbloquear para usar"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Produciuse un problema ao obter as tarxetas. Téntao de novo máis tarde"</string>
<string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Configuración da pantalla de bloqueo"</string>
- <string name="qr_code_scanner_title" msgid="5660820608548306581">"Código QR"</string>
- <string name="qr_code_scanner_description" msgid="7937603775306661863">"Tocar para escanear"</string>
+ <!-- no translation found for qr_code_scanner_title (5290201053875420785) -->
+ <skip />
<string name="status_bar_work" msgid="5238641949837091056">"Perfil de traballo"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Modo avión"</string>
<string name="zen_alarm_warning" msgid="7844303238486849503">"Non escoitarás a alarma seguinte <xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -491,6 +498,8 @@
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"&lt;b&gt;Estado:&lt;/b&gt; clasificouse nun nivel inferior"</string>
<string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"Móstrase na parte superior das notificacións das conversas e como imaxe do perfil na pantalla de bloqueo"</string>
<string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"Móstrase na parte superior das notificacións das conversas e como imaxe do perfil na pantalla de bloqueo, e aparece como unha burbulla"</string>
+ <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"Móstrase na parte superior das notificacións das conversas e como imaxe do perfil na pantalla de bloqueo, e interrompe o modo Non molestar"</string>
+ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Móstrase na parte superior das notificacións das conversas e como imaxe do perfil na pantalla de bloqueo, aparece como unha burbulla e interrompe o modo Non molestar"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioridade"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> non admite funcións de conversa"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Estas notificacións non se poden modificar."</string>
@@ -566,6 +575,7 @@
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"SMS"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"Música"</string>
<string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Calendar"</string>
+ <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Non molestar"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"Atallo dos botóns de volume"</string>
<string name="battery" msgid="769686279459897127">"Batería"</string>
<string name="headset" msgid="4485892374984466437">"Auriculares"</string>
@@ -684,6 +694,10 @@
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"A wifi está desactivada"</string>
<string name="bt_is_off" msgid="7436344904889461591">"O Bluetooth está desactivado"</string>
+ <string name="dnd_is_off" msgid="3185706903793094463">"O modo Non molestar está desactivado"</string>
+ <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"Unha norma automática (<xliff:g id="ID_1">%s</xliff:g>) activou o modo Non molestar."</string>
+ <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"Unha aplicación (<xliff:g id="ID_1">%s</xliff:g>) activou o modo Non molestar."</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"Unha aplicación ou norma automática activou o modo Non molestar."</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"Aplicacións que se executan en segundo plano"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"Toca para obter información sobre o uso de datos e a batería"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Queres desactivar os datos móbiles?"</string>
@@ -708,6 +722,8 @@
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(traballo)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"Chamada de teléfono"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(mediante <xliff:g id="APPLICATION_NAME_S_">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_label" msgid="3385241594101496292">"(<xliff:g id="ATTRIBUTION_LABEL">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_proxy_label" msgid="1111829599659403249">"(<xliff:g id="ATTRIBUTION_LABEL">%1$s</xliff:g> • <xliff:g id="PROXY_LABEL">%2$s</xliff:g>)"</string>
<string name="privacy_type_camera" msgid="7974051382167078332">"a cámara"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"a localiz."</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"o micrófono"</string>
@@ -806,6 +822,9 @@
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(desconectado)"</string>
<string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Non se puido realizar o cambio. Toca para tentalo de novo."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Vincular dispositivo novo"</string>
+ <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Para emitir esta sesión, abre a aplicación."</string>
+ <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Aplicación descoñecida"</string>
+ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Deter emisión"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Número de compilación"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Copiouse o número de compilación no portapapeis."</string>
<string name="basic_status" msgid="2315371112182658176">"Conversa aberta"</string>
@@ -839,6 +858,7 @@
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"+ de <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Consulta as mensaxes recentes, as chamadas perdidas e as actualizacións dos estados"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Conversa"</string>
+ <string name="paused_by_dnd" msgid="7856941866433556428">"Púxose en pausa debido ao modo Non molestar"</string>
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> enviou unha mensaxe: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> enviou unha imaxe"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> cambiou de estado: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
@@ -877,8 +897,7 @@
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> aplicacións activas</item>
<item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> aplicación activa</item>
</plurals>
- <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
- <skip />
+ <string name="fgs_dot_content_description" msgid="2865071539464777240">"Nova información"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Aplicacións activas"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Deter"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Detida"</string>
@@ -886,14 +905,15 @@
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Copiouse"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"De <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Ignorar interface de copia"</string>
- <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
- <skip />
- <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
- <skip />
- <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
- <skip />
- <!-- no translation found for add (81036585205287996) -->
- <skip />
- <!-- no translation found for manage_users (1823875311934643849) -->
- <skip />
+ <string name="clipboard_edit_text_description" msgid="805254383912962103">"Editar texto copiado"</string>
+ <string name="clipboard_edit_image_description" msgid="8904857948976041306">"Editar imaxe copiada"</string>
+ <string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Enviar a dispositivo próximo"</string>
+ <string name="add" msgid="81036585205287996">"Engadir"</string>
+ <string name="manage_users" msgid="1823875311934643849">"Xestionar usuarios"</string>
+ <string name="drag_split_not_supported" msgid="4326847447699729722">"Esta notificación non pode arrastrarse á pantalla dividida."</string>
+ <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"A wifi non está dispoñible"</string>
+ <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Modo de prioridade"</string>
+ <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarma definida"</string>
+ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"A cámara e o micrófono están desactivados"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notificación}other{# notificacións}}"</string>
</resources>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index 98510d5012f6..497029e8927e 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -20,14 +20,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4811759950673118541">"સિસ્ટમ UI"</string>
- <string name="battery_low_title" msgid="6891106956328275225">"બૅટરી ટૂંક સમયમાં સમાપ્ત થશે"</string>
+ <string name="battery_low_title" msgid="5319680173344341779">"બૅટરી સેવર ચાલુ કરીએ?"</string>
+ <string name="battery_low_description" msgid="3282977755476423966">"તમારી પાસે <xliff:g id="PERCENTAGE">%s</xliff:g> બૅટરી બાકી છે. બૅટરી સેવર ઘેરી થીમની સુવિધા ચાલુ કરે છે, બૅકગ્રાઉન્ડ પ્રવૃત્તિ પ્રતિબંધિત કરે છે અને નોટિફિકેશન વિલંબે મોકલે છે."</string>
+ <string name="battery_low_intro" msgid="5148725009653088790">"બૅટરી સેવર ઘેરી થીમની સુવિધા ચાલુ કરે છે, બૅકગ્રાઉન્ડ પ્રવૃત્તિ પ્રતિબંધિત કરે છે અને નોટિફિકેશન વિલંબે મોકલે છે."</string>
<string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> બાકી"</string>
<string name="invalid_charger_title" msgid="938685362320735167">"USB મારફતે ચાર્જ કરી શકતા નથી"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"તમારા ઉપકરણ સાથે આવેલ ચાર્જરનો ઉપયોગ કરો"</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"બૅટરી સેવર ચાલુ કરીએ?"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"બૅટરી સેવર વિશે"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"ચાલુ કરો"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"બૅટરી સેવર ચાલુ કરો"</string>
+ <string name="battery_saver_start_action" msgid="8353766979886287140">"ચાલુ કરો"</string>
+ <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"ના, આભાર"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"ઑટો રોટેટ સ્ક્રીન"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"<xliff:g id="USB_DEVICE">%2$s</xliff:g>ના ઍક્સેસ માટે <xliff:g id="APPLICATION">%1$s</xliff:g>ને મંજૂરી આપીએ?"</string>
<string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"<xliff:g id="APPLICATION">%1$s</xliff:g>ને <xliff:g id="USB_DEVICE">%2$s</xliff:g> ઍક્સેસ કરવાની મંજૂરી આપીએ?\nઆ ઍપને રેકૉર્ડ કરવાની પરવાનગી આપવામાં આવી નથી પરંતુ તે આ USB ડિવાઇસ મારફત ઑડિયો કૅપ્ચર કરી શકે છે."</string>
@@ -128,6 +131,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"ચહેરાનું પ્રમાણીકરણ થયું"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"પુષ્ટિ કરી"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"પરીક્ષણ પૂર્ણ કરવા કન્ફર્મ કરોને ટૅપ કરો"</string>
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"તમારા ચહેરા વડે અનલૉક કર્યું. આગળ વધવા માટે ટૅપ કરો."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"પ્રમાણિત"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"પિનનો ઉપયોગ કરો"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"પૅટર્નનો ઉપયોગ કરો"</string>
@@ -181,6 +185,7 @@
<string name="accessibility_desc_close" msgid="8293708213442107755">"બંધ કરો"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"બિલકુલ અવાજ નહીં"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"માત્ર અલાર્મ"</string>
+ <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"ખલેલ પાડશો નહીં."</string>
<string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"બ્લૂટૂથ."</string>
<string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"બ્લૂટૂથ ચાલુ."</string>
<string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"<xliff:g id="TIME">%s</xliff:g> માટે એલાર્મ સેટ કર્યું."</string>
@@ -205,6 +210,7 @@
<string name="dessert_case" msgid="9104973640704357717">"ડેઝર્ટ કેસ"</string>
<string name="start_dreams" msgid="9131802557946276718">"સ્ક્રીન સેવર"</string>
<string name="ethernet_label" msgid="2203544727007463351">"ઇથરનેટ"</string>
+ <string name="quick_settings_dnd_label" msgid="7728690179108024338">"ખલેલ પાડશો નહીં"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"બ્લૂટૂથ"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"કોઈ જોડી કરેલ ઉપકરણો ઉપલબ્ધ નથી"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> બૅટરી"</string>
@@ -348,6 +354,7 @@
<string name="notification_section_header_alerting" msgid="5581175033680477651">"નોટિફિકેશન"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"વાતચીત"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"બધા સાઇલન્ટ નોટિફિકેશન સાફ કરો"</string>
+ <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"ખલેલ પાડશો નહીં દ્વારા થોભાવેલ નોટિફિકેશન"</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"હવે શરૂ કરો"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"કોઈ નોટિફિકેશન નથી"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"આ ડિવાઇસ તમારા માતાપિતા દ્વારા મેનેજ કરવામાં આવે છે"</string>
@@ -452,8 +459,8 @@
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"ઉપયોગ કરવા માટે અનલૉક કરો"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"તમારા કાર્ડની માહિતી મેળવવામાં સમસ્યા આવી હતી, કૃપા કરીને થોડા સમય પછી ફરી પ્રયાસ કરો"</string>
<string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"લૉક સ્ક્રીનના સેટિંગ"</string>
- <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR કોડ"</string>
- <string name="qr_code_scanner_description" msgid="7937603775306661863">"સ્કૅન કરવા માટે ટૅપ કરો"</string>
+ <!-- no translation found for qr_code_scanner_title (5290201053875420785) -->
+ <skip />
<string name="status_bar_work" msgid="5238641949837091056">"ઑફિસની પ્રોફાઇલ"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"એરપ્લેન મોડ"</string>
<string name="zen_alarm_warning" msgid="7844303238486849503">"તમે <xliff:g id="WHEN">%1$s</xliff:g> એ તમારો આગલો એલાર્મ સાંભળશો નહીં"</string>
@@ -491,6 +498,8 @@
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"&lt;b&gt;સ્ટેટસ:&lt;/b&gt; નીચલી રેંક આપવામાં આવી"</string>
<string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"વાતચીતના નોટિફિકેશન વિભાગની ટોચ પર અને લૉક કરેલી સ્ક્રીન પર પ્રોફાઇલ ફોટો તરીકે બતાવે છે"</string>
<string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"વાતચીતના નોટિફિકેશન વિભાગની ટોચ પર અને લૉક કરેલી સ્ક્રીન પર પ્રોફાઇલ ફોટો તરીકે બતાવે છે, બબલ તરીકે દેખાય છે"</string>
+ <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"વાતચીતના નોટિફિકેશન વિભાગની ટોચ પર અને લૉક કરેલી સ્ક્રીન પર પ્રોફાઇલ ફોટો તરીકે બતાવે છે, ખલેલ પાડશો નહીં મોડમાં વિક્ષેપ ઊભો કરે છે"</string>
+ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"વાતચીતના નોટિફિકેશન વિભાગની ટોચ પર અને લૉક કરેલી સ્ક્રીન પર પ્રોફાઇલ ફોટો તરીકે બતાવે છે, બબલ તરીકે દેખાય છે, ખલેલ પાડશો નહીં મોડમાં વિક્ષેપ ઊભો કરે છે"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"પ્રાધાન્યતા"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> વાતચીતની સુવિધાઓને સપોર્ટ આપતી નથી"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"આ નોટિફિકેશનમાં કોઈ ફેરફાર થઈ શકશે નહીં."</string>
@@ -566,6 +575,7 @@
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"SMS"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"સંગીત"</string>
<string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Calendar"</string>
+ <string name="volume_and_do_not_disturb" msgid="502044092739382832">"ખલેલ પાડશો નહીં"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"વૉલ્યૂમ બટન્સ શૉર્ટકટ"</string>
<string name="battery" msgid="769686279459897127">"બૅટરી"</string>
<string name="headset" msgid="4485892374984466437">"હૅડસેટ"</string>
@@ -684,6 +694,10 @@
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"વાઇ-ફાઇ બંધ છે"</string>
<string name="bt_is_off" msgid="7436344904889461591">"બ્લૂટૂથ બંધ છે"</string>
+ <string name="dnd_is_off" msgid="3185706903793094463">"ખલેલ પાડશો નહીં બંધ છે"</string>
+ <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"ખલેલ પાડશો નહીં એક સ્વચાલિત નિયમ દ્વારા ચાલુ કરાયું હતું (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"ખલેલ પાડશો નહીં એક ઍપ્લિકેશન દ્વારા ચાલુ કરાયું હતું (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"ખલેલ પાડશો નહીં એક સ્વચાલિત નિયમ અથવા ઍપ્લિકેશન દ્વારા ચાલુ કરાયું હતું."</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"પૃષ્ઠભૂમિમાં ચાલી રહેલ ઍપ્લિકેશનો"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"બૅટરી અને ડેટા વપરાશ વિશેની વિગતો માટે ટૅપ કરો"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"મોબાઇલ ડેટા બંધ કરીએ?"</string>
@@ -708,6 +722,8 @@
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(ઑફિસ)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"ફોન કૉલ"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(<xliff:g id="APPLICATION_NAME_S_">%s</xliff:g> મારફતે)"</string>
+ <string name="ongoing_privacy_dialog_attribution_label" msgid="3385241594101496292">"(<xliff:g id="ATTRIBUTION_LABEL">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_proxy_label" msgid="1111829599659403249">"(<xliff:g id="ATTRIBUTION_LABEL">%1$s</xliff:g> • <xliff:g id="PROXY_LABEL">%2$s</xliff:g>)"</string>
<string name="privacy_type_camera" msgid="7974051382167078332">"કૅમેરા"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"સ્થાન"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"માઇક્રોફોન"</string>
@@ -806,6 +822,9 @@
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(ડિસ્કનેક્ટ કરેલું)"</string>
<string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"સ્વિચ કરી શકતા નથી. ફરી પ્રયાસ કરવા માટે ટૅપ કરો."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"નવા ડિવાઇસ સાથે જોડાણ કરો"</string>
+ <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"આ સત્ર કાસ્ટ કરવા માટે, કૃપા કરીને ઍપ ખોલો."</string>
+ <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"અજાણી ઍપ"</string>
+ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"કાસ્ટ કરવાનું રોકો"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"બિલ્ડ નંબર"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"બિલ્ડ નંબર ક્લિપબૉર્ડ પર કૉપિ કર્યો."</string>
<string name="basic_status" msgid="2315371112182658176">"વાતચીત ખોલો"</string>
@@ -839,6 +858,7 @@
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"તાજેતરના સંદેશા, ચૂકી ગયેલા કૉલ અને સ્ટેટસ અપડેટ જુઓ"</string>
<string name="people_tile_title" msgid="6589377493334871272">"વાતચીત"</string>
+ <string name="paused_by_dnd" msgid="7856941866433556428">"\'ખલેલ પાડશો નહીં\'ની સુવિધા દ્વારા થોભાવેલું"</string>
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> દ્વારા કોઈ સંદેશ મોકલવામાં આવ્યો: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> દ્વારા કોઈ છબી મોકલવામાં આવી"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> દ્વારા નવી સ્ટેટસ અપડેટ પોસ્ટ કરવામાં આવી: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
@@ -877,8 +897,7 @@
<item quantity="one"><xliff:g id="COUNT_1">%s</xliff:g> સક્રિય ઍપ</item>
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> સક્રિય ઍપ</item>
</plurals>
- <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
- <skip />
+ <string name="fgs_dot_content_description" msgid="2865071539464777240">"નવી માહિતી"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"સક્રિય ઍપ"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"રોકો"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"બંધ કરેલી છે"</string>
@@ -886,14 +905,15 @@
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"કૉપિ કરવામાં આવી"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"<xliff:g id="APPNAME">%1$s</xliff:g>માંથી"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"\'UI | યૂઝર ઇન્ટરફેસ (UI) કૉપિ કરો\'ને છોડી દો"</string>
- <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
- <skip />
- <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
- <skip />
- <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
- <skip />
- <!-- no translation found for add (81036585205287996) -->
- <skip />
- <!-- no translation found for manage_users (1823875311934643849) -->
- <skip />
+ <string name="clipboard_edit_text_description" msgid="805254383912962103">"કૉપિ કરેલી ટેક્સ્ટમાં ફેરફાર કરો"</string>
+ <string name="clipboard_edit_image_description" msgid="8904857948976041306">"કૉપિ કરેલી છબીમાં ફેરફાર કરો"</string>
+ <string name="clipboard_send_nearby_description" msgid="4629769637846717650">"નજીકના ડિવાઇસને મોકલો"</string>
+ <string name="add" msgid="81036585205287996">"ઉમેરો"</string>
+ <string name="manage_users" msgid="1823875311934643849">"વપરાશકર્તાઓને મેનેજ કરો"</string>
+ <string name="drag_split_not_supported" msgid="4326847447699729722">"આ નોટિફિકેશન તેને સ્પ્લિટસ્ક્રીનમાં ખેંચવાની સુવિધાને સપોર્ટ કરતું નથી."</string>
+ <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"વાઇ-ફાઇ ઉપલબ્ધ નથી"</string>
+ <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"પ્રાધાન્યતા મોડ"</string>
+ <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"અલાર્મ સેટ"</string>
+ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"કૅમેરા અને માઇક બંધ છે"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# નોટિફિકેશન}one{# નોટિફિકેશન}other{# નોટિફિકેશન}}"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 2631f550d459..d7b9f327d821 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -20,14 +20,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4811759950673118541">"सिस्‍टम यूआई"</string>
- <string name="battery_low_title" msgid="6891106956328275225">"बैटरी जल्दी ही खत्म हो जाएगी"</string>
+ <string name="battery_low_title" msgid="5319680173344341779">"क्या आपको बैटरी सेवर मोड चालू करना है?"</string>
+ <string name="battery_low_description" msgid="3282977755476423966">"आपकी बैटरी <xliff:g id="PERCENTAGE">%s</xliff:g> बची है. बैटरी सेवर मोड पर, गहरे रंग वाली थीम चालू होती है और बैकग्राउंड में चल रही गतिविधियों पर रोक लग जाती है. इसके अलावा, आपको सूचनाएं भी देरी से मिलती हैं."</string>
+ <string name="battery_low_intro" msgid="5148725009653088790">"बैटरी सेवर मोड पर, गहरे रंग वाली थीम चालू होती है और बैकग्राउंड में चल रही गतिविधियों पर रोक लग जाती है. इसके अलावा, आपको सूचनाएं भी देरी से मिलती हैं."</string>
<string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> शेष"</string>
<string name="invalid_charger_title" msgid="938685362320735167">"यूएसबी के ज़रिए चार्ज नहीं किया जा सकता"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"अपने डिवाइस के साथ मिलने वाले चार्जर का इस्तेमाल करें"</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"क्या आप बैटरी सेवर चालू करना चाहते हैं?"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"बैटरी सेवर के बारे में"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"चालू करें"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"बैटरी सेवर चालू करें"</string>
+ <string name="battery_saver_start_action" msgid="8353766979886287140">"चालू करें"</string>
+ <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"रहने दें"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"स्‍क्रीन अपने आप घुमाना"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"<xliff:g id="APPLICATION">%1$s</xliff:g> को <xliff:g id="USB_DEVICE">%2$s</xliff:g> के ऐक्सेस की अनुमति दें?"</string>
<string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"आप <xliff:g id="APPLICATION">%1$s</xliff:g> को <xliff:g id="USB_DEVICE">%2$s</xliff:g> ऐक्सेस करने की अनुमति देना चाहते हैं?\nइस ऐप्लिकेशन को रिकॉर्ड करने की अनुमति नहीं दी गई है. हालांकि, ऐप्लिकेशन इस यूएसबी डिवाइस से ऑडियो कैप्चर कर सकता है."</string>
@@ -128,6 +131,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"चेहरे की पुष्टि हो गई"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"पुष्टि हो गई"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"\'पुष्टि करें\' पर टैप करके पूरा करें"</string>
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"आपके चेहरे से अनलॉक किया गया. जारी रखने के लिए टैप करें."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"पुष्टि हो गई"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"पिन इस्तेमाल करें"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"पैटर्न इस्तेमाल करें"</string>
@@ -181,6 +185,7 @@
<string name="accessibility_desc_close" msgid="8293708213442107755">"बंद करें"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"कोई आवाज़ सुनाई नहीं देगी"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"सिर्फ़ अलार्म की आवाज़ सुनाई देगी"</string>
+ <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"परेशान न करें."</string>
<string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"ब्लूटूथ."</string>
<string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"ब्लूटूथ चालू है."</string>
<string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"<xliff:g id="TIME">%s</xliff:g> के लिए अलार्म सेट किया गया."</string>
@@ -205,6 +210,7 @@
<string name="dessert_case" msgid="9104973640704357717">"मिठाई का डिब्बा"</string>
<string name="start_dreams" msgid="9131802557946276718">"स्क्रीन सेवर"</string>
<string name="ethernet_label" msgid="2203544727007463351">"ईथरनेट"</string>
+ <string name="quick_settings_dnd_label" msgid="7728690179108024338">"परेशान न करें"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"ब्लूटूथ"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"कोई भी युग्मित डिवाइस उपलब्ध नहीं"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> बैटरी"</string>
@@ -348,6 +354,7 @@
<string name="notification_section_header_alerting" msgid="5581175033680477651">"सूचनाएं"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"बातचीत"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"बिना आवाज़ की सभी सूचनाएं हटाएं"</string>
+ <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"\'परेशान न करें\' सुविधा के ज़रिए कुछ समय के लिए सूचनाएं दिखाना रोक दिया गया है"</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"अभी शुरू करें"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"कोई सूचना नहीं है"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"इस डिवाइस का प्रबंधन आपके अभिभावक करते हैं"</string>
@@ -452,8 +459,8 @@
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"इस्तेमाल करने के लिए, डिवाइस अनलॉक करें"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"आपके कार्ड की जानकारी पाने में कोई समस्या हुई है. कृपया बाद में कोशिश करें"</string>
<string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"लॉक स्क्रीन की सेटिंग"</string>
- <string name="qr_code_scanner_title" msgid="5660820608548306581">"क्यूआर कोड"</string>
- <string name="qr_code_scanner_description" msgid="7937603775306661863">"स्कैन करने के लिए टैप करें"</string>
+ <!-- no translation found for qr_code_scanner_title (5290201053875420785) -->
+ <skip />
<string name="status_bar_work" msgid="5238641949837091056">"वर्क प्रोफ़ाइल"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"हवाई जहाज़ मोड"</string>
<string name="zen_alarm_warning" msgid="7844303238486849503">"आपको <xliff:g id="WHEN">%1$s</xliff:g> पर अपना अगला अलार्म नहीं सुनाई देगा"</string>
@@ -491,6 +498,8 @@
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"&lt;b&gt;स्थिति:&lt;/b&gt; रैंकिंग में नीचे किया गया"</string>
<string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"यह कई तरीकों से दिखती है, जैसे कि लॉक स्क्रीन पर प्रोफ़ाइल फ़ोटो के तौर पर और बातचीत वाली सूचनाओं में सबसे ऊपर"</string>
<string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"यह कई तरीकों से दिखती है, जैसे कि बातचीत वाली सूचनाओं में सबसे ऊपर, बबल के तौर पर, और लॉक स्क्रीन पर प्रोफ़ाइल फ़ोटो के तौर पर"</string>
+ <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"यह कई तरीकों से दिखती है, जैसे कि लॉक स्क्रीन पर प्रोफ़ाइल फ़ोटो के तौर पर और बातचीत वाली सूचनाओं में सबसे ऊपर. साथ ही, इसकी वजह से, \'परेशान न करें\' सुविधा में भी रुकावट आती है"</string>
+ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"यह कई तरीकों से दिखती है, जैसे कि बातचीत वाली सूचनाओं में सबसे ऊपर, बबल के तौर पर, और लॉक स्क्रीन पर प्रोफ़ाइल फ़ोटो के तौर पर. साथ ही, इसकी वजह से, \'परेशान न करें\' सुविधा में भी रुकावट आती है"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"प्राथमिकता"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> पर बातचीत की सुविधाएं काम नहीं करतीं"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"ये सूचनाएं नहीं बदली जा सकती हैं."</string>
@@ -566,6 +575,7 @@
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"मैसेज (एसएमएस) करें"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"संगीत"</string>
<string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Calendar"</string>
+ <string name="volume_and_do_not_disturb" msgid="502044092739382832">"परेशान न करें"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"वॉल्यूम बटन का शॉर्टकट"</string>
<string name="battery" msgid="769686279459897127">"बैटरी"</string>
<string name="headset" msgid="4485892374984466437">"हेडसेट"</string>
@@ -684,6 +694,10 @@
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"वाई-फ़ाई बंद है"</string>
<string name="bt_is_off" msgid="7436344904889461591">"ब्लूटूथ बंद है"</string>
+ <string name="dnd_is_off" msgid="3185706903793094463">"परेशान न करें बंद है"</string>
+ <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"एक ऑटोमैटिक नियम (<xliff:g id="ID_1">%s</xliff:g>) ने परेशान न करें को चालू कर दिया था."</string>
+ <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"एक ऐप्लिकेशन (<xliff:g id="ID_1">%s</xliff:g>) ने परेशान न करें को चालू कर दिया था."</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"एक ऑटोमैटिक नियम या ऐप्लिकेशन ने परेशान न करें को चालू कर दिया था."</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"बैकग्राउंड में चल रहे ऐप्लिकेशन"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"बैटरी और डेटा खर्च की जानकारी के लिए छूएं"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"मोबाइल डेटा बंद करना चाहते हैं?"</string>
@@ -708,6 +722,8 @@
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(ऑफ़िस)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"फ़ोन कॉल"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(<xliff:g id="APPLICATION_NAME_S_">%s</xliff:g> की मदद से)"</string>
+ <string name="ongoing_privacy_dialog_attribution_label" msgid="3385241594101496292">"(<xliff:g id="ATTRIBUTION_LABEL">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_proxy_label" msgid="1111829599659403249">"(<xliff:g id="ATTRIBUTION_LABEL">%1$s</xliff:g> • <xliff:g id="PROXY_LABEL">%2$s</xliff:g>)"</string>
<string name="privacy_type_camera" msgid="7974051382167078332">"कैमरा"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"जगह"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"माइक्रोफ़ोन"</string>
@@ -806,6 +822,9 @@
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(डिसकनेक्ट हो गया)"</string>
<string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"स्विच नहीं किया जा सकता. फिर से कोशिश करने के लिए टैप करें."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"नया डिवाइस जोड़ें"</string>
+ <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"इस सेशन को कास्ट करने के लिए, कृपया ऐप्लिकेशन खोलें."</string>
+ <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"अनजान ऐप्लिकेशन"</string>
+ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"कास्टिंग करना रोकें"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"बिल्ड नंबर"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"बिल्ड नंबर को क्लिपबोर्ड पर कॉपी किया गया."</string>
<string name="basic_status" msgid="2315371112182658176">"ऐसी बातचीत जिसमें इंटरैक्शन डेटा मौजूद नहीं है"</string>
@@ -839,6 +858,7 @@
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"हाल के मैसेज, मिस्ड कॉल, और स्टेटस अपडेट देखें"</string>
<string name="people_tile_title" msgid="6589377493334871272">"बातचीत"</string>
+ <string name="paused_by_dnd" msgid="7856941866433556428">"\'परेशान न करें\' की वजह से सूचनाएं नहीं दिख रहीं"</string>
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> ने एक मैसेज भेजा है: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> ने एक इमेज भेजी है"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> ने स्टेटस अपडेट किया है: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
@@ -877,8 +897,7 @@
<item quantity="one"><xliff:g id="COUNT_1">%s</xliff:g> ऐप्लिकेशन चालू है</item>
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> ऐप्लिकेशन चालू हैं</item>
</plurals>
- <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
- <skip />
+ <string name="fgs_dot_content_description" msgid="2865071539464777240">"नई जानकारी"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"ये ऐप्लिकेशन चालू हैं"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"बंद करें"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"रुका हुआ है"</string>
@@ -886,14 +905,15 @@
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"कॉपी किया गया"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"<xliff:g id="APPNAME">%1$s</xliff:g> से"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"कॉपी किया गया यूज़र इंटरफ़ेस (यूआई) खारिज करें"</string>
- <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
- <skip />
- <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
- <skip />
- <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
- <skip />
- <!-- no translation found for add (81036585205287996) -->
- <skip />
- <!-- no translation found for manage_users (1823875311934643849) -->
- <skip />
+ <string name="clipboard_edit_text_description" msgid="805254383912962103">"कॉपी किए गए टेक्स्ट में बदलाव करें"</string>
+ <string name="clipboard_edit_image_description" msgid="8904857948976041306">"कॉपी की गई इमेज में बदलाव करें"</string>
+ <string name="clipboard_send_nearby_description" msgid="4629769637846717650">"कॉन्टेंट को आस-पास मौजूद डिवाइस पर भेजें"</string>
+ <string name="add" msgid="81036585205287996">"जोड़ें"</string>
+ <string name="manage_users" msgid="1823875311934643849">"उपयोगकर्ताओं को मैनेज करें"</string>
+ <string name="drag_split_not_supported" msgid="4326847447699729722">"इस सूचना को स्प्लिट स्क्रीन मोड में, खींचा और छोड़ा नहीं जा सकता."</string>
+ <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"वाई-फ़ाई उपलब्ध नहीं है"</string>
+ <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"प्राथमिकता मोड"</string>
+ <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"अलार्म सेट किया गया"</string>
+ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"कैमरा और माइक बंद हैं"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# सूचना}one{# सूचना}other{# सूचनाएं}}"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index da84b86547d1..77cf81422a41 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -20,14 +20,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4811759950673118541">"UI sustava"</string>
- <string name="battery_low_title" msgid="6891106956328275225">"Baterija bi se uskoro mogla isprazniti"</string>
+ <string name="battery_low_title" msgid="5319680173344341779">"Želite li uključiti štednju baterije?"</string>
+ <string name="battery_low_description" msgid="3282977755476423966">"Imate još <xliff:g id="PERCENTAGE">%s</xliff:g> baterije. Štednja baterije uključuje tamnu temu, ograničava aktivnosti u pozadini i odgađa obavijesti."</string>
+ <string name="battery_low_intro" msgid="5148725009653088790">"Štednja baterije uključuje tamnu temu, ograničava aktivnosti u pozadini i odgađa obavijesti."</string>
<string name="battery_low_percent_format" msgid="4276661262843170964">"Preostalo <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="invalid_charger_title" msgid="938685362320735167">"Punjenje putem USB-a nije moguće"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"Koristite punjač koji ste dobili s uređajem"</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Uključiti Štednju baterije?"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"O Štednji baterije"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Uključi"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"Uključite Štednju baterije"</string>
+ <string name="battery_saver_start_action" msgid="8353766979886287140">"Uključi"</string>
+ <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Ne, hvala"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Automatski zakreni zaslon"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"Želite li dopustiti aplikaciji <xliff:g id="APPLICATION">%1$s</xliff:g> pristup uređaju <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
<string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Želite li dopustiti aplikaciji <xliff:g id="APPLICATION">%1$s</xliff:g> da pristupa uređaju <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nTa aplikacija nema dopuštenje za snimanje, no mogla bi primati zvuk putem tog USB uređaja."</string>
@@ -128,6 +131,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Lice je autentificirano"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Potvrđeno"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Dodirnite Potvrdi za dovršetak"</string>
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Otključano vašim licem. Pritisnite da biste nastavili."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Autentičnost provjerena"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Koristite PIN"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Koristite uzorak"</string>
@@ -181,6 +185,7 @@
<string name="accessibility_desc_close" msgid="8293708213442107755">"Zatvaranje"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"potpuna tišina"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"samo alarmi"</string>
+ <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"Ne uznemiravaj."</string>
<string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"Bluetooth."</string>
<string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"Bluetooth uključen."</string>
<string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"Vrijeme alarma: <xliff:g id="TIME">%s</xliff:g>."</string>
@@ -206,6 +211,7 @@
<string name="dessert_case" msgid="9104973640704357717">"Izlog za slastice"</string>
<string name="start_dreams" msgid="9131802557946276718">"Čuvar zaslona"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
+ <string name="quick_settings_dnd_label" msgid="7728690179108024338">"Ne uznemiravaj"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Upareni uređaji nisu dostupni"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> baterije"</string>
@@ -351,6 +357,7 @@
<string name="notification_section_header_alerting" msgid="5581175033680477651">"Obavijesti"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Razgovori"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Izbriši sve bešumne obavijesti"</string>
+ <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Značajka Ne uznemiravaj pauzirala je Obavijesti"</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"Započni"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Nema obavijesti"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Ovim uređajem upravlja tvoj roditelj"</string>
@@ -455,8 +462,7 @@
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Otključajte da biste koristili"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Pojavio se problem prilikom dohvaćanja kartica, pokušajte ponovo kasnije"</string>
<string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Postavke zaključanog zaslona"</string>
- <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR kôd"</string>
- <string name="qr_code_scanner_description" msgid="7937603775306661863">"Dodirnite za skeniranje"</string>
+ <string name="qr_code_scanner_title" msgid="5290201053875420785">"Skeniraj QR kôd"</string>
<string name="status_bar_work" msgid="5238641949837091056">"Poslovni profil"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Način rada u zrakoplovu"</string>
<string name="zen_alarm_warning" msgid="7844303238486849503">"Nećete čuti sljedeći alarm <xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -494,6 +500,8 @@
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"&lt;b&gt;Status:&lt;/b&gt; niže rangirana"</string>
<string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"Prikazuje se pri vrhu obavijesti razgovora i kao profilna slika na zaključanom zaslonu"</string>
<string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"Prikazuje se pri vrhu obavijesti razgovora i kao profilna slika na zaključanom zaslonu, izgleda kao oblačić"</string>
+ <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"Prikazuje se pri vrhu obavijesti razgovora i kao profilna slika na zaključanom zaslonu, prekida Ne uznemiravaj"</string>
+ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Prikazuje se pri vrhu obavijesti razgovora i kao profilna slika na zaključanom zaslonu, izgleda kao oblačić, prekida Ne uznemiravaj"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritetno"</string>
<string name="no_shortcut" msgid="8257177117568230126">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> ne podržava značajke razgovora"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Te se obavijesti ne mogu izmijeniti."</string>
@@ -571,6 +579,7 @@
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"SMS"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"Glazba"</string>
<string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Kalendar"</string>
+ <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Ne uznemiravaj"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"Prečac tipki za glasnoću"</string>
<string name="battery" msgid="769686279459897127">"Baterija"</string>
<string name="headset" msgid="4485892374984466437">"Slušalice"</string>
@@ -689,6 +698,10 @@
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"Wi-Fi je isključen"</string>
<string name="bt_is_off" msgid="7436344904889461591">"Bluetooth je isključen"</string>
+ <string name="dnd_is_off" msgid="3185706903793094463">"Način Ne uznemiravaj isključen"</string>
+ <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"Način Ne uznemiravaj uključilo je automatsko pravilo (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"Način Ne uznemiravaj uključila je aplikacija (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"Način Ne uznemiravaj uključilo je automatsko pravilo ili aplikacija."</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"Izvođenje aplikacija u pozadini"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"Dodirnite da biste vidjeli pojedinosti o potrošnji baterije i podatkovnom prometu"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Isključiti mobilne podatke?"</string>
@@ -713,6 +726,8 @@
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(posao)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"Telefonski poziv"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(putem apl. <xliff:g id="APPLICATION_NAME_S_">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_label" msgid="3385241594101496292">"(<xliff:g id="ATTRIBUTION_LABEL">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_proxy_label" msgid="1111829599659403249">"(<xliff:g id="ATTRIBUTION_LABEL">%1$s</xliff:g> • <xliff:g id="PROXY_LABEL">%2$s</xliff:g>)"</string>
<string name="privacy_type_camera" msgid="7974051382167078332">"fotoaparat"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"lokaciju"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofon"</string>
@@ -812,6 +827,9 @@
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(nije povezano)"</string>
<string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Nije prebačeno. Dodirnite da biste pokušali ponovo."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Uparite novi uređaj"</string>
+ <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Da biste emitirali ovu sesiju, otvorite aplikaciju."</string>
+ <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Nepoznata aplikacija"</string>
+ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Zaustavi emitiranje"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Broj međuverzije"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Broj međuverzije kopiran je u međuspremnik."</string>
<string name="basic_status" msgid="2315371112182658176">"Otvoreni razgovor"</string>
@@ -845,6 +863,7 @@
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Pogledajte nedavne poruke, propuštene pozive i ažuriranja statusa"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Razgovor"</string>
+ <string name="paused_by_dnd" msgid="7856941866433556428">"Pauzirala značajka Ne uznemiravaj"</string>
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> šalje poruku: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"Korisnik <xliff:g id="NAME">%1$s</xliff:g> poslao je sliku"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> ima ažuriranje statusa: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
@@ -884,8 +903,7 @@
<item quantity="few"><xliff:g id="COUNT_1">%s</xliff:g> aktivne aplikacije</item>
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> aktivnih aplikacija</item>
</plurals>
- <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
- <skip />
+ <string name="fgs_dot_content_description" msgid="2865071539464777240">"Nove informacije"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Aktivne aplikacije"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Zaustavi"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Zaustavljeno"</string>
@@ -893,14 +911,15 @@
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Kopirano"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Iz aplikacije <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Odbaci kopiranje korisničkog sučelja"</string>
- <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
- <skip />
- <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
- <skip />
- <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
- <skip />
- <!-- no translation found for add (81036585205287996) -->
- <skip />
- <!-- no translation found for manage_users (1823875311934643849) -->
- <skip />
+ <string name="clipboard_edit_text_description" msgid="805254383912962103">"Uredi kopirani tekst"</string>
+ <string name="clipboard_edit_image_description" msgid="8904857948976041306">"Uredi kopiranu sliku"</string>
+ <string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Pošalji uređaju u blizini"</string>
+ <string name="add" msgid="81036585205287996">"Dodaj"</string>
+ <string name="manage_users" msgid="1823875311934643849">"Upravljanje korisnicima"</string>
+ <string name="drag_split_not_supported" msgid="4326847447699729722">"Ova obavijest ne podržava povlačenje na podijeljeni zaslon."</string>
+ <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi nije dostupan"</string>
+ <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Prioritetni način rada"</string>
+ <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarm je postavljen"</string>
+ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Fotoaparat i mikrofon su isključeni"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# obavijest}one{# obavijest}few{# obavijesti}other{# obavijesti}}"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 30a5be844385..f256bc14b63f 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -20,14 +20,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4811759950673118541">"Rendszer UI"</string>
- <string name="battery_low_title" msgid="6891106956328275225">"Az akkumulátor hamarosan lemerül"</string>
+ <string name="battery_low_title" msgid="5319680173344341779">"Bekapcsolja az Akkumulátorkímélő módot?"</string>
+ <string name="battery_low_description" msgid="3282977755476423966">"Az akkumulátor töltöttségi szintje <xliff:g id="PERCENTAGE">%s</xliff:g>. Az Akkumulátorkímélő mód bekapcsolja a Sötét témát, korlátozza a háttérbeli tevékenységeket, és késlelteti az értesítéseket."</string>
+ <string name="battery_low_intro" msgid="5148725009653088790">"Az Akkumulátorkímélő mód bekapcsolja a Sötét témát, korlátozza a háttérbeli tevékenységeket, és késlelteti az értesítéseket."</string>
<string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> maradt"</string>
<string name="invalid_charger_title" msgid="938685362320735167">"Nem tölthető USB-n keresztül"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"Használja az eszközhöz kapott eredeti töltőt"</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Bekapcsolja az Akkumulátorkímélő módot?"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Az Akkumulátorkímélő módról"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Bekapcsolás"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"Akkumulátorkímélő mód bekapcsolása"</string>
+ <string name="battery_saver_start_action" msgid="8353766979886287140">"Bekapcsolás"</string>
+ <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Most nem"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Képernyő automatikus forgatása"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"Engedélyezi a(z) <xliff:g id="APPLICATION">%1$s</xliff:g> számára, hogy hozzáférjen a következőhöz: <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
<string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Lehetővé teszi a(z) <xliff:g id="APPLICATION">%1$s</xliff:g> alkalmazásnak, hogy hozzáférjen a következőhöz: <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nEz az alkalmazás nem rendelkezik rögzítési engedéllyel, de ezzel az USB-eszközzel képes a hangfelvételre."</string>
@@ -128,6 +131,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Arc hitelesítve"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Megerősítve"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Koppintson a Megerősítés lehetőségre"</string>
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Zárolás feloldva arccal. Nyomja meg a folytatáshoz."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Hitelesítve"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"PIN-kód használata"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Minta használata"</string>
@@ -181,6 +185,7 @@
<string name="accessibility_desc_close" msgid="8293708213442107755">"Bezárás"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"teljes némítás"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"csak ébresztések"</string>
+ <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"Ne zavarjanak."</string>
<string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"Bluetooth"</string>
<string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"Bluetooth bekapcsolva."</string>
<string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"Ébresztés időpontja: <xliff:g id="TIME">%s</xliff:g>."</string>
@@ -205,6 +210,7 @@
<string name="dessert_case" msgid="9104973640704357717">"Dessert Case"</string>
<string name="start_dreams" msgid="9131802557946276718">"Képernyővédő"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
+ <string name="quick_settings_dnd_label" msgid="7728690179108024338">"Ne zavarjanak"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Nem áll rendelkezésre párosított eszköz"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Akkumulátor: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
@@ -348,6 +354,7 @@
<string name="notification_section_header_alerting" msgid="5581175033680477651">"Értesítések"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Beszélgetések"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Az összes néma értesítés törlése"</string>
+ <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Ne zavarjanak funkcióval szüneteltetett értesítések"</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"Indítás most"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Nincs értesítés"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Az eszközt a szülőd felügyeli"</string>
@@ -452,8 +459,7 @@
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Oldja fel a használathoz"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Probléma merült fel a kártyák lekérésekor, próbálja újra később"</string>
<string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Lezárási képernyő beállításai"</string>
- <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR-kód"</string>
- <string name="qr_code_scanner_description" msgid="7937603775306661863">"Koppintson a beolvasáshoz"</string>
+ <string name="qr_code_scanner_title" msgid="5290201053875420785">"QR-kód beolvasása"</string>
<string name="status_bar_work" msgid="5238641949837091056">"Munkahelyi profil"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Repülős üzemmód"</string>
<string name="zen_alarm_warning" msgid="7844303238486849503">"Nem fogja hallani az ébresztést ekkor: <xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -491,6 +497,8 @@
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"&lt;b&gt;Állapot:&lt;/b&gt; hátrébb sorolva"</string>
<string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"A beszélgetésekre vonatkozó értesítések tetején látható, és megjeleníti a profilképet a lezárási képernyőn"</string>
<string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"A beszélgetésekre vonatkozó értesítések tetején, lebegő buborékként látható, és megjeleníti a profilképet a lezárási képernyőn"</string>
+ <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"A beszélgetésekre vonatkozó értesítések tetején látható, megjeleníti a profilképet a lezárási képernyőn, és megszakítja a Ne zavarjanak funkciót"</string>
+ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"A beszélgetésekre vonatkozó értesítések tetején, lebegő buborékként látható, megjeleníti a profilképet a lezárási képernyőn, és megszakítja a Ne zavarjanak funkciót"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritás"</string>
<string name="no_shortcut" msgid="8257177117568230126">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> nem támogatja a beszélgetési funkciókat"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Ezeket az értesítéseket nem lehet módosítani."</string>
@@ -566,6 +574,7 @@
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"SMS-üzenetek"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"Zene"</string>
<string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Naptár"</string>
+ <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Ne zavarjanak"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"A hangerőgombok gyorsbillentyűk"</string>
<string name="battery" msgid="769686279459897127">"Akkumulátor"</string>
<string name="headset" msgid="4485892374984466437">"Headset"</string>
@@ -684,6 +693,10 @@
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"A Wi-Fi ki van kapcsolva"</string>
<string name="bt_is_off" msgid="7436344904889461591">"A Bluetooth ki van kapcsolva"</string>
+ <string name="dnd_is_off" msgid="3185706903793094463">"A „Ne zavarjanak” mód ki van kapcsolva"</string>
+ <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"Az egyik automatikus szabály (<xliff:g id="ID_1">%s</xliff:g>) bekapcsolta a „Ne zavarjanak” módot."</string>
+ <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"Az egyik alkalmazás (<xliff:g id="ID_1">%s</xliff:g>) bekapcsolta a „Ne zavarjanak” módot."</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"Az egyik alkalmazás vagy automatikus szabály bekapcsolta a „Ne zavarjanak” módot."</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"A háttérben még futnak alkalmazások"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"Koppintson az akkumulátor- és adathasználat részleteinek megtekintéséhez"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Kikapcsolja a mobiladatokat?"</string>
@@ -708,6 +721,8 @@
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(munkahely)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"Telefonhívás"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(a következőn keresztül: <xliff:g id="APPLICATION_NAME_S_">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_label" msgid="3385241594101496292">"(<xliff:g id="ATTRIBUTION_LABEL">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_proxy_label" msgid="1111829599659403249">"(<xliff:g id="ATTRIBUTION_LABEL">%1$s</xliff:g> • <xliff:g id="PROXY_LABEL">%2$s</xliff:g>)"</string>
<string name="privacy_type_camera" msgid="7974051382167078332">"kamera"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"helyadatok"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofon"</string>
@@ -806,6 +821,9 @@
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(leválasztva)"</string>
<string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"A váltás nem sikerült. Próbálja újra."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Új eszköz párosítása"</string>
+ <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"A munkamenet átküldéséhez nyissa meg az alkalmazást."</string>
+ <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Ismeretlen alkalmazás"</string>
+ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Átküldés leállítása"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Buildszám"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Buildszám a vágólapra másolva."</string>
<string name="basic_status" msgid="2315371112182658176">"Beszélgetés megnyitása"</string>
@@ -839,6 +857,7 @@
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Megtekintheti a legutóbbi üzeneteket, a nem fogadott hívásokat és az állapotfrissítéseket."</string>
<string name="people_tile_title" msgid="6589377493334871272">"Beszélgetés"</string>
+ <string name="paused_by_dnd" msgid="7856941866433556428">"A Ne zavarjanak mód által szüneteltetve"</string>
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> üzenetet küldött: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> képet küldött"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> frissítette állapotát: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
@@ -877,8 +896,7 @@
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> aktív alkalmazás</item>
<item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> aktív alkalmazás</item>
</plurals>
- <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
- <skip />
+ <string name="fgs_dot_content_description" msgid="2865071539464777240">"Új információ"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Aktív alkalmazások"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Leállítás"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Leállítva"</string>
@@ -889,8 +907,12 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Vágólapra másolt szöveg szerkesztése"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Vágólapra másolt kép szerkesztése"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Küldés közeli eszközre"</string>
- <!-- no translation found for add (81036585205287996) -->
- <skip />
- <!-- no translation found for manage_users (1823875311934643849) -->
- <skip />
+ <string name="add" msgid="81036585205287996">"Hozzáadás"</string>
+ <string name="manage_users" msgid="1823875311934643849">"Felhasználók kezelése"</string>
+ <string name="drag_split_not_supported" msgid="4326847447699729722">"Az értesítés nem támogatja a megosztott képernyőre való áthúzást."</string>
+ <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"A Wi‑Fi nem áll rendelkezésre"</string>
+ <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Prioritás mód"</string>
+ <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Ébresztő beállítva"</string>
+ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"A kamera és a mikrofon ki vannak kapcsolva"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# értesítés}other{# értesítés}}"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index 443da54eaf3d..a4e3b82b264b 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -20,14 +20,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4811759950673118541">"Համակարգի ինտերֆեյս"</string>
- <string name="battery_low_title" msgid="6891106956328275225">"Մարտկոցի լիցքը շուտով կարող է սպառվել"</string>
+ <string name="battery_low_title" msgid="5319680173344341779">"Միացնե՞լ մարտկոցի տնտեսման ռեժիմը"</string>
+ <string name="battery_low_description" msgid="3282977755476423966">"Մարտկոցի լիցքը՝ <xliff:g id="PERCENTAGE">%s</xliff:g>։ Մարտկոցի տնտեսման ռեժիմում միացվում է մուգ թեման, աշխատանքը ֆոնային ռեժիմում սահմանափակվում է, իսկ ծանուցումները՝ հետաձգվում։"</string>
+ <string name="battery_low_intro" msgid="5148725009653088790">"Մարտկոցի տնտեսման ռեժիմում միացվում է մուգ թեման, աշխատանքը ֆոնային ռեժիմում սահմանափակվում է, իսկ ծանուցումները՝ հետաձգվում։"</string>
<string name="battery_low_percent_format" msgid="4276661262843170964">"Մնաց <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="invalid_charger_title" msgid="938685362320735167">"Սարքը հնարավոր չէ լիցքավորել USB-ի միջոցով"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"Օգտագործեք սարքի լիցքավորիչը"</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Միացնե՞լ մարտկոցի տնտեսումը"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Մարտկոցի տնտեսման ռեժիմի մասին"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Միացնել"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"Միացնել մարտկոցի տնտեսումը"</string>
+ <string name="battery_saver_start_action" msgid="8353766979886287140">"Միացնել"</string>
+ <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Ոչ, շնորհակալություն"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Ինքնապտտվող էկրան"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"Թույլատրե՞լ <xliff:g id="APPLICATION">%1$s</xliff:g> հավելվածին օգտագործել <xliff:g id="USB_DEVICE">%2$s</xliff:g> լրասարքը։"</string>
<string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Թույլատրե՞լ <xliff:g id="APPLICATION">%1$s</xliff:g> հավելվածին օգտագործել <xliff:g id="USB_DEVICE">%2$s</xliff:g>ը։\nՀավելվածը ձայնագրելու թույլտվություն չունի, սակայն կկարողանա գրանցել ձայնն այս USB սարքի միջոցով։"</string>
@@ -128,6 +131,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Դեմքը ճանաչվեց"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Հաստատվեց"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Ավարտելու համար հպեք «Հաստատել»"</string>
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Ապակողպվեց դեմքով։ Սեղմեք՝ շարունակելու համար։"</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Նույնականացված է"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Օգտագործել PIN կոդ"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Օգտագործել նախշ"</string>
@@ -181,6 +185,7 @@
<string name="accessibility_desc_close" msgid="8293708213442107755">"Փակել"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"կատարյալ լռություն"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"միայն զարթուցիչը"</string>
+ <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"Չանհանգստացնել։"</string>
<string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"Bluetooth:"</string>
<string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"Bluetooth-ը միացված է:"</string>
<string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"Զարթուցիչը դրված է <xliff:g id="TIME">%s</xliff:g>-ին:"</string>
@@ -205,6 +210,7 @@
<string name="dessert_case" msgid="9104973640704357717">"Dessert Case"</string>
<string name="start_dreams" msgid="9131802557946276718">"Էկրանապահ"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
+ <string name="quick_settings_dnd_label" msgid="7728690179108024338">"Չանհանգստացնել"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Զուգակցված սարքեր չկան"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Մարտկոցի լիցքը՝ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
@@ -348,6 +354,7 @@
<string name="notification_section_header_alerting" msgid="5581175033680477651">"Ծանուցումներ"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Զրույցներ"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Ջնջել բոլոր անձայն ծանուցումները"</string>
+ <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Ծանուցումները չեն ցուցադրվի «Չանհանգստացնել» ռեժիմում"</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"Սկսել հիմա"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Ծանուցումներ չկան"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Այս սարքը կառավարում է ձեր ծնողը"</string>
@@ -452,8 +459,8 @@
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Ապակողպել՝ օգտագործելու համար"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Չհաջողվեց բեռնել քարտերը։ Նորից փորձեք։"</string>
<string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Կողպէկրանի կարգավորումներ"</string>
- <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR կոդ"</string>
- <string name="qr_code_scanner_description" msgid="7937603775306661863">"Հպեք՝ սկանավորելու համար"</string>
+ <!-- no translation found for qr_code_scanner_title (5290201053875420785) -->
+ <skip />
<string name="status_bar_work" msgid="5238641949837091056">"Android for Work-ի պրոֆիլ"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Ավիառեժիմ"</string>
<string name="zen_alarm_warning" msgid="7844303238486849503">"Ժամը <xliff:g id="WHEN">%1$s</xliff:g>-ի զարթուցիչը չի զանգի"</string>
@@ -491,6 +498,8 @@
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"&lt;b&gt;Կարգավիճակը․&lt;/b&gt; կարևորության մակարդակն իջեցվել է"</string>
<string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"Ցուցադրվում է զրույցների ծանուցումների վերևում, ինչպես նաև կողպէկրանին որպես պրոֆիլի նկար"</string>
<string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"Ցուցադրվում է զրույցների ծանուցումների վերևում, ինչպես նաև կողպէկրանին որպես պրոֆիլի նկար, հայտնվում է ամպիկի տեսքով"</string>
+ <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"Ցուցադրվում է զրույցների ծանուցումների վերևում, ինչպես նաև կողպէկրանին որպես պրոֆիլի նկար, ընդհատում է «Չանհանգստացնել» ռեժիմը"</string>
+ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Ցուցադրվում է զրույցների ծանուցումների վերևում, ինչպես նաև կողպէկրանին որպես պրոֆիլի նկար, հայտնվում է ամպիկի տեսքով, ընդհատում է «Չանհանգստացնել» ռեժիմը"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Կարևոր"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածը զրույցի գործառույթներ չի աջակցում"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Այս ծանուցումները չեն կարող փոփոխվել:"</string>
@@ -566,6 +575,7 @@
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"SMS"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"Երաժշտություն"</string>
<string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Օրացույց"</string>
+ <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Չանհանգստացնել"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"Ձայնի կոճակների դյուրանցում"</string>
<string name="battery" msgid="769686279459897127">"Մարտկոց"</string>
<string name="headset" msgid="4485892374984466437">"Ականջակալ"</string>
@@ -684,6 +694,10 @@
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"Wi-Fi-ն անջատված է"</string>
<string name="bt_is_off" msgid="7436344904889461591">"Bluetooth-ն անջատված է"</string>
+ <string name="dnd_is_off" msgid="3185706903793094463">"Չանհանգստացնելու ռեժիմն անջատված է"</string>
+ <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"Չանհանգստացնել գործառույթը միացված է ավտոմատ կանոնի կողմից (<xliff:g id="ID_1">%s</xliff:g>):"</string>
+ <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"Չանհանգստացնել գործառույթը միացված է հավելվածի կողմից (<xliff:g id="ID_1">%s</xliff:g>):"</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"Չանհանգստացնել գործառույթը միացված է ավտոմատ կանոնի կամ հավելվածի կողմից:"</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"Ֆոնային ռեժիմում աշխատող հավելվածներ"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"Հպեք՝ մարտկոցի և թրաֆիկի մանրամասները տեսնելու համար"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Անջատե՞լ բջջային ինտերնետը"</string>
@@ -708,6 +722,8 @@
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(աշխատանքային)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"Հեռախոսազանգ"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(հետևյալ հավելված(ներ)ի միջոցով՝ <xliff:g id="APPLICATION_NAME_S_">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_label" msgid="3385241594101496292">"(<xliff:g id="ATTRIBUTION_LABEL">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_proxy_label" msgid="1111829599659403249">"(<xliff:g id="ATTRIBUTION_LABEL">%1$s</xliff:g> • <xliff:g id="PROXY_LABEL">%2$s</xliff:g>)"</string>
<string name="privacy_type_camera" msgid="7974051382167078332">"տեսախցիկը"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"վայրը"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"խոսափողը"</string>
@@ -806,6 +822,9 @@
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(անջատված է)"</string>
<string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Սխալ առաջացավ։ Հպեք՝ կրկնելու համար։"</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Նոր սարքի զուգակցում"</string>
+ <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Այս աշխատաշրջանը հեռարձակելու համար բացեք հավելվածը"</string>
+ <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Անհայտ հավելված"</string>
+ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Դադարեցնել հեռարձակումը"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Կառուցման համարը"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Կառուցման համարը պատճենվեց սեղմատախտակին։"</string>
<string name="basic_status" msgid="2315371112182658176">"Բաց զրույց"</string>
@@ -839,6 +858,7 @@
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Տեսեք վերջին հաղորդագրությունները, բաց թողնված զանգերը և կարգավիճակի մասին թարմացումները"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Զրույց"</string>
+ <string name="paused_by_dnd" msgid="7856941866433556428">"Դադարեցվել է «Չանհանգստացնել» գործառույթի կողմից"</string>
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> օգտատերը հաղորդագրություն է ուղարկել. «<xliff:g id="NOTIFICATION">%2$s</xliff:g>»"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> օգտատերը պատկեր է ուղարկել"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> օգտատերը նոր կարգավիճակ է հրապարակել. «<xliff:g id="STATUS">%2$s</xliff:g>»"</string>
@@ -877,8 +897,7 @@
<item quantity="one"><xliff:g id="COUNT_1">%s</xliff:g> ակտիվ հավելված</item>
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> ակտիվ հավելված</item>
</plurals>
- <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
- <skip />
+ <string name="fgs_dot_content_description" msgid="2865071539464777240">"Նոր տեղեկություն"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Ակտիվ հավելվածներ"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Դադարեցնել"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Կանգնեցված է"</string>
@@ -886,14 +905,15 @@
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Պատճենվեց"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"<xliff:g id="APPNAME">%1$s</xliff:g> հավելվածից"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Փակել պատճենների միջերեսը"</string>
- <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
- <skip />
- <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
- <skip />
- <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
- <skip />
- <!-- no translation found for add (81036585205287996) -->
- <skip />
- <!-- no translation found for manage_users (1823875311934643849) -->
- <skip />
+ <string name="clipboard_edit_text_description" msgid="805254383912962103">"Փոփոխել պատճենված տեքստը"</string>
+ <string name="clipboard_edit_image_description" msgid="8904857948976041306">"Փոփոխել պատճենված պատկերը"</string>
+ <string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Ուղարկել մոտակա սարքի"</string>
+ <string name="add" msgid="81036585205287996">"Ավելացնել"</string>
+ <string name="manage_users" msgid="1823875311934643849">"Օգտատերերի կառավարում"</string>
+ <string name="drag_split_not_supported" msgid="4326847447699729722">"Այս ծանուցումը հնարավոր չէ քաշել տրոհված էկրանի մեկ հատվածից մյուսը։"</string>
+ <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi-ը հասանելի չէ"</string>
+ <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Առաջնահերթության ռեժիմ"</string>
+ <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Զարթուցիչը դրված է"</string>
+ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Տեսախցիկը և խոսափողն անջատված են"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# ծանուցում}one{# ծանուցում}other{# ծանուցում}}"</string>
</resources>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index c7339c70eb71..c9ce287484ab 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -20,14 +20,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4811759950673118541">"UI Sistem"</string>
- <string name="battery_low_title" msgid="6891106956328275225">"Baterai mungkin akan segera habis"</string>
+ <string name="battery_low_title" msgid="5319680173344341779">"Aktifkan Penghemat Baterai?"</string>
+ <string name="battery_low_description" msgid="3282977755476423966">"Daya baterai tersisa <xliff:g id="PERCENTAGE">%s</xliff:g>. Penghemat Baterai akan mengaktifkan Tema gelap, membatasi aktivitas latar belakang, dan menunda notifikasi."</string>
+ <string name="battery_low_intro" msgid="5148725009653088790">"Penghemat Baterai akan mengaktifkan Tema gelap, membatasi aktivitas latar belakang, dan menunda notifikasi."</string>
<string name="battery_low_percent_format" msgid="4276661262843170964">"Tersisa <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="invalid_charger_title" msgid="938685362320735167">"Tidak dapat mengisi daya melalui USB"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"Gunakan pengisi daya yang disertakan dengan perangkat"</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Aktifkan Penghemat Baterai?"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Tentang Penghemat Baterai"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Aktifkan"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"Aktifkan Penghemat Baterai"</string>
+ <string name="battery_saver_start_action" msgid="8353766979886287140">"Aktifkan"</string>
+ <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Lain kali"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Putar layar otomatis"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"Izinkan <xliff:g id="APPLICATION">%1$s</xliff:g> mengakses <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
<string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Izinkan <xliff:g id="APPLICATION">%1$s</xliff:g> mengakses <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nAplikasi ini belum diberi izin merekam, tetapi dapat merekam audio melalui perangkat USB ini."</string>
@@ -128,6 +131,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Wajah diautentikasi"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Dikonfirmasi"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Ketuk Konfirmasi untuk menyelesaikan"</string>
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Kunci dibuka dengan wajah Anda. Tekan untuk melanjutkan."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Diautentikasi"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Gunakan PIN"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Gunakan pola"</string>
@@ -181,6 +185,7 @@
<string name="accessibility_desc_close" msgid="8293708213442107755">"Tutup"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"senyap total"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"hanya alarm"</string>
+ <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"Jangan Ganggu."</string>
<string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"Bluetooth."</string>
<string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"Bluetooth aktif."</string>
<string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"Alarm disetel ke <xliff:g id="TIME">%s</xliff:g>."</string>
@@ -205,6 +210,7 @@
<string name="dessert_case" msgid="9104973640704357717">"Etalase Hidangan Penutup"</string>
<string name="start_dreams" msgid="9131802557946276718">"Screen saver"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
+ <string name="quick_settings_dnd_label" msgid="7728690179108024338">"Jangan Ganggu"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Perangkat yang disandingkan tak tersedia"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Baterai <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
@@ -348,6 +354,7 @@
<string name="notification_section_header_alerting" msgid="5581175033680477651">"Notifikasi"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Percakapan"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Hapus semua notifikasi senyap"</string>
+ <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Notifikasi dijeda oleh mode Jangan Ganggu"</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"Mulai sekarang"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Tidak ada notifikasi"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Perangkat ini dikelola oleh orang tuamu"</string>
@@ -452,8 +459,8 @@
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Buka kunci untuk menggunakan"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Terjadi masalah saat mendapatkan kartu Anda, coba lagi nanti"</string>
<string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Setelan layar kunci"</string>
- <string name="qr_code_scanner_title" msgid="5660820608548306581">"Kode QR"</string>
- <string name="qr_code_scanner_description" msgid="7937603775306661863">"Ketuk untuk memindai"</string>
+ <!-- no translation found for qr_code_scanner_title (5290201053875420785) -->
+ <skip />
<string name="status_bar_work" msgid="5238641949837091056">"Profil kerja"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Mode pesawat"</string>
<string name="zen_alarm_warning" msgid="7844303238486849503">"Anda tidak akan mendengar alarm berikutnya <xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -491,6 +498,8 @@
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"&lt;b&gt;Status:&lt;/b&gt; Diberi Peringkat Lebih Rendah"</string>
<string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"Muncul di atas notifikasi percakapan dan sebagai foto profil di layar kunci"</string>
<string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"Muncul di atas notifikasi percakapan dan sebagai foto profil di layar kunci, ditampilkan sebagai balon"</string>
+ <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"Muncul di atas notifikasi percakapan dan sebagai foto profil di layar kunci, mengganggu fitur Jangan Ganggu"</string>
+ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Muncul di atas notifikasi percakapan dan sebagai foto profil di layar kunci, ditampilkan sebagai balon, mengganggu fitur Jangan Ganggu"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritas"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> tidak mendukung fitur percakapan"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Notifikasi ini tidak dapat diubah."</string>
@@ -566,6 +575,7 @@
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"SMS"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"Musik"</string>
<string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Kalender"</string>
+ <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Jangan Ganggu"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"Pintasan tombol volume"</string>
<string name="battery" msgid="769686279459897127">"Baterai"</string>
<string name="headset" msgid="4485892374984466437">"Headset"</string>
@@ -684,6 +694,10 @@
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"Wi-Fi nonaktif"</string>
<string name="bt_is_off" msgid="7436344904889461591">"Bluetooth nonaktif"</string>
+ <string name="dnd_is_off" msgid="3185706903793094463">"Fitur Jangan Ganggu nonaktif"</string>
+ <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"Mode Jangan Ganggu diaktifkan oleh aturan otomatis (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"Mode Jangan Ganggu diaktifkan oleh aplikasi (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"Mode Jangan Ganggu diaktifkan oleh aturan otomatis atau aplikasi."</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"Aplikasi yang sedang berjalan di latar belakang"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"Ketuk untuk melihat detail penggunaan baterai dan data"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Nonaktifkan data seluler?"</string>
@@ -708,6 +722,8 @@
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(kerja)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"Panggilan telepon"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(melalui <xliff:g id="APPLICATION_NAME_S_">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_label" msgid="3385241594101496292">"(<xliff:g id="ATTRIBUTION_LABEL">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_proxy_label" msgid="1111829599659403249">"(<xliff:g id="ATTRIBUTION_LABEL">%1$s</xliff:g> • <xliff:g id="PROXY_LABEL">%2$s</xliff:g>)"</string>
<string name="privacy_type_camera" msgid="7974051382167078332">"kamera"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"lokasi"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofon"</string>
@@ -806,6 +822,9 @@
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(terputus)"</string>
<string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Tidak dapat beralih. Ketuk untuk mencoba lagi."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Sambungkan perangkat baru"</string>
+ <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Buka aplikasi untuk mentransmisikan sesi ini."</string>
+ <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Aplikasi tidak dikenal"</string>
+ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Hentikan transmisi"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Nomor build"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Nomor versi disalin ke papan klip."</string>
<string name="basic_status" msgid="2315371112182658176">"Membuka percakapan"</string>
@@ -839,6 +858,7 @@
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Lihat pesan terbaru, panggilan tak terjawab, dan pembaruan status"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Percakapan"</string>
+ <string name="paused_by_dnd" msgid="7856941866433556428">"Dijeda oleh fitur Jangan Ganggu"</string>
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> mengirim pesan: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> mengirim gambar"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> memposting pembaruan status: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
@@ -877,8 +897,7 @@
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> aplikasi aktif</item>
<item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> aplikasi aktif</item>
</plurals>
- <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
- <skip />
+ <string name="fgs_dot_content_description" msgid="2865071539464777240">"Informasi baru"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Aplikasi aktif"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Berhenti"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Dihentikan"</string>
@@ -886,14 +905,15 @@
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Disalin"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Dari <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Tutup UI salin"</string>
- <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
- <skip />
- <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
- <skip />
- <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
- <skip />
- <!-- no translation found for add (81036585205287996) -->
- <skip />
- <!-- no translation found for manage_users (1823875311934643849) -->
- <skip />
+ <string name="clipboard_edit_text_description" msgid="805254383912962103">"Edit teks yang disalin"</string>
+ <string name="clipboard_edit_image_description" msgid="8904857948976041306">"Edit gambar yang disalin"</string>
+ <string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Kirim ke perangkat di sekitar"</string>
+ <string name="add" msgid="81036585205287996">"Tambahkan"</string>
+ <string name="manage_users" msgid="1823875311934643849">"Kelola pengguna"</string>
+ <string name="drag_split_not_supported" msgid="4326847447699729722">"Notifikasi ini tidak mendukung fitur tarik ke Layar terpisah."</string>
+ <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi tidak tersedia"</string>
+ <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Mode prioritas"</string>
+ <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarm disetel"</string>
+ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Kamera dan mikrofon nonaktif"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notifikasi}other{# notifikasi}}"</string>
</resources>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index eddd24648a7b..78d2ecf38a18 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -20,14 +20,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4811759950673118541">"Kerfisviðmót"</string>
- <string name="battery_low_title" msgid="6891106956328275225">"Rafhlaðan gæti tæmst bráðlega"</string>
+ <string name="battery_low_title" msgid="5319680173344341779">"Kveikja á rafhlöðusparnaði?"</string>
+ <string name="battery_low_description" msgid="3282977755476423966">"<xliff:g id="PERCENTAGE">%s</xliff:g> rafhlöðuhleðsla eftir. Rafhlöðusparnaður kveikir á dökku þema, dregur úr bakgrunnsvirkni og seinkar tilkynningum."</string>
+ <string name="battery_low_intro" msgid="5148725009653088790">"Rafhlöðusparnaður kveikir á dökku þema, dregur úr bakgrunnsvirkni og seinkar tilkynningum."</string>
<string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> eftir"</string>
<string name="invalid_charger_title" msgid="938685362320735167">"Ekki er hægt að hlaða í gegnum USB"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"Notaðu hleðslutækið sem fylgdi tækinu þínu"</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Kveikja á rafhlöðusparnaði?"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Um rafhlöðusparnað"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Kveikja"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"Kveikja á rafhlöðusparnaði"</string>
+ <string name="battery_saver_start_action" msgid="8353766979886287140">"Kveikja"</string>
+ <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Nei, takk"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Snúa skjá sjálfkrafa"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"Viltu veita <xliff:g id="APPLICATION">%1$s</xliff:g> aðgang að <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
<string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Viltu veita <xliff:g id="APPLICATION">%1$s</xliff:g> aðgang að <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nÞetta forrit hefur ekki fengið heimild fyrir upptöku en gæti tekið upp hljóð í gegnum þetta USB-tæki."</string>
@@ -128,6 +131,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Andlit staðfest"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Staðfest"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Ýttu á „Staðfesta“ til að ljúka"</string>
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Opnað með andlitinu á þér. Ýttu til að halda áfram."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Auðkennt"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Nota PIN-númer"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Nota mynstur"</string>
@@ -181,6 +185,7 @@
<string name="accessibility_desc_close" msgid="8293708213442107755">"Loka"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"algjör þögn"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"aðeins vekjarar"</string>
+ <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"Ónáðið ekki."</string>
<string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"Bluetooth."</string>
<string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"Kveikt á Bluetooth."</string>
<string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"Vekjari stilltur á <xliff:g id="TIME">%s</xliff:g>."</string>
@@ -205,6 +210,7 @@
<string name="dessert_case" msgid="9104973640704357717">"Eftirréttaborð"</string>
<string name="start_dreams" msgid="9131802557946276718">"Skjávari"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
+ <string name="quick_settings_dnd_label" msgid="7728690179108024338">"Ónáðið ekki"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Engin pöruð tæki til staðar"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> rafhlöðuhleðsla"</string>
@@ -348,6 +354,7 @@
<string name="notification_section_header_alerting" msgid="5581175033680477651">"Tilkynningar"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Samtöl"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Hreinsa allar þöglar tilkynningar"</string>
+ <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Hlé gert á tilkynningum þar sem stillt er á „Ónáðið ekki“"</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"Byrja núna"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Engar tilkynningar"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Foreldri þitt stjórnar þessu tæki"</string>
@@ -452,8 +459,8 @@
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Taktu úr lás til að nota"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Vandamál kom upp við að sækja kortin þín. Reyndu aftur síðar"</string>
<string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Stillingar fyrir læstan skjá"</string>
- <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR-kóði"</string>
- <string name="qr_code_scanner_description" msgid="7937603775306661863">"Ýttu til að skanna"</string>
+ <!-- no translation found for qr_code_scanner_title (5290201053875420785) -->
+ <skip />
<string name="status_bar_work" msgid="5238641949837091056">"Vinnusnið"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Flugstilling"</string>
<string name="zen_alarm_warning" msgid="7844303238486849503">"Ekki mun heyrast í vekjaranum <xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -491,6 +498,8 @@
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"&lt;b&gt;Staða:&lt;/b&gt; fékk lægri stöðu"</string>
<string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"Birtist efst í samtalstilkynningum og sem prófílmynd á lásskjánum"</string>
<string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"Birtist efst í samtalstilkynningum og sem prófílmynd á lásskjánum, birtist sem blaðra"</string>
+ <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"Birtist efst í samtalstilkynningum og sem prófílmynd á lásskjánum. Truflar „Ónáðið ekki“"</string>
+ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Birtist efst í samtalstilkynningum og sem prófílmynd á lásskjánum. Birtist sem blaðra sem truflar „Ónáðið ekki“"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Forgangur"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> styður ekki samtalseiginleika"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Ekki er hægt að breyta þessum tilkynningum."</string>
@@ -566,6 +575,7 @@
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"SMS-skilaboð"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"Tónlist"</string>
<string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Dagatal"</string>
+ <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Ónáðið ekki"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"Flýtihnappar fyrir hljóðstyrk"</string>
<string name="battery" msgid="769686279459897127">"Rafhlaða"</string>
<string name="headset" msgid="4485892374984466437">"Höfuðtól"</string>
@@ -684,6 +694,10 @@
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"Slökkt á Wi-Fi"</string>
<string name="bt_is_off" msgid="7436344904889461591">"Slökkt á Bluetooth"</string>
+ <string name="dnd_is_off" msgid="3185706903793094463">"Slökkt á „Ónáðið ekki“"</string>
+ <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"Sjálfvirk regla kveikti á „Ónáðið ekki“ (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"Forrit kveikti á „Ónáðið ekki“ (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"Sjálfvirk regla eða forrit kveikti á „Ónáðið ekki“"</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"Forrit sem keyra í bakgrunni"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"Ýttu til að fá upplýsingar um rafhlöðu- og gagnanotkun"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Viltu slökkva á farsímagögnum?"</string>
@@ -708,6 +722,8 @@
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(vinna)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"Símtal"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(í gegnum <xliff:g id="APPLICATION_NAME_S_">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_label" msgid="3385241594101496292">"(<xliff:g id="ATTRIBUTION_LABEL">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_proxy_label" msgid="1111829599659403249">"(<xliff:g id="ATTRIBUTION_LABEL">%1$s</xliff:g> • <xliff:g id="PROXY_LABEL">%2$s</xliff:g>)"</string>
<string name="privacy_type_camera" msgid="7974051382167078332">"myndavél"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"staðsetning"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"hljóðnemi"</string>
@@ -806,6 +822,9 @@
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(aftengt)"</string>
<string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Ekki er hægt að skipta. Ýttu til að reyna aftur."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Para nýtt tæki"</string>
+ <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Opnaðu forritið til að senda þessa lotu út."</string>
+ <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Óþekkt forrit"</string>
+ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Stöðva útsendingu"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Útgáfunúmer smíðar"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Útgáfunúmer smíðar afritað á klippiborð."</string>
<string name="basic_status" msgid="2315371112182658176">"Opna samtal"</string>
@@ -839,6 +858,7 @@
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Sjá nýleg skilboð, ósvöruð símtöl og stöðuuppfærslur"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Samtal"</string>
+ <string name="paused_by_dnd" msgid="7856941866433556428">"Sett í bið af „Ónáðið ekki“"</string>
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> sendi skilaboð: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> sendi mynd"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> er með stöðuuppfærslu: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
@@ -877,8 +897,7 @@
<item quantity="one"><xliff:g id="COUNT_1">%s</xliff:g> virkt forrit</item>
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> virk forrit</item>
</plurals>
- <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
- <skip />
+ <string name="fgs_dot_content_description" msgid="2865071539464777240">"Nýjar upplýsingar"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Virk forrit"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Stöðva"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Stöðvað"</string>
@@ -886,14 +905,15 @@
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Afritað"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Frá <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Loka afriti notendaviðmóts"</string>
- <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
- <skip />
- <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
- <skip />
- <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
- <skip />
- <!-- no translation found for add (81036585205287996) -->
- <skip />
- <!-- no translation found for manage_users (1823875311934643849) -->
- <skip />
+ <string name="clipboard_edit_text_description" msgid="805254383912962103">"Breyta afrituðum texta"</string>
+ <string name="clipboard_edit_image_description" msgid="8904857948976041306">"Breyta afritaðri mynd"</string>
+ <string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Senda í nálægt tæki"</string>
+ <string name="add" msgid="81036585205287996">"Bæta við"</string>
+ <string name="manage_users" msgid="1823875311934643849">"Stjórna notendum"</string>
+ <string name="drag_split_not_supported" msgid="4326847447699729722">"Þessi tilkynning styður ekki að draga yfir á skiptan skjá."</string>
+ <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"WiFi ekki tiltækt"</string>
+ <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Forgangsstilling"</string>
+ <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Vekjari stilltur"</string>
+ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Slökkt á myndavél og hljóðnema"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# tilkynning}one{# tilkynning}other{# tilkynningar}}"</string>
</resources>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 6a07f79e9e6f..9b0f917759d3 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -20,14 +20,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4811759950673118541">"UI sistema"</string>
- <string name="battery_low_title" msgid="6891106956328275225">"La batteria potrebbe esaurirsi a breve"</string>
+ <string name="battery_low_title" msgid="5319680173344341779">"Vuoi attivare il risparmio energetico?"</string>
+ <string name="battery_low_description" msgid="3282977755476423966">"Batteria rimanente: <xliff:g id="PERCENTAGE">%s</xliff:g>. Il risparmio energetico attiva il tema scuro, limita l\'attività in background e ritarda le notifiche."</string>
+ <string name="battery_low_intro" msgid="5148725009653088790">"Il risparmio energetico attiva il tema scuro, limita l\'attività in background e ritarda le notifiche."</string>
<string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> rimanente"</string>
<string name="invalid_charger_title" msgid="938685362320735167">"Impossibile ricaricare tramite USB"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"Utilizza il caricabatterie fornito in dotazione con il dispositivo"</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Attivare Risparmio energetico?"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Informazioni su Risparmio energetico"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Attiva"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"Attiva Risparmio energetico"</string>
+ <string name="battery_saver_start_action" msgid="8353766979886287140">"Attiva"</string>
+ <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"No, grazie"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Rotazione automatica schermo"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"Consentire a <xliff:g id="APPLICATION">%1$s</xliff:g> di accedere a <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
<string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Vuoi consentire all\'app <xliff:g id="APPLICATION">%1$s</xliff:g> di accedere a <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nA questa app non è stata concessa l\'autorizzazione di registrazione, ma l\'app potrebbe acquisire l\'audio tramite questo dispositivo USB."</string>
@@ -128,6 +131,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Volto autenticato"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Confermato"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Tocca Conferma per completare"</string>
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Dispositivo sbloccato con il volto. Premi per continuare."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Autenticazione eseguita"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Utilizza PIN"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Usa sequenza"</string>
@@ -181,6 +185,7 @@
<string name="accessibility_desc_close" msgid="8293708213442107755">"Chiudi"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"silenzio totale"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"solo sveglie"</string>
+ <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"Non disturbare."</string>
<string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"Bluetooth."</string>
<string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"Bluetooth attivo."</string>
<string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"Sveglia impostata per le <xliff:g id="TIME">%s</xliff:g>."</string>
@@ -197,14 +202,15 @@
<string name="accessibility_clear_all" msgid="970525598287244592">"Cancella tutte le notifiche."</string>
<string name="notification_group_overflow_indicator" msgid="7605120293801012648">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
<plurals name="notification_group_overflow_description" formatted="false" msgid="91483442850649192">
- <item quantity="one"><xliff:g id="NUMBER_1">%s</xliff:g> more notifications inside.</item>
<item quantity="other">Altre <xliff:g id="NUMBER_1">%s</xliff:g> notifiche nel gruppo.</item>
+ <item quantity="one"><xliff:g id="NUMBER_0">%s</xliff:g> altra notifica nel gruppo.</item>
</plurals>
<string name="accessibility_rotation_lock_on_landscape" msgid="936972553861524360">"Lo schermo è bloccato in orientamento orizzontale."</string>
<string name="accessibility_rotation_lock_on_portrait" msgid="2356633398683813837">"Lo schermo è bloccato in orientamento verticale."</string>
<string name="dessert_case" msgid="9104973640704357717">"Vetrina di dolci"</string>
<string name="start_dreams" msgid="9131802557946276718">"Salvaschermo"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
+ <string name="quick_settings_dnd_label" msgid="7728690179108024338">"Non disturbare"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Nessun dispositivo accoppiato disponibile"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Batteria: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
@@ -246,8 +252,8 @@
<string name="quick_settings_hotspot_secondary_label_transient" msgid="7585604088079160564">"Attivazione…"</string>
<string name="quick_settings_hotspot_secondary_label_data_saver_enabled" msgid="1280433136266439372">"Risp. dati attivo"</string>
<plurals name="quick_settings_hotspot_secondary_label_num_devices" formatted="false" msgid="3142308865165871976">
- <item quantity="one">%d devices</item>
<item quantity="other">%d dispositivi</item>
+ <item quantity="one">%d dispositivo</item>
</plurals>
<string name="quick_settings_flashlight_label" msgid="4904634272006284185">"Torcia"</string>
<string name="quick_settings_flashlight_camera_in_use" msgid="4820591564526512571">"Fotocamera in uso"</string>
@@ -330,8 +336,8 @@
<string name="user_add_user_message_short" msgid="2599370307878014791">"Il nuovo utente, una volta aggiunto, deve impostare il proprio spazio.\n\nQualsiasi utente può aggiornare le app per tutti gli altri."</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"Limite di utenti raggiunto"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
- <item quantity="one">You can add up to <xliff:g id="COUNT">%d</xliff:g> users.</item>
<item quantity="other">Puoi aggiungere fino a <xliff:g id="COUNT">%d</xliff:g> utenti.</item>
+ <item quantity="one">È possibile creare un solo utente.</item>
</plurals>
<string name="user_remove_user_title" msgid="9124124694835811874">"Rimuovere l\'utente?"</string>
<string name="user_remove_user_message" msgid="6702834122128031833">"Tutte le app e i dati di questo utente verranno eliminati."</string>
@@ -348,6 +354,7 @@
<string name="notification_section_header_alerting" msgid="5581175033680477651">"Notifiche"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Conversazioni"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Cancella tutte le notifiche silenziose"</string>
+ <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Notifiche messe in pausa in base alla modalità Non disturbare"</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"Avvia adesso"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Nessuna notifica"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Questo dispositivo è gestito dai tuoi genitori"</string>
@@ -452,8 +459,7 @@
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Sblocca per usare"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Si è verificato un problema durante il recupero delle tue carte. Riprova più tardi."</string>
<string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Impostazioni schermata di blocco"</string>
- <string name="qr_code_scanner_title" msgid="5660820608548306581">"Codice QR"</string>
- <string name="qr_code_scanner_description" msgid="7937603775306661863">"Tocca per scansionare"</string>
+ <string name="qr_code_scanner_title" msgid="5290201053875420785">"Scansiona codice QR"</string>
<string name="status_bar_work" msgid="5238641949837091056">"Profilo di lavoro"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Modalità aereo"</string>
<string name="zen_alarm_warning" msgid="7844303238486849503">"Non sentirai la tua prossima sveglia <xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -491,6 +497,8 @@
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"&lt;b&gt;Stato:&lt;/b&gt; posizionata più in basso"</string>
<string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"Appare in cima alle notifiche delle conversazioni e compare come immagine del profilo nella schermata di blocco"</string>
<string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"Appare in cima alle notifiche delle conversazioni, nonché compare come immagine del profilo nella schermata di blocco e come bolla"</string>
+ <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"Appare in cima alle notifiche delle conversazioni, interrompe la modalità Non disturbare e compare come immagine del profilo nella schermata di blocco"</string>
+ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Appare in cima alle notifiche delle conversazioni, interrompe la modalità Non disturbare, nonché compare come immagine del profilo nella schermata di blocco e come bolla"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Priorità"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> non supporta le funzionalità delle conversazioni"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Impossibile modificare queste notifiche."</string>
@@ -516,12 +524,12 @@
<string name="snooze_undo" msgid="2738844148845992103">"Annulla"</string>
<string name="snoozed_for_time" msgid="7586689374860469469">"Posticipato di <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>"</string>
<plurals name="snoozeHourOptions" formatted="false" msgid="2066838694120718170">
- <item quantity="one">%d hours</item>
<item quantity="other">%d ore</item>
+ <item quantity="one">%d ora</item>
</plurals>
<plurals name="snoozeMinuteOptions" formatted="false" msgid="8998483159208055980">
- <item quantity="one">%d minutes</item>
<item quantity="other">%d minuti</item>
+ <item quantity="one">%d minuto</item>
</plurals>
<string name="battery_detail_switch_title" msgid="6940976502957380405">"Risparmio energetico"</string>
<string name="keyboard_key_button_template" msgid="8005673627272051429">"Pulsante <xliff:g id="NAME">%1$s</xliff:g>"</string>
@@ -566,6 +574,7 @@
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"SMS"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"Musica"</string>
<string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Calendario"</string>
+ <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Non disturbare"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"Pulsanti del volume come scorciatoia"</string>
<string name="battery" msgid="769686279459897127">"Batteria"</string>
<string name="headset" msgid="4485892374984466437">"Auricolare"</string>
@@ -684,6 +693,10 @@
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g> <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"Wi-Fi disattivato"</string>
<string name="bt_is_off" msgid="7436344904889461591">"Bluetooth non attivo"</string>
+ <string name="dnd_is_off" msgid="3185706903793094463">"Funzione Non disturbare disattivata"</string>
+ <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"La funzione Non disturbare è stata attivata da una regola automatica (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"La funzione Non disturbare è stata attivata da un\'app (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"La funzione Non disturbare è stata attivata da una regola automatica o da un\'app."</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"App in esecuzione in background"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"Tocca per conoscere i dettagli sull\'utilizzo dei dati e della batteria"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Disattivare i dati mobili?"</string>
@@ -708,6 +721,8 @@
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(lavoro)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"Telefonata"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(tramite <xliff:g id="APPLICATION_NAME_S_">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_label" msgid="3385241594101496292">"(<xliff:g id="ATTRIBUTION_LABEL">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_proxy_label" msgid="1111829599659403249">"(<xliff:g id="ATTRIBUTION_LABEL">%1$s</xliff:g> • <xliff:g id="PROXY_LABEL">%2$s</xliff:g>)"</string>
<string name="privacy_type_camera" msgid="7974051382167078332">"fotocamera"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"posizione"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"microfono"</string>
@@ -737,8 +752,8 @@
<string name="quick_controls_title" msgid="6839108006171302273">"Controllo dispositivi"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Scegli un\'app per aggiungere controlli"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
- <item quantity="one"><xliff:g id="NUMBER_1">%s</xliff:g> controlli aggiunti.</item>
<item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> controlli aggiunti.</item>
+ <item quantity="one"><xliff:g id="NUMBER_0">%s</xliff:g> controllo aggiunto.</item>
</plurals>
<string name="controls_removed" msgid="3731789252222856959">"Rimosso"</string>
<string name="accessibility_control_favorite" msgid="8694362691985545985">"Aggiunto ai preferiti"</string>
@@ -806,6 +821,9 @@
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(disconnesso)"</string>
<string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Non puoi cambiare. Tocca per riprovare."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Accoppia nuovo dispositivo"</string>
+ <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Per trasmettere questa sessione devi aprire l\'app."</string>
+ <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"App sconosciuta"</string>
+ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Interrompi trasmissione"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Numero build"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Numero build copiato negli appunti."</string>
<string name="basic_status" msgid="2315371112182658176">"Apri conversazione"</string>
@@ -839,6 +857,7 @@
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"+<xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Visualizza messaggi recenti, chiamate senza risposta e aggiornamenti dello stato"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Conversazione"</string>
+ <string name="paused_by_dnd" msgid="7856941866433556428">"In pausa in base alla modalità Non disturbare"</string>
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> ha inviato un messaggio: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> ha inviato un\'immagine"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> ha aggiornato lo stato: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
@@ -874,25 +893,26 @@
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Non aggiungerlo"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Seleziona utente"</string>
<plurals name="fgs_manager_footer_label" formatted="false" msgid="9091110396713032871">
- <item quantity="one"><xliff:g id="COUNT_1">%s</xliff:g> app attiva</item>
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> app attive</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> app attiva</item>
</plurals>
- <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
- <skip />
+ <string name="fgs_dot_content_description" msgid="2865071539464777240">"Nuove informazioni"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"App attive"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Interrompi"</string>
- <!-- no translation found for fgs_manager_app_item_stop_button_stopped_label (6950382004441263922) -->
- <skip />
+ <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Interrotta"</string>
<string name="clipboard_edit_text_copy" msgid="770856373439969178">"Copia"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Copiato"</string>
- <!-- no translation found for clipboard_edit_source (9156488177277788029) -->
- <skip />
+ <string name="clipboard_edit_source" msgid="9156488177277788029">"Da <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Ignora copia UI"</string>
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Modifica testo copiato"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Modifica immagine copiata"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Invia a dispositivo nelle vicinanze"</string>
- <!-- no translation found for add (81036585205287996) -->
- <skip />
- <!-- no translation found for manage_users (1823875311934643849) -->
- <skip />
+ <string name="add" msgid="81036585205287996">"Aggiungi"</string>
+ <string name="manage_users" msgid="1823875311934643849">"Gestisci utenti"</string>
+ <string name="drag_split_not_supported" msgid="4326847447699729722">"Non è possibile trascinare questa notifica tra le due parti dello schermo diviso."</string>
+ <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi non disponibile"</string>
+ <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Modalità Priorità"</string>
+ <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Sveglia impostata"</string>
+ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Fotocamera e microfono non attivi"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notifica}other{# notifiche}}"</string>
</resources>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index f959774c81ef..7dcde9cf4f5c 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -20,14 +20,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4811759950673118541">"ממשק משתמש של המערכת"</string>
- <string name="battery_low_title" msgid="6891106956328275225">"ייתכן שהסוללה תתרוקן בקרוב"</string>
+ <string name="battery_low_title" msgid="5319680173344341779">"להפעיל את התכונה \'חיסכון בסוללה\'?"</string>
+ <string name="battery_low_description" msgid="3282977755476423966">"אחוז הטעינה של הסוללה: <xliff:g id="PERCENTAGE">%s</xliff:g>. התכונה \'חיסכון בסוללה\' מפעילה עיצוב כהה, מגבילה את הפעילת ברקע ומשהה את ההתראות."</string>
+ <string name="battery_low_intro" msgid="5148725009653088790">"התכונה \'חיסכון בסוללה\' מפעילה עיצוב כהה, מגבילה את הפעילת ברקע ומשהה את ההתראות."</string>
<string name="battery_low_percent_format" msgid="4276661262843170964">"נותרו <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="invalid_charger_title" msgid="938685362320735167">"‏לא ניתן לטעון באמצעות USB"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"שימוש במטען שסופק עם המכשיר"</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"להפעיל את תכונת החיסכון בסוללה?"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"מידע על מצב \'חיסכון בסוללה\'"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"הפעלה"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"הפעלת תכונת החיסכון בסוללה"</string>
+ <string name="battery_saver_start_action" msgid="8353766979886287140">"הפעלה"</string>
+ <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"לא תודה"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"סיבוב אוטומטי של המסך"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"לתת לאפליקציה <xliff:g id="APPLICATION">%1$s</xliff:g> גישה אל <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
<string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"‏האם לאפשר לאפליקציה <xliff:g id="APPLICATION">%1$s</xliff:g> גישה אל <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nאפליקציה זו לא קיבלה הרשאה להקליט אך יכולה לתעד אודיו באמצעות מכשיר USB זה."</string>
@@ -128,6 +131,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"זיהוי הפנים בוצע"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"יש אישור"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"יש להקיש על \'אישור\' לסיום התהליך"</string>
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"הנעילה בוטלה עם זיהוי הפנים שלך. יש ללחוץ כדי להמשיך."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"מאומת"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"שימוש בקוד אימות"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"שימוש בקו ביטול נעילה"</string>
@@ -181,6 +185,7 @@
<string name="accessibility_desc_close" msgid="8293708213442107755">"סגירה"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"השתקה מוחלטת"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"רק התראות"</string>
+ <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"נא לא להפריע."</string>
<string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"Bluetooth."</string>
<string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"‏Bluetooth מופעל."</string>
<string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"ההתראה נקבעה ל-<xliff:g id="TIME">%s</xliff:g>."</string>
@@ -207,6 +212,7 @@
<string name="dessert_case" msgid="9104973640704357717">"מזנון קינוחים"</string>
<string name="start_dreams" msgid="9131802557946276718">"שומר מסך"</string>
<string name="ethernet_label" msgid="2203544727007463351">"אתרנט"</string>
+ <string name="quick_settings_dnd_label" msgid="7728690179108024338">"נא לא להפריע"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"אין מכשירים מותאמים זמינים"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> סוללה"</string>
@@ -354,6 +360,7 @@
<string name="notification_section_header_alerting" msgid="5581175033680477651">"התראות"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"שיחות"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"ניקוי כל ההתראות השקטות"</string>
+ <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"התראות הושהו על ידי מצב \'נא לא להפריע\'"</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"כן, אפשר להתחיל"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"אין התראות"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"המכשיר הזה מנוהל על ידי ההורה שלך"</string>
@@ -458,8 +465,8 @@
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"יש לבטל את הנעילה כדי להשתמש"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"הייתה בעיה בקבלת הכרטיסים שלך. כדאי לנסות שוב מאוחר יותר"</string>
<string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"הגדרות מסך הנעילה"</string>
- <string name="qr_code_scanner_title" msgid="5660820608548306581">"‏קוד QR"</string>
- <string name="qr_code_scanner_description" msgid="7937603775306661863">"צריך להקיש כדי לסרוק"</string>
+ <!-- no translation found for qr_code_scanner_title (5290201053875420785) -->
+ <skip />
<string name="status_bar_work" msgid="5238641949837091056">"פרופיל עבודה"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"מצב טיסה"</string>
<string name="zen_alarm_warning" msgid="7844303238486849503">"לא ניתן יהיה לשמוע את ההתראה הבאה שלך <xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -497,6 +504,8 @@
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"‏&lt;b&gt;הסטטוס:&lt;/b&gt; דורג נמוך יותר"</string>
<string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"מוצגת בחלק העליון של קטע ההתראות וכתמונת פרופיל במסך הנעילה"</string>
<string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"מוצגת בחלק העליון של קטע התראות השיחה וכתמונת פרופיל במסך הנעילה, מופיעה בבועה"</string>
+ <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"מוצגת בחלק העליון של קטע התראות השיחה וכתמונת פרופיל במסך הנעילה, מפריעה במצב \'נא לא להפריע\'"</string>
+ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"מוצגת בחלק העליון של קטע התראות השיחה וכתמונת פרופיל במסך הנעילה, מופיעה בבועה צפה ומפריעה במצב \'נא לא להפריע\'"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"בעדיפות גבוהה"</string>
<string name="no_shortcut" msgid="8257177117568230126">"האפליקציה <xliff:g id="APP_NAME">%1$s</xliff:g> לא תומכת בתכונות השיחה"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"לא ניתן לשנות את ההתראות האלה."</string>
@@ -576,6 +585,7 @@
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"SMS"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"מוזיקה"</string>
<string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"יומן"</string>
+ <string name="volume_and_do_not_disturb" msgid="502044092739382832">"נא לא להפריע"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"קיצור דרך ללחצני עוצמת קול"</string>
<string name="battery" msgid="769686279459897127">"סוללה"</string>
<string name="headset" msgid="4485892374984466437">"אוזניות"</string>
@@ -694,6 +704,10 @@
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"‏Wi-Fi כבוי"</string>
<string name="bt_is_off" msgid="7436344904889461591">"‏Bluetooth כבוי"</string>
+ <string name="dnd_is_off" msgid="3185706903793094463">"מצב \'נא לא להפריע\' כבוי"</string>
+ <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"מצב \'נא לא להפריע\' הופעל על ידי כלל אוטומטי (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"מצב \'נא לא להפריע\' הופעל על ידי אפליקציה (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"מצב \'נא לא להפריע\' הופעל על ידי אפליקציה או על ידי כלל אוטומטי."</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"אפליקציות שפועלות ברקע"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"אפשר להקיש לקבלת פרטים על צריכה של נתונים וסוללה"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"לכבות את חבילת הגלישה?"</string>
@@ -718,6 +732,8 @@
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(עבודה)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"שיחת טלפון"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(באמצעות <xliff:g id="APPLICATION_NAME_S_">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_label" msgid="3385241594101496292">"(<xliff:g id="ATTRIBUTION_LABEL">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_proxy_label" msgid="1111829599659403249">"(<xliff:g id="ATTRIBUTION_LABEL">%1$s</xliff:g> • <xliff:g id="PROXY_LABEL">%2$s</xliff:g>)"</string>
<string name="privacy_type_camera" msgid="7974051382167078332">"מצלמה"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"מיקום"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"מיקרופון"</string>
@@ -818,6 +834,9 @@
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(מנותק)"</string>
<string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"לא ניתן להחליף. צריך להקיש כדי לנסות שוב."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"התאמה של מכשיר חדש"</string>
+ <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"‏כדי להעביר (cast) את הסשן הזה, צריך לפתוח את האפליקציה."</string>
+ <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"אפליקציה לא ידועה"</string>
+ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"‏עצירת ההעברה (casting)"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"‏מספר Build"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"‏מספר ה-Build הועתק ללוח."</string>
<string name="basic_status" msgid="2315371112182658176">"פתיחת שיחה"</string>
@@ -851,6 +870,7 @@
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"ההודעות האחרונות, שיחות שלא נענו ועדכוני סטטוס"</string>
<string name="people_tile_title" msgid="6589377493334871272">"שיחה"</string>
+ <string name="paused_by_dnd" msgid="7856941866433556428">"ההתראה הושהתה על ידי \'נא לא להפריע\'"</string>
<string name="new_notification_text_content_description" msgid="2915029960094389291">"התקבלה הודעה מ<xliff:g id="NAME">%1$s</xliff:g>: ‏<xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> שלח/ה תמונה"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"הסטטוס של <xliff:g id="NAME">%1$s</xliff:g> עודכן: ‏<xliff:g id="STATUS">%2$s</xliff:g>"</string>
@@ -891,8 +911,7 @@
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> אפליקציות פעילות</item>
<item quantity="one">אפליקציה פעילה אחת (<xliff:g id="COUNT_0">%s</xliff:g>)</item>
</plurals>
- <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
- <skip />
+ <string name="fgs_dot_content_description" msgid="2865071539464777240">"מידע חדש"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"אפליקציות פעילות"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"עצירה"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"הופסקה"</string>
@@ -900,14 +919,15 @@
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"הועתק"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"המקור: <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"ביטול של העתקת ממשק המשתמש"</string>
- <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
- <skip />
- <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
- <skip />
- <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
- <skip />
- <!-- no translation found for add (81036585205287996) -->
- <skip />
- <!-- no translation found for manage_users (1823875311934643849) -->
- <skip />
+ <string name="clipboard_edit_text_description" msgid="805254383912962103">"עריכת הטקסט שהועתק"</string>
+ <string name="clipboard_edit_image_description" msgid="8904857948976041306">"עריכת התמונה שהועתקה"</string>
+ <string name="clipboard_send_nearby_description" msgid="4629769637846717650">"שליחה למכשיר בקרבת מקום"</string>
+ <string name="add" msgid="81036585205287996">"הוספה"</string>
+ <string name="manage_users" msgid="1823875311934643849">"ניהול משתמשים"</string>
+ <string name="drag_split_not_supported" msgid="4326847447699729722">"ההתראה הזו לא תומכת בגרירה למסך מפוצל."</string>
+ <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"‏Wi‑Fi לא זמין"</string>
+ <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"מצב עדיפות"</string>
+ <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"ההתראה מוגדרת"</string>
+ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"המצלמה והמיקרופון כבויים"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{התראה אחת}two{# התראות}many{# התראות}other{# התראות}}"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 05ddace4a496..956826bb5e37 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -20,14 +20,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4811759950673118541">"システム UI"</string>
- <string name="battery_low_title" msgid="6891106956328275225">"もうすぐ電池がなくなります"</string>
+ <string name="battery_low_title" msgid="5319680173344341779">"バッテリー セーバーを ON にしますか?"</string>
+ <string name="battery_low_description" msgid="3282977755476423966">"バッテリー残量は <xliff:g id="PERCENTAGE">%s</xliff:g> です。バッテリー セーバーを有効にすると、ダークモードが ON になります。また、バックグラウンド アクティビティが制限され、通知が届くのが遅くなります。"</string>
+ <string name="battery_low_intro" msgid="5148725009653088790">"バッテリー セーバーを有効にすると、ダークモードが ON になります。また、バックグラウンド アクティビティが制限され、通知が届くのが遅くなります。"</string>
<string name="battery_low_percent_format" msgid="4276661262843170964">"残量が<xliff:g id="PERCENTAGE">%s</xliff:g>です"</string>
<string name="invalid_charger_title" msgid="938685362320735167">"USB 経由では充電できません"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"デバイスに付属の充電器を使用してください"</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"バッテリー セーバーを ON にしますか?"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"バッテリー セーバーについて"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"ONにする"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"バッテリー セーバーを ON"</string>
+ <string name="battery_saver_start_action" msgid="8353766979886287140">"ON にする"</string>
+ <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"いいえ"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"自動回転画面"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"<xliff:g id="APPLICATION">%1$s</xliff:g> に <xliff:g id="USB_DEVICE">%2$s</xliff:g> へのアクセスを許可しますか?"</string>
<string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"<xliff:g id="APPLICATION">%1$s</xliff:g> に <xliff:g id="USB_DEVICE">%2$s</xliff:g>へのアクセスを許可しますか?\nこのアプリに録音権限は付与されていませんが、アクセスを許可すると、この USB デバイスから音声を収集できるようになります。"</string>
@@ -128,6 +131,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"顔を認証しました"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"確認しました"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"完了するには [確認] をタップしてください"</string>
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"顔認識でロックを解除しました。押して続行してください。"</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"認証済み"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"PIN を使用"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"パターンを使用"</string>
@@ -181,6 +185,7 @@
<string name="accessibility_desc_close" msgid="8293708213442107755">"閉じる"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"サイレント"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"アラームのみ"</string>
+ <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"サイレント モード。"</string>
<string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"Bluetooth"</string>
<string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"BluetoothがONです。"</string>
<string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"アラームは<xliff:g id="TIME">%s</xliff:g>に設定されています。"</string>
@@ -205,6 +210,7 @@
<string name="dessert_case" msgid="9104973640704357717">"デザートケース"</string>
<string name="start_dreams" msgid="9131802557946276718">"スクリーン セーバー"</string>
<string name="ethernet_label" msgid="2203544727007463351">"イーサネット"</string>
+ <string name="quick_settings_dnd_label" msgid="7728690179108024338">"サイレント モード"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"ペア設定されたデバイスがありません"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"バッテリー <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
@@ -348,6 +354,7 @@
<string name="notification_section_header_alerting" msgid="5581175033680477651">"通知"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"会話"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"サイレント通知がすべて消去されます"</string>
+ <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"サイレント モードにより通知は一時停止中です"</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"今すぐ開始"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"通知はありません"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"このデバイスは保護者によって管理されています"</string>
@@ -452,8 +459,7 @@
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"ロックを解除して使用"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"カードの取得中に問題が発生しました。しばらくしてからもう一度お試しください"</string>
<string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"ロック画面の設定"</string>
- <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR コード"</string>
- <string name="qr_code_scanner_description" msgid="7937603775306661863">"タップしてスキャンします"</string>
+ <string name="qr_code_scanner_title" msgid="5290201053875420785">"QR コードのスキャン"</string>
<string name="status_bar_work" msgid="5238641949837091056">"仕事用プロファイル"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"機内モード"</string>
<string name="zen_alarm_warning" msgid="7844303238486849503">"次回のアラーム(<xliff:g id="WHEN">%1$s</xliff:g>)は鳴りません"</string>
@@ -491,6 +497,8 @@
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"&lt;b&gt;ステータス:&lt;/b&gt; ランクが下がりました"</string>
<string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"会話通知の一番上に表示されると同時に、ロック画面にプロフィール写真として表示されます"</string>
<string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"会話通知の一番上に表示されると同時に、ロック画面にプロフィール写真として表示されるほか、バブルとして表示されます"</string>
+ <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"会話通知の一番上に表示されると同時に、ロック画面にプロフィール写真として表示され、サイレント モードが中断されます"</string>
+ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"会話通知の一番上に表示されると同時に、ロック画面にプロフィール写真として表示されるほか、バブルとして表示され、サイレント モードが中断されます"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"優先"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g>は会話機能に対応していません"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"これらの通知は変更できません。"</string>
@@ -566,6 +574,7 @@
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"SMS"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"音楽"</string>
<string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"カレンダー"</string>
+ <string name="volume_and_do_not_disturb" msgid="502044092739382832">"サイレント モード"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"音量ボタンのショートカット"</string>
<string name="battery" msgid="769686279459897127">"バッテリー"</string>
<string name="headset" msgid="4485892374984466437">"ヘッドセット"</string>
@@ -684,6 +693,10 @@
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>、<xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"Wi-Fi は OFF です"</string>
<string name="bt_is_off" msgid="7436344904889461591">"Bluetooth は OFF です"</string>
+ <string name="dnd_is_off" msgid="3185706903793094463">"サイレント モードは OFF です"</string>
+ <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"サイレント モードが自動ルール(<xliff:g id="ID_1">%s</xliff:g>)によって ON になりました。"</string>
+ <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"サイレント モードがアプリ(<xliff:g id="ID_1">%s</xliff:g>)によって ON になりました。"</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"サイレント モードが自動ルールまたはアプリによって ON になりました。"</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"バックグラウンドで実行中のアプリ"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"タップしてバッテリーやデータの使用量を確認"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"モバイルデータを OFF にしますか?"</string>
@@ -708,6 +721,8 @@
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(業務用)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"通話"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(<xliff:g id="APPLICATION_NAME_S_">%s</xliff:g> 経由)"</string>
+ <string name="ongoing_privacy_dialog_attribution_label" msgid="3385241594101496292">"(<xliff:g id="ATTRIBUTION_LABEL">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_proxy_label" msgid="1111829599659403249">"(<xliff:g id="ATTRIBUTION_LABEL">%1$s</xliff:g> • <xliff:g id="PROXY_LABEL">%2$s</xliff:g>)"</string>
<string name="privacy_type_camera" msgid="7974051382167078332">"カメラ"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"現在地情報"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"マイク"</string>
@@ -806,6 +821,9 @@
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(接続解除済み)"</string>
<string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"切り替えられません。タップしてやり直してください。"</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"新しいデバイスとのペア設定"</string>
+ <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"このセッションをキャストするには、アプリを開いてください。"</string>
+ <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"不明なアプリ"</string>
+ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"キャストを停止"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"ビルド番号"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"ビルド番号をクリップボードにコピーしました。"</string>
<string name="basic_status" msgid="2315371112182658176">"空の会話"</string>
@@ -839,6 +857,7 @@
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g> 件以上"</string>
<string name="people_tile_description" msgid="8154966188085545556">"最近のメッセージ、不在着信、最新のステータスが表示されます"</string>
<string name="people_tile_title" msgid="6589377493334871272">"会話"</string>
+ <string name="paused_by_dnd" msgid="7856941866433556428">"サイレント モードにより一時停止"</string>
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> さんからのメッセージ: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> さんが画像を送信しました"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> さんの近況: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
@@ -877,8 +896,7 @@
<item quantity="other">有効なアプリ: <xliff:g id="COUNT_1">%s</xliff:g> 個</item>
<item quantity="one">有効なアプリ: <xliff:g id="COUNT_0">%s</xliff:g> 個</item>
</plurals>
- <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
- <skip />
+ <string name="fgs_dot_content_description" msgid="2865071539464777240">"最新情報"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"有効なアプリ"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"停止"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"停止中"</string>
@@ -889,8 +907,12 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"コピーしたテキストを編集"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"コピーした画像を編集"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"付近のデバイスに送信"</string>
- <!-- no translation found for add (81036585205287996) -->
- <skip />
- <!-- no translation found for manage_users (1823875311934643849) -->
- <skip />
+ <string name="add" msgid="81036585205287996">"追加"</string>
+ <string name="manage_users" msgid="1823875311934643849">"ユーザーの管理"</string>
+ <string name="drag_split_not_supported" msgid="4326847447699729722">"この通知は、分割画面へのドラッグがサポートされていません。"</string>
+ <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi-Fi を利用できません"</string>
+ <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"優先順位モード"</string>
+ <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"アラームを設定しました"</string>
+ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"カメラとマイクが OFF です"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# 件の通知}other{# 件の通知}}"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index cf77cacaaa3d..7ecdfd93b2c4 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -20,14 +20,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4811759950673118541">"სისტემის UI"</string>
- <string name="battery_low_title" msgid="6891106956328275225">"ბატარეა შესაძლოა მალე ამოიწუროს"</string>
+ <string name="battery_low_title" msgid="5319680173344341779">"გსურთ ბატარეის დამზოგის ჩართვა?"</string>
+ <string name="battery_low_description" msgid="3282977755476423966">"თქვენი ბატარეა დატენილია <xliff:g id="PERCENTAGE">%s</xliff:g>-ზე. ბატარეის დამზოგი ჩართავს მუქ თემას, შეზღუდავს აქტივობას ფონურ რეჟიმში და შეტყობინებების მიღება შეფერხდება."</string>
+ <string name="battery_low_intro" msgid="5148725009653088790">"ბატარეის დამზოგი ჩართავს მუქ თემას, შეზღუდავს აქტივობას ფონურ რეჟიმში და შეტყობინებების მიღება შეფერხდება."</string>
<string name="battery_low_percent_format" msgid="4276661262843170964">"დარჩენილია <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="invalid_charger_title" msgid="938685362320735167">"USB-თ დატენვა ვერ ხერხდება"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"გამოიყენეთ დამტენი, რომელიც თქვენს მოწყობილობას მოჰყვა"</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"გსურთ ბატარეის დამზოგის ჩართვა?"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"ბატარეის დამზოგის შესახებ"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"ჩართვა"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"ბატარეის დამზოგის ჩართვა"</string>
+ <string name="battery_saver_start_action" msgid="8353766979886287140">"ჩართვა"</string>
+ <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"არა, გმადლობთ"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"ეკრანის ავტოროტაცია"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"მიეცეს <xliff:g id="APPLICATION">%1$s</xliff:g>-ს <xliff:g id="USB_DEVICE">%2$s</xliff:g>-ზე წვდომის უფლება?"</string>
<string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"დართავთ <xliff:g id="APPLICATION">%1$s</xliff:g>-ს <xliff:g id="USB_DEVICE">%2$s</xliff:g>-ზე წვდომის ნებას?\nამ აპს არ აქვს მინიჭებული ჩაწერის ნებართვა, მაგრამ შეუძლია ჩაიწეროს აუდიო ამ USB მოწყობილობის მეშვეობით."</string>
@@ -128,6 +131,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"სახის ამოცნობილია"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"დადასტურებული"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"დასასრულებლად შეეხეთ „დადასტურებას“"</string>
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"განბლოკილია თქვენი სახით. დააჭირეთ გასაგრძელებლად."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"ავტორიზებულია"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"PIN-კოდის გამოყენება"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"ნიმუშის გამოყენება"</string>
@@ -181,6 +185,7 @@
<string name="accessibility_desc_close" msgid="8293708213442107755">"დახურვა"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"სრული სიჩუმე"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"მხოლოდ მაღვიძარები"</string>
+ <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"არ შემაწუხოთ."</string>
<string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"Bluetooth."</string>
<string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"Bluetooth ჩართულია."</string>
<string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"მაღვიძარა დაყენებულია: <xliff:g id="TIME">%s</xliff:g>"</string>
@@ -205,6 +210,7 @@
<string name="dessert_case" msgid="9104973640704357717">"სადესერტო ყუთი"</string>
<string name="start_dreams" msgid="9131802557946276718">"ეკრანმზოგი"</string>
<string name="ethernet_label" msgid="2203544727007463351">"ეთერნეტი"</string>
+ <string name="quick_settings_dnd_label" msgid="7728690179108024338">"არ შემაწუხოთ"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"დაწყვილებული მოწყობილობები მიუწვდომელია"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> ბატარეა"</string>
@@ -348,6 +354,7 @@
<string name="notification_section_header_alerting" msgid="5581175033680477651">"შეტყობინებები"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"საუბრები"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"ყველა ჩუმი შეტყობინების გასუფთავება"</string>
+ <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"შეტყობინებები დაპაუზდა „არ შემაწუხოთ“ რეჟიმის მეშვეობით"</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"დაწყება ახლავე"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"შეტყობინებები არ არის."</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"მოწყობილობას თქვენი მშობელი მართავს"</string>
@@ -452,8 +459,8 @@
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"გამოსაყენებლად განბლოკვა"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"თქვენი ბარათების მიღებისას პრობლემა წარმოიშვა. ცადეთ ხელახლა მოგვიანებით"</string>
<string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"ჩაკეტილი ეკრანის პარამეტრები"</string>
- <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR კოდი"</string>
- <string name="qr_code_scanner_description" msgid="7937603775306661863">"შეეხეთ დასასკანირებლად"</string>
+ <!-- no translation found for qr_code_scanner_title (5290201053875420785) -->
+ <skip />
<string name="status_bar_work" msgid="5238641949837091056">"სამსახურის პროფილი"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"თვითმფრინავის რეჟიმი"</string>
<string name="zen_alarm_warning" msgid="7844303238486849503">"ვერ გაიგონებთ მომდევნო მაღვიძარას <xliff:g id="WHEN">%1$s</xliff:g>-ზე"</string>
@@ -491,6 +498,8 @@
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"&lt;b&gt;სტატუსი:&lt;/b&gt; ნაკლებად პრიორიტეტული"</string>
<string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"გამოჩნდება საუბრის შეტყობინებების თავში და პროფილის სურათის სახით ჩაკეტილ ეკრანზე"</string>
<string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"გამოჩნდება საუბრის შეტყობინებების თავში და პროფილის სურათის სახით ჩაკეტილ ეკრანზე, ჩნდება ბუშტის სახით"</string>
+ <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"გამოჩნდება საუბრის შეტყობინებების თავში და პროფილის სურათის სახით ჩაკეტილ ეკრანზე, წყვეტს ფუნქციას „არ შემაწუხოთ“"</string>
+ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"გამოჩნდება საუბრის შეტყობინებების თავში და პროფილის სურათის სახით ჩაკეტილ ეკრანზე, ჩნდება ბუშტის სახით, წყვეტს ფუნქციას „არ შემაწუხოთ“"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"პრიორიტეტი"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g>-ს არ აქვს მიმოწერის ფუნქციების მხარდაჭერა"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"ამ შეტყობინებების შეცვლა შეუძლებელია."</string>
@@ -566,6 +575,7 @@
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"SMS"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"მუსიკა"</string>
<string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"კალენდარი"</string>
+ <string name="volume_and_do_not_disturb" msgid="502044092739382832">"არ შემაწუხოთ"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"ხმის ღილაკების მალსახმობი"</string>
<string name="battery" msgid="769686279459897127">"ბატარეა"</string>
<string name="headset" msgid="4485892374984466437">"ყურსაცვამი"</string>
@@ -684,6 +694,10 @@
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"Wi-Fi გამორთულია"</string>
<string name="bt_is_off" msgid="7436344904889461591">"Bluetooth გამორთულია"</string>
+ <string name="dnd_is_off" msgid="3185706903793094463">"„არ შემაწუხოთ“ რეჟიმი გამორთულია"</string>
+ <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"„არ შემაწუხოთ“ ჩაირთო ავტომატური წესის მიხედვით (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"„არ შემაწუხოთ“ ჩაირთო აპის მიერ (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"„არ შემაწუხოთ“ ჩაირთო ავტომატური წესის მიხედვით ან აპის მიერ."</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"ფონურ რეჟიმში გაშვებული აპები"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"შეეხეთ ბატარეისა და მონაცემების მოხმარების შესახებ დეტალური ინფორმაციისთვის"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"გსურთ მობილური ინტერნეტის გამორთვა?"</string>
@@ -708,6 +722,8 @@
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(სამსახური)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"სატელეფონო ზარი"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(<xliff:g id="APPLICATION_NAME_S_">%s</xliff:g>-ის მეშვეობით)"</string>
+ <string name="ongoing_privacy_dialog_attribution_label" msgid="3385241594101496292">"(<xliff:g id="ATTRIBUTION_LABEL">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_proxy_label" msgid="1111829599659403249">"(<xliff:g id="ATTRIBUTION_LABEL">%1$s</xliff:g> • <xliff:g id="PROXY_LABEL">%2$s</xliff:g>)"</string>
<string name="privacy_type_camera" msgid="7974051382167078332">"კამერა"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"მდებარეობა"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"მიკროფონი"</string>
@@ -806,6 +822,9 @@
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(კავშირი გაწყვეტილია)"</string>
<string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"ვერ გადაირთო. შეეხეთ ხელახლა საცდელად."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"ახალი მოწყობილობის დაწყვილება"</string>
+ <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"ამ სესიის ტრანსლირებისთვის გახსენით აპი."</string>
+ <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"უცნობი აპი"</string>
+ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"ტრანსლირების შეწყვეტა"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"ანაწყობის ნომერი"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"ანაწყობის ნომერი დაკოპირებულია გაცვლის ბუფერში."</string>
<string name="basic_status" msgid="2315371112182658176">"მიმოწერის გახსნა"</string>
@@ -839,6 +858,7 @@
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"ბოლოდროინდელი შეტყობინებების, გამოტოვებული ზარების და სტატუსის განახლებების ნახვა"</string>
<string name="people_tile_title" msgid="6589377493334871272">"მიმოწერა"</string>
+ <string name="paused_by_dnd" msgid="7856941866433556428">"დაპაუზებულია ფუნქციის „არ შემაწუხოთ“ მიერ"</string>
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g>-მა გაგზავნა შეტყობინება: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g>-მ(ა) სურათი გამოგზავნა"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g>-მა განაახლა სტატუსი: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
@@ -877,8 +897,7 @@
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> აქტიური აპი</item>
<item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> აქტიური აპი</item>
</plurals>
- <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
- <skip />
+ <string name="fgs_dot_content_description" msgid="2865071539464777240">"ახალი ინფორმაცია"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"აქტიური აპები"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"შეწყვეტა"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"შეწყვეტილია"</string>
@@ -889,8 +908,12 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"კოპირებული ტექსტის რედაქტირება"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"კოპირებული სურათის რედაქტირება"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"ახლომახლო მოწყობილობაზე გაგზავნა"</string>
- <!-- no translation found for add (81036585205287996) -->
- <skip />
- <!-- no translation found for manage_users (1823875311934643849) -->
- <skip />
+ <string name="add" msgid="81036585205287996">"დამატება"</string>
+ <string name="manage_users" msgid="1823875311934643849">"მომხმარებლების მართვა"</string>
+ <string name="drag_split_not_supported" msgid="4326847447699729722">"ამ შეტყობინების გადათრევა გაყოფილ ეკრანებს შორის არ არის მხარდაჭერილი."</string>
+ <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi მიუწვდომელია"</string>
+ <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"პრიორიტეტული რეჟიმი"</string>
+ <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"მაღვიძარა დაყენებულია"</string>
+ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"კამერა და მიკროფონი გამორთულია"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# შეტყობინება}other{# შეტყობინება}}"</string>
</resources>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index 32d2e512f1a7..85283de03b1c 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -20,14 +20,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4811759950673118541">"Жүйе интерфейсі"</string>
- <string name="battery_low_title" msgid="6891106956328275225">"Батерея заряды жақын арада бітуі мүмкін"</string>
+ <string name="battery_low_title" msgid="5319680173344341779">"Батареяны үнемдеу режимі қосылсын ба?"</string>
+ <string name="battery_low_description" msgid="3282977755476423966">"<xliff:g id="PERCENTAGE">%s</xliff:g> заряд қалды. Батареяны үнемдеу режимі қараңғы тақырыпты іске қосады, фондық әрекеттерге шектеу қояды және хабарландыруларды кідіртеді."</string>
+ <string name="battery_low_intro" msgid="5148725009653088790">"Батареяны үнемдеу режимі қараңғы тақырыпты іске қосады, фондық әрекеттерге шектеу қояды және хабарландыруларды кідіртеді."</string>
<string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> қалды"</string>
<string name="invalid_charger_title" msgid="938685362320735167">"USB арқылы зарядтау мүмкін емес"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"Құрылғымен бірге берілген зарядтау құралын пайдаланыңыз"</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Батареяны үнемдеу режимін қосу керек пе?"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Батареяны үнемдеу режимі туралы ақпарат"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Қосу"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"Батареяны үнемдеу режимін қосу"</string>
+ <string name="battery_saver_start_action" msgid="8353766979886287140">"Қосу"</string>
+ <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Жоқ, рақмет"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Авто айналатын экран"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"<xliff:g id="APPLICATION">%1$s</xliff:g> қолданбасына <xliff:g id="USB_DEVICE">%2$s</xliff:g> құрылғысына кіруге рұқсат берілсін бе?"</string>
<string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"<xliff:g id="APPLICATION">%1$s</xliff:g> қолданбасына <xliff:g id="USB_DEVICE">%2$s</xliff:g> құрылғысын пайдалануға рұқсат етілсін бе?\nҚолданбаның жазу рұқсаты жоқ, бірақ осы USB құрылғысы арқылы аудио жаза алады."</string>
@@ -128,6 +131,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Бет танылды."</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Расталды"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Аяқтау үшін \"Растау\" түймесін түртіңіз."</string>
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Құлып бетіңіз арқылы ашылды. Жалғастыру үшін басыңыз."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Аутентификацияланған"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"PIN кодын пайдалану"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Өрнекті пайдалану"</string>
@@ -181,6 +185,7 @@
<string name="accessibility_desc_close" msgid="8293708213442107755">"Жабу"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"үнсіз"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"оятқыштар ғана"</string>
+ <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"Мазаламау."</string>
<string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"Bluetooth."</string>
<string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"Bluetooth қосулы."</string>
<string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"Дабыл <xliff:g id="TIME">%s</xliff:g> уақытына реттелген."</string>
@@ -205,6 +210,7 @@
<string name="dessert_case" msgid="9104973640704357717">"Десерт жағдайы"</string>
<string name="start_dreams" msgid="9131802557946276718">"Скринсейвер"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Этернет"</string>
+ <string name="quick_settings_dnd_label" msgid="7728690179108024338">"Мазаламау"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Жұптасқан құрылғылар жоқ"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Батарея деңгейі: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
@@ -348,6 +354,7 @@
<string name="notification_section_header_alerting" msgid="5581175033680477651">"Хабарландырулар"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Әңгімелер"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Барлық үнсіз хабарландыруларды өшіру"</string>
+ <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Хабарландырулар Мазаламау режимінде кідіртілді"</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"Қазір бастау"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Хабарландырулар жоқ"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Бұл құрылғыны ата-анаңыз басқарады."</string>
@@ -452,8 +459,8 @@
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Пайдалану үшін құлыпты ашу"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Карталарыңыз алынбады, кейінірек қайталап көріңіз."</string>
<string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Экран құлпының параметрлері"</string>
- <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR коды"</string>
- <string name="qr_code_scanner_description" msgid="7937603775306661863">"Сканерлеу үшін түртіңіз."</string>
+ <!-- no translation found for qr_code_scanner_title (5290201053875420785) -->
+ <skip />
<string name="status_bar_work" msgid="5238641949837091056">"Жұмыс профилі"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Ұшақ режимі"</string>
<string name="zen_alarm_warning" msgid="7844303238486849503">"Келесі <xliff:g id="WHEN">%1$s</xliff:g> дабылыңызды есітпейсіз"</string>
@@ -491,6 +498,8 @@
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"&lt;b&gt;Күйі:&lt;/b&gt; маңыздылық деңгейі төмендетілген"</string>
<string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"Әңгіме туралы хабарландырулардың жоғарғы жағында тұрады және құлыптаулы экранда профиль суреті ретінде көрсетіледі."</string>
<string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"Әңгіме туралы хабарландырулардың жоғарғы жағында тұрады және құлыптаулы экранда профиль суреті болып көрсетіледі, қалқыма хабар түрінде шығады."</string>
+ <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"Әңгіме туралы хабарландырулардың жоғарғы жағында тұрады және құлыптаулы экранда профиль суреті ретінде көрсетіледі, Мазаламау режимін тоқтатады."</string>
+ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Әңгіме туралы хабарландырулардың жоғарғы жағында тұрады және құлыптаулы экранда профиль суреті болып көрсетіледі, қалқыма хабар түрінде шығады, Мазаламау режимін тоқтатады."</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Маңызды"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> әңгіме функцияларын қолдамайды."</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Бұл хабарландыруларды өзгерту мүмкін емес."</string>
@@ -566,6 +575,7 @@
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"Мәтіндік хабар"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"Mузыка"</string>
<string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Күнтізбе"</string>
+ <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Мазаламау"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"Дыбыс деңгейі түймелерінің төте жолы"</string>
<string name="battery" msgid="769686279459897127">"Батарея"</string>
<string name="headset" msgid="4485892374984466437">"Құлақаспап жинағы"</string>
@@ -684,6 +694,10 @@
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"Wi-Fi өшірулі"</string>
<string name="bt_is_off" msgid="7436344904889461591">"Bluetooth өшірулі"</string>
+ <string name="dnd_is_off" msgid="3185706903793094463">"Мазаламау режимі өшірулі"</string>
+ <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"Мазаламау режимі (<xliff:g id="ID_1">%s</xliff:g>) автоматты ережесі арқылы қосылды."</string>
+ <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"Мазаламау режимі (<xliff:g id="ID_1">%s</xliff:g>) қолданбасы арқылы қосылды."</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"Мазаламау режимі автоматты ереже немесе қолданба арқылы қосылды."</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"Фонда жұмыс істеп тұрған қолданбалар"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"Батарея мен деректер трафигі туралы білу үшін түртіңіз"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Мобильдік деректер өшірілсін бе?"</string>
@@ -708,6 +722,8 @@
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(жұмыс)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"Телефон қоңырауы"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(<xliff:g id="APPLICATION_NAME_S_">%s</xliff:g> арқылы)"</string>
+ <string name="ongoing_privacy_dialog_attribution_label" msgid="3385241594101496292">"(<xliff:g id="ATTRIBUTION_LABEL">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_proxy_label" msgid="1111829599659403249">"(<xliff:g id="ATTRIBUTION_LABEL">%1$s</xliff:g> • <xliff:g id="PROXY_LABEL">%2$s</xliff:g>)"</string>
<string name="privacy_type_camera" msgid="7974051382167078332">"камера"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"геодерек"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"микрофон"</string>
@@ -806,6 +822,9 @@
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(ажыратулы)"</string>
<string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Ауысу мүмкін емес. Әрекетті қайталау үшін түртіңіз."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Жаңа құрылғымен жұптау"</string>
+ <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Бұл сеансты трансляциялау үшін қолданбаны ашыңыз."</string>
+ <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Белгісіз қолданба"</string>
+ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Трансляцияны тоқтату"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Құрама нөмірі"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Құрама нөмірі буферге көшірілді."</string>
<string name="basic_status" msgid="2315371112182658176">"Ашық әңгіме"</string>
@@ -839,6 +858,7 @@
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Соңғы хабарларды, өткізіп алған қоңыраулар мен жаңартылған күйлерді көруге болады."</string>
<string name="people_tile_title" msgid="6589377493334871272">"Әңгіме"</string>
+ <string name="paused_by_dnd" msgid="7856941866433556428">"Мазаламау режимі арқылы кідіртілді."</string>
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> хабар жіберді: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> сурет жіберді."</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> ағымдағы күйін жаңартты: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
@@ -877,8 +897,7 @@
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> белсенді қолданба</item>
<item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> белсенді қолданба</item>
</plurals>
- <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
- <skip />
+ <string name="fgs_dot_content_description" msgid="2865071539464777240">"Жаңа ақпарат"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Белсенді қолданбалар"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Тоқтату"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Тоқтатылған"</string>
@@ -886,14 +905,15 @@
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Көшірілді"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"<xliff:g id="APPNAME">%1$s</xliff:g> қолданбасынан"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Көшіру интерфейсін жабу"</string>
- <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
- <skip />
- <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
- <skip />
- <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
- <skip />
- <!-- no translation found for add (81036585205287996) -->
- <skip />
- <!-- no translation found for manage_users (1823875311934643849) -->
- <skip />
+ <string name="clipboard_edit_text_description" msgid="805254383912962103">"Көшірілген мәтінді өңдеу"</string>
+ <string name="clipboard_edit_image_description" msgid="8904857948976041306">"Көшірілген суретті өңдеу"</string>
+ <string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Маңайдағы құрылғыға жіберу"</string>
+ <string name="add" msgid="81036585205287996">"Қосу"</string>
+ <string name="manage_users" msgid="1823875311934643849">"Пайдаланушыларды басқару"</string>
+ <string name="drag_split_not_supported" msgid="4326847447699729722">"Бұл хабарландыруды бөлінген экранға сүйреп апару мүмкін емес."</string>
+ <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi қолжетімсіз"</string>
+ <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Басымдық режимі"</string>
+ <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Оятқыш орнатылды"</string>
+ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Камера мен микрофон өшірулі"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# хабарландыру}other{# хабарландыру}}"</string>
</resources>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index 581d3e6bc6b2..9e527e4a04c6 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -20,14 +20,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4811759950673118541">"UI ប្រព័ន្ធ"</string>
- <string name="battery_low_title" msgid="6891106956328275225">"អាចនឹងអស់ថ្មក្នុងពេលបន្តិចទៀត"</string>
+ <string name="battery_low_title" msgid="5319680173344341779">"បើក​មុខងារ​សន្សំ​ថ្មឬ?"</string>
+ <string name="battery_low_description" msgid="3282977755476423966">"អ្នក​នៅសល់ថ្ម <xliff:g id="PERCENTAGE">%s</xliff:g> ទៀត។ មុខងារសន្សំថ្មបើករចនាប័ទ្មងងឹត ដាក់កំហិតសកម្មភាពនៅផ្ទៃខាងក្រោយ និងពន្យារពេលជូនដំណឹង។"</string>
+ <string name="battery_low_intro" msgid="5148725009653088790">"មុខងារសន្សំថ្មបើករចនាប័ទ្មងងឹត ដាក់កំហិតសកម្មភាពនៅផ្ទៃខាងក្រោយ និងពន្យារពេលជូនដំណឹង។"</string>
<string name="battery_low_percent_format" msgid="4276661262843170964">"នៅ​សល់ <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="invalid_charger_title" msgid="938685362320735167">"មិន​អាច​សាក​តាម USB បានទេ"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"សូមប្រើ​ឆ្នាំង​សាក​ដែល​ភ្ជាប់​មក​ជាមួយ​ឧបករណ៍​របស់អ្នក"</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"បើក​មុខងារ​សន្សំ​ថ្ម?"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"អំពី​មុខងារ​សន្សំ​ថ្ម"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"បើក"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"បើក​មុខងារ​សន្សំ​ថ្ម"</string>
+ <string name="battery_saver_start_action" msgid="8353766979886287140">"បើក"</string>
+ <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"ទេ អរគុណ"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"បង្វិល​អេក្រង់​ស្វ័យ​ប្រវត្តិ"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"អនុញ្ញាត <xliff:g id="APPLICATION">%1$s</xliff:g> ឱ្យចូលប្រើ <xliff:g id="USB_DEVICE">%2$s</xliff:g> មែនទេ?"</string>
<string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"អនុញ្ញាតឱ្យ <xliff:g id="APPLICATION">%1$s</xliff:g> ចូលប្រើ <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nកម្មវិធីនេះ​មិនទាន់បាន​ទទួលសិទ្ធិ​ថតសំឡេងនៅឡើយទេ ប៉ុន្តែ​អាចថត​សំឡេង​តាមរយៈ​ឧបករណ៍ USB នេះបាន។"</string>
@@ -128,6 +131,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"បានផ្ទៀងផ្ទាត់​មុខ"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"បានបញ្ជាក់"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"ចុច \"បញ្ជាក់\" ដើម្បីបញ្ចប់"</string>
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"បានដោះសោ​ដោយប្រើ​មុខរបស់អ្នក។ ចុច ដើម្បីបន្ត។"</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"បាន​ផ្ទៀងផ្ទាត់"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"ប្រើកូដ PIN"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"ប្រើ​លំនាំ"</string>
@@ -181,6 +185,7 @@
<string name="accessibility_desc_close" msgid="8293708213442107755">"បិទ"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"បិទសំឡេង​ទាំងស្រុង"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"សំឡេងរោទ៍​ប៉ុណ្ណោះ"</string>
+ <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"កុំ​រំខាន។"</string>
<string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"ប៊្លូធូស"</string>
<string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"បើក​ប៊្លូធូស។"</string>
<string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"កំណត់​សំឡេង​រោទ៍​សម្រាប់ <xliff:g id="TIME">%s</xliff:g> ។"</string>
@@ -205,6 +210,7 @@
<string name="dessert_case" msgid="9104973640704357717">"ករណី Dessert"</string>
<string name="start_dreams" msgid="9131802557946276718">"ធាតុរក្សាអេក្រង់"</string>
<string name="ethernet_label" msgid="2203544727007463351">"អ៊ីសឺរណិត"</string>
+ <string name="quick_settings_dnd_label" msgid="7728690179108024338">"កុំ​រំខាន"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"ប៊្លូធូស"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"មិន​មាន​ឧបករណ៍​ផ្គូផ្គង​ដែល​អាច​ប្រើ​បាន"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"ថ្ម <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
@@ -348,6 +354,7 @@
<string name="notification_section_header_alerting" msgid="5581175033680477651">"ការជូនដំណឹង"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"ការសន្ទនា"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"សម្អាត​ការជូនដំណឹង​ស្ងាត់ទាំងអស់"</string>
+ <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"ការជូនដំណឹង​បានផ្អាក​ដោយ​មុខងារកុំរំខាន"</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"ចាប់ផ្ដើម​ឥឡូវ"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"គ្មាន​ការ​ជូនដំណឹង"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"ឧបករណ៍​នេះ​ស្ថិត​ក្រោម​ការ​គ្រប់គ្រង​របស់មាតាបិតាអ្នក"</string>
@@ -452,8 +459,8 @@
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"ដោះសោដើម្បីប្រើប្រាស់"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"មានបញ្ហា​ក្នុងការទាញយក​កាត​របស់អ្នក សូម​ព្យាយាមម្ដងទៀត​នៅពេលក្រោយ"</string>
<string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"ការកំណត់អេក្រង់ចាក់សោ"</string>
- <string name="qr_code_scanner_title" msgid="5660820608548306581">"​កូដ QR"</string>
- <string name="qr_code_scanner_description" msgid="7937603775306661863">"ចុច​ដើម្បីស្កេន"</string>
+ <!-- no translation found for qr_code_scanner_title (5290201053875420785) -->
+ <skip />
<string name="status_bar_work" msgid="5238641949837091056">"ប្រវត្តិរូបការងារ"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"ពេលជិះយន្តហោះ"</string>
<string name="zen_alarm_warning" msgid="7844303238486849503">"អ្នកនឹងមិនលឺម៉ោងរោទ៍ <xliff:g id="WHEN">%1$s</xliff:g> បន្ទាប់របស់អ្នកទេ"</string>
@@ -491,6 +498,8 @@
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"&lt;b&gt;ស្ថានភាព៖&lt;/b&gt; បានចាត់ថ្នាក់ទាបជាងមុន"</string>
<string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"បង្ហាញនៅខាងលើ​ការជូនដំណឹងអំពីការសន្ទនា និងជារូបភាព​កម្រង​ព័ត៌មាននៅលើអេក្រង់ចាក់សោ"</string>
<string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"បង្ហាញនៅខាងលើ​ការជូនដំណឹងអំពីការសន្ទនា និងជារូបភាព​កម្រង​ព័ត៌មាននៅលើអេក្រង់ចាក់សោ បង្ហាញជាពពុះ"</string>
+ <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"បង្ហាញនៅខាងលើ​ការជូនដំណឹងអំពីការសន្ទនា និងជារូបភាព​កម្រង​ព័ត៌មាននៅលើអេក្រង់ចាក់សោ បង្អាក់មុខងារកុំ​រំខាន"</string>
+ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"បង្ហាញនៅខាងលើ​ការជូនដំណឹងអំពីការសន្ទនា និងជារូបភាព​កម្រង​ព័ត៌មាននៅលើអេក្រង់ចាក់សោ បង្ហាញជាពពុះ បង្អាក់មុខងារកុំ​រំខាន"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"អាទិភាព"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> មិនអាចប្រើ​មុខងារ​សន្ទនា​បានទេ"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"មិនអាច​កែប្រែ​ការជូនដំណឹង​ទាំងនេះ​បានទេ។"</string>
@@ -566,6 +575,7 @@
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"សារ SMS"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"តន្ត្រី"</string>
<string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"ប្រតិទិន"</string>
+ <string name="volume_and_do_not_disturb" msgid="502044092739382832">"កុំ​រំខាន"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"ផ្លូវកាត់ប៊ូតុងកម្រិតសំឡេង"</string>
<string name="battery" msgid="769686279459897127">"ថ្ម"</string>
<string name="headset" msgid="4485892374984466437">"កាស"</string>
@@ -684,6 +694,10 @@
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"Wi-Fi បាន​បិទ"</string>
<string name="bt_is_off" msgid="7436344904889461591">"ប៊្លូធូស​បាន​បិទ"</string>
+ <string name="dnd_is_off" msgid="3185706903793094463">"មុខងារ​កុំរំខាន​បាន​បិទ"</string>
+ <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"មុខងារ​កុំ​រំខាន​ត្រូវបាន​បើកដោយច្បាប់​ស្វ័យ​ប្រវត្តិ (<xliff:g id="ID_1">%s</xliff:g>)។"</string>
+ <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"មុខងារ​កុំ​រំខាន​ត្រូវបាន​បើកដោយកម្មវិធី (<xliff:g id="ID_1">%s</xliff:g>)។"</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"មុខងារ​កុំ​រំខាន​ត្រូវបាន​បើកដោយច្បាប់​ស្វ័យ​ប្រវត្តិ ឬ​កម្មវិធី។"</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"កម្មវិធីដែលកំពុងដំណើរការនៅផ្ទៃខាងក្រោយ"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"ចុចដើម្បីមើលព័ត៌មានលម្អិតអំពីការប្រើប្រាស់ទិន្នន័យ និងថ្ម"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"បិទទិន្នន័យទូរសព្ទចល័ត?"</string>
@@ -708,6 +722,8 @@
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(ការងារ)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"ការហៅ​ទូរសព្ទ"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(តាមរយៈ <xliff:g id="APPLICATION_NAME_S_">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_label" msgid="3385241594101496292">"(<xliff:g id="ATTRIBUTION_LABEL">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_proxy_label" msgid="1111829599659403249">"(<xliff:g id="ATTRIBUTION_LABEL">%1$s</xliff:g> • <xliff:g id="PROXY_LABEL">%2$s</xliff:g>)"</string>
<string name="privacy_type_camera" msgid="7974051382167078332">"កាមេរ៉ា"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"ទីតាំង"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"មីក្រូហ្វូន"</string>
@@ -806,6 +822,9 @@
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(បាន​ដាច់)"</string>
<string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"មិនអាចប្ដូរបានទេ។ សូមចុចដើម្បី​ព្យាយាម​ម្ដងទៀត។"</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"ផ្គូផ្គង​ឧបករណ៍ថ្មី"</string>
+ <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"ដើម្បីភ្ជាប់វគ្គនេះ សូមបើកកម្មវិធី។"</string>
+ <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"កម្មវិធី​ដែលមិន​ស្គាល់"</string>
+ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"បញ្ឈប់ការភ្ជាប់"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"លេខ​កំណែបង្កើត"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"បានចម្លងលេខ​កំណែបង្កើតទៅឃ្លីបបត។"</string>
<string name="basic_status" msgid="2315371112182658176">"បើកការសន្ទនា"</string>
@@ -839,6 +858,7 @@
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"មើលព័ត៌មាន​ថ្មីៗ​អំពីស្ថានភាព ការខកខាន​ទទួល និងសារថ្មីៗ"</string>
<string name="people_tile_title" msgid="6589377493334871272">"ការ​សន្ទនា"</string>
+ <string name="paused_by_dnd" msgid="7856941866433556428">"បានផ្អាក​ដោយមុខងារ​កុំរំខាន"</string>
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> បានផ្ញើសារ៖ <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> បាន​ផ្ញើ​រូបភាព"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> មាន​បច្ចុប្បន្នភាព​ស្ថានភាព៖ <xliff:g id="STATUS">%2$s</xliff:g>"</string>
@@ -877,8 +897,7 @@
<item quantity="other">កម្មវិធីសកម្ម <xliff:g id="COUNT_1">%s</xliff:g></item>
<item quantity="one">កម្មវិធីសកម្ម <xliff:g id="COUNT_0">%s</xliff:g></item>
</plurals>
- <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
- <skip />
+ <string name="fgs_dot_content_description" msgid="2865071539464777240">"ព័ត៌មានថ្មី"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"កម្មវិធីសកម្ម"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"ឈប់"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"បានឈប់"</string>
@@ -886,14 +905,15 @@
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"បានចម្លង"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"ពី <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"ច្រានចោល UI ចម្លង"</string>
- <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
- <skip />
- <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
- <skip />
- <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
- <skip />
- <!-- no translation found for add (81036585205287996) -->
- <skip />
- <!-- no translation found for manage_users (1823875311934643849) -->
- <skip />
+ <string name="clipboard_edit_text_description" msgid="805254383912962103">"កែអត្ថបទ​ដែលបានចម្លង"</string>
+ <string name="clipboard_edit_image_description" msgid="8904857948976041306">"កែរូបភាព​ដែលបានចម្លង"</string>
+ <string name="clipboard_send_nearby_description" msgid="4629769637846717650">"ផ្ញើទៅ​ឧបករណ៍​នៅជិត"</string>
+ <string name="add" msgid="81036585205287996">"បញ្ចូល"</string>
+ <string name="manage_users" msgid="1823875311934643849">"គ្រប់គ្រង​អ្នក​ប្រើប្រាស់"</string>
+ <string name="drag_split_not_supported" msgid="4326847447699729722">"ការជូនដំណឹងនេះមិនអាចឱ្យអូសដើម្បីបំបែកអេក្រង់បានទេ។"</string>
+ <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi ត្រូវបានបិទ"</string>
+ <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"មុខងារ​អាទិភាព"</string>
+ <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"រូបកំណត់​ម៉ោងរោទ៍"</string>
+ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"កាមេរ៉ា និង​មីក្រូហ្វូន​ត្រូវបានបិទ"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{ការ​ជូន​ដំណឹង #}other{ការ​ជូនដំណឹង #}}"</string>
</resources>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index f1428a0abce2..ce0ca0e62f2f 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -20,14 +20,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4811759950673118541">"ಸಿಸ್ಟಂ UI"</string>
- <string name="battery_low_title" msgid="6891106956328275225">"ಬ್ಯಾಟರಿ ಸದ್ಯದಲ್ಲೇ ಖಾಲಿಯಾಗಬಹುದು"</string>
+ <string name="battery_low_title" msgid="5319680173344341779">"ಬ್ಯಾಟರಿ ಸೇವರ್ ಅನ್ನು ಆನ್ ಮಾಡಬೇಕೇ?"</string>
+ <string name="battery_low_description" msgid="3282977755476423966">"ನಿಮ್ಮ ಬಳಿ <xliff:g id="PERCENTAGE">%s</xliff:g> ಬ್ಯಾಟರಿ ಉಳಿದಿದೆ. ಬ್ಯಾಟರಿ ಸೇವರ್ ಡಾರ್ಕ್ ಥೀಮ್ ಅನ್ನು ಆನ್ ಮಾಡುತ್ತದೆ, ಹಿನ್ನೆಲೆ ಚಟುವಟಿಕೆಯನ್ನು ನಿರ್ಬಂಧಿಸುತ್ತದೆ ಮತ್ತು ಅಧಿಸೂಚನೆಗಳನ್ನು ವಿಳಂಬಮಾಡುತ್ತದೆ."</string>
+ <string name="battery_low_intro" msgid="5148725009653088790">"ಬ್ಯಾಟರಿ ಸೇವರ್ ಡಾರ್ಕ್ ಥೀಮ್ ಅನ್ನು ಆನ್ ಮಾಡುತ್ತದೆ, ಹಿನ್ನೆಲೆ ಚಟುವಟಿಕೆಯನ್ನು ನಿರ್ಬಂಧಿಸುತ್ತದೆ ಮತ್ತು ಅಧಿಸೂಚನೆಗಳನ್ನು ವಿಳಂಬಮಾಡುತ್ತದೆ."</string>
<string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> ಉಳಿದಿದೆ"</string>
<string name="invalid_charger_title" msgid="938685362320735167">"USB ಮೂಲಕ ಚಾರ್ಜ್‌ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"ನಿಮ್ಮ ಸಾಧನದೊಂದಿಗೆ ನೀಡಲಾಗಿರುವ ಚಾರ್ಜರ್‌ ಬಳಸಿ"</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"ಬ್ಯಾಟರಿ ಸೇವರ್‌ ಆನ್‌ ಮಾಡಬೇಕೇ?"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"ಬ್ಯಾಟರಿ ಸೇವರ್ ಕುರಿತು"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"ಆನ್‌ ಮಾಡಿ"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"ಬ್ಯಾಟರಿ ಸೇವರ್‌ ಆನ್‌ ಮಾಡಿ"</string>
+ <string name="battery_saver_start_action" msgid="8353766979886287140">"ಆನ್ ಮಾಡಿ"</string>
+ <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"ಬೇಡ"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"ಪರದೆಯನ್ನು ಸ್ವಯಂ-ತಿರುಗಿಸಿ"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> ಪ್ರವೇಶಿಸಲು <xliff:g id="APPLICATION">%1$s</xliff:g> ಅನ್ನು ಅನುಮತಿಸುವುದೇ?"</string>
<string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> ಅನ್ನು ಪ್ರವೇಶಿಸಲು <xliff:g id="APPLICATION">%1$s</xliff:g> ಅನ್ನು ಅನುಮತಿಸುವುದೇ?\nಈ ಆ್ಯಪ್‌ಗೆ ರೆಕಾರ್ಡ್ ಅನುಮತಿಯನ್ನು ನೀಡಲಾಗಿಲ್ಲ, ಆದರೆ ಈ USB ಸಾಧನದ ಮೂಲಕ ಆಡಿಯೊವನ್ನು ಸೆರೆಹಿಡಿಯಬಹುದು."</string>
@@ -128,6 +131,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"ಮುಖವನ್ನು ದೃಢೀಕರಿಸಲಾಗಿದೆ"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"ದೃಢೀಕರಿಸಲಾಗಿದೆ"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"ಪೂರ್ಣಗೊಳಿಸಲು ದೃಢೀಕರಿಸಿ ಅನ್ನು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"ನಿಮ್ಮ ಮುಖವನ್ನು ಬಳಸಿ ಅನ್‌ಲಾಕ್ ಮಾಡಲಾಗಿದೆ. ಮುಂದುವರಿಯಲು ಒತ್ತಿ."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"ದೃಢೀಕರಿಸಲಾಗಿದೆ"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"ಪಿನ್ ಬಳಸಿ"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"ಪ್ಯಾಟರ್ನ್ ಬಳಸಿ"</string>
@@ -176,11 +180,12 @@
<skip />
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"ಅಧಿಸೂಚನೆಯ ಛಾಯೆ."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"ತ್ವರಿತ ಸೆಟ್ಟಿಂಗ್‍ಗಳು."</string>
- <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"ಲಾಕ್‌ ಪರದೆ."</string>
+ <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"ಲಾಕ್‌ ಸ್ಕ್ರೀನ್."</string>
<string name="accessibility_desc_work_lock" msgid="4355620395354680575">"ಕೆಲಸದ ಲಾಕ್ ಪರದೆ"</string>
<string name="accessibility_desc_close" msgid="8293708213442107755">"ಮುಚ್ಚು"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"ಸಂಪೂರ್ಣ ನಿಶ್ಯಬ್ಧ"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"ಅಲಾರಮ್‌ಗಳು ಮಾತ್ರ"</string>
+ <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"ಅಡಚಣೆ ಮಾಡಬೇಡ."</string>
<string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"ಬ್ಲೂಟೂತ್."</string>
<string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"ಬ್ಲೂಟೂತ್ ಆನ್ ಆಗಿದೆ."</string>
<string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"<xliff:g id="TIME">%s</xliff:g> ಗಂಟೆಗೆ ಅಲಾರಮ್ ಹೊಂದಿಸಲಾಗಿದೆ."</string>
@@ -205,6 +210,7 @@
<string name="dessert_case" msgid="9104973640704357717">"ಡೆಸರ್ಟ್ ಕೇಸ್"</string>
<string name="start_dreams" msgid="9131802557946276718">"ಸ್ಕ್ರೀನ್ ಸೇವರ್"</string>
<string name="ethernet_label" msgid="2203544727007463351">"ಇಥರ್ನೆಟ್"</string>
+ <string name="quick_settings_dnd_label" msgid="7728690179108024338">"ಅಡಚಣೆ ಮಾಡಬೇಡ"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"ಬ್ಲೂಟೂತ್‌"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"ಯಾವುದೇ ಜೋಡಿಸಲಾದ ಸಾಧನಗಳು ಲಭ್ಯವಿಲ್ಲ"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> ಬ್ಯಾಟರಿ"</string>
@@ -348,6 +354,7 @@
<string name="notification_section_header_alerting" msgid="5581175033680477651">"ಅಧಿಸೂಚನೆಗಳು"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"ಸಂಭಾಷಣೆಗಳು"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"ಎಲ್ಲಾ ನಿಶ್ಶಬ್ಧ ಅಧಿಸೂಚನೆಗಳನ್ನು ತೆರವುಗೊಳಿಸಿ"</string>
+ <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"ಅಡಚಣೆ ಮಾಡಬೇಡಿ ಎನ್ನುವ ಮೂಲಕ ಅಧಿಸೂಚನೆಗಳನ್ನು ವಿರಾಮಗೊಳಿಸಲಾಗಿದೆ"</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"ಈಗ ಪ್ರಾರಂಭಿಸಿ"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"ಯಾವುದೇ ಅಧಿಸೂಚನೆಗಳಿಲ್ಲ"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"ಈ ಸಾಧನವನ್ನು ನಿಮ್ಮ ಪೋಷಕರು ನಿರ್ವಹಿಸುತ್ತಿದ್ದಾರೆ"</string>
@@ -452,8 +459,8 @@
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"ಬಳಸಲು ಅನ್‌ಲಾಕ್ ಮಾಡಿ"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"ನಿಮ್ಮ ಕಾರ್ಡ್‌ಗಳನ್ನು ಪಡೆಯುವಾಗ ಸಮಸ್ಯೆ ಉಂಟಾಗಿದೆ, ನಂತರ ಪುನಃ ಪ್ರಯತ್ನಿಸಿ"</string>
<string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"ಲಾಕ್ ಸ್ಕ್ರ್ರೀನ್ ಸೆಟ್ಟಿಂಗ್‌ಗಳು"</string>
- <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR ಕೋಡ್"</string>
- <string name="qr_code_scanner_description" msgid="7937603775306661863">"ಸ್ಕ್ಯಾನ್ ಮಾಡಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
+ <!-- no translation found for qr_code_scanner_title (5290201053875420785) -->
+ <skip />
<string name="status_bar_work" msgid="5238641949837091056">"ಕೆಲಸದ ಪ್ರೊಫೈಲ್"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"ಏರ್‌ಪ್ಲೇನ್ ಮೋಡ್"</string>
<string name="zen_alarm_warning" msgid="7844303238486849503">"ನಿಮ್ಮ ಮುಂದಿನ <xliff:g id="WHEN">%1$s</xliff:g> ಅಲಾರಮ್ ಅನ್ನು ನೀವು ಆಲಿಸುವುದಿಲ್ಲ"</string>
@@ -491,6 +498,8 @@
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"&lt;b&gt;ಸ್ಥಿತಿ:&lt;/b&gt; ಕಡಿಮೆ ಸ್ಥಾನವನ್ನು ಹೊಂದಿದೆ"</string>
<string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"ಸಂಭಾಷಣೆ ಅಧಿಸೂಚನೆಗಳ ಮೇಲ್ಭಾಗದಲ್ಲಿ ಹಾಗೂ ಲಾಕ್ ಸ್ಕ್ರೀನ್‌ನ ಮೇಲೆ ಪ್ರೊಫೈಲ್ ಚಿತ್ರವಾಗಿ ತೋರಿಸುತ್ತದೆ"</string>
<string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"ಸಂಭಾಷಣೆ ಅಧಿಸೂಚನೆಗಳ ಮೇಲ್ಭಾಗದಲ್ಲಿ ಹಾಗೂ ಲಾಕ್ ಸ್ಕ್ರೀನ್‌ನ ಮೇಲೆ ಪ್ರೊಫೈಲ್ ಚಿತ್ರವಾಗಿ ತೋರಿಸುತ್ತದೆ, ಬಬಲ್‌ನಂತೆ ಗೋಚರಿಸುತ್ತದೆ"</string>
+ <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"ಸಂಭಾಷಣೆ ಅಧಿಸೂಚನೆಗಳ ಮೇಲ್ಭಾಗದಲ್ಲಿ ಹಾಗೂ ಲಾಕ್ ಸ್ಕ್ರೀನ್‌ನ ಮೇಲೆ ಪ್ರೊಫೈಲ್ ಚಿತ್ರವಾಗಿ ತೋರಿಸುತ್ತದೆ, ಅಡಚಣೆ ಮಾಡಬೇಡ ಮೋಡ್‌ಗೆ ಅಡ್ಡಿಯುಂಟುಮಾಡುತ್ತದೆ"</string>
+ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"ಸಂಭಾಷಣೆ ಅಧಿಸೂಚನೆಗಳ ಮೇಲ್ಭಾಗದಲ್ಲಿ ಹಾಗೂ ಲಾಕ್ ಸ್ಕ್ರೀನ್‌ನ ಮೇಲೆ ಪ್ರೊಫೈಲ್ ಚಿತ್ರವಾಗಿ ತೋರಿಸುತ್ತದೆ, ಬಬಲ್‌ನಂತೆ ಗೋಚರಿಸುತ್ತದೆ, ಅಡಚಣೆ ಮಾಡಬೇಡ ಮೋಡ್‌ಗೆ ಅಡ್ಡಿಯುಂಟುಮಾಡುತ್ತದೆ"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"ಆದ್ಯತೆ"</string>
<string name="no_shortcut" msgid="8257177117568230126">"ಸಂವಾದ ಫೀಚರ್‌ಗಳನ್ನು <xliff:g id="APP_NAME">%1$s</xliff:g> ಬೆಂಬಲಿಸುವುದಿಲ್ಲ"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"ಈ ಅಧಿಸೂಚನೆಗಳನ್ನು ಮಾರ್ಪಡಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ."</string>
@@ -566,6 +575,7 @@
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"ಎಸ್ಎಂಎಸ್"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"ಸಂಗೀತ"</string>
<string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Calendar"</string>
+ <string name="volume_and_do_not_disturb" msgid="502044092739382832">"ಅಡಚಣೆ ಮಾಡಬೇಡ"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"ವಾಲ್ಯೂಮ್ ಬಟನ್‌ಗಳ ಶಾರ್ಟ್‌ಕಟ್‌"</string>
<string name="battery" msgid="769686279459897127">"ಬ್ಯಾಟರಿ"</string>
<string name="headset" msgid="4485892374984466437">"ಹೆಡ್‌ಸೆಟ್"</string>
@@ -684,6 +694,10 @@
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"ವೈ-ಫೈ ಆಫ್ ಆಗಿದೆ"</string>
<string name="bt_is_off" msgid="7436344904889461591">"ಬ್ಲೂಟೂತ್‌ ಆಫ್ ಆಗಿದೆ"</string>
+ <string name="dnd_is_off" msgid="3185706903793094463">"ಅಡಚಣೆ ಮಾಡಬೇಡಿ ಆಫ್ ಆಗಿದೆ"</string>
+ <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"(<xliff:g id="ID_1">%s</xliff:g>) ಸ್ವಯಂಚಾಲಿತ ನಿಯಮದ ಮೂಲಕ ಅಡಚಣೆ ಮಾಡಬೇಡಿ ಆನ್ ಆಗಿದೆ."</string>
+ <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"(<xliff:g id="ID_1">%s</xliff:g>) ಅಪ್ಲಿಕೇಶನ್‌ ಮೂಲಕ ಅಡಚಣೆ ಮಾಡಬೇಡಿ ಆನ್ ಆಗಿದೆ."</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"ಸ್ವಯಂಚಾಲಿತ ನಿಯಮ ಅಥವಾ ಅಪ್ಲಿಕೇಶನ್‌ ಮೂಲಕ ಅಡಚಣೆ ಮಾಡಬೇಡಿ ಆನ್ ಆಗಿದೆ."</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"ಅಪ್ಲಿಕೇಶನ್‌ಗಳು ಹಿನ್ನೆಲೆಯಲ್ಲಿ ರನ್ ಆಗುತ್ತಿವೆ"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"ಬ್ಯಾಟರಿ,ಡೇಟಾ ಬಳಕೆಯ ವಿವರಗಳಿಗಾಗಿ ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"ಮೊಬೈಲ್ ಡೇಟಾ ಆಫ್ ಮಾಡಬೇಕೆ?"</string>
@@ -708,6 +722,8 @@
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(ಉದ್ಯೋಗ)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"ಫೋನ್ ಕರೆ"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(<xliff:g id="APPLICATION_NAME_S_">%s</xliff:g> ಮೂಲಕ)"</string>
+ <string name="ongoing_privacy_dialog_attribution_label" msgid="3385241594101496292">"(<xliff:g id="ATTRIBUTION_LABEL">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_proxy_label" msgid="1111829599659403249">"(<xliff:g id="ATTRIBUTION_LABEL">%1$s</xliff:g> • <xliff:g id="PROXY_LABEL">%2$s</xliff:g>)"</string>
<string name="privacy_type_camera" msgid="7974051382167078332">"ಕ್ಯಾಮರಾ"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"ಸ್ಥಳ"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"ಮೈಕ್ರೋಫೋನ್‌"</string>
@@ -806,6 +822,9 @@
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(ಡಿಸ್‌ಕನೆಕ್ಟ್ ಆಗಿದೆ)"</string>
<string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"ಬದಲಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ. ಪುನಃ ಪ್ರಯತ್ನಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"ಹೊಸ ಸಾಧನವನ್ನು ಜೋಡಿಸಿ"</string>
+ <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"ಈ ಸೆಶನ್ ಕಾಸ್ಟ್ ಮಾಡಲು, ಆ್ಯಪ್ ಅನ್ನು ತೆರೆಯಿರಿ."</string>
+ <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"ಅಪರಿಚಿತ ಆ್ಯಪ್"</string>
+ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"ಬಿತ್ತರಿಸುವುದನ್ನು ನಿಲ್ಲಿಸಿ"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"ಬಿಲ್ಡ್ ಸಂಖ್ಯೆ"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"ಬಿಲ್ಡ್ ಸಂಖ್ಯೆಯನ್ನು ಕ್ಲಿಪ್‌ಬೋರ್ಡ್‌ನಲ್ಲಿ ನಕಲಿಸಲಾಗಿದೆ."</string>
<string name="basic_status" msgid="2315371112182658176">"ಸಂಭಾಷಣೆಯನ್ನು ತೆರೆಯಿರಿ"</string>
@@ -839,6 +858,7 @@
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"ಇತ್ತೀಚಿನ ಸಂದೇಶಗಳು, ಮಿಸ್ಡ್ ಕಾಲ್‌ಗಳು ಮತ್ತು ಸ್ಥಿತಿ ಅಪ್‌ಡೇಟ್‌ಗಳು"</string>
<string name="people_tile_title" msgid="6589377493334871272">"ಸಂಭಾಷಣೆ"</string>
+ <string name="paused_by_dnd" msgid="7856941866433556428">"\'ಅಡಚಣೆ ಮಾಡಬೇಡಿ\' ನಿಂದ ವಿರಾಮಗೊಳಿಸಲಾಗಿದೆ"</string>
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> ಅವರು ಸಂದೇಶವನ್ನು ಕಳುಹಿಸಿದ್ದಾರೆ: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> ಅವರು ಚಿತ್ರವನ್ನು ಕಳುಹಿಸಿದ್ದಾರೆ"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> ಅವರು ಸ್ಥಿತಿಯ ಅಪ್‌ಡೇಟ್ ಹೊಂದಿದ್ದಾರೆ: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
@@ -877,8 +897,7 @@
<item quantity="one"><xliff:g id="COUNT_1">%s</xliff:g> ಸಕ್ರಿಯ ಆ್ಯಪ್‌ಗಳು</item>
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> ಸಕ್ರಿಯ ಆ್ಯಪ್‌ಗಳು</item>
</plurals>
- <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
- <skip />
+ <string name="fgs_dot_content_description" msgid="2865071539464777240">"ಹೊಸ ಮಾಹಿತಿ"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"ಸಕ್ರಿಯ ಆ್ಯಪ್‌ಗಳು"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"ನಿಲ್ಲಿಸಿ"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"ನಿಲ್ಲಿಸಿದೆ"</string>
@@ -889,8 +908,12 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"ನಕಲಿಸಿದ ಪಠ್ಯವನ್ನು ಎಡಿಟ್ ಮಾಡಿ"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"ನಕಲಿಸಿದ ಚಿತ್ರವನ್ನು ಎಡಿಟ್ ಮಾಡಿ"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"ಸಮೀಪದಲ್ಲಿರುವ ಸಾಧನಕ್ಕೆ ಕಳುಹಿಸಿ"</string>
- <!-- no translation found for add (81036585205287996) -->
- <skip />
- <!-- no translation found for manage_users (1823875311934643849) -->
- <skip />
+ <string name="add" msgid="81036585205287996">"ಸೇರಿಸಿ"</string>
+ <string name="manage_users" msgid="1823875311934643849">"ಬಳಕೆದಾರರನ್ನು ನಿರ್ವಹಿಸಿ"</string>
+ <string name="drag_split_not_supported" msgid="4326847447699729722">"ಸ್ಪ್ಲಿಟ್ ಸ್ಕ್ರೀನ್‌ಗೆ ಡ್ರ್ಯಾಗ್ ಮಾಡುವುದನ್ನು ಈ ಅಧಿಸೂಚನೆಯು ಬೆಂಬಲಿಸುವುದಿಲ್ಲ."</string>
+ <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"ವೈ-ಫೈ ಲಭ್ಯವಿಲ್ಲ"</string>
+ <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"ಆದ್ಯತೆ ಮೋಡ್"</string>
+ <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"ಅಲಾರಾಂ ಹೊಂದಿಸಲಾಗಿದೆ"</string>
+ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"ಕ್ಯಾಮರಾ ಮತ್ತು ಮೈಕ್ ಆಫ್ ಆಗಿದೆ"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# ಅಧಿಸೂಚನೆ}one{# ಅಧಿಸೂಚನೆಗಳು}other{# ಅಧಿಸೂಚನೆಗಳು}}"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 02246b48d4b1..8705e7105385 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -20,14 +20,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4811759950673118541">"시스템 UI"</string>
- <string name="battery_low_title" msgid="6891106956328275225">"배터리가 얼마 남지 않음"</string>
+ <string name="battery_low_title" msgid="5319680173344341779">"절전 모드를 사용 설정하시겠습니까?"</string>
+ <string name="battery_low_description" msgid="3282977755476423966">"배터리가 <xliff:g id="PERCENTAGE">%s</xliff:g> 남았습니다. 절전 모드는 어두운 테마를 사용 설정하고 백그라운드 활동을 제한하며 알림을 지연시킵니다."</string>
+ <string name="battery_low_intro" msgid="5148725009653088790">"절전 모드는 어두운 테마를 사용 설정하고 백그라운드 활동을 제한하며 알림을 지연시킵니다."</string>
<string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> 남았습니다."</string>
<string name="invalid_charger_title" msgid="938685362320735167">"USB로 충전할 수 없습니다."</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"기기와 함께 제공된 충전기를 사용하세요."</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"절전 모드를 사용 설정하시겠습니까?"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"절전 모드 정보"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"사용"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"절전 모드 사용 설정"</string>
+ <string name="battery_saver_start_action" msgid="8353766979886287140">"사용"</string>
+ <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"사용 안함"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"화면 자동 회전"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"<xliff:g id="APPLICATION">%1$s</xliff:g> 앱이 <xliff:g id="USB_DEVICE">%2$s</xliff:g>에 액세스하도록 허용하시겠습니까?"</string>
<string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"<xliff:g id="APPLICATION">%1$s</xliff:g>에서 <xliff:g id="USB_DEVICE">%2$s</xliff:g>에 액세스하도록 허용하시겠습니까?\n이 앱에는 녹음 권한이 부여되지 않았지만, 이 USB 기기를 통해 오디오를 녹음할 수 있습니다."</string>
@@ -128,6 +131,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"얼굴이 인증되었습니다."</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"확인함"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"완료하려면 확인을 탭하세요."</string>
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"얼굴 인식으로 잠금 해제했습니다. 계속하려면 누르세요."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"인증됨"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"PIN 사용"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"패턴 사용"</string>
@@ -181,6 +185,7 @@
<string name="accessibility_desc_close" msgid="8293708213442107755">"닫기"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"모두 음소거"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"알람만 허용"</string>
+ <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"방해 금지 모드"</string>
<string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"블루투스"</string>
<string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"블루투스: 사용"</string>
<string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"알람이 <xliff:g id="TIME">%s</xliff:g>(으)로 설정되었습니다."</string>
@@ -205,6 +210,7 @@
<string name="dessert_case" msgid="9104973640704357717">"디저트 케이스"</string>
<string name="start_dreams" msgid="9131802557946276718">"화면 보호기"</string>
<string name="ethernet_label" msgid="2203544727007463351">"이더넷"</string>
+ <string name="quick_settings_dnd_label" msgid="7728690179108024338">"방해 금지 모드"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"블루투스"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"페어링된 기기가 없습니다"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"배터리 <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
@@ -348,6 +354,7 @@
<string name="notification_section_header_alerting" msgid="5581175033680477651">"알림"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"대화"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"무음 알림 모두 삭제"</string>
+ <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"방해 금지 모드로 알림이 일시중지됨"</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"시작하기"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"알림 없음"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"부모님이 관리하는 기기입니다."</string>
@@ -452,8 +459,8 @@
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"잠금 해제하여 사용"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"카드를 가져오는 중에 문제가 발생했습니다. 나중에 다시 시도해 보세요."</string>
<string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"잠금 화면 설정"</string>
- <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR 코드"</string>
- <string name="qr_code_scanner_description" msgid="7937603775306661863">"탭하여 스캔"</string>
+ <!-- no translation found for qr_code_scanner_title (5290201053875420785) -->
+ <skip />
<string name="status_bar_work" msgid="5238641949837091056">"직장 프로필"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"비행기 모드"</string>
<string name="zen_alarm_warning" msgid="7844303238486849503">"<xliff:g id="WHEN">%1$s</xliff:g>에 다음 알람을 들을 수 없습니다."</string>
@@ -491,6 +498,8 @@
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"&lt;b&gt;상태:&lt;/b&gt; 순위 낮춤"</string>
<string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"대화 알림 상단에 표시, 잠금 화면에 프로필 사진으로 표시"</string>
<string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"대화 알림 상단에 표시, 잠금 화면에 프로필 사진으로 표시, 대화창으로 표시"</string>
+ <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"대화 알림 상단에 표시, 잠금 화면에 프로필 사진으로 표시, 방해 금지 모드를 무시함"</string>
+ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"대화 알림 상단에 표시, 잠금 화면에 프로필 사진으로 표시, 대화창으로 표시, 방해 금지 모드를 무시함"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"우선순위"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> 앱은 대화 기능을 지원하지 않습니다."</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"이 알림은 수정할 수 없습니다."</string>
@@ -566,6 +575,7 @@
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"SMS"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"음악"</string>
<string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"캘린더"</string>
+ <string name="volume_and_do_not_disturb" msgid="502044092739382832">"방해 금지 모드"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"볼륨 버튼 단축키"</string>
<string name="battery" msgid="769686279459897127">"배터리"</string>
<string name="headset" msgid="4485892374984466437">"헤드셋"</string>
@@ -684,6 +694,10 @@
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"Wi-Fi가 사용 중지됨"</string>
<string name="bt_is_off" msgid="7436344904889461591">"블루투스가 사용 중지됨"</string>
+ <string name="dnd_is_off" msgid="3185706903793094463">"방해 금지 모드가 사용 중지됨"</string>
+ <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"방해 금지 모드가 자동 규칙(<xliff:g id="ID_1">%s</xliff:g>)에 의해 사용 설정되었습니다."</string>
+ <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"방해 금지 모드가 앱(<xliff:g id="ID_1">%s</xliff:g>)에 의해 사용 설정되었습니다."</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"방해 금지 모드가 자동 규칙 또는 앱에 의해 사용 설정되었습니다."</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"백그라운드에서 실행 중인 앱"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"탭하여 배터리 및 데이터 사용량 확인"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"모바일 데이터를 사용 중지하시겠습니까?"</string>
@@ -708,6 +722,8 @@
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(직장)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"전화 통화"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(<xliff:g id="APPLICATION_NAME_S_">%s</xliff:g> 사용)"</string>
+ <string name="ongoing_privacy_dialog_attribution_label" msgid="3385241594101496292">"(<xliff:g id="ATTRIBUTION_LABEL">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_proxy_label" msgid="1111829599659403249">"(<xliff:g id="ATTRIBUTION_LABEL">%1$s</xliff:g> • <xliff:g id="PROXY_LABEL">%2$s</xliff:g>)"</string>
<string name="privacy_type_camera" msgid="7974051382167078332">"카메라"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"위치"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"마이크"</string>
@@ -806,6 +822,9 @@
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(연결 끊김)"</string>
<string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"전환할 수 없습니다. 다시 시도하려면 탭하세요."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"새 기기와 페어링"</string>
+ <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"세션을 전송하려면 앱을 열어 주세요"</string>
+ <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"알 수 없는 앱"</string>
+ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"전송 중지"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"빌드 번호"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"빌드 번호가 클립보드에 복사되었습니다."</string>
<string name="basic_status" msgid="2315371112182658176">"대화 열기"</string>
@@ -839,6 +858,7 @@
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"최근 메시지, 부재중 전화, 상태 업데이트 보기"</string>
<string name="people_tile_title" msgid="6589377493334871272">"대화"</string>
+ <string name="paused_by_dnd" msgid="7856941866433556428">"방해 금지 모드로 인해 일시중지됨"</string>
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g>님이 메시지를 보냈습니다: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g>님이 이미지를 보냈습니다."</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g>님의 상태가 업데이트되었습니다: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
@@ -877,8 +897,7 @@
<item quantity="other">활성 상태의 앱 <xliff:g id="COUNT_1">%s</xliff:g>개</item>
<item quantity="one">활성 상태의 앱 <xliff:g id="COUNT_0">%s</xliff:g>개</item>
</plurals>
- <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
- <skip />
+ <string name="fgs_dot_content_description" msgid="2865071539464777240">"새로운 정보"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"활성 상태의 앱"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"중지"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"중지됨"</string>
@@ -886,14 +905,15 @@
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"복사됨"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"복사한 위치: <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"UI 복사 닫기"</string>
- <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
- <skip />
- <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
- <skip />
- <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
- <skip />
- <!-- no translation found for add (81036585205287996) -->
- <skip />
- <!-- no translation found for manage_users (1823875311934643849) -->
- <skip />
+ <string name="clipboard_edit_text_description" msgid="805254383912962103">"복사된 텍스트 편집"</string>
+ <string name="clipboard_edit_image_description" msgid="8904857948976041306">"복사된 이미지 편집"</string>
+ <string name="clipboard_send_nearby_description" msgid="4629769637846717650">"근처 기기에 전송"</string>
+ <string name="add" msgid="81036585205287996">"추가"</string>
+ <string name="manage_users" msgid="1823875311934643849">"사용자 관리"</string>
+ <string name="drag_split_not_supported" msgid="4326847447699729722">"드래그하여 화면을 분할하는 기능이 지원되지 않는 알림입니다."</string>
+ <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi를 이용할 수 없습니다."</string>
+ <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"우선순위 모드입니다."</string>
+ <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"알람이 설정되었습니다."</string>
+ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"카메라 및 마이크가 사용 중지되었습니다."</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{알림 #개}other{알림 #개}}"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index c8c56caa9dea..6187f3a27c6c 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -20,14 +20,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4811759950673118541">"Тутум UI"</string>
- <string name="battery_low_title" msgid="6891106956328275225">"Батарея жакында отуруп калышы мүмкүн"</string>
+ <string name="battery_low_title" msgid="5319680173344341779">"Батареяны үнөмдөгүч режими күйгүзүлсүнбү?"</string>
+ <string name="battery_low_description" msgid="3282977755476423966">"Батареянын деңгээли: <xliff:g id="PERCENTAGE">%s</xliff:g>. Батареяны үнөмдөгүч режими Караңгы теманы күйгүзүп, фондогу аракеттерди чектеп, билдирмелерди кечиктирет."</string>
+ <string name="battery_low_intro" msgid="5148725009653088790">"Батареяны үнөмдөгүч режими Караңгы теманы күйгүзүп, фондогу аракеттерди чектеп, билдирмелерди кечиктирет."</string>
<string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> калды"</string>
<string name="invalid_charger_title" msgid="938685362320735167">"USB аркылуу кубатталбай жатат"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"Түзмөгүңүз менен келген кубаттагычты колдонуңуз"</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Батареяны үнөмдөө режимин күйгүзөсүзбү?"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Батареяны үнөмдөгүч режими жөнүндө маалымат"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Күйгүзүү"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"Батареяны үнөмдөгүчтү күйгүзүү"</string>
+ <string name="battery_saver_start_action" msgid="8353766979886287140">"Күйгүзүү"</string>
+ <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Жок, рахмат"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Экранды авто буруу"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"<xliff:g id="APPLICATION">%1$s</xliff:g> колдонмосу <xliff:g id="USB_DEVICE">%2$s</xliff:g> түзмөгүн колдоно берсинби?"</string>
<string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"<xliff:g id="APPLICATION">%1$s</xliff:g> колдонмосу үчүн <xliff:g id="USB_DEVICE">%2$s</xliff:g> түзмөгүнө мүмкүнчүлүк алууга уруксат бересизби?\nБул колдонмонун жаздырууга уруксаты жок, бирок бул USB түзмөгү аркылуу аудиону жаздыра алат."</string>
@@ -111,7 +114,7 @@
<string name="accessibility_phone_button" msgid="4256353121703100427">"Телефон"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Үн жардамчысы"</string>
<string name="accessibility_wallet_button" msgid="1458258783460555507">"Капчык"</string>
- <string name="accessibility_qr_code_scanner_button" msgid="7521277927692910795">"QR кодунун сканери"</string>
+ <string name="accessibility_qr_code_scanner_button" msgid="7521277927692910795">"QR коддорунун сканери"</string>
<string name="accessibility_unlock_button" msgid="122785427241471085">"Кулпусун ачуу"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"Түзмөк кулпуланды"</string>
<string name="accessibility_scanning_face" msgid="3093828357921541387">"Жүз скандалууда"</string>
@@ -128,6 +131,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Жүздүн аныктыгы текшерилди"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Ырасталды"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Бүтүрүү үчүн \"Ырастоо\" баскычын басыңыз"</string>
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Жүзүңүз менен ачылды. Улантуу үчүн басыңыз."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Аныктыгы текшерилди"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"PIN кодду колдонуу"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Графикалык ачкычты колдонуу"</string>
@@ -181,6 +185,7 @@
<string name="accessibility_desc_close" msgid="8293708213442107755">"Жабуу"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"тымтырс"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"ойготкуч гана"</string>
+ <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"Тынчымды алба."</string>
<string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"Bluetooth."</string>
<string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"Bluetooth күйүк."</string>
<string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"Ойготкуч кийинкиге коюлган: <xliff:g id="TIME">%s</xliff:g>."</string>
@@ -205,6 +210,7 @@
<string name="dessert_case" msgid="9104973640704357717">"Десерт себети"</string>
<string name="start_dreams" msgid="9131802557946276718">"Көшөгө"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
+ <string name="quick_settings_dnd_label" msgid="7728690179108024338">"Тынчымды алба"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Жупташкан түзмөктөр жок"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Батареянын деңгээли <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
@@ -348,6 +354,7 @@
<string name="notification_section_header_alerting" msgid="5581175033680477651">"Билдирмелер"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Сүйлөшүүлөр"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Бардык үнсүз билдирмелерди өчүрүү"</string>
+ <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"\"Тынчымды алба\" режиминде билдирмелер тындырылды"</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"Азыр баштоо"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Билдирме жок"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Бул түзмөктү ата-энең башкарат"</string>
@@ -452,8 +459,8 @@
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Колдонуу үчүн кулпусун ачыңыз"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Кыйытмаларды алууда ката кетти. Бир аздан кийин кайталап көрүңүз."</string>
<string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Кулпуланган экран жөндөөлөрү"</string>
- <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR коду"</string>
- <string name="qr_code_scanner_description" msgid="7937603775306661863">"Скандоо үчүн таптап коюңуз"</string>
+ <!-- no translation found for qr_code_scanner_title (5290201053875420785) -->
+ <skip />
<string name="status_bar_work" msgid="5238641949837091056">"Жумуш профили"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Учак режими"</string>
<string name="zen_alarm_warning" msgid="7844303238486849503">"<xliff:g id="WHEN">%1$s</xliff:g> боло турган кийинки эскертмени укпайсыз"</string>
@@ -491,6 +498,8 @@
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"&lt;b&gt;Абалы:&lt;/b&gt; Төмөндөдү"</string>
<string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"Сүйлөшүүлөр тууралуу билдирмелердин жогору жагында, ошондой эле кулпуланган экранда профилдин сүрөтү түрүндө көрүнөт"</string>
<string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"Cүйлөшүүлөр тууралуу билдирмелердин жогору жагында жана кулпуланган экранда профилдин сүрөтү, ошондой эле калкып чыкма билдирме түрүндө көрүнөт"</string>
+ <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"Cүйлөшүүлөр тууралуу билдирмелердин жогору жагында жана кулпуланган экранда профилдин сүрөтү түрүндө көрүнүп, \"Тынчымды алба\" режимин токтотот"</string>
+ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Cүйлөшүүлөр тууралуу билдирмелердин жогору жагында жана кулпуланган экранда профилдин сүрөтү, ошондой эле калкып чыкма билдирме түрүндө көрүнүп, \"Тынчымды алба\" режимин токтотот"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Маанилүүлүгү"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> колдонмосунда оозеки сүйлөшкөнгө болбойт"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Бул билдирмелерди өзгөртүүгө болбойт."</string>
@@ -566,6 +575,7 @@
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"SMS"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"Музыка"</string>
<string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Жылнаама"</string>
+ <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Тынчымды алба"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"Үндү көзөмөлдөөчү баскычтардын кыска жолдору"</string>
<string name="battery" msgid="769686279459897127">"Батарея"</string>
<string name="headset" msgid="4485892374984466437">"Гарнитура"</string>
@@ -684,6 +694,10 @@
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"Wi-Fi өчүк"</string>
<string name="bt_is_off" msgid="7436344904889461591">"Bluetooth өчүк"</string>
+ <string name="dnd_is_off" msgid="3185706903793094463">"\"Тынчымды алба\" режими өчүк"</string>
+ <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"Автоматтык эреже \"Тынчымды алба\" режимин күйгүздү (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"Колдонмо \"Тынчымды алба\" режимин күйгүздү (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"Автоматтык эреже же колдонмо \"Тынчымды алба\" режимин күйгүздү."</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"Фондо иштеп жаткан колдонмолор"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"Батареянын кубаты жана трафиктин көлөмү жөнүндө билүү үчүн таптап коюңуз"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Мобилдик Интернетти өчүрөсүзбү?"</string>
@@ -708,6 +722,8 @@
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(жумуш)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"Телефон чалуу"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(<xliff:g id="APPLICATION_NAME_S_">%s</xliff:g> аркылуу)"</string>
+ <string name="ongoing_privacy_dialog_attribution_label" msgid="3385241594101496292">"(<xliff:g id="ATTRIBUTION_LABEL">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_proxy_label" msgid="1111829599659403249">"(<xliff:g id="ATTRIBUTION_LABEL">%1$s</xliff:g> • <xliff:g id="PROXY_LABEL">%2$s</xliff:g>)"</string>
<string name="privacy_type_camera" msgid="7974051382167078332">"камера"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"жайгашкан жер"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"микрофон"</string>
@@ -806,6 +822,9 @@
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(ажыратылды)"</string>
<string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Которулбай жатат. Кайталоо үчүн басыңыз."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Жаңы түзмөктү жупташтыруу"</string>
+ <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Бул сеансты тышкы экранга чыгаруу үчүн колдонмону ачыңыз."</string>
+ <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Белгисиз колдонмо"</string>
+ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Тышкы экранга чыгарууну токтотуу"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Курама номери"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Курама номери алмашуу буферине көчүрүлдү."</string>
<string name="basic_status" msgid="2315371112182658176">"Ачык сүйлөшүү"</string>
@@ -839,6 +858,7 @@
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Акыркы билдирүүлөрдү, жооп берилбеген чалууларды жана статустардын жаңырганын көрөсүз"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Сүйлөшүү"</string>
+ <string name="paused_by_dnd" msgid="7856941866433556428">"\"Тынчымды алба\" режими тындырды"</string>
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> билдирүү жөнөттү: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> сүрөт жөнөттү"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> жаңы абалы тууралуу жарыялады: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
@@ -877,8 +897,7 @@
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> жигердүү колдонмо</item>
<item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> жигердүү колдонмо</item>
</plurals>
- <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
- <skip />
+ <string name="fgs_dot_content_description" msgid="2865071539464777240">"Жаңы маалымат"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Жигердүү колдонмолор"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Токтотуу"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Токтотулду"</string>
@@ -886,14 +905,15 @@
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Көчүрүлдү"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"<xliff:g id="APPNAME">%1$s</xliff:g> колдонмосунан"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Көчүрмөнү жабуу интерфейси"</string>
- <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
- <skip />
- <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
- <skip />
- <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
- <skip />
- <!-- no translation found for add (81036585205287996) -->
- <skip />
- <!-- no translation found for manage_users (1823875311934643849) -->
- <skip />
+ <string name="clipboard_edit_text_description" msgid="805254383912962103">"Көчүрүлгөн текстти түзөтүү"</string>
+ <string name="clipboard_edit_image_description" msgid="8904857948976041306">"Көчүрүлгөн сүрөттү түзөтүү"</string>
+ <string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Жакын жердеги түзмөккө жөнөтүү"</string>
+ <string name="add" msgid="81036585205287996">"Кошуу"</string>
+ <string name="manage_users" msgid="1823875311934643849">"Колдонуучуларды башкаруу"</string>
+ <string name="drag_split_not_supported" msgid="4326847447699729722">"Бул билдирмени бөлүнгөн экранда сүйрөөгө болбойт."</string>
+ <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi жеткиликсиз"</string>
+ <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Маанилүү сүйлөшүүлөр режими"</string>
+ <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Ойготкуч коюлду"</string>
+ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Камера жана микрофон өчүк"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# билдирме}other{# билдирме}}"</string>
</resources>
diff --git a/packages/SystemUI/res/values-land/styles.xml b/packages/SystemUI/res/values-land/styles.xml
index f3d83645a8e0..89191984b9e8 100644
--- a/packages/SystemUI/res/values-land/styles.xml
+++ b/packages/SystemUI/res/values-land/styles.xml
@@ -18,15 +18,4 @@
<style name="BrightnessDialogContainer" parent="@style/BaseBrightnessDialogContainer">
<item name="android:layout_width">360dp</item>
</style>
-
- <style name="DockedDividerBackground">
- <item name="android:layout_width">10dp</item>
- <item name="android:layout_height">match_parent</item>
- <item name="android:layout_gravity">center_horizontal</item>
- </style>
-
- <style name="DockedDividerMinimizedShadow">
- <item name="android:layout_width">8dp</item>
- <item name="android:layout_height">match_parent</item>
- </style>
</resources>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index 6b96c1a57d55..3343bcfa0a53 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -20,14 +20,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4811759950673118541">"ສ່ວນຕິດຕໍ່ຜູ້ໃຊ້ຂອງລະບົບ"</string>
- <string name="battery_low_title" msgid="6891106956328275225">"ແບັດເຕີຣີໃກ້ຈະໝົດແລ້ວ"</string>
+ <string name="battery_low_title" msgid="5319680173344341779">"ເປີດໃຊ້ຕົວປະຢັດແບັດເຕີຣີບໍ?"</string>
+ <string name="battery_low_description" msgid="3282977755476423966">"ທ່ານມີແບັດເຕີຣີເຫຼືອ <xliff:g id="PERCENTAGE">%s</xliff:g>. ຕົວປະຢັດແບັດເຕີຣີຈະເປີດໃຊ້ຮູບແບບສີສັນມືດ, ຈຳກັດການເຄື່ອນໄຫວໃນພື້ນຫຼັງ ແລະ ເລື່ອນການແຈ້ງເຕືອນອອກໄປ."</string>
+ <string name="battery_low_intro" msgid="5148725009653088790">"ຕົວປະຢັດແບັດເຕີຣີຈະເປີດໃຊ້ຮູບແບບສີສັນມືດ, ຈຳກັດການເຄື່ອນໄຫວໃນພື້ນຫຼັງ ແລະ ເລື່ອນການແຈ້ງເຕືອນອອກໄປ."</string>
<string name="battery_low_percent_format" msgid="4276661262843170964">"ຍັງ​ເຫຼືອ <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="invalid_charger_title" msgid="938685362320735167">"ບໍ່ສາມາດສາກຜ່ານ USB ໄດ້"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"ກະລຸນາໃຊ້ຕົວສາກທີ່ມາພ້ອມກັບອຸປະກອນຂອງທ່ານ"</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"ເປີດໃຊ້ຕົວປະຢັດແບັດເຕີຣີບໍ?"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"ກ່ຽວກັບຕົວປະຢັດແບັດເຕີຣີ"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"ເປີດ​ໃຊ້"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"ເປີດໃຊ້ຕົວປະຢັດແບັດເຕີຣີ"</string>
+ <string name="battery_saver_start_action" msgid="8353766979886287140">"ເປີດໃຊ້"</string>
+ <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"ບໍ່, ຂອບໃຈ"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"ໝຸນໜ້າຈໍອັດຕະໂນມັດ"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"ອະນຸຍາດໃຫ້ <xliff:g id="APPLICATION">%1$s</xliff:g> ເຂົ້າເຖິງ <xliff:g id="USB_DEVICE">%2$s</xliff:g> ໄດ້ບໍ?"</string>
<string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"ອະນຸຍາດໃຫ້ <xliff:g id="APPLICATION">%1$s</xliff:g> ເຂົ້າເຖິງ <xliff:g id="USB_DEVICE">%2$s</xliff:g> ໄດ້ບໍ?\nແອັບນີ້ບໍ່ໄດ້ຮັບອະນຸາດໃຫ້ບັນທຶກໄດ້ແຕ່ສາມາດບັນທຶກສຽງໄດ້ຜ່ານອຸປະກອນ USB ນີ້."</string>
@@ -128,6 +131,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"ພິສູດຢືນຢັນໃບໜ້າແລ້ວ"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"ຢືນຢັນແລ້ວ"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"ແຕະຢືນຢັນເພື່ອສຳເລັດ"</string>
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"ປົດລັອກດ້ວຍໜ້າຂອງທ່ານແລ້ວ. ກົດເພື່ອສືບຕໍ່."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"ຮັບຮອງຄວາມຖືກຕ້ອງແລ້ວ"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"ໃຊ້ PIN"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"ໃຊ້ຮູບແບບ"</string>
@@ -181,6 +185,7 @@
<string name="accessibility_desc_close" msgid="8293708213442107755">"ປິດ"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"ງຽບທັງໝົດ"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"ໂມງປຸກເທົ່ານັ້ນ"</string>
+ <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"ຫ້າມລົບກວນ."</string>
<string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"Bluetooth."</string>
<string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"Bluetooth ເປີດ."</string>
<string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"ຕັ້ງໂມງປຸກ <xliff:g id="TIME">%s</xliff:g> ແລ້ວ."</string>
@@ -205,6 +210,7 @@
<string name="dessert_case" msgid="9104973640704357717">"ກ່ອງຂອງຫວານ"</string>
<string name="start_dreams" msgid="9131802557946276718">"ພາບພັກໜ້າຈໍ"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
+ <string name="quick_settings_dnd_label" msgid="7728690179108024338">"ຫ້າມລົບກວນ"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"ບໍ່​ມີ​ອຸ​ປະ​ກອນ​ທີ່​ສາ​ມາດ​ຈັບ​ຄູ່​ໄດ້"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"ແບັດເຕີຣີ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
@@ -348,6 +354,7 @@
<string name="notification_section_header_alerting" msgid="5581175033680477651">"ການແຈ້ງເຕືອນ"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"ການສົນທະນາ"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"ລຶບລ້າງການແຈ້ງເຕືອນແບບງຽບທັງໝົດ"</string>
+ <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"ຢຸດການແຈ້ງເຕືອນໂດຍໂໝດຫ້າມລົບກວນແລ້ວ"</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"ເລີ່ມດຽວນີ້"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"ບໍ່ມີການແຈ້ງເຕືອນ"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"ອຸປະກອນນີ້ແມ່ນຈັດການໂດຍພໍ່ແມ່ຂອງທ່ານ"</string>
@@ -452,8 +459,8 @@
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"ປົດລັອກເພື່ອໃຊ້"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"ເກີດບັນຫາໃນການໂຫຼດບັດຂອງທ່ານ, ກະລຸນາລອງໃໝ່ໃນພາຍຫຼັງ"</string>
<string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"ການຕັ້ງຄ່າໜ້າຈໍລັອກ"</string>
- <string name="qr_code_scanner_title" msgid="5660820608548306581">"ລະຫັດ QR"</string>
- <string name="qr_code_scanner_description" msgid="7937603775306661863">"ແຕະເພື່ອສະແກນ"</string>
+ <!-- no translation found for qr_code_scanner_title (5290201053875420785) -->
+ <skip />
<string name="status_bar_work" msgid="5238641949837091056">"​ໂປຣ​ໄຟລ໌​ບ່ອນ​ເຮັດ​ວຽກ"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"ໂໝດເຮືອ​ບິນ"</string>
<string name="zen_alarm_warning" msgid="7844303238486849503">"ທ່ານ​ຈະ​ບໍ່​ໄດ້​ຍິນ​ສຽງ​ໂມງ​ປ <xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -491,6 +498,8 @@
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"&lt;b&gt;ສະຖານະ:&lt;/b&gt; ມີອັນດັບຕ່ຳລົງແລ້ວ"</string>
<string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"ສະແດງຢູ່ເທິງສຸດຂອງການແຈ້ງເຕືອນການສົນທະນາ ແລະ ເປັນຮູບໂປຣໄຟລ໌ຢູ່ໜ້າຈໍລັອກ"</string>
<string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"ສະແດງຢູ່ເທິງສຸດຂອງການແຈ້ງເຕືອນການສົນທະນາ ແລະ ເປັນຮູບໂປຣໄຟລ໌ຢູ່ໜ້າຈໍລັອກ, ປາກົດເປັນຟອງ"</string>
+ <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"ສະແດງຢູ່ເທິງສຸດຂອງການແຈ້ງເຕືອນການສົນທະນາ ແລະ ເປັນຮູບໂປຣໄຟລ໌ຢູ່ໜ້າຈໍລັອກ, ສະແດງໃນໂໝດຫ້າມລົບກວນໄດ້"</string>
+ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"ສະແດງຢູ່ເທິງສຸດຂອງການແຈ້ງເຕືອນການສົນທະນາ ແລະ ເປັນຮູບໂປຣໄຟລ໌ຢູ່ໜ້າຈໍລັອກ, ປາກົດເປັນຟອງ, ສະແດງໃນໂໝດຫ້າມລົບກວນໄດ້"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"ສຳຄັນ"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> ບໍ່ຮອງຮັບຄຸນສົມບັດການສົນທະນາ"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"ບໍ່ສາມາດແກ້ໄຂການແຈ້ງເຕືອນເຫຼົ່ານີ້ໄດ້."</string>
@@ -566,6 +575,7 @@
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"ຂໍ້ຄວາມສັ້ນ(SMS)"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"ດົນຕີ"</string>
<string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"ປະຕິທິນ"</string>
+ <string name="volume_and_do_not_disturb" msgid="502044092739382832">"ຫ້າມລົບກວນ"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"ທາງລັດປຸ່ມສຽງ"</string>
<string name="battery" msgid="769686279459897127">"ແບັດເຕີຣີ"</string>
<string name="headset" msgid="4485892374984466437">"​ຊຸດ​ຫູ​ຟັງ"</string>
@@ -684,6 +694,10 @@
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"Wi-Fi ປິດຢູ່"</string>
<string name="bt_is_off" msgid="7436344904889461591">"Bluetooth ປິດຢູ່"</string>
+ <string name="dnd_is_off" msgid="3185706903793094463">"ຫ້າມລົບກວນ ປິດຢູ່"</string>
+ <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"ໂໝດຫ້າມລົບກວນຖືກເປີດໃຊ້ໂດຍກົດອັດຕະໂນມັດ (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"ມີແອັບເປີດໃຊ້ໂໝດຫ້າມລົບກວນ (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"ໂໝດຫ້າມລົບກວນຖືກເປີດໃຊ້ໂດຍກົດອັດຕະໂນມັດ ຫຼື ແອັບໃດໜຶ່ງ."</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"ແອັບທີ່ກຳລັງເຮັດວຽກໃນພື້ນຫຼັງ"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"ແຕະເພື່ອເບິ່ງລາຍລະອຽດການນຳໃຊ້ແບັດເຕີຣີ ແລະ ອິນເຕີເນັດ"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"ປິດອິນເຕີເນັດມືຖືໄວ້ບໍ?"</string>
@@ -708,6 +722,8 @@
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(ວຽກ)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"ໂທລະສັບ"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(ຜ່ານ <xliff:g id="APPLICATION_NAME_S_">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_label" msgid="3385241594101496292">"(<xliff:g id="ATTRIBUTION_LABEL">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_proxy_label" msgid="1111829599659403249">"(<xliff:g id="ATTRIBUTION_LABEL">%1$s</xliff:g> • <xliff:g id="PROXY_LABEL">%2$s</xliff:g>)"</string>
<string name="privacy_type_camera" msgid="7974051382167078332">"ກ້ອງຖ່າຍຮູບ"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"ສະຖານທີ່"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"ໄມໂຄຣໂຟນ"</string>
@@ -806,6 +822,9 @@
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(ຕັດການເຊື່ອມຕໍ່ແລ້ວ)"</string>
<string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"ບໍ່ສາມາດສະຫຼັບໄດ້. ແຕະເພື່ອລອງໃໝ່."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"ຈັບຄູ່ອຸປະກອນໃໝ່"</string>
+ <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"ເພື່ອສົ່ງສັນຍານເຊດຊັນນີ້, ກະລຸນາເປີດແອັບ."</string>
+ <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"ແອັບທີ່ບໍ່ຮູ້ຈັກ"</string>
+ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"ຢຸດການສົ່ງສັນຍານ"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"ໝາຍເລກສ້າງ"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"ສຳເນົາໝາຍເລກສ້າງໄປໃສ່ຄລິບບອດແລ້ວ."</string>
<string name="basic_status" msgid="2315371112182658176">"ເປີດການສົນທະນາ"</string>
@@ -839,6 +858,7 @@
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"ເບິ່ງຂໍ້ຄວາມຫຼ້າສຸດ, ສາຍບໍ່ໄດ້ຮັບ ແລະ ອັບເດດສະຖານະ"</string>
<string name="people_tile_title" msgid="6589377493334871272">"ການສົນທະນາ"</string>
+ <string name="paused_by_dnd" msgid="7856941866433556428">"ຢຸດຊົ່ວຄາວແລ້ວໂດຍໂໝດຫ້າມລົບກວນ"</string>
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> ສົ່ງຂໍ້ຄວາມ: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> ສົ່ງຮູບພາບແລ້ວ"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> ອັບເດດສະຖານະ: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
@@ -877,8 +897,7 @@
<item quantity="other">ແອັບທີ່ນຳໃຊ້ຢູ່ <xliff:g id="COUNT_1">%s</xliff:g> ແອັບ</item>
<item quantity="one">ແອັບທີ່ນຳໃຊ້ຢູ່ <xliff:g id="COUNT_0">%s</xliff:g> ແອັບ</item>
</plurals>
- <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
- <skip />
+ <string name="fgs_dot_content_description" msgid="2865071539464777240">"ຂໍ້ມູນໃໝ່"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"ແອັບທີ່ນຳໃຊ້ຢູ່"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"ຢຸດ"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"ຢຸດແລ້ວ"</string>
@@ -889,8 +908,12 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"ແກ້ໄຂຂໍ້ຄວາມທີ່ສຳເນົາແລ້ວ"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"ແກ້ໄຂຮູບທີ່ສຳເນົາແລ້ວ"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"ສົ່ງໄປຫາອຸປະກອນທີ່ຢູ່ໃກ້ຄຽງ"</string>
- <!-- no translation found for add (81036585205287996) -->
- <skip />
- <!-- no translation found for manage_users (1823875311934643849) -->
- <skip />
+ <string name="add" msgid="81036585205287996">"ເພີ່ມ"</string>
+ <string name="manage_users" msgid="1823875311934643849">"ຈັດການຜູ້ໃຊ້"</string>
+ <string name="drag_split_not_supported" msgid="4326847447699729722">"ການແຈ້ງເຕືອນນີ້ບໍ່ຮອງຮັບການລາກໄປໃສ່ Splitscreen."</string>
+ <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"ບໍ່ສາມາດໃຊ້ Wi‑Fi ໄດ້"</string>
+ <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"ໂໝດຄວາມສຳຄັນ"</string>
+ <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"ຕັ້ງໂມງປຸກແລ້ວ"</string>
+ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"ປິດກ້ອງຖ່າຍຮູບ ແລະ ໄມແລ້ວ"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# ການແຈ້ງເຕືອນ}other{# ການແຈ້ງເຕືອນ}}"</string>
</resources>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 5179ad9d3e15..547d250895ef 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -20,14 +20,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4811759950673118541">"Sistemos NS"</string>
- <string name="battery_low_title" msgid="6891106956328275225">"Akumuliatoriaus energija gali netrukus išsekti"</string>
+ <string name="battery_low_title" msgid="5319680173344341779">"Įjungti Akumuliatoriaus tausojimo priemonę?"</string>
+ <string name="battery_low_description" msgid="3282977755476423966">"Liko <xliff:g id="PERCENTAGE">%s</xliff:g> akumuliatoriaus energijos. Kai naudojama Akumuliatoriaus tausojimo priemonė, įjungiama Tamsioji tema, apribojama veikla fone ir atidedami pranešimai."</string>
+ <string name="battery_low_intro" msgid="5148725009653088790">"Kai naudojama Akumuliatoriaus tausojimo priemonė, įjungiama Tamsioji tema, apribojama veikla fone ir atidedami pranešimai."</string>
<string name="battery_low_percent_format" msgid="4276661262843170964">"Liko <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="invalid_charger_title" msgid="938685362320735167">"Negalima įkrauti naudojant USB"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"Naudokite originalų su įrenginiu pateiktą įkroviklį"</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Įjungti Akumuliatoriaus tausojimo priemonę?"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Apie Akumuliatoriaus tausojimo priemonę"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Įjungti"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"Įjungti Akumuliatoriaus tausojimo priemonę"</string>
+ <string name="battery_saver_start_action" msgid="8353766979886287140">"Įjungti"</string>
+ <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Ne, ačiū"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Automatiškai sukti ekraną"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"Leisti „<xliff:g id="APPLICATION">%1$s</xliff:g>“ pasiekti įrenginį (<xliff:g id="USB_DEVICE">%2$s</xliff:g>)?"</string>
<string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Leisti „<xliff:g id="APPLICATION">%1$s</xliff:g>“ pasiekti įrenginį (<xliff:g id="USB_DEVICE">%2$s</xliff:g>)?\nŠiai programai nebuvo suteiktas leidimas įrašyti, bet ji gali užfiksuoti garsą per šį USB įrenginį."</string>
@@ -128,6 +131,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Veidas autentifikuotas"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Patvirtinta"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Paliesk. „Patvirtinti“, kad užbaigtumėte"</string>
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Atrakinta pagal veidą. Paspauskite, jei norite tęsti."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Autentifikuota"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Naudoti PIN kodą"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Naudoti atrakinimo piešinį"</string>
@@ -181,6 +185,7 @@
<string name="accessibility_desc_close" msgid="8293708213442107755">"Uždaryti"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"visiška tyla"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"tik įspėjimai"</string>
+ <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"Netrukdymo režimas."</string>
<string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"„Bluetooth“."</string>
<string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"„Bluetooth“ įjungtas."</string>
<string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"Signalas nustatytas <xliff:g id="TIME">%s</xliff:g>."</string>
@@ -207,6 +212,7 @@
<string name="dessert_case" msgid="9104973640704357717">"Desertų dėklas"</string>
<string name="start_dreams" msgid="9131802557946276718">"Ekrano užsklanda"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Eternetas"</string>
+ <string name="quick_settings_dnd_label" msgid="7728690179108024338">"Netrukdymo režimas"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Nėra pasiekiamų susietų įrenginių"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Akumuliatorius: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
@@ -354,6 +360,7 @@
<string name="notification_section_header_alerting" msgid="5581175033680477651">"Pranešimai"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Pokalbiai"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Išvalyti visus tylius pranešimus"</string>
+ <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Pranešimai pristabdyti naudojant netrukdymo režimą"</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"Pradėti dabar"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Nėra įspėjimų"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Šį įrenginį tvarko vienas iš tavo tėvų"</string>
@@ -458,8 +465,8 @@
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Atrakinti, kad būtų galima naudoti"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Gaunant korteles kilo problema, bandykite dar kartą vėliau"</string>
<string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Užrakinimo ekrano nustatymai"</string>
- <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR kodas"</string>
- <string name="qr_code_scanner_description" msgid="7937603775306661863">"Palieskite, kad nuskaitytumėte"</string>
+ <!-- no translation found for qr_code_scanner_title (5290201053875420785) -->
+ <skip />
<string name="status_bar_work" msgid="5238641949837091056">"Darbo profilis"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Lėktuvo režimas"</string>
<string name="zen_alarm_warning" msgid="7844303238486849503">"Negirdėsite kito signalo <xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -497,6 +504,8 @@
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"&lt;b&gt;Būsenos:&lt;/b&gt; reitingas sumažintas"</string>
<string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"Rodoma pokalbių pranešimų viršuje ir kaip profilio nuotrauka užrakinimo ekrane"</string>
<string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"Rodoma pokalbių pranešimų viršuje ir kaip profilio nuotrauka užrakinimo ekrane, burbule"</string>
+ <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"Rodoma pokalbių pranešimų viršuje ir kaip profilio nuotrauka užrakinimo ekrane, pertraukia netrukdymo režimą"</string>
+ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Rodoma pokalbių pranešimų viršuje ir kaip profilio nuotrauka užrakinimo ekrane, debesėlyje, pertraukia netrukdymo režimą"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritetiniai"</string>
<string name="no_shortcut" msgid="8257177117568230126">"Programa „<xliff:g id="APP_NAME">%1$s</xliff:g>“ nepalaiko pokalbių funkcijų"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Šių pranešimų keisti negalima."</string>
@@ -576,6 +585,7 @@
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"SMS"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"Muzika"</string>
<string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Kalendorius"</string>
+ <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Netrukdymo režimas"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"Garsumo mygtukų spartusis klavišas"</string>
<string name="battery" msgid="769686279459897127">"Akumuliatorius"</string>
<string name="headset" msgid="4485892374984466437">"Ausinės"</string>
@@ -694,6 +704,10 @@
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"„<xliff:g id="CARRIER_NAME">%1$s</xliff:g>“, <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"„Wi-Fi“ išjungtas"</string>
<string name="bt_is_off" msgid="7436344904889461591">"„Bluetooth“ išjungtas"</string>
+ <string name="dnd_is_off" msgid="3185706903793094463">"Netrukdymo režimas išjungtas"</string>
+ <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"Netrukdymo režimą įjungė automatinė taisyklė (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"Netrukdymo režimą įjungė programa (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"Netrukdymo režimą įjungė automatinė taisyklė arba programa."</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"Programos, veikiančios fone"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"Palieskite ir sužinokite išsamios informacijos apie akumuliatoriaus bei duomenų naudojimą"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Išjungti mobiliojo ryšio duomenis?"</string>
@@ -718,6 +732,8 @@
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(darbas)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"Telefono skambutis"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(naud. <xliff:g id="APPLICATION_NAME_S_">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_label" msgid="3385241594101496292">"(<xliff:g id="ATTRIBUTION_LABEL">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_proxy_label" msgid="1111829599659403249">"(<xliff:g id="ATTRIBUTION_LABEL">%1$s</xliff:g> • <xliff:g id="PROXY_LABEL">%2$s</xliff:g>)"</string>
<string name="privacy_type_camera" msgid="7974051382167078332">"fotoaparatą"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"vietovę"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofoną"</string>
@@ -818,6 +834,9 @@
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(atjungta)"</string>
<string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Nepavyko perjungti. Bandykite vėl palietę."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Naujo įrenginio susiejimas"</string>
+ <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Jei norite perduoti šį seansą, atidarykite programą."</string>
+ <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Nežinoma programa"</string>
+ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Sustabdyti perdavimą"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Versijos numeris"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Versijos numeris nukopijuotas į iškarpinę."</string>
<string name="basic_status" msgid="2315371112182658176">"Atidaryti pokalbį"</string>
@@ -851,6 +870,7 @@
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g> +"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Peržiūrėkite naujausius pranešimus, praleistus skambučius ir būsenos atnaujinimus"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Pokalbis"</string>
+ <string name="paused_by_dnd" msgid="7856941866433556428">"Pristabdyta dėl netrukdymo režimo"</string>
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> išsiuntė pranešimą: „<xliff:g id="NOTIFICATION">%2$s</xliff:g>“"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> išsiuntė vaizdą"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> atnaujino būseną: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
@@ -891,8 +911,7 @@
<item quantity="many"><xliff:g id="COUNT_1">%s</xliff:g> aktyvios programos</item>
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> aktyvių programų</item>
</plurals>
- <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
- <skip />
+ <string name="fgs_dot_content_description" msgid="2865071539464777240">"Nauja informacija"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Aktyvios programos"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Sustabdyti"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Sustabdyta"</string>
@@ -903,8 +922,12 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Redaguoti nukopijuotą tekstą"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Redaguoti nukopijuotą vaizdą"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Siųsti į įrenginį netoliese"</string>
- <!-- no translation found for add (81036585205287996) -->
- <skip />
- <!-- no translation found for manage_users (1823875311934643849) -->
- <skip />
+ <string name="add" msgid="81036585205287996">"Pridėti"</string>
+ <string name="manage_users" msgid="1823875311934643849">"Tvarkyti naudotojus"</string>
+ <string name="drag_split_not_supported" msgid="4326847447699729722">"Šio pranešimo vilkimas išskaidyto ekrano režimu nepalaikomas."</string>
+ <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"„Wi‑Fi“ ryšys nepasiekiamas"</string>
+ <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Prioriteto režimas"</string>
+ <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Signalas nustatytas"</string>
+ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Vaizdo kamera ir mikrofonas išjungti"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# pranešimas}one{# pranešimas}few{# pranešimai}many{# pranešimo}other{# pranešimų}}"</string>
</resources>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 63b6b2e01d96..5e79f75557be 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -20,14 +20,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4811759950673118541">"Sistēmas UI"</string>
- <string name="battery_low_title" msgid="6891106956328275225">"Akumulators, iespējams, drīz izlādēsies"</string>
+ <string name="battery_low_title" msgid="5319680173344341779">"Vai ieslēgt akumulatora enerģijas taupīšanas režīmu?"</string>
+ <string name="battery_low_description" msgid="3282977755476423966">"Atlikušais akumulatora uzlādes līmenis: <xliff:g id="PERCENTAGE">%s</xliff:g>. Akumulatora enerģijas taupīšanas režīmā tiek ieslēgts tumšais motīvs, ierobežotas darbības fonā un aizkavēti paziņojumi."</string>
+ <string name="battery_low_intro" msgid="5148725009653088790">"Akumulatora enerģijas taupīšanas režīmā tiek ieslēgts tumšais motīvs, ierobežotas darbības fonā un aizkavēti paziņojumi."</string>
<string name="battery_low_percent_format" msgid="4276661262843170964">"Atlikuši <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="invalid_charger_title" msgid="938685362320735167">"Nevar veikt uzlādi, izmantojot USB"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"Izmantojiet ierīces komplektācijā iekļauto lādētāju"</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Vai ieslēgt akumulatora enerģijas taupīšanas režīmu?"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Par akumulatora enerģijas taupīšanas režīmu"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Ieslēgt"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"Ieslēgt akumulatora enerģijas taupīšanas režīmu"</string>
+ <string name="battery_saver_start_action" msgid="8353766979886287140">"Ieslēgt"</string>
+ <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Nē, paldies"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Automātiska ekrāna pagriešana"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"Vai atļaut lietotnei <xliff:g id="APPLICATION">%1$s</xliff:g> piekļūt šai ierīcei: <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
<string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Vai atļaut lietotnei <xliff:g id="APPLICATION">%1$s</xliff:g> piekļūt ierīcei “<xliff:g id="USB_DEVICE">%2$s</xliff:g>”?\nŠai lietotnei nav piešķirta ierakstīšanas atļauja, taču tā varētu tvert audio, izmantojot šo USB ierīci."</string>
@@ -128,6 +131,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Seja autentificēta"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Apstiprināts"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Lai pabeigtu, pieskarieties Apstiprināt"</string>
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Sākta autorizācija pēc sejas. Nospiediet, lai turpinātu."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Autentifikācija veikta"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Izmantot PIN"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Izmantot kombināciju"</string>
@@ -181,6 +185,7 @@
<string name="accessibility_desc_close" msgid="8293708213442107755">"Aizvērt"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"pilnīgs klusums"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"tikai signāli"</string>
+ <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"Režīms “Netraucēt”."</string>
<string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"Bluetooth."</string>
<string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"Bluetooth savienojums ir ieslēgts."</string>
<string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"Signāls ir iestatīts uz: <xliff:g id="TIME">%s</xliff:g>."</string>
@@ -206,6 +211,7 @@
<string name="dessert_case" msgid="9104973640704357717">"Saldo ēdienu stends"</string>
<string name="start_dreams" msgid="9131802557946276718">"Ekrānsaudzētājs"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Tīkls Ethernet"</string>
+ <string name="quick_settings_dnd_label" msgid="7728690179108024338">"Režīms “Netraucēt”"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Nav pieejama neviena pārī savienota ierīce."</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Akumulators: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
@@ -351,6 +357,7 @@
<string name="notification_section_header_alerting" msgid="5581175033680477651">"Paziņojumi"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Sarunas"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Notīrīt visus klusos paziņojumus"</string>
+ <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Paziņojumi pārtraukti, izmantojot iestatījumu “Netraucēt”"</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"Sākt tūlīt"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Nav paziņojumu"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Šo ierīci pārvalda viens no jūsu vecākiem."</string>
@@ -455,8 +462,8 @@
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Lai izmantotu, atbloķējiet ekrānu"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Ienesot jūsu kartes, radās problēma. Lūdzu, vēlāk mēģiniet vēlreiz."</string>
<string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Bloķēšanas ekrāna iestatījumi"</string>
- <string name="qr_code_scanner_title" msgid="5660820608548306581">"Ātrās atbildes kods"</string>
- <string name="qr_code_scanner_description" msgid="7937603775306661863">"Pieskarieties, lai skenētu"</string>
+ <!-- no translation found for qr_code_scanner_title (5290201053875420785) -->
+ <skip />
<string name="status_bar_work" msgid="5238641949837091056">"Darba profils"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Lidojuma režīms"</string>
<string name="zen_alarm_warning" msgid="7844303238486849503">"Nākamais signāls (<xliff:g id="WHEN">%1$s</xliff:g>) netiks atskaņots."</string>
@@ -494,6 +501,8 @@
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"&lt;b&gt;Statuss:&lt;/b&gt; rangs pazemināts"</string>
<string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"Parādās sarunu paziņojumu augšdaļā un kā profila attēls bloķēšanas ekrānā."</string>
<string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"Parādās sarunu paziņojumu augšdaļā un kā profila attēls bloķēšanas ekrānā, arī kā burbulis."</string>
+ <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"Parādās sarunu paziņojumu augšdaļā un kā profila attēls bloķēšanas ekrānā, pārtrauc režīmu “Netraucēt”."</string>
+ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Parādās sarunu paziņojumu augšdaļā un kā profila attēls bloķēšanas ekrānā, arī kā burbulis, pārtrauc režīmu “Netraucēt”."</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritārs"</string>
<string name="no_shortcut" msgid="8257177117568230126">"Lietotnē <xliff:g id="APP_NAME">%1$s</xliff:g> netiek atbalstītas sarunu funkcijas."</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Šos paziņojumus nevar modificēt."</string>
@@ -571,6 +580,7 @@
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"Īsziņas"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"Mūzika"</string>
<string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Kalendārs"</string>
+ <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Režīms “Netraucēt”"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"Skaļuma pogu saīsne"</string>
<string name="battery" msgid="769686279459897127">"Akumulators"</string>
<string name="headset" msgid="4485892374984466437">"Austiņas"</string>
@@ -689,6 +699,10 @@
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"Wi-Fi ir izslēgts"</string>
<string name="bt_is_off" msgid="7436344904889461591">"Bluetooth ir izslēgts"</string>
+ <string name="dnd_is_off" msgid="3185706903793094463">"Režīms “Netraucēt” ir izslēgts"</string>
+ <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"Režīmu “Netraucēt” ieslēdza automātiska kārtula (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"Režīmu “Netraucēt” ieslēdza lietotne (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"Režīmu “Netraucēt” ieslēdza automātiska kārtula vai lietotne."</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"Lietotnes, kas darbojas fonā"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"Pieskarieties, lai skatītu detalizētu informāciju par akumulatora un datu lietojumu"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Vai izslēgt mobilos datus?"</string>
@@ -713,6 +727,8 @@
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(darbs)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"Tālruņa zvans"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(izmantojot: <xliff:g id="APPLICATION_NAME_S_">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_label" msgid="3385241594101496292">"(<xliff:g id="ATTRIBUTION_LABEL">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_proxy_label" msgid="1111829599659403249">"(<xliff:g id="ATTRIBUTION_LABEL">%1$s</xliff:g> • <xliff:g id="PROXY_LABEL">%2$s</xliff:g>)"</string>
<string name="privacy_type_camera" msgid="7974051382167078332">"kamera"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"atrašanās vieta"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofons"</string>
@@ -812,6 +828,9 @@
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(savienojums pārtraukts)"</string>
<string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Nevar pārslēgt. Pieskarieties, lai mēģinātu vēlreiz."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Savienošana pārī ar jaunu ierīci"</string>
+ <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Lai apraidītu šo sesiju, lūdzu, atveriet lietotni."</string>
+ <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Nezināma lietotne"</string>
+ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Apturēt apraidi"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Versijas numurs"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Versijas numurs ir kopēts starpliktuvē."</string>
<string name="basic_status" msgid="2315371112182658176">"Atvērt sarunu"</string>
@@ -845,6 +864,7 @@
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Skatiet jaunākos ziņojumus, neatbildētos zvanus un statusa atjauninājumus."</string>
<string name="people_tile_title" msgid="6589377493334871272">"Saruna"</string>
+ <string name="paused_by_dnd" msgid="7856941866433556428">"Rādīšana pārtraukta režīma Netraucēt dēļ"</string>
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> nosūtīja ziņojumu: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> nosūtīja attēlu"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> atjaunināja statusu: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
@@ -884,8 +904,7 @@
<item quantity="one"><xliff:g id="COUNT_1">%s</xliff:g> aktīva lietotne</item>
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> aktīvas lietotnes</item>
</plurals>
- <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
- <skip />
+ <string name="fgs_dot_content_description" msgid="2865071539464777240">"Jauna informācija"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Aktīvās lietotnes"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Apturēt"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Apturēta"</string>
@@ -893,14 +912,15 @@
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Nokopēts"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"No lietotnes <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Noraidīt ar kopēšanu saistīto lietotāja saskarnes elementu"</string>
- <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
- <skip />
- <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
- <skip />
- <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
- <skip />
- <!-- no translation found for add (81036585205287996) -->
- <skip />
- <!-- no translation found for manage_users (1823875311934643849) -->
- <skip />
+ <string name="clipboard_edit_text_description" msgid="805254383912962103">"Rediģēt nokopēto tekstu"</string>
+ <string name="clipboard_edit_image_description" msgid="8904857948976041306">"Rediģēt nokopēto attēlu"</string>
+ <string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Sūtīt uz tuvumā esošu ierīci"</string>
+ <string name="add" msgid="81036585205287996">"Pievienot"</string>
+ <string name="manage_users" msgid="1823875311934643849">"Pārvaldīt lietotājus"</string>
+ <string name="drag_split_not_supported" msgid="4326847447699729722">"Šis paziņojums neatbalsta vilkšanu uz dalīto ekrānu."</string>
+ <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi nav pieejams"</string>
+ <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Prioritātes režīms"</string>
+ <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Signāls ir iestatīts"</string>
+ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Kamera un mikrofons ir izslēgti"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# paziņojums}zero{# paziņojumu}one{# paziņojums}other{# paziņojumi}}"</string>
</resources>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index 7642a9af994e..0bde00b24b63 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -20,14 +20,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4811759950673118541">"Кориснички интерфејс на систем"</string>
- <string name="battery_low_title" msgid="6891106956328275225">"Наскоро може да снема батерија"</string>
+ <string name="battery_low_title" msgid="5319680173344341779">"Да се вклучи „Штедачот на батерија“?"</string>
+ <string name="battery_low_description" msgid="3282977755476423966">"Имате уште <xliff:g id="PERCENTAGE">%s</xliff:g> батерија. „Штедачот на батерија“ ја вклучува „Темната тема“, ја ограничува активноста во заднина и ги одложува известувањата."</string>
+ <string name="battery_low_intro" msgid="5148725009653088790">"„Штедачот на батерија“ ја вклучува „Темната тема“, ја ограничува активноста во заднина и ги одложува известувањата."</string>
<string name="battery_low_percent_format" msgid="4276661262843170964">"Преостануваат <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="invalid_charger_title" msgid="938685362320735167">"Не може да се полни преку USB"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"Користете го полначот што дојде со вашиот уред"</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Да се вклучи „Штедачот на батерија“?"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"За „Штедачот на батерија“"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Вклучи"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"Да се вклучи штедачот на батерија?"</string>
+ <string name="battery_saver_start_action" msgid="8353766979886287140">"Вклучи"</string>
+ <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Не, фала"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Автоматско ротирање на екранот"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"Ќе дозволите <xliff:g id="APPLICATION">%1$s</xliff:g> да пристапува до <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
<string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Дали дозволувате <xliff:g id="APPLICATION">%1$s</xliff:g> да пристапи до <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nНа апликацијава не ѝ е доделена дозвола за снимање, но може да снима аудио преку овој USB-уред."</string>
@@ -128,6 +131,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Лицето е проверено"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Потврдено"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Допрете „Потврди“ за да се заврши"</string>
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Отклучен со вашето лице. Притиснете за да продолжите."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Проверена"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Користи PIN"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Користи шема"</string>
@@ -181,6 +185,7 @@
<string name="accessibility_desc_close" msgid="8293708213442107755">"Затвори"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"целосна тишина"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"само аларми"</string>
+ <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"Не вознемирувај."</string>
<string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"Bluetooth."</string>
<string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"Bluetooth е вклучен."</string>
<string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"Аларм наместен за <xliff:g id="TIME">%s</xliff:g>."</string>
@@ -205,6 +210,7 @@
<string name="dessert_case" msgid="9104973640704357717">"Dessert Case"</string>
<string name="start_dreams" msgid="9131802557946276718">"Заштитник на екран"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Етернет"</string>
+ <string name="quick_settings_dnd_label" msgid="7728690179108024338">"Не вознемирувај"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Нема достапни спарени уреди"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> батерија"</string>
@@ -348,6 +354,7 @@
<string name="notification_section_header_alerting" msgid="5581175033680477651">"Известувања"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Разговори"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Избриши ги сите бесчујни известувања"</string>
+ <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Известувањата се паузирани од „Не вознемирувај“"</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"Започни сега"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Нема известувања"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Родителот управува со уредов"</string>
@@ -452,8 +459,8 @@
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Отклучете за да користите"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Имаше проблем при преземањето на картичките. Обидете се повторно подоцна"</string>
<string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Поставки за заклучен екран"</string>
- <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR-код"</string>
- <string name="qr_code_scanner_description" msgid="7937603775306661863">"Допрете за скенирање"</string>
+ <!-- no translation found for qr_code_scanner_title (5290201053875420785) -->
+ <skip />
<string name="status_bar_work" msgid="5238641949837091056">"Работен профил"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Авионски режим"</string>
<string name="zen_alarm_warning" msgid="7844303238486849503">"Нема да го слушнете следниот аларм <xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -491,6 +498,8 @@
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"&lt;b&gt;Статус:&lt;/b&gt; рангирано пониско"</string>
<string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"Се прикажува најгоре во известувањата за разговор и како профилна слика на заклучен екран"</string>
<string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"Се прикажува најгоре во известувањата за разговор и како профилна слика на заклучен екран, се појавува како балонче"</string>
+ <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"Се прикажува најгоре во известувањата за разговор и како профилна слика на заклучен екран, го прекинува „Не вознемирувај“"</string>
+ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Се прикажува најгоре во известувањата за разговор и како профилна слика на заклучен екран, се појавува како балонче, го прекинува „Не вознемирувај“"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Приоритетно"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> не поддржува функции за разговор"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Овие известувања не може да се изменат"</string>
@@ -566,6 +575,7 @@
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"SMS"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"Музика"</string>
<string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Календар"</string>
+ <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Не вознемирувај"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"Кратенка за копчињата за јачина на звук"</string>
<string name="battery" msgid="769686279459897127">"Батерија"</string>
<string name="headset" msgid="4485892374984466437">"Слушалки"</string>
@@ -684,6 +694,10 @@
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"Wi-Fi е исклучено"</string>
<string name="bt_is_off" msgid="7436344904889461591">"Bluetooth е исклучен"</string>
+ <string name="dnd_is_off" msgid="3185706903793094463">"„Не вознемирувај“ е исклучено"</string>
+ <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"Едно автоматско правило (<xliff:g id="ID_1">%s</xliff:g>) ја вклучи „Не вознемирувај“."</string>
+ <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"Една апликација (<xliff:g id="ID_1">%s</xliff:g>) ја вклучи „Не вознемирувај“."</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"Едно автоматско правило или апликација ја вклучи „Не вознемирувај“."</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"Апликациите се извршуваат во заднина"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"Допрете за детали за батеријата и потрошениот интернет"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Да се исклучи мобилниот интернет?"</string>
@@ -708,6 +722,8 @@
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(службена)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"Телефонски повик"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(преку <xliff:g id="APPLICATION_NAME_S_">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_label" msgid="3385241594101496292">"(<xliff:g id="ATTRIBUTION_LABEL">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_proxy_label" msgid="1111829599659403249">"(<xliff:g id="ATTRIBUTION_LABEL">%1$s</xliff:g> • <xliff:g id="PROXY_LABEL">%2$s</xliff:g>)"</string>
<string name="privacy_type_camera" msgid="7974051382167078332">"камера"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"локација"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"микрофон"</string>
@@ -806,6 +822,9 @@
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(врската е прекината)"</string>
<string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Не се префрла. Допрете и обидете се пак."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Спарете нов уред"</string>
+ <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"За да ја емитувате сесијава, отворете ја апликацијата."</string>
+ <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Непозната апликација"</string>
+ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Сопри со емитување"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Број на верзија"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Бројот на верзијата е копиран во привремената меморија."</string>
<string name="basic_status" msgid="2315371112182658176">"Започни разговор"</string>
@@ -839,6 +858,7 @@
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Видете ги неодамнешните пораки, пропуштени повици и промени на статусот"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Разговор"</string>
+ <string name="paused_by_dnd" msgid="7856941866433556428">"Паузирано од „Не вознемирувај“"</string>
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> испрати порака: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> испрати слика"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> има ажурирање на статусот: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
@@ -877,8 +897,7 @@
<item quantity="one"><xliff:g id="COUNT_1">%s</xliff:g> активна апликација</item>
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> активни апликации</item>
</plurals>
- <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
- <skip />
+ <string name="fgs_dot_content_description" msgid="2865071539464777240">"Нови информации"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Активни апликации"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Крај"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Запрено"</string>
@@ -886,14 +905,15 @@
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Копирано"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Од <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Отфрли го корисничкиот интерфејс за копирање"</string>
- <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
- <skip />
- <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
- <skip />
- <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
- <skip />
- <!-- no translation found for add (81036585205287996) -->
- <skip />
- <!-- no translation found for manage_users (1823875311934643849) -->
- <skip />
+ <string name="clipboard_edit_text_description" msgid="805254383912962103">"Изменете го копираниот текст"</string>
+ <string name="clipboard_edit_image_description" msgid="8904857948976041306">"Изменете ја копираната слика"</string>
+ <string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Испратете до уред во близина"</string>
+ <string name="add" msgid="81036585205287996">"Додај"</string>
+ <string name="manage_users" msgid="1823875311934643849">"Управувајте со корисниците"</string>
+ <string name="drag_split_not_supported" msgid="4326847447699729722">"Известувањево не поддржува влечење на поделен екран."</string>
+ <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi е недостапна"</string>
+ <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Приоритетен режим"</string>
+ <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Алармот е наместен"</string>
+ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Камерата и микрофонот се исклучени"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# известување}one{# известување}other{# известувања}}"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 1bde5a008916..e7ccae0997c6 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -20,14 +20,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4811759950673118541">"സിസ്റ്റം UI"</string>
- <string name="battery_low_title" msgid="6891106956328275225">"ബാറ്ററി ഉടൻ തീർന്നേക്കാം"</string>
+ <string name="battery_low_title" msgid="5319680173344341779">"ബാറ്ററി ലാഭിക്കൽ ഓണാക്കണോ?"</string>
+ <string name="battery_low_description" msgid="3282977755476423966">"നിങ്ങളുടെ ബാറ്ററിയിൽ <xliff:g id="PERCENTAGE">%s</xliff:g> ചാർജ് ശേഷിക്കുന്നു. ബാറ്ററി ലാഭിക്കൽ, ഡാർക്ക് തീം ഓണാക്കുകയും പശ്ചാത്തല ആക്‌റ്റിവിറ്റി നിയന്ത്രിക്കുകയും അറിയിപ്പുകൾ വെെകിപ്പിക്കുകയും ചെയ്യുന്നു."</string>
+ <string name="battery_low_intro" msgid="5148725009653088790">"ബാറ്ററി ലാഭിക്കൽ, ഡാർക്ക് തീം ഓണാക്കുകയും പശ്ചാത്തല ആക്‌റ്റിവിറ്റി നിയന്ത്രിക്കുകയും അറിയിപ്പുകൾ വെെകിപ്പിക്കുകയും ചെയ്യുന്നു."</string>
<string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> ശേഷിക്കുന്നു"</string>
<string name="invalid_charger_title" msgid="938685362320735167">"USB വഴി ചാർജ് ചെയ്യാനാകില്ല"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"ഉപകരണത്തിനൊപ്പം ലഭിച്ച ചാർജർ ഉപയോഗിക്കുക"</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"ബാറ്ററി ലാഭിക്കൽ ഓണാക്കണോ?"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"ബാറ്ററി ലാഭിക്കലിനെ കുറിച്ച്"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"ഓൺ ചെയ്യുക"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"ബാറ്ററി ലാഭിക്കൽ ഓണാക്കുക"</string>
+ <string name="battery_saver_start_action" msgid="8353766979886287140">"ഓണാക്കുക"</string>
+ <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"വേണ്ട"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"സ്‌ക്രീൻ സ്വയമേ തിരിയുക"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> ആക്‌സസ് ചെയ്യാൻ <xliff:g id="APPLICATION">%1$s</xliff:g>-നെ അനുവദിക്കണോ?"</string>
<string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> ആക്‌സസ് ചെയ്യാൻ <xliff:g id="APPLICATION">%1$s</xliff:g> എന്നതിനെ അനുവദിക്കണോ?\nഈ ആപ്പിന് റെക്കോർഡ് അനുമതി നൽകിയിട്ടില്ല, എന്നാൽ ഈ USB ഉപകരണത്തിലൂടെ ഓഡിയോ ക്യാപ്‌ചർ ചെയ്യാനാവും."</string>
@@ -128,6 +131,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"മുഖം പരിശോധിച്ചുറപ്പിച്ചു"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"സ്ഥിരീകരിച്ചു"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"പൂർത്തിയാക്കാൻ സ്ഥിരീകരിക്കുക ടാപ്പ് ചെയ്യൂ"</string>
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"മുഖം ഉപയോഗിച്ച് അൺലോക്ക് ചെയ്‌തു. തുടരാൻ അമർത്തുക."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"പരിശോധിച്ചുറപ്പിച്ചു"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"പിൻ ഉപയോഗിക്കുക"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"പാറ്റേൺ ഉപയോഗിക്കുക"</string>
@@ -181,6 +185,7 @@
<string name="accessibility_desc_close" msgid="8293708213442107755">"അവസാനിപ്പിക്കുക"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"പൂർണ്ണ നിശബ്‌ദത"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"അലാറങ്ങൾ മാത്രം"</string>
+ <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"ശല്യപ്പെടുത്തരുത്."</string>
<string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"Bluetooth"</string>
<string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"ബ്ലൂടൂത്ത് ഓണാണ്."</string>
<string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"<xliff:g id="TIME">%s</xliff:g>-ന് അലാറം സജ്ജീകരിച്ചു."</string>
@@ -205,6 +210,7 @@
<string name="dessert_case" msgid="9104973640704357717">"ഡെസേർട്ട് കെയ്സ്"</string>
<string name="start_dreams" msgid="9131802557946276718">"സ്ക്രീൻ സേവർ"</string>
<string name="ethernet_label" msgid="2203544727007463351">"ഇതർനെറ്റ്"</string>
+ <string name="quick_settings_dnd_label" msgid="7728690179108024338">"ശല്യപ്പെടുത്തരുത്"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"ജോടിയാക്കിയ ഉപകരണങ്ങളൊന്നും ലഭ്യമല്ല"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> ബാറ്ററി"</string>
@@ -348,6 +354,7 @@
<string name="notification_section_header_alerting" msgid="5581175033680477651">"അറിയിപ്പുകൾ"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"സംഭാഷണങ്ങൾ"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"എല്ലാ നിശബ്‌ദ അറിയിപ്പുകളും മായ്ക്കുക"</string>
+ <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"\'ശല്യപ്പെടുത്തരുത്\' വഴി അറിയിപ്പുകൾ താൽക്കാലികമായി നിർത്തി"</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"ഇപ്പോൾ ആരംഭിക്കുക"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"അറിയിപ്പുകൾ ഒന്നുമില്ല"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"ഈ ഉപകരണം മാനേജ് ചെയ്യുന്നത് നിങ്ങളുടെ രക്ഷിതാവാണ്"</string>
@@ -452,8 +459,8 @@
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"ഉപയോഗിക്കാൻ അൺലോക്ക് ചെയ്യുക"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"നിങ്ങളുടെ കാർഡുകൾ ലഭ്യമാക്കുന്നതിൽ ഒരു പ്രശ്‌നമുണ്ടായി, പിന്നീട് വീണ്ടും ശ്രമിക്കുക"</string>
<string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"ലോക്ക് സ്ക്രീൻ ക്രമീകരണം"</string>
- <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR കോഡ്"</string>
- <string name="qr_code_scanner_description" msgid="7937603775306661863">"സ്‌കാൻ ചെയ്യാൻ ടാപ്പ് ചെയ്യുക"</string>
+ <!-- no translation found for qr_code_scanner_title (5290201053875420785) -->
+ <skip />
<string name="status_bar_work" msgid="5238641949837091056">"ഔദ്യോഗിക പ്രൊഫൈൽ"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"ഫ്ലൈറ്റ് മോഡ്"</string>
<string name="zen_alarm_warning" msgid="7844303238486849503">"<xliff:g id="WHEN">%1$s</xliff:g>-നുള്ള നിങ്ങളുടെ അടുത്ത അലാറം കേൾക്കില്ല"</string>
@@ -491,6 +498,8 @@
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"&lt;b&gt;നില:&lt;/b&gt; താഴ്ന്ന റാങ്കിംഗ് നൽകി"</string>
<string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"സംഭാഷണ അറിയിപ്പുകളുടെ മുകളിലും സ്ക്രീൻ ലോക്കായിരിക്കുമ്പോൾ ഒരു പ്രൊഫൈൽ ചിത്രമായും കാണിക്കുന്നു"</string>
<string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"സംഭാഷണ അറിയിപ്പുകളുടെ മുകളിലും സ്ക്രീൻ ലോക്കായിരിക്കുമ്പോൾ ഒരു പ്രൊഫൈൽ ചിത്രമായും കാണിക്കുന്നു, ഒരു ബബിൾ രൂപത്തിൽ ദൃശ്യമാകുന്നു"</string>
+ <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"സംഭാഷണ അറിയിപ്പുകളുടെ മുകളിലും സ്ക്രീൻ ലോക്കായിരിക്കുമ്പോൾ ഒരു പ്രൊഫൈൽ ചിത്രമായും കാണിക്കുന്നു, ശല്യപ്പെടുത്തരുത് മോഡ് തടസ്സപ്പെടുത്തുന്നു"</string>
+ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"സംഭാഷണ അറിയിപ്പുകളുടെ മുകളിലും സ്ക്രീൻ ലോക്കായിരിക്കുമ്പോൾ ഒരു പ്രൊഫൈൽ ചിത്രമായും ബബിൾ രൂപത്തിൽ ദൃശ്യമാകുന്നു, ശല്യപ്പെടുത്തരുത് മോഡ് തടസ്സപ്പെടുത്തുന്നു"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"മുൻഗണന"</string>
<string name="no_shortcut" msgid="8257177117568230126">"സംഭാഷണ ഫീച്ചറുകളെ <xliff:g id="APP_NAME">%1$s</xliff:g> പിന്തുണയ്‌ക്കുന്നില്ല"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"ഈ അറിയിപ്പുകൾ പരിഷ്ക്കരിക്കാനാവില്ല."</string>
@@ -566,6 +575,7 @@
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"SMS:"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"സംഗീതം"</string>
<string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Calendar"</string>
+ <string name="volume_and_do_not_disturb" msgid="502044092739382832">"ശല്യപ്പെടുത്തരുത്"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"വോളിയം ബട്ടൺ കുറുക്കുവഴി"</string>
<string name="battery" msgid="769686279459897127">"ബാറ്ററി"</string>
<string name="headset" msgid="4485892374984466437">"ഹെഡ്‌സെറ്റ്"</string>
@@ -684,6 +694,10 @@
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"വൈഫൈ ഓഫാണ്"</string>
<string name="bt_is_off" msgid="7436344904889461591">"Bluetooth ഓഫാണ്"</string>
+ <string name="dnd_is_off" msgid="3185706903793094463">"\'ശല്യപ്പെടുത്തരുത്\' ഓഫാണ്"</string>
+ <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"സ്വയമേവയുള്ള ഒരു നയം (<xliff:g id="ID_1">%s</xliff:g>) \'ശല്യപ്പെടുത്തരുത്\' ഓണാക്കിയിരിക്കുന്നു."</string>
+ <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"ഒരു ആപ്പ് (<xliff:g id="ID_1">%s</xliff:g>) \'ശല്യപ്പെടുത്തരുത്\' ഓണാക്കിയിരിക്കുന്നു."</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"സ്വയമേവയുള്ള ഒരു നയമോ ആപ്പോ \'ശല്യപ്പെടുത്തരുത്\' ഓണാക്കിയിരിക്കുന്നു."</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"ആപ്പുകൾ പശ്ചാത്തലത്തിൽ റൺ ചെയ്യുന്നു"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"ബാറ്ററി, ഡാറ്റ ഉപയോഗം എന്നിവയുടെ വിശദാംശങ്ങളറിയാൻ ടാപ്പുചെയ്യുക"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"മൊബൈൽ ഡാറ്റ ഓഫാക്കണോ?"</string>
@@ -708,6 +722,8 @@
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(ഔദ്യോഗികം)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"ഫോൺ കോൾ"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(<xliff:g id="APPLICATION_NAME_S_">%s</xliff:g> എന്നതിലൂടെ)"</string>
+ <string name="ongoing_privacy_dialog_attribution_label" msgid="3385241594101496292">"(<xliff:g id="ATTRIBUTION_LABEL">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_proxy_label" msgid="1111829599659403249">"(<xliff:g id="ATTRIBUTION_LABEL">%1$s</xliff:g> • <xliff:g id="PROXY_LABEL">%2$s</xliff:g>)"</string>
<string name="privacy_type_camera" msgid="7974051382167078332">"ക്യാമറ"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"ലൊക്കേഷന്‍"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"മൈക്രോഫോൺ"</string>
@@ -806,6 +822,9 @@
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(വിച്ഛേദിച്ചു)"</string>
<string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"മാറാനാകുന്നില്ല. വീണ്ടും ശ്രമിക്കാൻ ടാപ്പ് ചെയ്യുക."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"പുതിയ ഉപകരണവുമായി ജോടിയാക്കുക"</string>
+ <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"ഈ സെഷൻ കാസ്റ്റ് ചെയ്യാൻ, ആപ്പ് തുറക്കുക."</string>
+ <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"അജ്ഞാതമായ ആപ്പ്"</string>
+ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"കാസ്റ്റ് ചെയ്യുന്നത് നിർത്തുക"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"ബിൽഡ് നമ്പർ"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"ക്ലിപ്പ്ബോർഡിലേക്ക് ബിൽഡ് നമ്പർ പകർത്തി."</string>
<string name="basic_status" msgid="2315371112182658176">"സംഭാഷണം തുറക്കുക"</string>
@@ -839,6 +858,7 @@
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"അടുത്തിടെയുള്ള സന്ദേശങ്ങൾ, മിസ്‌ഡ് കോൾ, സ്റ്റാറ്റസ് അപ്‌ഡേറ്റുകൾ എന്നിവ കാണൂ"</string>
<string name="people_tile_title" msgid="6589377493334871272">"സംഭാഷണം"</string>
+ <string name="paused_by_dnd" msgid="7856941866433556428">"\'ശല്യപ്പെടുത്തരുത്\' ഓണായതിനാൽ തൽക്കാലം നിർത്തി"</string>
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> ഒരു സന്ദേശം അയച്ചു: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g>, ഒരു ചിത്രം അയച്ചു"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> എന്നയാൾ സ്‌റ്റാറ്റസ് അപ്‌ഡേറ്റ് ചെയ്‌തു: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
@@ -877,8 +897,7 @@
<item quantity="other">സജീവമായ <xliff:g id="COUNT_1">%s</xliff:g> ആപ്പുകൾ</item>
<item quantity="one">സജീവമായ <xliff:g id="COUNT_0">%s</xliff:g> ആപ്പ്</item>
</plurals>
- <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
- <skip />
+ <string name="fgs_dot_content_description" msgid="2865071539464777240">"പുതിയ വിവരങ്ങൾ"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"സജീവമായ ആപ്പുകൾ"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"നിർത്തുക"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"നിർത്തി"</string>
@@ -889,8 +908,12 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"പകർത്തിയ ടെക്സ്റ്റ് എഡിറ്റ് ചെയ്യുക"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"പകർത്തിയ ചിത്രം എഡിറ്റ് ചെയ്യുക"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"സമീപത്തുള്ള ഉപകരണത്തിലേക്ക് അയയ്ക്കുക"</string>
- <!-- no translation found for add (81036585205287996) -->
- <skip />
- <!-- no translation found for manage_users (1823875311934643849) -->
- <skip />
+ <string name="add" msgid="81036585205287996">"ചേർക്കുക"</string>
+ <string name="manage_users" msgid="1823875311934643849">"ഉപയോക്താക്കളെ മാനേജ് ചെയ്യുക"</string>
+ <string name="drag_split_not_supported" msgid="4326847447699729722">"സ്പ്ലിറ്റ് സ്ക്രീനിലേക്ക് വലിച്ചിടുന്നതിനെ ഈ അറിയിപ്പ് പിന്തുണയ്ക്കുന്നില്ല."</string>
+ <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"വൈഫൈ ലഭ്യമല്ല"</string>
+ <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"മുൻഗണനാ മോഡ്"</string>
+ <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"അലാറം സജ്ജീകരിച്ചു"</string>
+ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"ക്യാമറയും മൈക്കും ഓഫാണ്"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# അറിയിപ്പ്}other{# അറിയിപ്പുകൾ}}"</string>
</resources>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index c63bd3d7d9dc..b136674ea9d7 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -20,14 +20,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4811759950673118541">"Систем UI"</string>
- <string name="battery_low_title" msgid="6891106956328275225">"Батaрей удахгүй дуусaж болзошгүй"</string>
+ <string name="battery_low_title" msgid="5319680173344341779">"Батарей хэмнэгчийг асаах уу?"</string>
+ <string name="battery_low_description" msgid="3282977755476423966">"Танд <xliff:g id="PERCENTAGE">%s</xliff:g> батарей үлдсэн байна. Батарей хэмнэгч нь Бараан загварыг асааж, дэвсгэрийн үйл ажиллагааг хязгаарлаж мөн мэдэгдлийг саатуулна."</string>
+ <string name="battery_low_intro" msgid="5148725009653088790">"Батарей хэмнэгч нь Бараан загварыг асааж, дэвсгэрийн үйл ажиллагааг хязгаарлаж мөн мэдэгдлийг саатуулна."</string>
<string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> үлдсэн"</string>
<string name="invalid_charger_title" msgid="938685362320735167">"USB-р цэнэглэх боломжгүй байна"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"Төхөөрөмждөө дагалдаж ирсэн цэнэглэгчийг ашиглах"</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Батарей хэмнэгчийг асаах уу?"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Батарей хэмнэгчийн тухай"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Асаах"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"Батарей хэмнэгчийг асаах"</string>
+ <string name="battery_saver_start_action" msgid="8353766979886287140">"Асаах"</string>
+ <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Үгүй, баярлалаа"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Дэлгэцийг автоматаар эргүүлэх"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"<xliff:g id="APPLICATION">%1$s</xliff:g>-г <xliff:g id="USB_DEVICE">%2$s</xliff:g>-д хандахыг зөвшөөрөх үү?"</string>
<string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"<xliff:g id="APPLICATION">%1$s</xliff:g>-д <xliff:g id="USB_DEVICE">%2$s</xliff:g>-д хандахыг зөвшөөрөх үү?\nЭнэ аппад бичих зөвшөөрөл олгогдоогүй ч USB төхөөрөмжөөр дамжуулан аудио бичиж чадсан."</string>
@@ -128,6 +131,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Царайг баталгаажууллаа"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Баталгаажсан"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Дуусгахын тулд баталгаажуулахыг товших"</string>
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Таны царайгаар түгжээг тайлсан. Үргэлжлүүлэхийн тулд дарна уу."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Баталгаажуулагдсан"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"ПИН ашиглах"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Хээ ашиглах"</string>
@@ -181,6 +185,7 @@
<string name="accessibility_desc_close" msgid="8293708213442107755">"Хаах"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"бүх дууг хаах"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"зөвхөн сэрүүлэг"</string>
+ <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"Бүү саад бол."</string>
<string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"Bluetooth."</string>
<string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"Bluetooth идэвхтэй."</string>
<string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"Сэрүүлгийг <xliff:g id="TIME">%s</xliff:g>-д тохируулсан."</string>
@@ -205,6 +210,7 @@
<string name="dessert_case" msgid="9104973640704357717">"Амттаны хайрцаг"</string>
<string name="start_dreams" msgid="9131802557946276718">"Дэлгэц амраагч"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Этернет"</string>
+ <string name="quick_settings_dnd_label" msgid="7728690179108024338">"Бүү саад бол"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Хослуулсан төхөөрөмж байхгүй"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> батерей"</string>
@@ -348,6 +354,7 @@
<string name="notification_section_header_alerting" msgid="5581175033680477651">"Мэдэгдлүүд"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Харилцан яриа"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Бүх чимээгүй мэдэгдлийг арилгах"</string>
+ <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Бүү саад бол горимын түр зогсоосон мэдэгдэл"</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"Одоо эхлүүлэх"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Мэдэгдэл байхгүй"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Энэ төхөөрөмжийг таны эцэг эх удирддаг"</string>
@@ -452,8 +459,7 @@
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Ашиглахын тулд түгжээг тайлах"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Таны картыг авахад асуудал гарлаа. Дараа дахин оролдоно уу"</string>
<string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Түгжигдсэн дэлгэцийн тохиргоо"</string>
- <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR код"</string>
- <string name="qr_code_scanner_description" msgid="7937603775306661863">"Скан хийхийн тулд товшино уу"</string>
+ <string name="qr_code_scanner_title" msgid="5290201053875420785">"QR код скан хийх"</string>
<string name="status_bar_work" msgid="5238641949837091056">"Ажлын профайл"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Нислэгийн горим"</string>
<string name="zen_alarm_warning" msgid="7844303238486849503">"<xliff:g id="WHEN">%1$s</xliff:g>-т та дараагийн сэрүүлгээ сонсохгүй"</string>
@@ -491,6 +497,8 @@
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"&lt;b&gt;Төлөв:&lt;/b&gt; Доогуур зэрэглэл хийсэн"</string>
<string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"Харилцан ярианы дээд талд болон түгжигдсэн дэлгэц дээр профайл зураг байдлаар харуулна"</string>
<string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"Харилцан ярианы мэдэгдлийн дээд талд болон түгжигдсэн дэлгэц дээр профайл зураг байдлаар харуулах бөгөөд бөмбөлөг хэлбэрээр харагдана"</string>
+ <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"Харилцан ярианы мэдэгдлийн дээд талд болон түгжигдсэн дэлгэц дээр профайл зураг байдлаар харуулах бөгөөд Бүү саад бол горимыг тасалдуулна"</string>
+ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Харилцан ярианы мэдэгдлийн дээд талд болон түгжигдсэн дэлгэц дээр профайл зураг байдлаар харуулах бөгөөд бөмбөлөг хэлбэрээр харагдана. Бүү саад бол горимыг тасалдуулна"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Чухал"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> нь харилцан ярианы онцлогуудыг дэмждэггүй"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Эдгээр мэдэгдлийг өөрчлөх боломжгүй."</string>
@@ -566,6 +574,7 @@
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"SMS"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"Хөгжим"</string>
<string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Календарь"</string>
+ <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Бүү саад бол"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"Дууны түвшний товчлуурын товчлол"</string>
<string name="battery" msgid="769686279459897127">"Батарей"</string>
<string name="headset" msgid="4485892374984466437">"Чихэвч"</string>
@@ -684,6 +693,10 @@
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"Wi-Fi унтраалттай байна"</string>
<string name="bt_is_off" msgid="7436344904889461591">"Bluetooth унтраалттай байна"</string>
+ <string name="dnd_is_off" msgid="3185706903793094463">"Бүү саад бол горим унтраалттай байна"</string>
+ <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"Автомат дүрэм (<xliff:g id="ID_1">%s</xliff:g>) Бүү саад бол горимыг асаасан."</string>
+ <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"Апп (<xliff:g id="ID_1">%s</xliff:g>) Бүү саад бол горимыг асаасан."</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"Автомат дүрэм эсвэл апп Бүү саад бол горимыг асаасан."</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"Цаана ажиллаж буй апп"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"Батерей, дата ашиглалтын талаар дэлгэрэнгүйг харахын тулд товшино уу"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Мобайл датаг унтраах уу?"</string>
@@ -708,6 +721,8 @@
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(ажил)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"Утасны дуудлага"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(<xliff:g id="APPLICATION_NAME_S_">%s</xliff:g>-р)"</string>
+ <string name="ongoing_privacy_dialog_attribution_label" msgid="3385241594101496292">"(<xliff:g id="ATTRIBUTION_LABEL">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_proxy_label" msgid="1111829599659403249">"(<xliff:g id="ATTRIBUTION_LABEL">%1$s</xliff:g> • <xliff:g id="PROXY_LABEL">%2$s</xliff:g>)"</string>
<string name="privacy_type_camera" msgid="7974051382167078332">"камер"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"байршил"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"микрофон"</string>
@@ -806,6 +821,9 @@
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(салсан)"</string>
<string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Сэлгэх боломжгүй. Дахин оролдохын тулд товшино уу."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Шинэ төхөөрөмж хослуулах"</string>
+ <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Энэ үйл явдлыг дамжуулахын тулд аппыг нээнэ үү."</string>
+ <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Үл мэдэгдэх апп"</string>
+ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Дамжуулахыг зогсоох"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Хийцийн дугаар"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Хийцийн дугаарыг түр санах ойд хуулсан."</string>
<string name="basic_status" msgid="2315371112182658176">"Харилцан яриаг нээх"</string>
@@ -839,6 +857,7 @@
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Саяхны мессеж, аваагүй дуудлага болон төлөвийн шинэчлэлтийг харах"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Харилцан яриа"</string>
+ <string name="paused_by_dnd" msgid="7856941866433556428">"Бүү саад бол горимоор түр зогсоосон"</string>
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> мессеж илгээсэн: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> зураг илгээсэн"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> төлөвийн шинэчлэлт хийсэн байна: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
@@ -877,8 +896,7 @@
<item quantity="other">Идэвхтэй <xliff:g id="COUNT_1">%s</xliff:g> апп</item>
<item quantity="one">Идэвхтэй <xliff:g id="COUNT_0">%s</xliff:g> апп</item>
</plurals>
- <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
- <skip />
+ <string name="fgs_dot_content_description" msgid="2865071539464777240">"Шинэ мэдээлэл"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Идэвхтэй аппууд"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Зогсоох"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Зогсоосон"</string>
@@ -889,8 +907,12 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Хуулсан текстийг засах"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Хуулсан зургийг засах"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Ойролцоох төхөөрөмж рүү илгээх"</string>
- <!-- no translation found for add (81036585205287996) -->
- <skip />
- <!-- no translation found for manage_users (1823875311934643849) -->
- <skip />
+ <string name="add" msgid="81036585205287996">"Нэмэх"</string>
+ <string name="manage_users" msgid="1823875311934643849">"Хэрэглэгчдийг удирдах"</string>
+ <string name="drag_split_not_supported" msgid="4326847447699729722">"Энэ мэдэгдэл нь Дэлгэцийг хуваах горим руу чирэхийг дэмждэггүй."</string>
+ <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi боломжгүй"</string>
+ <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Чухал горим"</string>
+ <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Сэрүүлгийг тохируулсан"</string>
+ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Камер болон микрофон унтраалттай байна"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# мэдэгдэл}other{# мэдэгдэл}}"</string>
</resources>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index fca67d2c5295..721368a04ccd 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -20,14 +20,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4811759950673118541">"सिस्टीम UI"</string>
- <string name="battery_low_title" msgid="6891106956328275225">"बॅटरी लवकर संपू शकते"</string>
+ <string name="battery_low_title" msgid="5319680173344341779">"बॅटरी सेव्हर सुरू करायचे आहे का?"</string>
+ <string name="battery_low_description" msgid="3282977755476423966">"तुमच्याकडे <xliff:g id="PERCENTAGE">%s</xliff:g> बॅटरी शिल्लक आहे. बॅटरी सेव्हर गडद थीम सुरू करते, बॅकग्राउंड ॲक्टिव्हिटी मर्यादित करते, यामुळे सूचना विलंबाने मिळतात."</string>
+ <string name="battery_low_intro" msgid="5148725009653088790">"बॅटरी सेव्हर गडद थीम सुरू करते, बॅकग्राउंड ॲक्टिव्हिटी मर्यादित करते, यामुळे सूचना विलंबाने मिळतात."</string>
<string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> शिल्लक"</string>
<string name="invalid_charger_title" msgid="938685362320735167">"USB द्वारे चार्ज होऊ शकत नाही"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"तुमच्या डिव्हाइससह आलेल्या चार्जरचा वापर करा"</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"बॅटरी सेव्हर सुरू करायचा का?"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"बॅटरी सेव्हर बाबत"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"सुरू करा"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"बॅटरी सेव्हर सुरू करा"</string>
+ <string name="battery_saver_start_action" msgid="8353766979886287140">"सुरू करा"</string>
+ <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"नाही, नको"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"ऑटो-रोटेट स्क्रीन"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"<xliff:g id="APPLICATION">%1$s</xliff:g> ला <xliff:g id="USB_DEVICE">%2$s</xliff:g> अ‍ॅक्सेस करण्याची अनुमती द्यायची का?"</string>
<string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"<xliff:g id="APPLICATION">%1$s</xliff:g> ला <xliff:g id="USB_DEVICE">%2$s</xliff:g> अ‍ॅक्सेस करण्याची अनुमती द्यायची का?\nया अ‍ॅपला रेकॉर्ड करण्याची परवानगी दिलेली नाही पण या USB डिव्हाइसद्वारे ऑडिओ कॅप्चर केला जाऊ शकतो."</string>
@@ -128,6 +131,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"चेहरा ऑथेंटिकेशन केलेला आहे"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"निश्चित केले"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"पूर्ण करण्यासाठी खात्री करा वर टॅप करा"</string>
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"तुमच्या चेहऱ्याने अनलॉक केले. पुढे सुरू ठेवण्यासाठी दाबा."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"ऑथेंटिकेशन केलेले"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"पिन वापरा"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"पॅटर्न वापरा"</string>
@@ -181,6 +185,7 @@
<string name="accessibility_desc_close" msgid="8293708213442107755">"बंद करा"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"संपूर्ण शांतता"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"फक्‍त अलार्म"</string>
+ <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"व्यत्यय आणू नका."</string>
<string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"ब्लूटूथ."</string>
<string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"ब्लूटूथ सुरू."</string>
<string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"<xliff:g id="TIME">%s</xliff:g> साठी अलार्म सेट केला."</string>
@@ -205,6 +210,7 @@
<string name="dessert_case" msgid="9104973640704357717">"मिष्ठान्न प्रकरण"</string>
<string name="start_dreams" msgid="9131802557946276718">"स्क्रीन सेव्हर"</string>
<string name="ethernet_label" msgid="2203544727007463351">"इथरनेट"</string>
+ <string name="quick_settings_dnd_label" msgid="7728690179108024338">"व्यत्यय आणू नका"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"ब्लूटूथ"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"कोणतेही जोडलेले डिव्हाइसेस उपलब्ध नाहीत"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> बॅटरी"</string>
@@ -348,6 +354,7 @@
<string name="notification_section_header_alerting" msgid="5581175033680477651">"सूचना"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"संभाषणे"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"सर्व सायलंट सूचना साफ करा"</string>
+ <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"व्यत्यय आणून नकाद्वारे सूचना थांबवल्या"</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"आता सुरू करा"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"सूचना नाहीत"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"हे डिव्हाइस तुमच्या पालकाने व्यवस्थापित केले आहे"</string>
@@ -452,8 +459,8 @@
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"वापरण्यासाठी अनलॉक करा"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"तुमची कार्ड मिळवताना समस्या आली, कृपया नंतर पुन्हा प्रयत्न करा"</string>
<string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"लॉक स्क्रीन सेटिंग्ज"</string>
- <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR कोड"</string>
- <string name="qr_code_scanner_description" msgid="7937603775306661863">"स्कॅन करण्यासाठी टॅप करा"</string>
+ <!-- no translation found for qr_code_scanner_title (5290201053875420785) -->
+ <skip />
<string name="status_bar_work" msgid="5238641949837091056">"कार्य प्रोफाईल"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"विमान मोड"</string>
<string name="zen_alarm_warning" msgid="7844303238486849503">"तुम्ही तुमचा <xliff:g id="WHEN">%1$s</xliff:g> वाजता होणारा पुढील अलार्म ऐकणार नाही"</string>
@@ -491,6 +498,8 @@
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"&lt;b&gt;स्थिती&lt;/b&gt; ला थोडी कमी म्हणून रँक केले गेले"</string>
<string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"संभाषण सूचनांच्या वरती आणि लॉक स्क्रीनवरील प्रोफाइल फोटो म्हणून दिसते"</string>
<string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"संभाषण सूचनांच्या वरती आणि लॉक स्क्रीनवरील प्रोफाइल फोटो म्हणून दिसते, बबल म्हणून दिसते"</string>
+ <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"संभाषण सूचनांच्या वरती आणि लॉक स्क्रीनवरील प्रोफाइल फोटो म्हणून दिसते, व्यत्यय आणू नका यामध्ये अडथळा आणते"</string>
+ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"संभाषण सूचनांच्या वरती आणि लॉक स्क्रीनवरील प्रोफाइल फोटो म्हणून दिसते, बबल म्हणून दिसते, व्यत्यय आणू नका यामध्ये अडथळा आणते"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"प्राधान्य"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> हे संभाषण वैशिष्ट्यांना सपोर्ट करत नाही"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"या सूचनांमध्ये सुधारणा केली जाऊ शकत नाही."</string>
@@ -566,6 +575,7 @@
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"SMS"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"संगीत"</string>
<string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"कॅलेंडर"</string>
+ <string name="volume_and_do_not_disturb" msgid="502044092739382832">"व्यत्यय आणू नका"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"आवाजाच्या बटणांचा शार्टकट"</string>
<string name="battery" msgid="769686279459897127">"बॅटरी"</string>
<string name="headset" msgid="4485892374984466437">"हेडसेट"</string>
@@ -684,6 +694,10 @@
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"वाय-फाय बंद आहे"</string>
<string name="bt_is_off" msgid="7436344904889461591">"ब्लूटूथ बंद आहे"</string>
+ <string name="dnd_is_off" msgid="3185706903793094463">"व्यत्यय आणू नका बंद आहे"</string>
+ <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"व्यत्यय आणू नका एका <xliff:g id="ID_1">%s</xliff:g> स्वयंचलित नियमाने सुरू केले."</string>
+ <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"व्यत्यय आणू नका (<xliff:g id="ID_1">%s</xliff:g>) ॲपने सुरू केले."</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"व्यत्यय आणू नका एका स्वयंचलित नियमाने किंवा ॲपने सुरू केले."</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"अ‍ॅप्स बॅकग्राउंडमध्‍ये सुरू आहेत"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"बॅटरी आणि डेटा वापराच्‍या तपशीलांसाठी टॅप करा"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"मोबाइल डेटा बंद करायचा?"</string>
@@ -708,6 +722,8 @@
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(ऑफिस)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"फोन कॉल"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(<xliff:g id="APPLICATION_NAME_S_">%s</xliff:g> द्वारे)"</string>
+ <string name="ongoing_privacy_dialog_attribution_label" msgid="3385241594101496292">"(<xliff:g id="ATTRIBUTION_LABEL">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_proxy_label" msgid="1111829599659403249">"(<xliff:g id="ATTRIBUTION_LABEL">%1$s</xliff:g> • <xliff:g id="PROXY_LABEL">%2$s</xliff:g>)"</string>
<string name="privacy_type_camera" msgid="7974051382167078332">"camera"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"स्थान"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"मायक्रोफोन"</string>
@@ -806,6 +822,9 @@
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(डिस्कनेक्ट केलेले)"</string>
<string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"स्विच करू शकत नाही. पुन्हा प्रयत्न करण्यासाठी टॅप करा."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"नवीन डिव्हाइससोबत पेअर करा"</string>
+ <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"हे सेशन कास्ट करण्यासाठी, कृपया ॲप उघडा."</string>
+ <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"अज्ञात अ‍ॅप"</string>
+ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"कास्ट करणे थांबवा"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"बिल्ड नंबर"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"बिल्ड नंबर क्लिपबोर्डवर कॉपी केला."</string>
<string name="basic_status" msgid="2315371112182658176">"संभाषण उघडा"</string>
@@ -839,6 +858,7 @@
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"अलीकडील मेसेज, मिस्ड कॉल आणि स्टेटस अपडेट पहा"</string>
<string name="people_tile_title" msgid="6589377493334871272">"संभाषण"</string>
+ <string name="paused_by_dnd" msgid="7856941866433556428">"व्यत्यय आणू नका द्वारे थांबवले गेले"</string>
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> यांनी मेसेज पाठवला: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> यांनी इमेज पाठवली"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> यांनी स्टेटस अपडेट केले: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
@@ -877,8 +897,7 @@
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> अ‍ॅक्टिव्ह ॲप्स</item>
<item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> अ‍ॅक्टिव्ह ॲप</item>
</plurals>
- <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
- <skip />
+ <string name="fgs_dot_content_description" msgid="2865071539464777240">"नवीन माहिती"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"अ‍ॅक्टिव्ह ॲप्स"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"थांबवा"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"थांबवले"</string>
@@ -889,8 +908,12 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"कॉपी केलेला मजकूर संपादित करा"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"कॉपी केलेली इमेज संपादित करा"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"जवळपासच्या डिव्हाइसवर पाठवा"</string>
- <!-- no translation found for add (81036585205287996) -->
- <skip />
- <!-- no translation found for manage_users (1823875311934643849) -->
- <skip />
+ <string name="add" msgid="81036585205287996">"जोडा"</string>
+ <string name="manage_users" msgid="1823875311934643849">"वापरकर्ते व्यवस्‍थापित करा"</string>
+ <string name="drag_split_not_supported" msgid="4326847447699729722">"ही सूचना स्प्लिटस्क्रीनवर ड्रॅग करण्याला सपोर्ट करत नाही."</string>
+ <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"वाय-फाय उपलब्ध नाही"</string>
+ <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"प्राधान्य मोड"</string>
+ <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"अलार्म सेट केला"</string>
+ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"कॅमेरा आणि माइक बंद आहेत"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# सूचना}other{# सूचना}}"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index b87a79cca38e..b34a312abac7 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -20,14 +20,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4811759950673118541">"UI Sistem"</string>
- <string name="battery_low_title" msgid="6891106956328275225">"Bateri mungkin kehabisan tidak lama lagi"</string>
+ <string name="battery_low_title" msgid="5319680173344341779">"Hidupkan Penjimat Bateri?"</string>
+ <string name="battery_low_description" msgid="3282977755476423966">"Anda mempunyai <xliff:g id="PERCENTAGE">%s</xliff:g> baki bateri. Penjimat Bateri menghidupkan Tema gelap, mengehadkan aktiviti latar dan menangguhkan pemberitahuan."</string>
+ <string name="battery_low_intro" msgid="5148725009653088790">"Penjimat Bateri menghidupkan Tema gelap, mengehadkan aktiviti latar dan menangguhkan pemberitahuan."</string>
<string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> yang tinggal"</string>
<string name="invalid_charger_title" msgid="938685362320735167">"Tidak dapat mengecas melalui USB"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"Gunakan pengecas yang disertakan dengan peranti anda"</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Hidupkan Penjimat Bateri?"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Tentang Penjimat Bateri"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Hidupkan"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"Hidupkan Penjimat Bateri"</string>
+ <string name="battery_saver_start_action" msgid="8353766979886287140">"Hidupkan"</string>
+ <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Tidak perlu"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Autoputar skrin"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"Benarkan <xliff:g id="APPLICATION">%1$s</xliff:g> mengakses <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
<string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Benarkan <xliff:g id="APPLICATION">%1$s</xliff:g> mengakses <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nApl ini belum diberikan kebenaran merakam tetapi dapat merakam audio melalui peranti USB ini."</string>
@@ -128,6 +131,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Wajah disahkan"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Disahkan"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Ketik Sahkan untuk menyelesaikan"</string>
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Dibuka kunci oleh wajah anda. Tekan untuk meneruskan."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Disahkan"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Gunakan PIN"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Gunakan corak"</string>
@@ -181,6 +185,7 @@
<string name="accessibility_desc_close" msgid="8293708213442107755">"Tutup"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"senyap sepenuhnya"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"penggera sahaja"</string>
+ <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"Jangan Ganggu."</string>
<string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"Bluetooth."</string>
<string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"Bluetooth dihidupkan."</string>
<string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"Penggera ditetapkan pada <xliff:g id="TIME">%s</xliff:g>."</string>
@@ -205,6 +210,7 @@
<string name="dessert_case" msgid="9104973640704357717">"Bekas Pencuci Mulut"</string>
<string name="start_dreams" msgid="9131802557946276718">"Penyelamat skrin"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
+ <string name="quick_settings_dnd_label" msgid="7728690179108024338">"Jangan Ganggu"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Tiada peranti berpasangan tersedia"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> bateri"</string>
@@ -348,6 +354,7 @@
<string name="notification_section_header_alerting" msgid="5581175033680477651">"Pemberitahuan"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Perbualan"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Kosongkan semua pemberitahuan senyap"</string>
+ <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Pemberitahuan dijeda oleh Jangan Ganggu"</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"Mulakan sekarang"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Tiada pemberitahuan"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Peranti ini diurus oleh ibu bapa anda"</string>
@@ -452,8 +459,8 @@
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Buka kunci untuk menggunakan"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Terdapat masalah sewaktu mendapatkan kad anda. Sila cuba sebentar lagi"</string>
<string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Tetapan skrin kunci"</string>
- <string name="qr_code_scanner_title" msgid="5660820608548306581">"Kod QR"</string>
- <string name="qr_code_scanner_description" msgid="7937603775306661863">"Ketik untuk membuat imbasan"</string>
+ <!-- no translation found for qr_code_scanner_title (5290201053875420785) -->
+ <skip />
<string name="status_bar_work" msgid="5238641949837091056">"Profil kerja"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Mod pesawat"</string>
<string name="zen_alarm_warning" msgid="7844303238486849503">"Anda tidak akan mendengar penggera yang seterusnya <xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -491,6 +498,8 @@
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"&lt;b&gt;Status:&lt;/b&gt; Dinilai Lebih Rendah"</string>
<string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"Ditunjukkan di bahagian atas pemberitahuan perbualan dan sebagai gambar profil pada skrin kunci"</string>
<string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"Ditunjukkan di bahagian atas pemberitahuan perbualan dan sebagai gambar profil pada skrin kunci, muncul sebagai gelembung"</string>
+ <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"Ditunjukkan di bahagian atas pemberitahuan perbualan dan sebagai gambar profil pada skrin kunci, mengganggu Jangan Ganggu"</string>
+ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Ditunjukkan di bahagian atas pemberitahuan perbualan dan sebagai gambar profil pada skrin kunci, muncul sebagai gelembung, mengganggu Jangan Ganggu"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Keutamaan"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> tidak menyokong ciri perbualan"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Pemberitahuan ini tidak boleh diubah suai."</string>
@@ -566,6 +575,7 @@
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"SMS"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"Muzik"</string>
<string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Kalendar"</string>
+ <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Jangan Ganggu"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"Pintasan butang kelantangan"</string>
<string name="battery" msgid="769686279459897127">"Bateri"</string>
<string name="headset" msgid="4485892374984466437">"Set Kepala"</string>
@@ -684,6 +694,10 @@
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g> <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"Wi-Fi dimatikan"</string>
<string name="bt_is_off" msgid="7436344904889461591">"Bluetooth dimatikan"</string>
+ <string name="dnd_is_off" msgid="3185706903793094463">"Jangan Ganggu dimatikan"</string>
+ <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"Jangan Ganggu dihidupkan oleh peraturan automatik (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"Jangan Ganggu dihidupkan oleh apl (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"Jangan Ganggu dihidupkan oleh peraturan automatik atau apl."</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"Apl yang berjalan di latar belakang"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"Ketik untuk mendapatkan butiran tentang penggunaan kuasa bateri dan data"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Matikan data mudah alih?"</string>
@@ -708,6 +722,8 @@
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(kerja)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"Panggilan telefon"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(melalui <xliff:g id="APPLICATION_NAME_S_">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_label" msgid="3385241594101496292">"(<xliff:g id="ATTRIBUTION_LABEL">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_proxy_label" msgid="1111829599659403249">"(<xliff:g id="ATTRIBUTION_LABEL">%1$s</xliff:g> • <xliff:g id="PROXY_LABEL">%2$s</xliff:g>)"</string>
<string name="privacy_type_camera" msgid="7974051382167078332">"kamera"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"lokasi"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofon"</string>
@@ -806,6 +822,9 @@
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(diputuskan sambungan)"</string>
<string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Tidak dapat menukar. Ketik untuk mencuba lagi."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Gandingkan peranti baharu"</string>
+ <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Untuk menghantar sesi ini, sila buka apl."</string>
+ <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Apl yang tidak diketahui"</string>
+ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Berhenti menghantar"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Nombor binaan"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Nombor binaan disalin ke papan keratan."</string>
<string name="basic_status" msgid="2315371112182658176">"Buka perbualan"</string>
@@ -839,6 +858,7 @@
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Lihat mesej terbaharu, panggilan terlepas dan kemaskinian status"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Perbualan"</string>
+ <string name="paused_by_dnd" msgid="7856941866433556428">"Dijeda oleh Jangan Ganggu"</string>
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> menghantar mesej: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> menghantar imej"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> mempunyai kemaskinian status: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
@@ -877,8 +897,7 @@
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> apl aktif</item>
<item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> apl aktif</item>
</plurals>
- <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
- <skip />
+ <string name="fgs_dot_content_description" msgid="2865071539464777240">"Maklumat baharu"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Apl aktif"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Berhenti"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Dihentikan"</string>
@@ -886,14 +905,15 @@
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Disalin"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Daripada <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Ketepikan penyalinan UI"</string>
- <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
- <skip />
- <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
- <skip />
- <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
- <skip />
- <!-- no translation found for add (81036585205287996) -->
- <skip />
- <!-- no translation found for manage_users (1823875311934643849) -->
- <skip />
+ <string name="clipboard_edit_text_description" msgid="805254383912962103">"Edit teks yang disalin"</string>
+ <string name="clipboard_edit_image_description" msgid="8904857948976041306">"Edit imej yang disalin"</string>
+ <string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Hantar ke peranti berdekatan"</string>
+ <string name="add" msgid="81036585205287996">"Tambah"</string>
+ <string name="manage_users" msgid="1823875311934643849">"Urus pengguna"</string>
+ <string name="drag_split_not_supported" msgid="4326847447699729722">"Pemberitahuan ini tidak menyokong penyeretan ke Skrin pisah."</string>
+ <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi dimatikan"</string>
+ <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Mod keutamaan"</string>
+ <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Penggera ditetapkan"</string>
+ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Kamera dan mikrofon dimatikan"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# pemberitahuan}other{# pemberitahuan}}"</string>
</resources>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index 0248d10fdda5..b1b2ceb9b77a 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -20,14 +20,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4811759950673118541">"စနစ်၏ UI"</string>
- <string name="battery_low_title" msgid="6891106956328275225">"မကြာမီ ဘက်ထရီကုန်သွားနိုင်ပါသည်"</string>
+ <string name="battery_low_title" msgid="5319680173344341779">"‘ဘက်ထရီ အားထိန်း’ ဖွင့်မလား။"</string>
+ <string name="battery_low_description" msgid="3282977755476423966">"သင့်တွင် ဘက်ထရီ <xliff:g id="PERCENTAGE">%s</xliff:g> ကျန်သည်။ ‘ဘက်ထရီ အားထိန်း’ က ‘မှောင်သည့် အပြင်အဆင်’ ဖွင့်ပြီး နောက်ခံလုပ်ဆောင်ချက်ကို ကန့်သတ်ကာ အကြောင်းကြားချက်များကို နှောင့်နှေးစေသည်။"</string>
+ <string name="battery_low_intro" msgid="5148725009653088790">"‘ဘက်ထရီ အားထိန်း’ က ‘မှောင်သည့် အပြင်အဆင်’ ဖွင့်ပြီး နောက်ခံလုပ်ဆောင်ချက်ကို ကန့်သတ်ကာ အကြောင်းကြားချက်များကို နှောင့်နှေးစေသည်။"</string>
<string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> ကျန်ရှိနေ"</string>
<string name="invalid_charger_title" msgid="938685362320735167">"USB ဖြင့် အားသွင်း၍မရပါ"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"သင့်စက်ပစ္စည်းနှင့် အတူပါလာသည့် အားသွင်းကိရိယာကို အသုံးပြုပါ"</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"ဘက်ထရီအားထိန်းကို ဖွင့်မလား။"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"\'ဘက်ထရီအားထိန်း\' အကြောင်း"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"ဖွင့်ရန်"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"ဘက်ထရီ အားထိန်းကို ဖွင့်ရန်"</string>
+ <string name="battery_saver_start_action" msgid="8353766979886287140">"ဖွင့်ရန်"</string>
+ <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"မလိုပါ"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"ဖန်သားပြင် အလိုအလျောက်လှည့်ရန်"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> အား ဝင်သုံးရန် <xliff:g id="APPLICATION">%1$s</xliff:g> ကို ခွင့်ပြုပါသလား။"</string>
<string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"<xliff:g id="APPLICATION">%1$s</xliff:g> အား <xliff:g id="USB_DEVICE">%2$s</xliff:g> ကို သုံးခွင့်ပြုမလား။\nဤအက်ပ်ကို အသံဖမ်းခွင့် ပေးမထားသော်လည်း ၎င်းသည် ဤ USB စက်ပစ္စည်းမှတစ်ဆင့် အသံများကို ဖမ်းယူနိုင်ပါသည်။"</string>
@@ -111,7 +114,7 @@
<string name="accessibility_phone_button" msgid="4256353121703100427">"ဖုန်း"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"အသံ အကူအညီ"</string>
<string name="accessibility_wallet_button" msgid="1458258783460555507">"Wallet"</string>
- <string name="accessibility_qr_code_scanner_button" msgid="7521277927692910795">"QR ကုဒ် စကင်ဖတ်စနစ်"</string>
+ <string name="accessibility_qr_code_scanner_button" msgid="7521277927692910795">"QR ကုဒ်ဖတ်စနစ်"</string>
<string name="accessibility_unlock_button" msgid="122785427241471085">"သော့ဖွင့်ရန်"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"စက်ပစ္စည်းကို လော့ခ်ချထားသည်"</string>
<string name="accessibility_scanning_face" msgid="3093828357921541387">"မျက်နှာ စကင်ဖတ်နေသည်"</string>
@@ -128,6 +131,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"မျက်နှာ အထောက်အထားစိစစ်ပြီးပြီ"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"အတည်ပြုပြီးပြီ"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"အပြီးသတ်ရန်အတွက် \'အတည်ပြုရန်\' ကို တို့ပါ"</string>
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"သင့်မျက်နှာဖြင့် ဖွင့်သည်။ ရှေ့ဆက်ရန် နှိပ်ပါ။"</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"အထောက်အထားစိစစ်ပြီးပြီ"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"ပင်နံပါတ်သုံးရန်"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"ပုံစံကို သုံးရန်"</string>
@@ -181,6 +185,7 @@
<string name="accessibility_desc_close" msgid="8293708213442107755">"ပိတ်ရန်"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"လုံးဝ အသံပိတ်ထားရန်"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"နှိုးစက်များသာ"</string>
+ <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"မနှောင့်ယှက်ရ။"</string>
<string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"ဘလူးတုသ်။"</string>
<string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"ဘလူးတုသ် ဖွင့်ထား။"</string>
<string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"နိုးစက်ပေးထားသော အချိန် <xliff:g id="TIME">%s</xliff:g>."</string>
@@ -205,6 +210,7 @@
<string name="dessert_case" msgid="9104973640704357717">"မုန့်ထည့်သော ပုံး"</string>
<string name="start_dreams" msgid="9131802557946276718">"ဖန်သားပြင်အသုံးပြုမှု ချွေတာမှုစနစ်"</string>
<string name="ethernet_label" msgid="2203544727007463351">"အီသာနက်"</string>
+ <string name="quick_settings_dnd_label" msgid="7728690179108024338">"မနှောင့်ယှက်ရ"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"ဘလူးတုသ်"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"ချိတ်တွဲထားသည့် ကိရိယာများ မရှိ"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> ဘက်ထရီ"</string>
@@ -348,6 +354,7 @@
<string name="notification_section_header_alerting" msgid="5581175033680477651">"အကြောင်းကြားချက်များ"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"စကားဝိုင်းများ"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"အသံတိတ် အကြောင်းကြားချက်များအားလုံးကို ရှင်းလင်းရန်"</string>
+ <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"အကြောင်းကြားချက်များကို \'မနှောင့်ယှက်ရ\' က ခေတ္တရပ်ထားသည်"</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"ယခု စတင်ပါ"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"အကြောင်းကြားချက်များ မရှိ"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"ဤစက်ပစ္စည်းကို သင့်မိဘက စီမံခန့်ခွဲသည်"</string>
@@ -452,8 +459,8 @@
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"သုံးရန် လော့ခ်ဖွင့်ပါ"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"သင်၏ကတ်များ ရယူရာတွင် ပြဿနာရှိနေသည်၊ နောက်မှ ထပ်စမ်းကြည့်ပါ"</string>
<string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"လော့ခ်မျက်နှာပြင် ဆက်တင်များ"</string>
- <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR ကုဒ်"</string>
- <string name="qr_code_scanner_description" msgid="7937603775306661863">"စကင်ဖတ်ရန် တို့နိုင်သည်"</string>
+ <!-- no translation found for qr_code_scanner_title (5290201053875420785) -->
+ <skip />
<string name="status_bar_work" msgid="5238641949837091056">"အလုပ် ပရိုဖိုင်"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"လေယာဉ်ပျံမုဒ်"</string>
<string name="zen_alarm_warning" msgid="7844303238486849503">"<xliff:g id="WHEN">%1$s</xliff:g> ၌သင့်နောက်ထပ် နှိုးစက်ကို ကြားမည်မဟုတ်ပါ"</string>
@@ -491,6 +498,8 @@
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"&lt;b&gt;အခြေအနေ-&lt;/b&gt; အဆင့်လျှော့ထားသည်"</string>
<string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"စကားဝိုင်း အကြောင်းကြားချက်များ၏ ထိပ်ပိုင်းတွင် ပြ၍ လော့ခ်မျက်နှာပြင်တွင် ပရိုဖိုင်ပုံအဖြစ် ပြသည်"</string>
<string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"စကားဝိုင်း အကြောင်းကြားချက်များ၏ ထိပ်ပိုင်းတွင် ပြ၍ လော့ခ်မျက်နှာပြင်တွင် ပရိုဖိုင်ပုံအဖြစ် ပြကာ ပူဖောင်းကွက်အဖြစ် မြင်ရသည်"</string>
+ <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"စကားဝိုင်း အကြောင်းကြားချက်များ၏ ထိပ်ပိုင်းတွင် ပြ၍ လော့ခ်မျက်နှာပြင်တွင် ပရိုဖိုင်ပုံအဖြစ် ပြကာ ‘မနှောင့်ယှက်ရ’ ကို ရပ်တန့်သည်"</string>
+ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"စကားဝိုင်း အကြောင်းကြားချက်များ၏ ထိပ်ပိုင်းတွင် ပြ၍ လော့ခ်မျက်နှာပြင်တွင် ပရိုဖိုင်ပုံအဖြစ် ပြကာ ပူဖောင်းကွက်အဖြစ် မြင်ရပြီး ‘မနှောင့်ယှက်ရ’ ကို ရပ်တန့်သည်"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"ဦးစားပေး"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> က စကားဝိုင်းဝန်ဆောင်မှုများကို မပံ့ပိုးပါ"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"ဤအကြောင်းကြားချက်များကို ပြုပြင်၍ မရပါ။"</string>
@@ -566,6 +575,7 @@
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"SMS စာတိုစနစ်"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"Music"</string>
<string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"ပြက္ခဒိန်"</string>
+ <string name="volume_and_do_not_disturb" msgid="502044092739382832">"မနှောင့်ယှက်ရ"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"အသံထိန်းချုပ်သည့်ခလုတ် ဖြတ်လမ်း"</string>
<string name="battery" msgid="769686279459897127">"ဘက်ထရီ"</string>
<string name="headset" msgid="4485892374984466437">"မိုက်ခွက်ပါနားကြပ်"</string>
@@ -684,6 +694,10 @@
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>၊ <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"Wi-Fi ပိတ်ထားသည်"</string>
<string name="bt_is_off" msgid="7436344904889461591">"ဘလူးတုသ်ကို ပိတ်ထားသည်"</string>
+ <string name="dnd_is_off" msgid="3185706903793094463">"\"မနှောင့်ယှက်ရ\" ကို ပိတ်ထားသည်"</string>
+ <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"\"မနှောင့်ယှက်ရ\" ကို အလိုအလျောက်စည်းမျဉ်း (<xliff:g id="ID_1">%s</xliff:g>) က ဖွင့်ခဲ့သည်။"</string>
+ <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"\"မနှောင့်ယှက်ရ\" ကို အက်ပ် (<xliff:g id="ID_1">%s</xliff:g>) က ဖွင့်ခဲ့သည်။"</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"\"မနှောင့်ယှက်ရ\" ကို အလိုအလျောက်စည်းမျဉ်းတစ်ခု သို့မဟုတ် အက်ပ်တစ်ခုက ဖွင့်ခဲ့သည်။"</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"နောက်ခံတွင် ပွင့်နေသော အက်ပ်များ"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"ဘက်ထရီနှင့် ဒေတာအသုံးပြုမှု အသေးစိတ်ကို ကြည့်ရန် တို့ပါ"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"မိုဘိုင်းဒေတာ ပိတ်မလား။"</string>
@@ -708,6 +722,8 @@
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(လုပ်ငန်းသုံး)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"ဖုန်းခေါ်ဆိုမှု"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(<xliff:g id="APPLICATION_NAME_S_">%s</xliff:g> မှတစ်ဆင့်)"</string>
+ <string name="ongoing_privacy_dialog_attribution_label" msgid="3385241594101496292">"(<xliff:g id="ATTRIBUTION_LABEL">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_proxy_label" msgid="1111829599659403249">"(<xliff:g id="ATTRIBUTION_LABEL">%1$s</xliff:g> • <xliff:g id="PROXY_LABEL">%2$s</xliff:g>)"</string>
<string name="privacy_type_camera" msgid="7974051382167078332">"ကင်မရာ"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"တည်နေရာ"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"မိုက်ခရိုဖုန်း"</string>
@@ -806,6 +822,9 @@
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(ချိတ်ဆက်မှု မရှိပါ)"</string>
<string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"ပြောင်း၍ မရပါ။ ပြန်စမ်းကြည့်ရန် တို့ပါ။"</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"စက်အသစ် တွဲချိတ်ရန်"</string>
+ <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"အက်ပ်ဖွင့်ပြီး ဤစက်ရှင်ကို ကာစ်လုပ်နိုင်သည်။"</string>
+ <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"အမည်မသိ အက်ပ်"</string>
+ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"ကာစ် ရပ်ရန်"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"တည်ဆောက်မှုနံပါတ်"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"တည်ဆောက်မှုနံပါတ်ကို ကလစ်ဘုတ်သို့ မိတ္တူကူးပြီးပါပြီ။"</string>
<string name="basic_status" msgid="2315371112182658176">"စကားဝိုင်းကို ဖွင့်ရန်"</string>
@@ -839,6 +858,7 @@
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"မကြာသေးမီက မက်ဆေ့ဂျ်၊ လွတ်သွားသောခေါ်ဆိုမှုနှင့် အခြေအနေအပ်ဒိတ်များကို ကြည့်နိုင်သည်"</string>
<string name="people_tile_title" msgid="6589377493334871272">"စကားဝိုင်း"</string>
+ <string name="paused_by_dnd" msgid="7856941866433556428">"‘မနှောင့်ယှက်ရ’ ဖြင့် ခဏရပ်ထားသည်"</string>
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> က မက်ဆေ့ဂျ်ပို့လိုက်သည်- <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> က ပုံပို့လိုက်သည်"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> က အခြေအနေ အပ်ဒိတ်လုပ်လိုက်သည်- <xliff:g id="STATUS">%2$s</xliff:g>"</string>
@@ -877,8 +897,7 @@
<item quantity="other">ပွင့်နေသည့်အက်ပ် <xliff:g id="COUNT_1">%s</xliff:g> ခု</item>
<item quantity="one">ပွင့်နေသည့်အက်ပ် <xliff:g id="COUNT_0">%s</xliff:g> ခု</item>
</plurals>
- <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
- <skip />
+ <string name="fgs_dot_content_description" msgid="2865071539464777240">"အချက်အလက်သစ်"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"ပွင့်နေသည့်အက်ပ်များ"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"ရပ်ရန်"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"ရပ်ထားသည်"</string>
@@ -886,14 +905,15 @@
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"ကူးပြီးပါပြီ"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"<xliff:g id="APPNAME">%1$s</xliff:g> ထံမှ"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"UI မိတ္တူမကူးတော့ရန်"</string>
- <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
- <skip />
- <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
- <skip />
- <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
- <skip />
- <!-- no translation found for add (81036585205287996) -->
- <skip />
- <!-- no translation found for manage_users (1823875311934643849) -->
- <skip />
+ <string name="clipboard_edit_text_description" msgid="805254383912962103">"ကူးထားသည့်စာသားကို တည်းဖြတ်ရန်"</string>
+ <string name="clipboard_edit_image_description" msgid="8904857948976041306">"ကူးထားသည့်ပုံကို ပြင်ဆင်ရန်"</string>
+ <string name="clipboard_send_nearby_description" msgid="4629769637846717650">"အနီးတစ်ဝိုက်ရှိ စက်များသို့ ပို့ရန်"</string>
+ <string name="add" msgid="81036585205287996">"ထည့်ရန်"</string>
+ <string name="manage_users" msgid="1823875311934643849">"အသုံးပြုသူများ စီမံရန်"</string>
+ <string name="drag_split_not_supported" msgid="4326847447699729722">"ဤအကြောင်းကြားချက်သည် ‘မျက်နှာပြင်ခွဲ၍ပြသမှု’ သို့ ဖိဆွဲခြင်းကို မပံ့ပိုးပါ။"</string>
+ <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi မရပါ"</string>
+ <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"ဦးစားပေးမုဒ်"</string>
+ <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"နိုးစက် သတ်မှတ်ထားသည်"</string>
+ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"ကင်မရာနှင့် မိုက် ပိတ်ထားသည်"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{အကြောင်းကြားချက် # ခု}other{အကြောင်းကြားချက် # ခု}}"</string>
</resources>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 76cfef5704b1..745454cc6e9b 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -20,14 +20,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4811759950673118541">"System-UI"</string>
- <string name="battery_low_title" msgid="6891106956328275225">"Batteriet går kanskje snart tomt"</string>
+ <string name="battery_low_title" msgid="5319680173344341779">"Vil du slå på batterisparing?"</string>
+ <string name="battery_low_description" msgid="3282977755476423966">"Du har <xliff:g id="PERCENTAGE">%s</xliff:g> batteri igjen. Batterisparing slår på mørkt tema, begrenser bakgrunnsaktivitet og forsinker varsler."</string>
+ <string name="battery_low_intro" msgid="5148725009653088790">"Batterisparing slår på mørkt tema, begrenser bakgrunnsaktivitet og forsinker varsler."</string>
<string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> gjenstår"</string>
<string name="invalid_charger_title" msgid="938685362320735167">"Kan ikke lade via USB"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"Bruk laderen som fulgte med enheten"</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Vil du slå på batterisparing?"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Om Batterisparing"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Slå på"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"Slå på batterisparing"</string>
+ <string name="battery_saver_start_action" msgid="8353766979886287140">"Slå på"</string>
+ <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Nei takk"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Rotér skjermen automatisk"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"Vil du gi <xliff:g id="APPLICATION">%1$s</xliff:g> tilgang til <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
<string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Vil du gi <xliff:g id="APPLICATION">%1$s</xliff:g> tilgang til <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nDenne appen har ikke fått tillatelse til å spille inn, men kan ta opp lyd med denne USB-enheten."</string>
@@ -128,6 +131,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Ansiktet er autentisert"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Bekreftet"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Trykk på Bekreft for å fullføre"</string>
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Låst opp med ansiktet ditt. Trykk for å fortsette."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Autentisert"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Bruk PIN-kode"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Bruk mønster"</string>
@@ -181,6 +185,7 @@
<string name="accessibility_desc_close" msgid="8293708213442107755">"Lukk"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"total stillhet"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"bare alarmer"</string>
+ <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"Ikke forstyrr."</string>
<string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"Bluetooth."</string>
<string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"Bluetooth er på."</string>
<string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"Alarmen ble stilt for <xliff:g id="TIME">%s</xliff:g>."</string>
@@ -205,6 +210,7 @@
<string name="dessert_case" msgid="9104973640704357717">"Dessertmonter"</string>
<string name="start_dreams" msgid="9131802557946276718">"Skjermsparer"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
+ <string name="quick_settings_dnd_label" msgid="7728690179108024338">"Ikke forstyrr"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Ingen sammenkoblede enheter er tilgjengelige"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> batteri"</string>
@@ -348,6 +354,7 @@
<string name="notification_section_header_alerting" msgid="5581175033680477651">"Varsler"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Samtaler"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Fjern alle lydløse varsler"</string>
+ <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Varsler er satt på pause av «Ikke forstyrr»"</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"Start nå"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Ingen varsler"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Denne enheten administreres av forelderen din"</string>
@@ -452,8 +459,8 @@
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Lås opp for å bruke"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Det oppsto et problem med henting av kortene. Prøv igjen senere"</string>
<string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Innstillinger for låseskjermen"</string>
- <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR-kode"</string>
- <string name="qr_code_scanner_description" msgid="7937603775306661863">"Trykk for å skanne"</string>
+ <!-- no translation found for qr_code_scanner_title (5290201053875420785) -->
+ <skip />
<string name="status_bar_work" msgid="5238641949837091056">"Work-profil"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Flymodus"</string>
<string name="zen_alarm_warning" msgid="7844303238486849503">"Du hører ikke neste innstilte alarm <xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -491,6 +498,8 @@
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"&lt;b&gt;Status:&lt;/b&gt; Rangert lavere"</string>
<string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"Vises øverst på samtalevarsler og som et profilbilde på låseskjermen"</string>
<string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"Vises øverst på samtalevarsler og som et profilbilde på låseskjermen, vises som en boble"</string>
+ <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"Vises øverst på samtalevarsler og som et profilbilde på låseskjermen, avbryter «Ikke forstyrr»"</string>
+ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Vises øverst på samtalevarsler og som et profilbilde på låseskjermen, vises som en boble, avbryter «Ikke forstyrr»"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritet"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> støtter ikke samtalefunksjoner"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Disse varslene kan ikke endres."</string>
@@ -566,6 +575,7 @@
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"SMS"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"Musikk"</string>
<string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Kalender"</string>
+ <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Ikke forstyrr"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"Hurtigtast for volumknappene"</string>
<string name="battery" msgid="769686279459897127">"Batteri"</string>
<string name="headset" msgid="4485892374984466437">"Hodetelefoner"</string>
@@ -684,6 +694,10 @@
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g> <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"Wi-Fi er av"</string>
<string name="bt_is_off" msgid="7436344904889461591">"Bluetooth er av"</string>
+ <string name="dnd_is_off" msgid="3185706903793094463">"Ikke forstyrr er av"</string>
+ <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"Ikke forstyrr ble slått på av en automatisk regel (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"Ikke forstyrr ble slått på av en app (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"Ikke forstyrr ble slått på av en automatisk regel eller en app."</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"Apper kjører i bakgrunnen"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"Trykk for detaljer om batteri- og databruk"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Vil du slå av mobildata?"</string>
@@ -708,6 +722,8 @@
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(jobb)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"Telefonsamtale"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(via <xliff:g id="APPLICATION_NAME_S_">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_label" msgid="3385241594101496292">"(<xliff:g id="ATTRIBUTION_LABEL">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_proxy_label" msgid="1111829599659403249">"(<xliff:g id="ATTRIBUTION_LABEL">%1$s</xliff:g> • <xliff:g id="PROXY_LABEL">%2$s</xliff:g>)"</string>
<string name="privacy_type_camera" msgid="7974051382167078332">"kameraet"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"posisjon"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofonen"</string>
@@ -806,6 +822,9 @@
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(frakoblet)"</string>
<string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Kan ikke bytte. Trykk for å prøve igjen."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Koble til en ny enhet"</string>
+ <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"For å caste denne økten, åpne appen."</string>
+ <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Ukjent app"</string>
+ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Stopp castingen"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Delversjonsnummer"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Delversjonsnummeret er kopiert til utklippstavlen."</string>
<string name="basic_status" msgid="2315371112182658176">"Åpen samtale"</string>
@@ -839,6 +858,7 @@
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Se nylige meldinger, tapte anrop og statusoppdateringer"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Samtale"</string>
+ <string name="paused_by_dnd" msgid="7856941866433556428">"Satt på pause av «Ikke forstyrr»"</string>
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> har sendt en melding: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> har sendt et bilde"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> har en statusoppdatering: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
@@ -877,8 +897,7 @@
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> aktive apper</item>
<item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> aktiv app</item>
</plurals>
- <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
- <skip />
+ <string name="fgs_dot_content_description" msgid="2865071539464777240">"Ny informasjon"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Aktive apper"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Stopp"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Stoppet"</string>
@@ -886,14 +905,15 @@
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Kopiert"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Fra <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Lukk kopi-UI"</string>
- <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
- <skip />
- <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
- <skip />
- <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
- <skip />
- <!-- no translation found for add (81036585205287996) -->
- <skip />
- <!-- no translation found for manage_users (1823875311934643849) -->
- <skip />
+ <string name="clipboard_edit_text_description" msgid="805254383912962103">"Rediger den kopierte teksten"</string>
+ <string name="clipboard_edit_image_description" msgid="8904857948976041306">"Rediger det kopierte bildet"</string>
+ <string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Send til en enhet i nærheten"</string>
+ <string name="add" msgid="81036585205287996">"Legg til"</string>
+ <string name="manage_users" msgid="1823875311934643849">"Administrer brukere"</string>
+ <string name="drag_split_not_supported" msgid="4326847447699729722">"Dette varselet støtter ikke at du drar det til en delt skjerm."</string>
+ <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi er utilgjengelig"</string>
+ <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Prioriteringsmodus"</string>
+ <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarmen er stilt inn"</string>
+ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Kamera og mikrofon er av"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# varsel}other{# varsler}}"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index 158a8913071a..bfe29aa5a26e 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -20,14 +20,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4811759950673118541">"सिस्टम UI"</string>
- <string name="battery_low_title" msgid="6891106956328275225">"ब्याट्री चाँडै सकिन सक्छ"</string>
+ <string name="battery_low_title" msgid="5319680173344341779">"ब्याट्री सेभर अन गर्ने हो?"</string>
+ <string name="battery_low_description" msgid="3282977755476423966">"तपाईंको डिभाइसको ब्याट्रीको चार्ज <xliff:g id="PERCENTAGE">%s</xliff:g> बाँकी छ। ब्याट्री सेभरले अँध्यारो थिम अन गर्छ, ब्याकग्राउन्डमा हुने क्रियाकलाप सीमित पार्छ र सूचनाहरू ढिलो देखाउँछ।"</string>
+ <string name="battery_low_intro" msgid="5148725009653088790">"ब्याट्री सेभरले अँध्यारो थिम अन गर्छ, ब्याकग्राउन्डमा हुने क्रियाकलाप सीमित पार्छ र सूचनाहरू ढिलो देखाउँछ।"</string>
<string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> बाँकी"</string>
<string name="invalid_charger_title" msgid="938685362320735167">"USB मार्फत चार्ज गर्न सकिँदैन"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"तपाईंको यन्त्रसँगै आएको चार्जर प्रयोग गर्नुहोस्‌"</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"ब्याट्री सेभर सक्रिय गर्ने हो?"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"ब्याट्री सेभरका बारेमा"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"खोल्नुहोस्"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"ब्याट्री सेभर सक्रिय गर्नुहोस्"</string>
+ <string name="battery_saver_start_action" msgid="8353766979886287140">"अन गर्नुहोस्"</string>
+ <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"पर्दैन"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"स्वत:घुम्ने स्क्रिन"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"<xliff:g id="APPLICATION">%1$s</xliff:g> लाई <xliff:g id="USB_DEVICE">%2$s</xliff:g> माथि पहुँच राख्ने अनुमति दिने हो?"</string>
<string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"<xliff:g id="APPLICATION">%1$s</xliff:g> लाई <xliff:g id="USB_DEVICE">%2$s</xliff:g> माथि पहुँच राख्न अनुमति दिने हो?\nयो एपलाई रेकर्ड गर्ने अनुमति प्रदान गरिएको छैन तर यसले USB यन्त्रमार्फत अडियो क्याप्चर गर्न सक्छ।"</string>
@@ -128,6 +131,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"अनुहार प्रमाणीकरण गरियो"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"पुष्टि भयो"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"पूरा गर्नका लागि पुष्टि गर्नुहोस् नामक विकल्पमा ट्याप गर्नुहोस्"</string>
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"तपाईंको अनुहार प्रयोग गरी अनलक गरियो। जारी राख्न थिच्नुहोस्।"</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"प्रमाणीकरण गरियो"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"PIN प्रयोग गर्नुहोस्"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"ढाँचा प्रयोग गर्नुहोस्"</string>
@@ -181,6 +185,7 @@
<string name="accessibility_desc_close" msgid="8293708213442107755">"बन्द गर्नुहोस्"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"पूर्ण मौनता"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"अलार्महरू मात्र"</string>
+ <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"बाधा नपुऱ्याउनुहोस्।"</string>
<string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"ब्लुटुथ।"</string>
<string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"ब्लुटुथ खुला छ।"</string>
<string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"<xliff:g id="TIME">%s</xliff:g>को लागि सङ्केत घन्टी सेट गरिएको"</string>
@@ -205,6 +210,7 @@
<string name="dessert_case" msgid="9104973640704357717">"Dessert Case"</string>
<string name="start_dreams" msgid="9131802557946276718">"स्क्रिन सेभर"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
+ <string name="quick_settings_dnd_label" msgid="7728690179108024338">"बाधा नपुऱ्याउनुहोस्"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"ब्लुटुथ"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"जोडी उपकरणहरू उपलब्ध छैन"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> ब्याट्री"</string>
@@ -348,6 +354,7 @@
<string name="notification_section_header_alerting" msgid="5581175033680477651">"सूचनाहरू"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"वार्तालापहरू"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"सबै मौन सूचनाहरू हटाउनुहोस्"</string>
+ <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"बाधा नपुऱ्याउनुहोस् नामक मोडमार्फत पज पारिएका सूचनाहरू"</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"अहिले न"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"कुनै सूचनाहरू छैनन्"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"यो डिभाइस तपाईंका अभिभावक व्यवस्थापन गर्नुहुन्छ"</string>
@@ -452,8 +459,7 @@
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"यो वालेट प्रयोग गर्न डिभाइस अनलक गर्नुहोस्"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"तपाईंका कार्डहरू प्राप्त गर्ने क्रममा समस्या भयो, कृपया पछि फेरि प्रयास गर्नुहोस्"</string>
<string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"लक स्क्रिनसम्बन्धी सेटिङ"</string>
- <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR कोड"</string>
- <string name="qr_code_scanner_description" msgid="7937603775306661863">"स्क्यान गर्न ट्याप गर्नुहोस्"</string>
+ <string name="qr_code_scanner_title" msgid="5290201053875420785">"QR कोड स्क्यान गर्नुहोस्"</string>
<string name="status_bar_work" msgid="5238641949837091056">"कार्य प्रोफाइल"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"हवाइजहाज मोड"</string>
<string name="zen_alarm_warning" msgid="7844303238486849503">"तपाईँले आफ्नो अर्को अलार्म <xliff:g id="WHEN">%1$s</xliff:g> सुन्नुहुने छैन"</string>
@@ -491,6 +497,8 @@
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"&lt;b&gt;स्थिति:&lt;/b&gt; कम महत्त्वपूर्ण सूचनाका रूपमा सेट गरिएको छ"</string>
<string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"यो वार्तालापका सूचनाहरूको सिरानमा र लक स्क्रिनमा प्रोफाइल फोटोका रूपमा देखिन्छ"</string>
<string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"यो वार्तालापका सूचनाहरूको सिरानमा, बबलका रूपमा र लक स्क्रिनमा प्रोफाइल फोटोका रूपमा देखिन्छ"</string>
+ <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"यो वार्तालापका सूचनाहरूको सिरानमा र लक स्क्रिनमा प्रोफाइल फोटोका रूपमा देखिन्छ। साथै, यसले गर्दा \'बाधा नपुऱ्याउनुहोस्\' नामक सुविधामा अवरोध आउँछ"</string>
+ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"यो वार्तालापका सूचनाहरूको सिरानमा, बबलका रूपमा र लक स्क्रिनमा प्रोफाइल फोटोका रूपमा देखिन्छ। साथै, यसले गर्दा \'बाधा नपुऱ्याउनुहोस्\' नामक सुविधामा अवरोध आउँछ"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"प्राथमिकता"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> मा वार्तालापसम्बन्धी सुविधा प्रयोग गर्न मिल्दैन"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"यी सूचनाहरू परिमार्जन गर्न मिल्दैन।"</string>
@@ -566,6 +574,7 @@
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"SMS"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"सङ्गीत"</string>
<string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"पात्रो"</string>
+ <string name="volume_and_do_not_disturb" msgid="502044092739382832">"बाधा नपुऱ्याउनुहोस्"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"भोल्युम बटनका सर्टकट"</string>
<string name="battery" msgid="769686279459897127">"ब्याट्री"</string>
<string name="headset" msgid="4485892374984466437">"हेडसेट"</string>
@@ -684,6 +693,10 @@
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"Wi‑Fi निष्क्रिय छ"</string>
<string name="bt_is_off" msgid="7436344904889461591">"ब्लुटुथ निष्क्रिय छ"</string>
+ <string name="dnd_is_off" msgid="3185706903793094463">"बाधा नपुर्‍याउनुहोस् नामक विकल्प निष्क्रिय छ"</string>
+ <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"कुनै स्वचालित नियमले बाधा नपुऱ्याउनुहोस् नामक विकल्पलाई सक्रियो गऱ्यो (<xliff:g id="ID_1">%s</xliff:g>)।"</string>
+ <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"कुनै अनुप्रयोगले बाधा नपुऱ्याउनुहोस् नामक विकल्पलाई सक्रिय गऱ्यो (<xliff:g id="ID_1">%s</xliff:g>)।"</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"कुनै स्वचालित नियम वा अनुप्रयोगले बाधा नपुऱ्याउनुहोस् नामक विकल्पलाई सक्रिय गऱ्यो।"</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"पृष्ठभूमिमा चल्ने एपहरू"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"ब्याट्री र डेटाका प्रयोग सम्बन्धी विवरणहरूका लागि ट्याप गर्नुहोस्"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"मोबाइल डेटा निष्क्रिय पार्ने हो?"</string>
@@ -708,6 +721,8 @@
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(कार्यालय)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"फोन कल"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(<xliff:g id="APPLICATION_NAME_S_">%s</xliff:g> मार्फत)"</string>
+ <string name="ongoing_privacy_dialog_attribution_label" msgid="3385241594101496292">"(<xliff:g id="ATTRIBUTION_LABEL">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_proxy_label" msgid="1111829599659403249">"(<xliff:g id="ATTRIBUTION_LABEL">%1$s</xliff:g> • <xliff:g id="PROXY_LABEL">%2$s</xliff:g>)"</string>
<string name="privacy_type_camera" msgid="7974051382167078332">"क्यामेरा"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"स्थान"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"माइक्रोफोन"</string>
@@ -806,6 +821,9 @@
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(डिस्कनेक्ट गरिएको छ)"</string>
<string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"बदल्न सकिएन। फेरि प्रयास गर्न ट्याप गर्नुहोस्।"</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"नयाँ डिभाइस कनेक्ट गर्नुहोस्"</string>
+ <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"यो सत्र कास्ट गर्न चाहनुहुन्छ भने कृपया एप खोल्नुहोस्।"</string>
+ <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"अज्ञात एप"</string>
+ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"कास्ट गर्न छाड्नुहोस्"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"बिल्ड नम्बर"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"बिल्ड नम्बर कपी गरी क्लिपबोर्डमा सारियो।"</string>
<string name="basic_status" msgid="2315371112182658176">"वार्तालाप खोल्नुहोस्"</string>
@@ -839,6 +857,7 @@
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"हालसालैका म्यासेज, मिस कल र स्ट्याटस अपडेट हेर्नुहोस्"</string>
<string name="people_tile_title" msgid="6589377493334871272">"वार्तालाप"</string>
+ <string name="paused_by_dnd" msgid="7856941866433556428">"\'बाधा नपुऱ्याउनुहोस्\' ले पज गरेको छ"</string>
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> ले एउटा म्यासेज पठाउनुभएको छ: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> ले एउटा फोटो पठाउनुभयो"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> ले स्ट्याटस अपडेट गर्नुभएको छ: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
@@ -877,8 +896,7 @@
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> वटा सक्रिय एप</item>
<item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> सक्रिय एप</item>
</plurals>
- <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
- <skip />
+ <string name="fgs_dot_content_description" msgid="2865071539464777240">"नयाँ जानकारी"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"सक्रिय एपहरू"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"रोक्नुहोस्"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"रोकिएको छ"</string>
@@ -889,8 +907,12 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"कपी गरिएको टेक्स्ट सम्पादन गर्नुहोस्"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"कपी गरिएको फोटो सम्पादन गर्नुहोस्"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"नजिकैको डिभाइसमा पठाउनुहोस्"</string>
- <!-- no translation found for add (81036585205287996) -->
- <skip />
- <!-- no translation found for manage_users (1823875311934643849) -->
- <skip />
+ <string name="add" msgid="81036585205287996">"हाल्नुहोस्"</string>
+ <string name="manage_users" msgid="1823875311934643849">"प्रयोगकर्ताहरूको व्यवस्थापन गर्नुहोस्"</string>
+ <string name="drag_split_not_supported" msgid="4326847447699729722">"यो सूचना ड्र्याग गरेर स्प्लिटस्क्रिनमा लैजान मिल्दैन।"</string>
+ <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi उपलब्ध छैन"</string>
+ <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"प्राथमिकता मोड"</string>
+ <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"अलार्म सेट गरिएको छ"</string>
+ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"क्यामेरा र माइक अफ छन्"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# वटा सूचना}other{# वटा सूचनाहरू}}"</string>
</resources>
diff --git a/packages/SystemUI/res/values-night/colors.xml b/packages/SystemUI/res/values-night/colors.xml
index 4b96d5d660ee..3a638b1e5098 100644
--- a/packages/SystemUI/res/values-night/colors.xml
+++ b/packages/SystemUI/res/values-night/colors.xml
@@ -67,10 +67,12 @@
<!-- media output dialog-->
<color name="media_dialog_background">@color/material_dynamic_neutral10</color>
- <color name="media_dialog_active_item_main_content">@color/material_dynamic_neutral10</color>
- <color name="media_dialog_inactive_item_main_content">@color/material_dynamic_neutral10</color>
- <color name="media_dialog_item_status">@color/material_dynamic_neutral10</color>
- <color name="media_dialog_item_background">@color/material_dynamic_secondary95</color>
+ <color name="media_dialog_item_main_content">@color/material_dynamic_primary90</color>
+ <color name="media_dialog_item_background">@color/material_dynamic_neutral_variant20</color>
+ <color name="media_dialog_connected_item_background">@color/material_dynamic_secondary20</color>
+ <color name="media_dialog_seekbar_progress">@color/material_dynamic_secondary40</color>
+ <color name="media_dialog_button_background">@color/material_dynamic_primary70</color>
+ <color name="media_dialog_solid_button_text">@color/material_dynamic_secondary20</color>
<!-- Biometric dialog colors -->
<color name="biometric_dialog_gray">#ffcccccc</color>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index f85bbee74115..0f49b75a06db 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -20,14 +20,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4811759950673118541">"Systeem-UI"</string>
- <string name="battery_low_title" msgid="6891106956328275225">"Batterij is bijna leeg"</string>
+ <string name="battery_low_title" msgid="5319680173344341779">"Batterijbesparing aanzetten?"</string>
+ <string name="battery_low_description" msgid="3282977755476423966">"Je hebt nog <xliff:g id="PERCENTAGE">%s</xliff:g> batterij. Batterijbesparing zet het donkere thema aan, beperkt activiteit op de achtergrond en vertraagt meldingen."</string>
+ <string name="battery_low_intro" msgid="5148725009653088790">"Batterijbesparing zet het donkere thema aan, beperkt activiteit op de achtergrond en vertraagt meldingen."</string>
<string name="battery_low_percent_format" msgid="4276661262843170964">"Nog <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="invalid_charger_title" msgid="938685362320735167">"Kan niet opladen via USB"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"Gebruik de oplader die bij je apparaat is geleverd"</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Batterijbesparing aanzetten?"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Over Batterijbesparing"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Aanzetten"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"Batterijbesparing aanzetten"</string>
+ <string name="battery_saver_start_action" msgid="8353766979886287140">"Aanzetten"</string>
+ <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Nee"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Scherm automatisch draaien"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"<xliff:g id="APPLICATION">%1$s</xliff:g> toegang geven tot <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
<string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"<xliff:g id="APPLICATION">%1$s</xliff:g> toegang geven tot <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nDeze app heeft geen opnamerechten gekregen, maar zou audio kunnen vastleggen via dit USB-apparaat."</string>
@@ -128,6 +131,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Gezicht geverifieerd"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Bevestigd"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Tik op Bevestigen om te voltooien"</string>
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Ontgrendeld met je gezicht. Druk om door te gaan."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Geverifieerd"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Pincode gebruiken"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Patroon gebruiken"</string>
@@ -181,6 +185,7 @@
<string name="accessibility_desc_close" msgid="8293708213442107755">"Sluiten"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"totale stilte"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"alleen wekkers"</string>
+ <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"Niet storen."</string>
<string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"Bluetooth."</string>
<string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"Bluetooth aan."</string>
<string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"Wekker is ingesteld op <xliff:g id="TIME">%s</xliff:g>."</string>
@@ -205,6 +210,7 @@
<string name="dessert_case" msgid="9104973640704357717">"Dessertshowcase"</string>
<string name="start_dreams" msgid="9131802557946276718">"Screensaver"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
+ <string name="quick_settings_dnd_label" msgid="7728690179108024338">"Niet storen"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Geen gekoppelde apparaten beschikbaar"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> batterijniveau"</string>
@@ -261,13 +267,13 @@
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"Werk-apps"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"Nachtverlichting"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"Aan bij zonsondergang"</string>
- <string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"Tot zonsopgang"</string>
+ <string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"Tot zonsopkomst"</string>
<string name="quick_settings_night_secondary_label_on_at" msgid="3584738542293528235">"Aan om <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_secondary_label_until" msgid="1883981263191927372">"Tot <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_ui_mode_night_label" msgid="1398928270610780470">"Donker thema"</string>
<string name="quick_settings_dark_mode_secondary_label_battery_saver" msgid="4990712734503013251">"Batterijbesparing"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at_sunset" msgid="6017379738102015710">"Aan bij zonsondergang"</string>
- <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Tot zonsopgang"</string>
+ <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Tot zonsopkomst"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Aan om <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Tot <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at_bedtime" msgid="2274300599408864897">"Aan als het bedtijd is"</string>
@@ -348,6 +354,7 @@
<string name="notification_section_header_alerting" msgid="5581175033680477651">"Meldingen"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Gesprekken"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Alle stille meldingen wissen"</string>
+ <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Meldingen onderbroken door \'Niet storen\'"</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"Nu starten"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Geen meldingen"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Dit apparaat wordt beheerd door je ouder"</string>
@@ -452,8 +459,8 @@
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Ontgrendelen om te gebruiken"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Er is een probleem opgetreden bij het ophalen van je kaarten. Probeer het later opnieuw."</string>
<string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Instellingen voor vergrendelscherm"</string>
- <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR-code"</string>
- <string name="qr_code_scanner_description" msgid="7937603775306661863">"Tik om te scannen"</string>
+ <!-- no translation found for qr_code_scanner_title (5290201053875420785) -->
+ <skip />
<string name="status_bar_work" msgid="5238641949837091056">"Werkprofiel"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Vliegtuigmodus"</string>
<string name="zen_alarm_warning" msgid="7844303238486849503">"Je hoort je volgende wekker niet <xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -491,6 +498,8 @@
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"&lt;b&gt;Status:&lt;/b&gt; lager gerangschikt"</string>
<string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"Wordt getoond bovenaan gespreksmeldingen en als profielfoto op het vergrendelscherm"</string>
<string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"Wordt getoond bovenaan gespreksmeldingen en als profielfoto op het vergrendelscherm, verschijnt als bubbel"</string>
+ <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"Wordt getoond bovenaan gespreksmeldingen en als profielfoto op het vergrendelscherm, onderbreekt Niet storen"</string>
+ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Wordt getoond bovenaan gespreksmeldingen en als profielfoto op het vergrendelscherm, verschijnt als bubbel, onderbreekt Niet storen"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioriteit"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> ondersteunt geen gespreksfuncties"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Deze meldingen kunnen niet worden aangepast."</string>
@@ -566,6 +575,7 @@
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"Sms"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"Muziek"</string>
<string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Agenda"</string>
+ <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Niet storen"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"Volumeknoppen als sneltoets"</string>
<string name="battery" msgid="769686279459897127">"Batterij"</string>
<string name="headset" msgid="4485892374984466437">"Headset"</string>
@@ -577,7 +587,7 @@
<string name="switch_bar_on" msgid="1770868129120096114">"Aan"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"Uit"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"Niet beschikbaar"</string>
- <string name="tile_disabled" msgid="373212051546573069">"Uit"</string>
+ <string name="tile_disabled" msgid="373212051546573069">"Uitgezet"</string>
<string name="nav_bar" msgid="4642708685386136807">"Navigatiebalk"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"Lay-out"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"Extra knoptype links"</string>
@@ -684,6 +694,10 @@
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"Wifi staat uit"</string>
<string name="bt_is_off" msgid="7436344904889461591">"Bluetooth staat uit"</string>
+ <string name="dnd_is_off" msgid="3185706903793094463">"Niet storen staat uit"</string>
+ <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"Niet storen is aangezet door een automatische regel (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"Niet storen is aangezet door een app (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"Niet storen is aangezet door een automatische regel of app."</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"Apps uitgevoerd op achtergrond"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"Tik voor batterij- en datagebruik"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Mobiele data uitzetten?"</string>
@@ -708,6 +722,8 @@
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(werk)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"Telefoongesprek"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(via <xliff:g id="APPLICATION_NAME_S_">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_label" msgid="3385241594101496292">"(<xliff:g id="ATTRIBUTION_LABEL">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_proxy_label" msgid="1111829599659403249">"(<xliff:g id="ATTRIBUTION_LABEL">%1$s</xliff:g> • <xliff:g id="PROXY_LABEL">%2$s</xliff:g>)"</string>
<string name="privacy_type_camera" msgid="7974051382167078332">"camera"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"locatie"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"microfoon"</string>
@@ -806,8 +822,11 @@
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(verbinding verbroken)"</string>
<string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Kan niet schakelen. Tik om het opnieuw te proberen."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Nieuw apparaat koppelen"</string>
- <string name="build_number_clip_data_label" msgid="3623176728412560914">"Build-nummer"</string>
- <string name="build_number_copy_toast" msgid="877720921605503046">"Build-nummer naar klembord gekopieerd."</string>
+ <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Als je deze sessie wilt casten, open je de app."</string>
+ <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Onbekende app"</string>
+ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Casten stoppen"</string>
+ <string name="build_number_clip_data_label" msgid="3623176728412560914">"Buildnummer"</string>
+ <string name="build_number_copy_toast" msgid="877720921605503046">"Buildnummer naar klembord gekopieerd."</string>
<string name="basic_status" msgid="2315371112182658176">"Gesprek openen"</string>
<string name="select_conversation_title" msgid="6716364118095089519">"Gesprekswidgets"</string>
<string name="select_conversation_text" msgid="3376048251434956013">"Tik op een gesprek om het toe te voegen aan je startscherm"</string>
@@ -839,6 +858,7 @@
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Bekijk recente berichten, gemiste gesprekken en statusupdates"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Gesprek"</string>
+ <string name="paused_by_dnd" msgid="7856941866433556428">"Onderbroken door Niet storen"</string>
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> heeft een bericht gestuurd: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> heeft een afbeelding gestuurd"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> heeft een statusupdate: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
@@ -877,8 +897,7 @@
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> actieve apps</item>
<item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> actieve app</item>
</plurals>
- <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
- <skip />
+ <string name="fgs_dot_content_description" msgid="2865071539464777240">"Nieuwe informatie"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Actieve apps"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Stoppen"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Gestopt"</string>
@@ -886,14 +905,15 @@
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Gekopieerd"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Uit <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"UI voor kopiëren sluiten"</string>
- <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
- <skip />
- <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
- <skip />
- <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
- <skip />
- <!-- no translation found for add (81036585205287996) -->
- <skip />
- <!-- no translation found for manage_users (1823875311934643849) -->
- <skip />
+ <string name="clipboard_edit_text_description" msgid="805254383912962103">"Gekopieerde tekst bewerken"</string>
+ <string name="clipboard_edit_image_description" msgid="8904857948976041306">"Gekopieerde afbeelding bewerken"</string>
+ <string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Naar apparaat in de buurt sturen"</string>
+ <string name="add" msgid="81036585205287996">"Toevoegen"</string>
+ <string name="manage_users" msgid="1823875311934643849">"Gebruikers beheren"</string>
+ <string name="drag_split_not_supported" msgid="4326847447699729722">"Deze melding biedt geen ondersteuning voor slepen naar het gesplitste scherm."</string>
+ <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wifi niet beschikbaar"</string>
+ <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Prioriteitsmodus"</string>
+ <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Wekker gezet"</string>
+ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Camera en microfoon staan uit"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# melding}other{# meldingen}}"</string>
</resources>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index dab199b72aa3..ed1fbbccdbe0 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -20,14 +20,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4811759950673118541">"ସିଷ୍ଟମ୍ UI"</string>
- <string name="battery_low_title" msgid="6891106956328275225">"ଖୁବ୍ ଶୀଘ୍ର ବ୍ୟାଟେରୀ ସରିଯାଇପାରେ"</string>
+ <string name="battery_low_title" msgid="5319680173344341779">"ବ୍ୟାଟେରୀ ସେଭର ଚାଲୁ କରିବେ?"</string>
+ <string name="battery_low_description" msgid="3282977755476423966">"ଆପଣଙ୍କର <xliff:g id="PERCENTAGE">%s</xliff:g> ବ୍ୟାଟେରୀ ଚାର୍ଜ ବାକି ଅଛି। ବ୍ୟାଟେରୀ ସେଭର ଗାଢ଼ା ଥିମକୁ ଚାଲୁ କରେ, ପୃଷ୍ଠପଟ କାର୍ଯ୍ୟକଳାପକୁ ପ୍ରତିବନ୍ଧିତ କରେ ଏବଂ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକୁ ବିଳମ୍ବିତ କରେ।"</string>
+ <string name="battery_low_intro" msgid="5148725009653088790">"ବ୍ୟାଟେରୀ ସେଭର ଗାଢ଼ା ଥିମକୁ ଚାଲୁ କରେ, ପୃଷ୍ଠପଟ କାର୍ଯ୍ୟକଳାପକୁ ପ୍ରତିବନ୍ଧିତ କରେ ଏବଂ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକୁ ବିଳମ୍ବିତ କରେ।"</string>
<string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> ବାକି ଅଛି"</string>
<string name="invalid_charger_title" msgid="938685362320735167">"USB ଦ୍ଵାରା ଚାର୍ଜ କରିହେବନାହିଁ"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"ଆପଣଙ୍କ ଡିଭାଇସ୍ ପାଇଁ ଥିବା ଚାର୍ଜର୍‌କୁ ବ୍ୟବହାର କରନ୍ତୁ"</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"ବ୍ୟାଟେରୀ ସେଭର୍‌ ଚାଲୁ କରିବେ?"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"ବ୍ୟାଟେରୀ ସେଭର୍ ବିଷୟରେ"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"ଚାଲୁ‌ କରନ୍ତୁ"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"ବ୍ୟାଟେରୀ ସେଭର୍‌ ଚାଲୁ କରନ୍ତୁ"</string>
+ <string name="battery_saver_start_action" msgid="8353766979886287140">"ଚାଲୁ କରନ୍ତୁ"</string>
+ <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"ନା, ଧନ୍ୟବାଦ"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"ଅଟୋ-ରୋଟେଟ୍‌ ସ୍କ୍ରିନ୍"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> ଆକ୍ସେସ୍‍ କରିବାକୁ <xliff:g id="APPLICATION">%1$s</xliff:g>କୁ ଅନୁମତି ଦେବେ?"</string>
<string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> ଆକ୍ସେସ୍ କରିବାକୁ <xliff:g id="APPLICATION">%1$s</xliff:g>କୁ ଅନୁମତି ଦେବେ କି?\nଏହି ଆପ୍‌କୁ ରେକର୍ଡ କରିବାକୁ ଅନୁମତି ଦିଆଯାଇ ନାହିଁ କିନ୍ତୁ ଏହି USB ଡିଭାଇସ୍ ଜରିଆରେ ଅଡିଓ କ୍ୟାପ୍ଟର୍ କରିପାରିବ।"</string>
@@ -128,6 +131,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"ମୁହଁ ପ୍ରାମାଣିକତା ହୋଇଛି"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"ସୁନିଶ୍ଚିତ କରାଯାଇଛି"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"ସମ୍ପୂର୍ଣ୍ଣ କରିବାକୁ ସୁନିଶ୍ଚିତ କରନ୍ତୁରେ ଟାପ୍ କରନ୍ତୁ"</string>
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"ଆପଣଙ୍କ ଫେସ ମାଧ୍ୟମରେ ଅନଲକ କରାଯାଇଛି। ଜାରି ରଖିବାକୁ ଦବାନ୍ତୁ।"</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"ପ୍ରାମାଣିକତା ହୋଇଛି"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"PIN ବ୍ୟବହାର କରନ୍ତୁ"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"ପାଟର୍ନ ବ୍ୟବହାର କରନ୍ତୁ"</string>
@@ -181,6 +185,7 @@
<string name="accessibility_desc_close" msgid="8293708213442107755">"ବନ୍ଦ କରନ୍ତୁ"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"ସମ୍ପୂର୍ଣ୍ଣ ନୀରବତା"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"କେବଳ ଆଲାର୍ମ"</string>
+ <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ।"</string>
<string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"ବ୍ଲୁଟୁଥ।"</string>
<string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"ବ୍ଲୁଟୂଥ୍‍‍ ଚାଲୁ ଅଛି।"</string>
<string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"<xliff:g id="TIME">%s</xliff:g>ରେ ଆଲାର୍ମ ସେଟ୍‍ କରାଯାଇଛି।"</string>
@@ -205,6 +210,7 @@
<string name="dessert_case" msgid="9104973640704357717">"ଡେଜର୍ଟ କେସ୍‌"</string>
<string name="start_dreams" msgid="9131802557946276718">"ସ୍କ୍ରିନ୍‌ ସେଭର୍‌"</string>
<string name="ethernet_label" msgid="2203544727007463351">"ଇଥରନେଟ୍‌"</string>
+ <string name="quick_settings_dnd_label" msgid="7728690179108024338">"ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"ବ୍ଲୁଟୁଥ"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"ପେୟାର୍‍ ହୋଇଥିବା କୌଣସି ଡିଭାଇସ୍ ଉପଲବ୍ଧ ନାହିଁ"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> ବ୍ୟାଟେରୀ"</string>
@@ -348,6 +354,7 @@
<string name="notification_section_header_alerting" msgid="5581175033680477651">"ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକ"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"ବାର୍ତ୍ତାଳାପଗୁଡ଼ିକ"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"ସମସ୍ତ ନୀରବ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକ ଖାଲି କରନ୍ତୁ"</string>
+ <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"\"ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ\" ବିକଳ୍ପ ଦ୍ୱାରା ବିଜ୍ଞପ୍ତି ପଜ୍‍ ହୋଇଛି"</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"ବର୍ତ୍ତମାନ ଆରମ୍ଭ କରନ୍ତୁ"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"କୌଣସି ବିଜ୍ଞପ୍ତି ନାହିଁ"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"ଏହି ଡିଭାଇସ୍ ଆପଣଙ୍କ ବାପାମାଙ୍କ ଦ୍ୱାରା ପରିଚାଳିତ"</string>
@@ -452,8 +459,8 @@
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"ବ୍ୟବହାର କରିବାକୁ ଅନଲକ୍ କରନ୍ତୁ"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"ଆପଣଙ୍କ କାର୍ଡଗୁଡ଼ିକ ପାଇବାରେ ଏକ ସମସ୍ୟା ହୋଇଥିଲା। ଦୟାକରି ପରେ ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ"</string>
<string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"ସ୍କ୍ରିନ୍ ଲକ୍ ସେଟିଂସ୍"</string>
- <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR କୋଡ"</string>
- <string name="qr_code_scanner_description" msgid="7937603775306661863">"ସ୍କାନ କରିବାକୁ ଟାପ କରନ୍ତୁ"</string>
+ <!-- no translation found for qr_code_scanner_title (5290201053875420785) -->
+ <skip />
<string name="status_bar_work" msgid="5238641949837091056">"ୱର୍କ ପ୍ରୋଫାଇଲ୍‌"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"ଏରୋପ୍ଲେନ୍‍ ମୋଡ୍"</string>
<string name="zen_alarm_warning" msgid="7844303238486849503">"<xliff:g id="WHEN">%1$s</xliff:g>ବେଳେ ଆପଣ ନିଜର ପରବର୍ତ୍ତୀ ଆଲାର୍ମ ଶୁଣିପାରିବେ ନାହିଁ"</string>
@@ -491,6 +498,8 @@
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"&lt;b&gt;ସ୍ଥିତି:&lt;/b&gt; ରେଙ୍କ ତଳକୁ କରାଯାଇଛି"</string>
<string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"ବାର୍ତ୍ତାଳାପ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକର ଶୀର୍ଷରେ ଏବଂ ଲକ୍ ସ୍କ୍ରିନରେ ଏକ ପ୍ରୋଫାଇଲ୍ ଛବି ଭାବେ ଦେଖାଏ"</string>
<string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"ବାର୍ତ୍ତାଳାପ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକର ଶୀର୍ଷରେ ଏବଂ ଲକ୍ ସ୍କ୍ରିନରେ ଏକ ପ୍ରୋଫାଇଲ୍ ଛବି ଭାବେ ଦେଖାଏ, ଏକ ବବଲ୍ ଭାବେ ଦେଖାଯାଏ"</string>
+ <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"ବାର୍ତ୍ତାଳାପ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକର ଶୀର୍ଷରେ ଏବଂ ଲକ୍ ସ୍କ୍ରିନରେ ଏକ ପ୍ରୋଫାଇଲ୍ ଛବି ଭାବେ ଦେଖାଏ, \'ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ\'କୁ ବାଧା ଦିଏ"</string>
+ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"ବାର୍ତ୍ତାଳାପ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକର ଶୀର୍ଷରେ ଏବଂ ଲକ୍ ସ୍କ୍ରିନରେ ଏକ ପ୍ରୋଫାଇଲ୍ ଛବି ଭାବେ ଦେଖାଏ, ଏକ ବବଲ୍ ଭାବେ ଦେଖାଯାଏ, \'ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ\'କୁ ବାଧା ଦିଏ"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"ପ୍ରାଥମିକତା"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> ବାର୍ତ୍ତାଳାପ ଫିଚରଗୁଡ଼ିକୁ ସମର୍ଥନ କରେ ନାହିଁ"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"ଏହି ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକ ପରିବର୍ତ୍ତନ କରିହେବ ନାହିଁ।"</string>
@@ -566,6 +575,7 @@
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"SMS"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"ମ୍ୟୁଜିକ୍‍"</string>
<string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"କ୍ୟାଲେଣ୍ଡର୍"</string>
+ <string name="volume_and_do_not_disturb" msgid="502044092739382832">"ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"ଭଲ୍ୟୁମ ବଟନ୍‍ ଶର୍ଟକଟ୍‍"</string>
<string name="battery" msgid="769686279459897127">"ବ୍ୟାଟେରୀ"</string>
<string name="headset" msgid="4485892374984466437">"ହେଡସେଟ୍‍"</string>
@@ -632,7 +642,7 @@
<string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"ଦ୍ରୁତ ସେଟିଙ୍ଗ ଏଡିଟର୍।"</string>
<string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"<xliff:g id="ID_1">%1$s</xliff:g> ବିଜ୍ଞପ୍ତି: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"ସେଟିଂସ୍ ଖୋଲନ୍ତୁ।"</string>
- <string name="accessibility_quick_settings_expand" msgid="2609275052412521467">"ଦ୍ରୁତ ସେଟିଙ୍ଗ ଖୋଲନ୍ତୁ।"</string>
+ <string name="accessibility_quick_settings_expand" msgid="2609275052412521467">"କ୍ଵିକ ସେଟିଂସ ଖୋଲନ୍ତୁ।"</string>
<string name="accessibility_quick_settings_collapse" msgid="4674876336725041982">"ଦ୍ରୁତ ସେଟିଂସ୍ ବନ୍ଦ କରନ୍ତୁ।"</string>
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"<xliff:g id="ID_1">%s</xliff:g> ଭାବରେ ସାଇନ୍‌ ଇନ୍‌ କରିଛନ୍ତି"</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"ଉପଯୋଗକର୍ତ୍ତା ବାଛନ୍ତୁ"</string>
@@ -684,6 +694,10 @@
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"ୱାଇ-ଫାଇ ଅଫ୍‍ ଅଛି"</string>
<string name="bt_is_off" msgid="7436344904889461591">"ବ୍ଲୁଟୂଥ୍‍‌ ଅଫ୍ ଅଛି"</string>
+ <string name="dnd_is_off" msgid="3185706903793094463">"\"ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ\" ଅଫ୍‍ ଅଛି"</string>
+ <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"ଏକ (<xliff:g id="ID_1">%s</xliff:g>) ନିୟମ ଦ୍ୱାରା \"ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ\" ସ୍ୱଚାଳିତ ଭାବେ ଅନ୍‍ କରାଗଲା।"</string>
+ <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"ଏକ ଆପ୍‍ (<xliff:g id="ID_1">%s</xliff:g>) ଦ୍ୱାରା \"ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ\" ଅନ୍‌ କରାଗଲା।"</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"ଏକ ସ୍ୱଚାଳିତ ନିୟମ କିମ୍ବା ଆପ୍‍ ଦ୍ୱାରା \"ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ\" ଅନ୍‍ କରାଗଲା।"</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"ବ୍ୟାକଗ୍ରାଉଣ୍ଡରେ ଆପ୍‍ ଚାଲୁଛି"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"ବ୍ୟାଟେରୀ ଏବଂ ଡାଟା ବ୍ୟବହାର ଉପରେ ବିବରଣୀ ପାଇଁ ଟାପ୍‍ କରନ୍ତୁ"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"ମୋବାଇଲ୍‌ ଡାଟା ବନ୍ଦ କରିବେ?"</string>
@@ -708,6 +722,8 @@
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(ୱାର୍କ)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"ଫୋନ୍ କଲ୍"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(<xliff:g id="APPLICATION_NAME_S_">%s</xliff:g> ମାଧ୍ୟମରେ)"</string>
+ <string name="ongoing_privacy_dialog_attribution_label" msgid="3385241594101496292">"(<xliff:g id="ATTRIBUTION_LABEL">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_proxy_label" msgid="1111829599659403249">"(<xliff:g id="ATTRIBUTION_LABEL">%1$s</xliff:g> • <xliff:g id="PROXY_LABEL">%2$s</xliff:g>)"</string>
<string name="privacy_type_camera" msgid="7974051382167078332">"କ୍ୟାମେରା"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"ଲୋକେସନ୍‍"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"ମାଇକ୍ରୋଫୋନ୍"</string>
@@ -806,6 +822,9 @@
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(ବିଚ୍ଛିନ୍ନ କରାଯାଇଛି)"</string>
<string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"ସ୍ୱିଚ କରାଯାଇପାରିବ ନାହିଁ। ପୁଣି ଚେଷ୍ଟା କରିବାକୁ ଟାପ କରନ୍ତୁ।"</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"ନୂଆ ଡିଭାଇସକୁ ପେୟାର୍ କରନ୍ତୁ"</string>
+ <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"ଏହି ସେସନକୁ କାଷ୍ଟ କରିବା ପାଇଁ, ଦୟାକରି ଆପ ଖୋଲନ୍ତୁ।"</string>
+ <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"ଅଜଣା ଆପ"</string>
+ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"କାଷ୍ଟ କରିବା ବନ୍ଦ କରନ୍ତୁ"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"ବିଲ୍ଡ ନମ୍ୱର"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"କ୍ଲିପବୋର୍ଡକୁ କପି କରାଯାଇଥିବା ବିଲ୍ଡ ନମ୍ୱର।"</string>
<string name="basic_status" msgid="2315371112182658176">"ବାର୍ତ୍ତାଳାପ ଖୋଲନ୍ତୁ"</string>
@@ -839,6 +858,7 @@
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"ବର୍ତ୍ତମାନର ମେସେଜ୍, ମିସ୍ଡ କଲ୍ ଏବଂ ସ୍ଥିତି ଅପଡେଟଗୁଡ଼ିକୁ ଦେଖନ୍ତୁ"</string>
<string name="people_tile_title" msgid="6589377493334871272">"ବାର୍ତ୍ତାଳାପ"</string>
+ <string name="paused_by_dnd" msgid="7856941866433556428">"\"ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ\" ଦ୍ୱାରା ବିରତ କରାଯାଇଛି"</string>
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> ଏକ ମେସେଜ୍ ପଠାଇଛନ୍ତି: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> ଏକ ଛବି ପଠାଇଛନ୍ତି"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> ଏକ ସ୍ଥିତି ଅପଡେଟ୍ କରିଛନ୍ତି: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
@@ -877,8 +897,7 @@
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g>ଟି ସକ୍ରିୟ ଆପ</item>
<item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g>ଟି ସକ୍ରିୟ ଆପ</item>
</plurals>
- <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
- <skip />
+ <string name="fgs_dot_content_description" msgid="2865071539464777240">"ନୂଆ ସୂଚନା"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"ସକ୍ରିୟ ଆପଗୁଡ଼ିକ"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"ବନ୍ଦ କରନ୍ତୁ"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"ବନ୍ଦ ହୋଇଛି"</string>
@@ -889,8 +908,12 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"କପି କରାଯାଇଥିବା ଟେକ୍ସଟକୁ ଏଡିଟ କରନ୍ତୁ"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"କପି କରାଯାଇଥିବା ଇମେଜକୁ ଏଡିଟ କରନ୍ତୁ"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"ନିକଟସ୍ଥ ଡିଭାଇସକୁ ପଠାନ୍ତୁ"</string>
- <!-- no translation found for add (81036585205287996) -->
- <skip />
- <!-- no translation found for manage_users (1823875311934643849) -->
- <skip />
+ <string name="add" msgid="81036585205287996">"ଯୋଗ କରନ୍ତୁ"</string>
+ <string name="manage_users" msgid="1823875311934643849">"ଉପଯୋଗକର୍ତ୍ତାମାନଙ୍କୁ ପରିଚାଳନା କରନ୍ତୁ"</string>
+ <string name="drag_split_not_supported" msgid="4326847447699729722">"ଏହି ବିଜ୍ଞପ୍ତି ସ୍ପ୍ଲିଟସ୍କ୍ରିନକୁ ଡ୍ରାଗ କରିବାକୁ ସମର୍ଥନ କରେ ନାହିଁ।"</string>
+ <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"ୱାଇ-ଫାଇ ଉପଲବ୍ଧ ନାହିଁ"</string>
+ <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"ପ୍ରାଥମିକତା ମୋଡ"</string>
+ <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"ଆଲାରାମ ସେଟ"</string>
+ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"କ୍ୟାମେରା ଏବଂ ମାଇକ ବନ୍ଦ ଅଛି"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{#ଟି ବିଜ୍ଞପ୍ତି}other{#ଟି ବିଜ୍ଞପ୍ତି}}"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index 20b5bf21ded3..beda96084ddd 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -20,14 +20,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4811759950673118541">"ਸਿਸਟਮ UI"</string>
- <string name="battery_low_title" msgid="6891106956328275225">"ਬੈਟਰੀ ਛੇਤੀ ਹੀ ਖਤਮ ਹੋ ਸਕਦੀ ਹੈ"</string>
+ <string name="battery_low_title" msgid="5319680173344341779">"ਕੀ ਬੈਟਰੀ ਸੇਵਰ ਚਾਲੂ ਕਰਨਾ ਹੈ?"</string>
+ <string name="battery_low_description" msgid="3282977755476423966">"ਤੁਹਾਡੇ ਕੋਲ <xliff:g id="PERCENTAGE">%s</xliff:g> ਬੈਟਰੀ ਬਾਕੀ ਬਚੀ ਹੈ। ਬੈਟਰੀ ਸੇਵਰ ਗੂੜ੍ਹੇ ਥੀਮ ਨੂੰ ਚਾਲੂ ਕਰਦਾ ਹੈ, ਬੈਕਗ੍ਰਾਊਂਡ ਸਰਗਰਮੀ \'ਤੇ ਪਾਬੰਦੀ ਲਗਾਉਂਦਾ ਹੈ ਅਤੇ ਸੂਚਨਾਵਾਂ ਵਿੱਚ ਦੇਰੀ ਕਰਦਾ ਹੈ।"</string>
+ <string name="battery_low_intro" msgid="5148725009653088790">"ਬੈਟਰੀ ਸੇਵਰ ਗੂੜ੍ਹੇ ਥੀਮ ਨੂੰ ਚਾਲੂ ਕਰਦਾ ਹੈ, ਬੈਕਗ੍ਰਾਊਂਡ ਸਰਗਰਮੀ \'ਤੇ ਪਾਬੰਦੀ ਲਗਾਉਂਦਾ ਹੈ ਅਤੇ ਸੂਚਨਾਵਾਂ ਵਿੱਚ ਦੇਰੀ ਕਰਦਾ ਹੈ।"</string>
<string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> ਬਾਕੀ"</string>
<string name="invalid_charger_title" msgid="938685362320735167">"USB ਰਾਹੀਂ ਚਾਰਜ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"ਆਪਣੇ ਡੀਵਾਈਸ ਨਾਲ ਮਿਲੇ ਚਾਰਜਰ ਦੀ ਵਰਤੋਂ ਕਰੋ"</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"ਕੀ ਬੈਟਰੀ ਸੇਵਰ ਚਾਲੂ ਕਰਨਾ ਹੈ?"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"ਬੈਟਰੀ ਸੇਵਰ ਬਾਰੇ"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"ਚਾਲੂ ਕਰੋ"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"ਬੈਟਰੀ ਸੇਵਰ ਚਾਲੂ ਕਰੋ"</string>
+ <string name="battery_saver_start_action" msgid="8353766979886287140">"ਚਾਲੂ ਕਰੋ"</string>
+ <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"ਨਹੀਂ ਧੰਨਵਾਦ"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"ਸਕ੍ਰੀਨ ਸਵੈ-ਘੁਮਾਓ"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"ਕੀ <xliff:g id="USB_DEVICE">%2$s</xliff:g> ਤੱਕ <xliff:g id="APPLICATION">%1$s</xliff:g> ਨੂੰ ਪਹੁੰਚ ਕਰਨ ਦੇਣੀ ਹੈ?"</string>
<string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"ਕੀ <xliff:g id="APPLICATION">%1$s</xliff:g> ਨੂੰ <xliff:g id="USB_DEVICE">%2$s</xliff:g> ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੇਣੀ ਹੈ?\nਇਸ ਐਪ ਨੂੰ ਰਿਕਾਰਡ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਨਹੀਂ ਦਿੱਤੀ ਗਈ ਪਰ ਇਹ USB ਡੀਵਾਈਸ ਰਾਹੀਂ ਆਡੀਓ ਕੈਪਚਰ ਕਰ ਸਕਦੀ ਹੈ।"</string>
@@ -128,6 +131,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"ਚਿਹਰਾ ਪ੍ਰਮਾਣੀਕਿਰਤ ਹੋਇਆ"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"ਪੁਸ਼ਟੀ ਕੀਤੀ ਗਈ"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"ਪੂਰਾ ਕਰਨ ਲਈ ਪੁਸ਼ਟੀ ਕਰੋ \'ਤੇ ਟੈਪ ਕਰੋ"</string>
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"ਤੁਹਾਡੇ ਚਿਹਰੇ ਵੱਲੋਂ ਅਣਲਾਕ ਕੀਤਾ ਗਿਆ। ਜਾਰੀ ਰੱਖਣ ਲਈ ਦਬਾਓ।"</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"ਪ੍ਰਮਾਣਿਤ ਹੋਇਆ"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"ਪਿੰਨ ਵਰਤੋ"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"ਪੈਟਰਨ ਵਰਤੋ"</string>
@@ -181,6 +185,7 @@
<string name="accessibility_desc_close" msgid="8293708213442107755">"ਬੰਦ ਕਰੋ"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"ਪੂਰਾ ਸ਼ਾਂਤ"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"ਸਿਰਫ਼ ਅਲਾਰਮ"</string>
+ <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"ਪਰੇਸ਼ਾਨ ਨਾ ਕਰੋ।"</string>
<string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"ਬਲੂਟੁੱਥ।"</string>
<string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"Bluetooth ਚਾਲੂ।"</string>
<string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"ਅਲਾਰਮ <xliff:g id="TIME">%s</xliff:g> ਲਈ ਸੈੱਟ ਕੀਤਾ ਗਿਆ।"</string>
@@ -205,6 +210,7 @@
<string name="dessert_case" msgid="9104973640704357717">"ਡੈਜ਼ਰਟ ਕੇਸ"</string>
<string name="start_dreams" msgid="9131802557946276718">"ਸਕ੍ਰੀਨ ਸੇਵਰ"</string>
<string name="ethernet_label" msgid="2203544727007463351">"ਈਥਰਨੈਟ"</string>
+ <string name="quick_settings_dnd_label" msgid="7728690179108024338">"ਪਰੇਸ਼ਾਨ ਨਾ ਕਰੋ"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"ਬਲੂਟੁੱਥ"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"ਕੋਈ ਜੋੜਾਬੱਧ ਕੀਤੀਆਂ ਡੀਵਾਈਸਾਂ ਉਪਲਬਧ ਨਹੀਂ"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> ਬੈਟਰੀ"</string>
@@ -348,6 +354,7 @@
<string name="notification_section_header_alerting" msgid="5581175033680477651">"ਸੂਚਨਾਵਾਂ"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"ਗੱਲਾਂਬਾਤਾਂ"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"ਸਾਰੀਆਂ ਖਾਮੋਸ਼ ਸੂਚਨਾਵਾਂ ਕਲੀਅਰ ਕਰੋ"</string>
+ <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"\'ਪਰੇਸ਼ਾਨ ਨਾ ਕਰੋ\' ਵੱਲੋਂ ਸੂਚਨਾਵਾਂ ਨੂੰ ਰੋਕਿਆ ਗਿਆ"</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"ਹੁਣ ਚਾਲੂ ਕਰੋ"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"ਕੋਈ ਸੂਚਨਾਵਾਂ ਨਹੀਂ"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"ਇਸ ਡੀਵਾਈਸ ਦਾ ਪ੍ਰਬੰਧਨ ਤੁਹਾਡੇ ਮਾਂ-ਪਿਓ ਵੱਲੋਂ ਕੀਤਾ ਜਾਂਦਾ ਹੈ"</string>
@@ -452,8 +459,8 @@
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"ਵਰਤਣ ਲਈ ਅਣਲਾਕ ਕਰੋ"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"ਤੁਹਾਡੇ ਕਾਰਡ ਪ੍ਰਾਪਤ ਕਰਨ ਵਿੱਚ ਕੋਈ ਸਮੱਸਿਆ ਆਈ, ਕਿਰਪਾ ਕਰਕੇ ਬਾਅਦ ਵਿੱਚ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ"</string>
<string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"ਲਾਕ ਸਕ੍ਰੀਨ ਸੈਟਿੰਗਾਂ"</string>
- <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR ਕੋਡ"</string>
- <string name="qr_code_scanner_description" msgid="7937603775306661863">"ਸਕੈਨ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ"</string>
+ <!-- no translation found for qr_code_scanner_title (5290201053875420785) -->
+ <skip />
<string name="status_bar_work" msgid="5238641949837091056">"ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"ਹਵਾਈ-ਜਹਾਜ਼ ਮੋਡ"</string>
<string name="zen_alarm_warning" msgid="7844303238486849503">"ਤੁਸੀਂ <xliff:g id="WHEN">%1$s</xliff:g> ਵਜੇ ਆਪਣਾ ਅਗਲਾ ਅਲਾਰਮ ਨਹੀਂ ਸੁਣੋਗੇ"</string>
@@ -491,6 +498,8 @@
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"&lt;b&gt;ਸਥਿਤੀ:&lt;/b&gt; ਦਰਜਾ ਘਟਾਇਆ ਗਿਆ"</string>
<string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"ਗੱਲਬਾਤ ਸੂਚਨਾਵਾਂ ਦੇ ਸਿਖਰ \'ਤੇ ਅਤੇ ਲਾਕ ਸਕ੍ਰੀਨ \'ਤੇ ਪ੍ਰੋਫਾਈਲ ਤਸਵੀਰ ਵਜੋਂ ਦਿਖਾਉਂਦਾ ਹੈ"</string>
<string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"ਗੱਲਬਾਤ ਸੂਚਨਾਵਾਂ ਦੇ ਸਿਖਰ \'ਤੇ ਅਤੇ ਲਾਕ ਸਕ੍ਰੀਨ \'ਤੇ ਪ੍ਰੋਫਾਈਲ ਤਸਵੀਰ ਵਜੋਂ ਦਿਖਾਈਆਂ ਜਾਂਦੀਆਂ ਹਨ, ਜੋ ਕਿ ਬਬਲ ਵਜੋਂ ਦਿਸਦੀਆਂ ਹਨ"</string>
+ <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"ਗੱਲਬਾਤ ਸੂਚਨਾਵਾਂ ਦੇ ਸਿਖਰ \'ਤੇ ਅਤੇ ਲਾਕ ਸਕ੍ਰੀਨ \'ਤੇ ਪ੍ਰੋਫਾਈਲ ਤਸਵੀਰ ਵਜੋਂ ਦਿਖਾਉਂਦਾ ਹੈ, \'ਪਰੇਸ਼ਾਨ ਨਾ ਕਰੋ\' ਸੁਵਿਧਾ ਵਿੱਚ ਵੀ ਵਿਘਨ ਪੈ ਸਕਦਾ ਹੈ"</string>
+ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"ਗੱਲਬਾਤ ਸੂਚਨਾਵਾਂ ਦੇ ਸਿਖਰ \'ਤੇ ਅਤੇ ਲਾਕ ਸਕ੍ਰੀਨ \'ਤੇ ਪ੍ਰੋਫਾਈਲ ਤਸਵੀਰ ਵਜੋਂ ਦਿਖਾਈਆਂ ਜਾਂਦੀਆਂ ਹਨ, ਜੋ ਕਿ ਬਬਲ ਵਜੋਂ ਦਿਸਦੀਆਂ ਹਨ ਅਤੇ \'ਪਰੇਸ਼ਾਨ ਨਾ ਕਰੋ\' ਸੁਵਿਧਾ ਵਿੱਚ ਵਿਘਨ ਵੀ ਪਾ ਸਕਦੀਆਂ ਹਨ"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"ਤਰਜੀਹ"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਐਪ ਗੱਲਬਾਤ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਦਾ ਸਮਰਥਨ ਨਹੀਂ ਕਰਦੀ"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"ਇਹਨਾਂ ਸੂਚਨਾਵਾਂ ਨੂੰ ਸੋਧਿਆ ਨਹੀਂ ਜਾ ਸਕਦਾ।"</string>
@@ -566,6 +575,7 @@
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"SMS"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"ਸੰਗੀਤ"</string>
<string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Calendar"</string>
+ <string name="volume_and_do_not_disturb" msgid="502044092739382832">"ਪਰੇਸ਼ਾਨ ਨਾ ਕਰੋ"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"ਵੌਲਿਊਮ ਬਟਨ ਸ਼ਾਰਟਕੱਟ"</string>
<string name="battery" msgid="769686279459897127">"ਬੈਟਰੀ"</string>
<string name="headset" msgid="4485892374984466437">"ਹੈੱਡਸੈੱਟ"</string>
@@ -684,6 +694,10 @@
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"ਵਾਈ-ਫਾਈ ਬੰਦ ਹੈ"</string>
<string name="bt_is_off" msgid="7436344904889461591">"ਬਲੂਟੁੱਥ ਬੰਦ ਹੈ"</string>
+ <string name="dnd_is_off" msgid="3185706903793094463">"\'ਪਰੇਸ਼ਾਨ ਨਾ ਕਰੋ\' ਬੰਦ ਹੈ"</string>
+ <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"ਸਵੈਚਲਿਤ ਨਿਯਮ (<xliff:g id="ID_1">%s</xliff:g>) ਦੁਆਰਾ \'ਪਰੇਸ਼ਾਨ ਨਾ ਕਰੋ\' ਚਾਲੂ ਕੀਤਾ ਗਿਆ ਸੀ।"</string>
+ <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"ਐਪ (<xliff:g id="ID_1">%s</xliff:g>) ਵੱਲੋਂ \'ਪਰੇਸ਼ਾਨ ਨਾ ਕਰੋ\' ਚਾਲੂ ਕੀਤਾ ਗਿਆ ਸੀ।"</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"ਇੱਕ ਸਵੈਚਲਿਤ ਨਿਯਮ ਜਾਂ ਐਪ ਵੱਲੋਂ \'ਪਰੇਸ਼ਾਨ ਨਾ ਕਰੋ\' ਚਾਲੂ ਕੀਤਾ ਗਿਆ ਸੀ।"</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"ਬੈਕਗ੍ਰਾਊਂਡ ਵਿੱਚ ਚੱਲ ਰਹੀਆਂ ਐਪਾਂ"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"ਬੈਟਰੀ ਅਤੇ ਡਾਟਾ ਵਰਤੋਂ ਸਬੰਧੀ ਵੇਰਵਿਆਂ ਲਈ ਟੈਪ ਕਰੋ"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"ਕੀ ਮੋਬਾਈਲ ਡਾਟਾ ਬੰਦ ਕਰਨਾ ਹੈ?"</string>
@@ -708,6 +722,8 @@
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(ਕਾਰਜ-ਸਥਾਨ)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"ਫ਼ੋਨ ਕਾਲ"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(<xliff:g id="APPLICATION_NAME_S_">%s</xliff:g> ਰਾਹੀਂ)"</string>
+ <string name="ongoing_privacy_dialog_attribution_label" msgid="3385241594101496292">"(<xliff:g id="ATTRIBUTION_LABEL">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_proxy_label" msgid="1111829599659403249">"(<xliff:g id="ATTRIBUTION_LABEL">%1$s</xliff:g> • <xliff:g id="PROXY_LABEL">%2$s</xliff:g>)"</string>
<string name="privacy_type_camera" msgid="7974051382167078332">"ਕੈਮਰਾ"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"ਟਿਕਾਣਾ"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"ਮਾਈਕ੍ਰੋਫ਼ੋਨ"</string>
@@ -806,6 +822,9 @@
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(ਡਿਸਕਨੈਕਟ ਹੈ)"</string>
<string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"ਬਦਲਿਆ ਨਹੀਂ ਜਾ ਸਕਦਾ। ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ।"</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"ਨਵਾਂ ਡੀਵਾਈਸ ਜੋੜਾਬੱਧ ਕਰੋ"</string>
+ <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"ਇਸ ਸੈਸ਼ਨ ਨੂੰ ਕਾਸਟ ਕਰਨ ਲਈ, ਕਿਰਪਾ ਕਰਕੇ ਐਪ ਖੋਲ੍ਹੋ।"</string>
+ <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"ਅਗਿਆਤ ਐਪ"</string>
+ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"ਕਾਸਟ ਕਰਨਾ ਬੰਦ ਕਰੋ"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"ਬਿਲਡ ਨੰਬਰ"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"ਬਿਲਡ ਨੰਬਰ ਨੂੰ ਕਲਿੱਪਬੋਰਡ \'ਤੇ ਕਾਪੀ ਕੀਤਾ ਗਿਆ।"</string>
<string name="basic_status" msgid="2315371112182658176">"ਗੱਲਬਾਤ ਖੋਲ੍ਹੋ"</string>
@@ -839,6 +858,7 @@
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"ਹਾਲੀਆ ਸੁਨੇਹੇ, ਮਿਸ ਕਾਲਾਂ ਅਤੇ ਸਥਿਤੀ ਸੰਬੰਧੀ ਅੱਪਡੇਟ ਦੇਖੋ"</string>
<string name="people_tile_title" msgid="6589377493334871272">"ਗੱਲਬਾਤ"</string>
+ <string name="paused_by_dnd" msgid="7856941866433556428">"\'ਪਰੇਸ਼ਾਨ ਨਾ ਕਰੋ\' ਵਿਸ਼ੇਸ਼ਤਾ ਨੇ ਰੋਕ ਦਿੱਤਾ"</string>
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> ਨੇ ਸੁਨੇਹਾ ਭੇਜਿਆ: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> ਨੇ ਇੱਕ ਚਿੱਤਰ ਭੇਜਿਆ ਹੈ"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> ਨੇ ਸਥਿਤੀ ਅੱਪਡੇਟ ਕੀਤੀ ਹੈ: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
@@ -877,8 +897,7 @@
<item quantity="one"><xliff:g id="COUNT_1">%s</xliff:g> ਕਿਰਿਆਸ਼ੀਲ ਐਪ</item>
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> ਕਿਰਿਆਸ਼ੀਲ ਐਪਾਂ</item>
</plurals>
- <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
- <skip />
+ <string name="fgs_dot_content_description" msgid="2865071539464777240">"ਨਵੀਂ ਜਾਣਕਾਰੀ"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"ਕਿਰਿਆਸ਼ੀਲ ਐਪਾਂ"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"ਬੰਦ ਕਰੋ"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"ਬੰਦ ਹੈ"</string>
@@ -886,14 +905,15 @@
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"ਕਾਪੀ ਕੀਤੀ ਗਈ"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"<xliff:g id="APPNAME">%1$s</xliff:g> ਤੋਂ"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"ਕਾਪੀ ਕੀਤੇ UI ਨੂੰ ਖਾਰਜ ਕਰੋ"</string>
- <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
- <skip />
- <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
- <skip />
- <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
- <skip />
- <!-- no translation found for add (81036585205287996) -->
- <skip />
- <!-- no translation found for manage_users (1823875311934643849) -->
- <skip />
+ <string name="clipboard_edit_text_description" msgid="805254383912962103">"ਕਾਪੀ ਕੀਤੀ ਲਿਖਤ ਦਾ ਸੰਪਾਦਨ ਕਰੋ"</string>
+ <string name="clipboard_edit_image_description" msgid="8904857948976041306">"ਕਾਪੀ ਕੀਤੇ ਗਏ ਚਿੱਤਰ ਦਾ ਸੰਪਾਦਨ ਕਰੋ"</string>
+ <string name="clipboard_send_nearby_description" msgid="4629769637846717650">"ਨਜ਼ਦੀਕੀ ਡੀਵਾਈਸ \'ਤੇ ਭੇਜੋ"</string>
+ <string name="add" msgid="81036585205287996">"ਸ਼ਾਮਲ ਕਰੋ"</string>
+ <string name="manage_users" msgid="1823875311934643849">"ਵਰਤੋਂਕਾਰਾਂ ਦਾ ਪ੍ਰਬੰਧਨ ਕਰੋ"</string>
+ <string name="drag_split_not_supported" msgid="4326847447699729722">"ਇਹ ਸੂਚਨਾ ਸਪਲਿਟ ਸਕ੍ਰੀਨ \'ਤੇ ਘਸੀਟਣ ਦਾ ਸਮਰਥਨ ਨਹੀਂ ਕਰਦੀ ਹੈ।"</string>
+ <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"ਵਾਈ-ਫਾਈ ਉਪਲਬਧ ਨਹੀਂ ਹੈ"</string>
+ <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"ਤਰਜੀਹੀ ਮੋਡ"</string>
+ <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"ਅਲਾਰਮ ਸੈੱਟ ਹੈ"</string>
+ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"ਕੈਮਰਾ ਅਤੇ ਮਾਈਕ ਬੰਦ ਹਨ"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# ਸੂਚਨਾ}one{# ਸੂਚਨਾ}other{# ਸੂਚਨਾਵਾਂ}}"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 4572922d60a5..a2f94fc657ca 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -20,14 +20,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4811759950673118541">"UI systemu"</string>
- <string name="battery_low_title" msgid="6891106956328275225">"Bateria może się wkrótce wyczerpać"</string>
+ <string name="battery_low_title" msgid="5319680173344341779">"Włączyć Oszczędzanie baterii?"</string>
+ <string name="battery_low_description" msgid="3282977755476423966">"Masz już tylko <xliff:g id="PERCENTAGE">%s</xliff:g> baterii. Oszczędzanie baterii uruchamia ciemny motyw, ogranicza aktywność w tle i opóźnia powiadomienia."</string>
+ <string name="battery_low_intro" msgid="5148725009653088790">"Oszczędzanie baterii uruchamia ciemny motyw, ogranicza aktywność w tle i opóźnia powiadomienia."</string>
<string name="battery_low_percent_format" msgid="4276661262843170964">"Pozostało <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="invalid_charger_title" msgid="938685362320735167">"Nie można naładować przez USB"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"Użyj ładowarki dostarczonej z urządzeniem"</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Włączyć Oszczędzanie baterii?"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Informacje o Oszczędzaniu baterii"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Włącz"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"Włączyć Oszczędzanie baterii?"</string>
+ <string name="battery_saver_start_action" msgid="8353766979886287140">"Włącz"</string>
+ <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Nie, dziękuję"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Autoobracanie ekranu"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"Zezwolić aplikacji <xliff:g id="APPLICATION">%1$s</xliff:g> na dostęp do urządzenia <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
<string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Zezwolić aplikacji <xliff:g id="APPLICATION">%1$s</xliff:g> na dostęp do urządzenia <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nTa aplikacja nie ma uprawnień do nagrywania, ale może rejestrować dźwięk za pomocą tego urządzenia USB."</string>
@@ -128,6 +131,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Twarz rozpoznana"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Potwierdzono"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Aby zakończyć, kliknij Potwierdź"</string>
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Odblokowano skanem twarzy. Kliknij, aby kontynuować."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Uwierzytelniono"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Użyj kodu PIN"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Użyj wzoru"</string>
@@ -181,6 +185,7 @@
<string name="accessibility_desc_close" msgid="8293708213442107755">"Zamknij"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"całkowita cisza"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"tylko alarmy"</string>
+ <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"Nie przeszkadzać."</string>
<string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"Bluetooth."</string>
<string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"Bluetooth włączony."</string>
<string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"Alarm ustawiony na <xliff:g id="TIME">%s</xliff:g>."</string>
@@ -207,6 +212,7 @@
<string name="dessert_case" msgid="9104973640704357717">"Półka ze słodkościami"</string>
<string name="start_dreams" msgid="9131802557946276718">"Wygaszacz ekranu"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
+ <string name="quick_settings_dnd_label" msgid="7728690179108024338">"Nie przeszkadzać"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Brak dostępnych sparowanych urządzeń"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> naładowania baterii"</string>
@@ -354,6 +360,7 @@
<string name="notification_section_header_alerting" msgid="5581175033680477651">"Powiadomienia"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Rozmowy"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Usuń wszystkie ciche powiadomienia"</string>
+ <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Powiadomienia wstrzymane przez tryb Nie przeszkadzać"</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"Rozpocznij teraz"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Brak powiadomień"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Tym urządzeniem zarządza Twój rodzic"</string>
@@ -458,8 +465,8 @@
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Odblokuj, aby użyć"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Podczas pobierania kart wystąpił problem. Spróbuj ponownie później."</string>
<string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Ustawienia ekranu blokady"</string>
- <string name="qr_code_scanner_title" msgid="5660820608548306581">"Kod QR"</string>
- <string name="qr_code_scanner_description" msgid="7937603775306661863">"Kliknij, aby zeskanować"</string>
+ <!-- no translation found for qr_code_scanner_title (5290201053875420785) -->
+ <skip />
<string name="status_bar_work" msgid="5238641949837091056">"Profil służbowy"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Tryb samolotowy"</string>
<string name="zen_alarm_warning" msgid="7844303238486849503">"Nie usłyszysz swojego następnego alarmu <xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -497,6 +504,8 @@
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"&lt;b&gt;Stan:&lt;/b&gt; obniżono ważność"</string>
<string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"Wyświetla się u góry powiadomień w rozmowach oraz jako zdjęcie profilowe na ekranie blokady"</string>
<string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"Wyświetla się u góry powiadomień w rozmowach oraz jako zdjęcie profilowe na ekranie blokady, jako dymek"</string>
+ <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"Wyświetla się u góry powiadomień w rozmowach oraz jako zdjęcie profilowe na ekranie blokady, przerywa działanie trybu Nie przeszkadzać"</string>
+ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Wyświetla się u góry powiadomień w rozmowach oraz jako zdjęcie profilowe na ekranie blokady, jako dymek, przerywa działanie trybu Nie przeszkadzać"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Priorytetowe"</string>
<string name="no_shortcut" msgid="8257177117568230126">"Aplikacja <xliff:g id="APP_NAME">%1$s</xliff:g> nie obsługuje funkcji rozmów"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Tych powiadomień nie można zmodyfikować."</string>
@@ -576,6 +585,7 @@
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"SMS"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"Muzyka"</string>
<string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Kalendarz"</string>
+ <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Nie przeszkadzać"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"Wł./wył. przyciskami głośności"</string>
<string name="battery" msgid="769686279459897127">"Bateria"</string>
<string name="headset" msgid="4485892374984466437">"Zestaw słuchawkowy"</string>
@@ -694,6 +704,10 @@
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"Wi-Fi jest wyłączone"</string>
<string name="bt_is_off" msgid="7436344904889461591">"Bluetooth jest wyłączony"</string>
+ <string name="dnd_is_off" msgid="3185706903793094463">"Tryb Nie przeszkadzać jest wyłączony"</string>
+ <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"Tryb Nie przeszkadzać został włączony przez regułę automatyczną (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"Tryb Nie przeszkadzać został włączony przez aplikację (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"Tryb Nie przeszkadzać został włączony przez regułę automatyczną lub aplikację."</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"Aplikacje działające w tle"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"Kliknij, by wyświetlić szczegóły wykorzystania baterii i użycia danych"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Wyłączyć mobilną transmisję danych?"</string>
@@ -718,6 +732,8 @@
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(praca)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"Rozmowa telefoniczna"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(przez: <xliff:g id="APPLICATION_NAME_S_">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_label" msgid="3385241594101496292">"(<xliff:g id="ATTRIBUTION_LABEL">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_proxy_label" msgid="1111829599659403249">"(<xliff:g id="ATTRIBUTION_LABEL">%1$s</xliff:g> • <xliff:g id="PROXY_LABEL">%2$s</xliff:g>)"</string>
<string name="privacy_type_camera" msgid="7974051382167078332">"aparat"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"lokalizacja"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofon"</string>
@@ -818,6 +834,9 @@
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(odłączono)"</string>
<string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Nie można przełączyć. Spróbuj ponownie."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Sparuj nowe urządzenie"</string>
+ <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Aby przesłać tę sesję, otwórz aplikację."</string>
+ <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Nieznana aplikacja"</string>
+ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Zatrzymaj przesyłanie"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Numer kompilacji"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Numer kompilacji został skopiowany do schowka."</string>
<string name="basic_status" msgid="2315371112182658176">"Otwarta rozmowa"</string>
@@ -851,6 +870,7 @@
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"+ <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Zobacz ostatnie wiadomości, nieodebrane połączenia i stany"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Rozmowa"</string>
+ <string name="paused_by_dnd" msgid="7856941866433556428">"Wstrzymane przez tryb Nie przeszkadzać"</string>
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> wysyła wiadomość: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> wysyła zdjęcie"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> ma nowy stan: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
@@ -891,8 +911,7 @@
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> aktywnej aplikacji</item>
<item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> aktywna aplikacja</item>
</plurals>
- <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
- <skip />
+ <string name="fgs_dot_content_description" msgid="2865071539464777240">"Nowa informacja"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Aktywne aplikacje"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Zatrzymaj"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Zatrzymano"</string>
@@ -900,14 +919,15 @@
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Skopiowano"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Od: <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Zamknij UI kopiowania"</string>
- <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
- <skip />
- <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
- <skip />
- <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
- <skip />
- <!-- no translation found for add (81036585205287996) -->
- <skip />
- <!-- no translation found for manage_users (1823875311934643849) -->
- <skip />
+ <string name="clipboard_edit_text_description" msgid="805254383912962103">"Edytuj skopiowany tekst"</string>
+ <string name="clipboard_edit_image_description" msgid="8904857948976041306">"Edytuj skopiowany obraz"</string>
+ <string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Wyślij na urządzenie w pobliżu"</string>
+ <string name="add" msgid="81036585205287996">"Dodaj"</string>
+ <string name="manage_users" msgid="1823875311934643849">"Zarządzaj użytkownikami"</string>
+ <string name="drag_split_not_supported" msgid="4326847447699729722">"To powiadomienie nie obsługuje dzielenia ekranu przez przeciąganie."</string>
+ <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Sieć Wi‑Fi niedostępna"</string>
+ <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Tryb priorytetowy"</string>
+ <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarm ustawiony"</string>
+ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Aparat i mikrofon są wyłączone"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# powiadomienie}few{# powiadomienia}many{# powiadomień}other{# powiadomienia}}"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 1c902b0b8d65..adc33a7ecd11 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -20,14 +20,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4811759950673118541">"Interface do sistema"</string>
- <string name="battery_low_title" msgid="6891106956328275225">"A bateria pode acabar em breve"</string>
+ <string name="battery_low_title" msgid="5319680173344341779">"Ativar Economia de bateria?"</string>
+ <string name="battery_low_description" msgid="3282977755476423966">"Você tem <xliff:g id="PERCENTAGE">%s</xliff:g> de bateria. A Economia de bateria ativa o tema escuro, restringe atividades em segundo plano e atrasa notificações."</string>
+ <string name="battery_low_intro" msgid="5148725009653088790">"A Economia de bateria ativa o tema escuro, restringe atividades em segundo plano e atrasa notificações."</string>
<string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> restantes"</string>
<string name="invalid_charger_title" msgid="938685362320735167">"Não é possível carregar via USB"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"Usar o carregador que acompanha o dispositivo"</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Ativar \"Economia de bateria\"?"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Sobre a Economia de bateria"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Ativar"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"Ativar a Economia de bateria"</string>
+ <string name="battery_saver_start_action" msgid="8353766979886287140">"Ativar"</string>
+ <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Agora não"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Giro automático da tela"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"Permitir que o app <xliff:g id="APPLICATION">%1$s</xliff:g> acesse <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
<string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Permitir que <xliff:g id="APPLICATION">%1$s</xliff:g> acesse <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nEsse app não tem permissão de gravação, mas pode capturar áudio pelo dispositivo USB."</string>
@@ -128,6 +131,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Rosto autenticado"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Confirmada"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Toque em \"Confirmar\" para concluir"</string>
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Desbloqueado pelo seu rosto. Pressione para continuar."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Autenticado"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Usar PIN"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Usar padrão"</string>
@@ -181,6 +185,7 @@
<string name="accessibility_desc_close" msgid="8293708213442107755">"Fechar"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"silêncio total"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"somente alarmes"</string>
+ <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"Não perturbe."</string>
<string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"Bluetooth."</string>
<string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"Bluetooth ativado."</string>
<string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"Alarme definido para <xliff:g id="TIME">%s</xliff:g>."</string>
@@ -205,6 +210,7 @@
<string name="dessert_case" msgid="9104973640704357717">"Mostruário de sobremesas"</string>
<string name="start_dreams" msgid="9131802557946276718">"Protetor de tela"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
+ <string name="quick_settings_dnd_label" msgid="7728690179108024338">"Não perturbe"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Não há dispositivos pareados disponíveis"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Bateria: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
@@ -348,6 +354,7 @@
<string name="notification_section_header_alerting" msgid="5581175033680477651">"Notificações"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Conversas"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Apagar todas as notificações silenciosas"</string>
+ <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Notificações pausadas pelo modo \"Não perturbe\""</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"Iniciar agora"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Sem notificações"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Este dispositivo é gerenciado pelo seu pai/mãe"</string>
@@ -452,8 +459,7 @@
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Desbloquear para usar"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Ocorreu um problema ao carregar os cards. Tente novamente mais tarde"</string>
<string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Configurações de tela de bloqueio"</string>
- <string name="qr_code_scanner_title" msgid="5660820608548306581">"Código QR"</string>
- <string name="qr_code_scanner_description" msgid="7937603775306661863">"Toque para fazer a leitura"</string>
+ <string name="qr_code_scanner_title" msgid="5290201053875420785">"Ler código QR"</string>
<string name="status_bar_work" msgid="5238641949837091056">"Perfil de trabalho"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Modo avião"</string>
<string name="zen_alarm_warning" msgid="7844303238486849503">"Você não ouvirá o próximo alarme às <xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -491,6 +497,8 @@
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"&lt;b&gt;Status:&lt;/b&gt; classificada com menor prioridade"</string>
<string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"Aparece na parte superior das notificações de conversa e como uma foto do perfil na tela de bloqueio"</string>
<string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"Aparece na parte superior das notificações de conversa, como uma foto do perfil na tela de bloqueio e como um balão"</string>
+ <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"Aparece na parte superior das notificações de conversa e como uma foto do perfil na tela de bloqueio. Interrompe o Não perturbe"</string>
+ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Aparece na parte superior das notificações de conversa, como uma foto do perfil na tela de bloqueio e como um balão. Interrompe o Não perturbe"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritárias"</string>
<string name="no_shortcut" msgid="8257177117568230126">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> não é compatível com recursos de conversa"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Não é possível modificar essas notificações."</string>
@@ -566,6 +574,7 @@
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"SMS"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"Música"</string>
<string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Agenda"</string>
+ <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Não perturbe"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"Atalho de botões de volume"</string>
<string name="battery" msgid="769686279459897127">"Bateria"</string>
<string name="headset" msgid="4485892374984466437">"Fone de ouvido"</string>
@@ -684,6 +693,10 @@
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"O Wi-Fi está desativado"</string>
<string name="bt_is_off" msgid="7436344904889461591">"Bluetooth desativado"</string>
+ <string name="dnd_is_off" msgid="3185706903793094463">"O recurso Não perturbe está desativado"</string>
+ <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"O recurso Não perturbe foi ativado por uma regra automática (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"O recurso Não perturbe foi ativado por um app (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"O recurso Não perturbe foi ativado por uma regra automática ou app."</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"Apps sendo executados em segundo plano"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"Tocar para ver detalhes sobre a bateria e o uso de dados"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Desativar os dados móveis?"</string>
@@ -708,6 +721,8 @@
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(trabalho)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"Chamada telefônica"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(por <xliff:g id="APPLICATION_NAME_S_">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_label" msgid="3385241594101496292">"(<xliff:g id="ATTRIBUTION_LABEL">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_proxy_label" msgid="1111829599659403249">"(<xliff:g id="ATTRIBUTION_LABEL">%1$s</xliff:g> • <xliff:g id="PROXY_LABEL">%2$s</xliff:g>)"</string>
<string name="privacy_type_camera" msgid="7974051382167078332">"câmera"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"localização"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"microfone"</string>
@@ -806,6 +821,9 @@
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(sem conexão)"</string>
<string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Não foi possível mudar. Toque para tentar novamente."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Parear novo dispositivo"</string>
+ <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Abra o app para transmitir esta sessão."</string>
+ <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"App desconhecido"</string>
+ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Parar transmissão"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Número da versão"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Número da versão copiado para a área de transferência."</string>
<string name="basic_status" msgid="2315371112182658176">"Conversa aberta"</string>
@@ -839,6 +857,7 @@
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Veja mensagens recentes, chamadas perdidas e atualizações de status"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Conversa"</string>
+ <string name="paused_by_dnd" msgid="7856941866433556428">"Pausado pelo Não perturbe"</string>
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> enviou uma mensagem: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> enviou uma imagem"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> atualizou o status: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
@@ -877,8 +896,7 @@
<item quantity="one"><xliff:g id="COUNT_1">%s</xliff:g> app ativo</item>
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> apps ativos</item>
</plurals>
- <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
- <skip />
+ <string name="fgs_dot_content_description" msgid="2865071539464777240">"Nova informação"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Apps ativos"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Parar"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Parado"</string>
@@ -886,14 +904,15 @@
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Copiado"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Do app <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Dispensar cópia da IU"</string>
- <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
- <skip />
- <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
- <skip />
- <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
- <skip />
- <!-- no translation found for add (81036585205287996) -->
- <skip />
- <!-- no translation found for manage_users (1823875311934643849) -->
- <skip />
+ <string name="clipboard_edit_text_description" msgid="805254383912962103">"Editar texto copiado"</string>
+ <string name="clipboard_edit_image_description" msgid="8904857948976041306">"Editar imagem copiada"</string>
+ <string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Enviar para dispositivo próximo"</string>
+ <string name="add" msgid="81036585205287996">"Adicionar"</string>
+ <string name="manage_users" msgid="1823875311934643849">"Gerenciar usuários"</string>
+ <string name="drag_split_not_supported" msgid="4326847447699729722">"Esta notificação não tem suporte para ser arrastada para a tela dividida."</string>
+ <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi-Fi indisponível"</string>
+ <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Modo de prioridade"</string>
+ <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarme definido"</string>
+ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"A câmera e o microfone estão desativados"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notificação}one{# notificação}other{# notificações}}"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 1562abc674ec..79f33fb5fcc1 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -20,14 +20,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4811759950673118541">"IU do sistema"</string>
- <string name="battery_low_title" msgid="6891106956328275225">"Pode ficar sem bateria em breve"</string>
+ <string name="battery_low_title" msgid="5319680173344341779">"Ativar a Poupança de bateria?"</string>
+ <string name="battery_low_description" msgid="3282977755476423966">"Resta-lhe <xliff:g id="PERCENTAGE">%s</xliff:g> de bateria. A Poupança de bateria ativa o tema escuro, restringe a atividade em segundo plano e atrasa as notificações."</string>
+ <string name="battery_low_intro" msgid="5148725009653088790">"A Poupança de bateria ativa o tema escuro, restringe a atividade em segundo plano e atrasa as notificações."</string>
<string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> restante"</string>
<string name="invalid_charger_title" msgid="938685362320735167">"Não é possível carregar através de USB."</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"Utilize o carregador fornecido com o dispositivo."</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Pretende ativar a Poupança de bateria?"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Acerca da Poupança de bateria"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Ativar"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"Ativar a Poupança de bateria"</string>
+ <string name="battery_saver_start_action" msgid="8353766979886287140">"Ativar"</string>
+ <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Não"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Rodar ecrã automaticamente"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"Permitir que a app <xliff:g id="APPLICATION">%1$s</xliff:g> aceda ao dispositivo <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
<string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Permitir que <xliff:g id="APPLICATION">%1$s</xliff:g> aceda a <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nEsta app não recebeu autorização de gravação, mas pode capturar áudio através deste dispositivo USB."</string>
@@ -128,6 +131,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Rosto autenticado"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Confirmado"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Toque em Confirmar para concluir."</string>
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Desbloqueado com o rosto. Prima para continuar."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Autenticado"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Utilizar PIN"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Utilizar padrão"</string>
@@ -181,6 +185,7 @@
<string name="accessibility_desc_close" msgid="8293708213442107755">"Fechar"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"silêncio total"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"apenas alarmes"</string>
+ <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"Não incomodar."</string>
<string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"Bluetooth."</string>
<string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"Bluetooth ligado."</string>
<string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"Alarme definido para <xliff:g id="TIME">%s</xliff:g>."</string>
@@ -197,14 +202,15 @@
<string name="accessibility_clear_all" msgid="970525598287244592">"Limpar todas as notificações."</string>
<string name="notification_group_overflow_indicator" msgid="7605120293801012648">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
<plurals name="notification_group_overflow_description" formatted="false" msgid="91483442850649192">
- <item quantity="one">Mais <xliff:g id="NUMBER_0">%s</xliff:g> notificação no grupo.</item>
<item quantity="other">Mais <xliff:g id="NUMBER_1">%s</xliff:g> notificações no grupo.</item>
+ <item quantity="one">Mais <xliff:g id="NUMBER_0">%s</xliff:g> notificação no grupo.</item>
</plurals>
<string name="accessibility_rotation_lock_on_landscape" msgid="936972553861524360">"O ecrã está bloqueado na orientação horizontal."</string>
<string name="accessibility_rotation_lock_on_portrait" msgid="2356633398683813837">"O ecrã está bloqueado na orientação vertical."</string>
<string name="dessert_case" msgid="9104973640704357717">"Vitrina de sobremesas"</string>
<string name="start_dreams" msgid="9131802557946276718">"Proteção de ecrã"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
+ <string name="quick_settings_dnd_label" msgid="7728690179108024338">"Não incomodar"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Sem dispositivos sincronizados disponíveis"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> de bateria"</string>
@@ -246,8 +252,8 @@
<string name="quick_settings_hotspot_secondary_label_transient" msgid="7585604088079160564">"A ativar..."</string>
<string name="quick_settings_hotspot_secondary_label_data_saver_enabled" msgid="1280433136266439372">"Poup. dados ativada"</string>
<plurals name="quick_settings_hotspot_secondary_label_num_devices" formatted="false" msgid="3142308865165871976">
- <item quantity="one">%d dispositivo</item>
<item quantity="other">%d dispositivos</item>
+ <item quantity="one">%d dispositivo</item>
</plurals>
<string name="quick_settings_flashlight_label" msgid="4904634272006284185">"Lanterna"</string>
<string name="quick_settings_flashlight_camera_in_use" msgid="4820591564526512571">"Câmara em utilização"</string>
@@ -330,8 +336,8 @@
<string name="user_add_user_message_short" msgid="2599370307878014791">"Ao adicionar um novo utilizador, essa pessoa tem de configurar o respetivo espaço.\n\nQualquer utilizador pode atualizar apps para todos os outros utilizadores."</string>
<string name="user_limit_reached_title" msgid="2429229448830346057">"Limite de utilizadores alcançado"</string>
<plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398">
- <item quantity="one">Apenas é possível criar um utilizador.</item>
<item quantity="other">Pode adicionar até <xliff:g id="COUNT">%d</xliff:g> utilizadores.</item>
+ <item quantity="one">Apenas é possível criar um utilizador.</item>
</plurals>
<string name="user_remove_user_title" msgid="9124124694835811874">"Remover o utilizador?"</string>
<string name="user_remove_user_message" msgid="6702834122128031833">"Serão eliminados todos os dados e todas as aplicações deste utilizador."</string>
@@ -348,6 +354,7 @@
<string name="notification_section_header_alerting" msgid="5581175033680477651">"Notificações"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Conversas"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Limpar todas as notificações silenciosas"</string>
+ <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Notificações colocadas em pausa pelo modo Não incomodar."</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"Começar agora"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Sem notificações"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Este dispositivo é gerido pelos teus pais"</string>
@@ -452,8 +459,8 @@
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Desbloquear para utilizar"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Ocorreu um problema ao obter os seus cartões. Tente novamente mais tarde."</string>
<string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Definições do ecrã de bloqueio"</string>
- <string name="qr_code_scanner_title" msgid="5660820608548306581">"Código QR"</string>
- <string name="qr_code_scanner_description" msgid="7937603775306661863">"Toque para ler"</string>
+ <!-- no translation found for qr_code_scanner_title (5290201053875420785) -->
+ <skip />
<string name="status_bar_work" msgid="5238641949837091056">"Perfil de trabalho"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Modo de avião"</string>
<string name="zen_alarm_warning" msgid="7844303238486849503">"Não vai ouvir o próximo alarme às <xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -491,6 +498,8 @@
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"&lt;b&gt;Estado:&lt;/b&gt; passou para classificação inferior"</string>
<string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"Aparece na parte superior das notificações de conversas e como uma imagem do perfil no ecrã de bloqueio"</string>
<string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"Aparece na parte superior das notificações de conversas e como uma imagem do perfil no ecrã de bloqueio, surge como um balão"</string>
+ <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"Aparece na parte superior das notificações de conversas e como uma imagem do perfil no ecrã de bloqueio, interrompe o modo Não incomodar"</string>
+ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Aparece na parte superior das notificações de conversas e como uma imagem do perfil no ecrã de bloqueio, surge como um balão, interrompe o modo Não incomodar"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioridade"</string>
<string name="no_shortcut" msgid="8257177117568230126">"A app <xliff:g id="APP_NAME">%1$s</xliff:g> não suporta funcionalidades de conversa."</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Não é possível modificar estas notificações."</string>
@@ -516,12 +525,12 @@
<string name="snooze_undo" msgid="2738844148845992103">"Anular"</string>
<string name="snoozed_for_time" msgid="7586689374860469469">"Suspensa por <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>"</string>
<plurals name="snoozeHourOptions" formatted="false" msgid="2066838694120718170">
- <item quantity="one">%d hora</item>
<item quantity="other">%d horas</item>
+ <item quantity="one">%d hora</item>
</plurals>
<plurals name="snoozeMinuteOptions" formatted="false" msgid="8998483159208055980">
- <item quantity="one">%d minuto</item>
<item quantity="other">%d minutos</item>
+ <item quantity="one">%d minuto</item>
</plurals>
<string name="battery_detail_switch_title" msgid="6940976502957380405">"Poupança de bateria"</string>
<string name="keyboard_key_button_template" msgid="8005673627272051429">"Botão <xliff:g id="NAME">%1$s</xliff:g>"</string>
@@ -566,6 +575,7 @@
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"SMS"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"Música"</string>
<string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Calendário"</string>
+ <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Não incomodar"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"Atalho dos botões de volume"</string>
<string name="battery" msgid="769686279459897127">"Bateria"</string>
<string name="headset" msgid="4485892374984466437">"Ausc. com microfone integrado"</string>
@@ -684,6 +694,10 @@
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"Wi-Fi desativado"</string>
<string name="bt_is_off" msgid="7436344904889461591">"Bluetooth desativado"</string>
+ <string name="dnd_is_off" msgid="3185706903793094463">"Não incomodar desativado"</string>
+ <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"O modo Não incomodar foi ativado por uma regra automática (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"O modo Não incomodar foi ativado por uma app (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"O modo Não incomodar foi ativado por uma regra automática ou por uma app."</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"Apps em execução em segundo plano"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"Toque para obter detalhes acerca da utilização da bateria e dos dados"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Pretende desativar os dados móveis?"</string>
@@ -708,6 +722,8 @@
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(trabalho)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"Chamada"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(através de <xliff:g id="APPLICATION_NAME_S_">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_label" msgid="3385241594101496292">"(<xliff:g id="ATTRIBUTION_LABEL">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_proxy_label" msgid="1111829599659403249">"(<xliff:g id="ATTRIBUTION_LABEL">%1$s</xliff:g> • <xliff:g id="PROXY_LABEL">%2$s</xliff:g>)"</string>
<string name="privacy_type_camera" msgid="7974051382167078332">"câmara"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"localização"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"microfone"</string>
@@ -737,8 +753,8 @@
<string name="quick_controls_title" msgid="6839108006171302273">"Controlos de dispositivos"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Escolha uma app para adicionar controlos"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
- <item quantity="one"><xliff:g id="NUMBER_0">%s</xliff:g> controlo adicionado.</item>
<item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> controlos adicionados.</item>
+ <item quantity="one"><xliff:g id="NUMBER_0">%s</xliff:g> controlo adicionado.</item>
</plurals>
<string name="controls_removed" msgid="3731789252222856959">"Removido"</string>
<string name="accessibility_control_favorite" msgid="8694362691985545985">"Adicionado aos favoritos"</string>
@@ -806,6 +822,9 @@
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(desligado)"</string>
<string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Não é possível mudar. Toque para tentar novamente."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Sincronize o novo dispositivo"</string>
+ <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Para transmitir esta sessão, abra a app."</string>
+ <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"App desconhecida"</string>
+ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Parar transmissão"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Número da compilação"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Número da compilação copiado para a área de transferência."</string>
<string name="basic_status" msgid="2315371112182658176">"Abrir conversa"</string>
@@ -839,6 +858,7 @@
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Veja mensagens recentes, chamadas não atendidas e atualizações de estado"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Conversa"</string>
+ <string name="paused_by_dnd" msgid="7856941866433556428">"Colocado em pausa pelo modo Não incomodar"</string>
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> enviou uma mensagem: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> enviou uma imagem"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> tem uma atualização de estado: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
@@ -874,11 +894,10 @@
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Não adicion. mosaico"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Selecione utilizador"</string>
<plurals name="fgs_manager_footer_label" formatted="false" msgid="9091110396713032871">
- <item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> app ativa</item>
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> apps ativas</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> app ativa</item>
</plurals>
- <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
- <skip />
+ <string name="fgs_dot_content_description" msgid="2865071539464777240">"Novas informações"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Apps ativas"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Parar"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Parada"</string>
@@ -886,14 +905,15 @@
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Copiado"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Da app <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Ignorar cópia de IU"</string>
- <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
- <skip />
- <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
- <skip />
- <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
- <skip />
- <!-- no translation found for add (81036585205287996) -->
- <skip />
- <!-- no translation found for manage_users (1823875311934643849) -->
- <skip />
+ <string name="clipboard_edit_text_description" msgid="805254383912962103">"Editar texto copiado"</string>
+ <string name="clipboard_edit_image_description" msgid="8904857948976041306">"Editar imagem copiada"</string>
+ <string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Enviar para dispositivo próximo"</string>
+ <string name="add" msgid="81036585205287996">"Adicionar"</string>
+ <string name="manage_users" msgid="1823875311934643849">"Gerir utilizadores"</string>
+ <string name="drag_split_not_supported" msgid="4326847447699729722">"Esta notificação não pode ser arrastada para o ecrã dividido."</string>
+ <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi indisponível"</string>
+ <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Modo Prioridade"</string>
+ <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarme definido"</string>
+ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"A câmara e o microfone estão desativados"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notificação}other{# notificações}}"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 1c902b0b8d65..adc33a7ecd11 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -20,14 +20,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4811759950673118541">"Interface do sistema"</string>
- <string name="battery_low_title" msgid="6891106956328275225">"A bateria pode acabar em breve"</string>
+ <string name="battery_low_title" msgid="5319680173344341779">"Ativar Economia de bateria?"</string>
+ <string name="battery_low_description" msgid="3282977755476423966">"Você tem <xliff:g id="PERCENTAGE">%s</xliff:g> de bateria. A Economia de bateria ativa o tema escuro, restringe atividades em segundo plano e atrasa notificações."</string>
+ <string name="battery_low_intro" msgid="5148725009653088790">"A Economia de bateria ativa o tema escuro, restringe atividades em segundo plano e atrasa notificações."</string>
<string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> restantes"</string>
<string name="invalid_charger_title" msgid="938685362320735167">"Não é possível carregar via USB"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"Usar o carregador que acompanha o dispositivo"</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Ativar \"Economia de bateria\"?"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Sobre a Economia de bateria"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Ativar"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"Ativar a Economia de bateria"</string>
+ <string name="battery_saver_start_action" msgid="8353766979886287140">"Ativar"</string>
+ <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Agora não"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Giro automático da tela"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"Permitir que o app <xliff:g id="APPLICATION">%1$s</xliff:g> acesse <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
<string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Permitir que <xliff:g id="APPLICATION">%1$s</xliff:g> acesse <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nEsse app não tem permissão de gravação, mas pode capturar áudio pelo dispositivo USB."</string>
@@ -128,6 +131,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Rosto autenticado"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Confirmada"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Toque em \"Confirmar\" para concluir"</string>
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Desbloqueado pelo seu rosto. Pressione para continuar."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Autenticado"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Usar PIN"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Usar padrão"</string>
@@ -181,6 +185,7 @@
<string name="accessibility_desc_close" msgid="8293708213442107755">"Fechar"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"silêncio total"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"somente alarmes"</string>
+ <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"Não perturbe."</string>
<string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"Bluetooth."</string>
<string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"Bluetooth ativado."</string>
<string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"Alarme definido para <xliff:g id="TIME">%s</xliff:g>."</string>
@@ -205,6 +210,7 @@
<string name="dessert_case" msgid="9104973640704357717">"Mostruário de sobremesas"</string>
<string name="start_dreams" msgid="9131802557946276718">"Protetor de tela"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
+ <string name="quick_settings_dnd_label" msgid="7728690179108024338">"Não perturbe"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Não há dispositivos pareados disponíveis"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Bateria: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
@@ -348,6 +354,7 @@
<string name="notification_section_header_alerting" msgid="5581175033680477651">"Notificações"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Conversas"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Apagar todas as notificações silenciosas"</string>
+ <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Notificações pausadas pelo modo \"Não perturbe\""</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"Iniciar agora"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Sem notificações"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Este dispositivo é gerenciado pelo seu pai/mãe"</string>
@@ -452,8 +459,7 @@
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Desbloquear para usar"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Ocorreu um problema ao carregar os cards. Tente novamente mais tarde"</string>
<string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Configurações de tela de bloqueio"</string>
- <string name="qr_code_scanner_title" msgid="5660820608548306581">"Código QR"</string>
- <string name="qr_code_scanner_description" msgid="7937603775306661863">"Toque para fazer a leitura"</string>
+ <string name="qr_code_scanner_title" msgid="5290201053875420785">"Ler código QR"</string>
<string name="status_bar_work" msgid="5238641949837091056">"Perfil de trabalho"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Modo avião"</string>
<string name="zen_alarm_warning" msgid="7844303238486849503">"Você não ouvirá o próximo alarme às <xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -491,6 +497,8 @@
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"&lt;b&gt;Status:&lt;/b&gt; classificada com menor prioridade"</string>
<string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"Aparece na parte superior das notificações de conversa e como uma foto do perfil na tela de bloqueio"</string>
<string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"Aparece na parte superior das notificações de conversa, como uma foto do perfil na tela de bloqueio e como um balão"</string>
+ <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"Aparece na parte superior das notificações de conversa e como uma foto do perfil na tela de bloqueio. Interrompe o Não perturbe"</string>
+ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Aparece na parte superior das notificações de conversa, como uma foto do perfil na tela de bloqueio e como um balão. Interrompe o Não perturbe"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritárias"</string>
<string name="no_shortcut" msgid="8257177117568230126">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> não é compatível com recursos de conversa"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Não é possível modificar essas notificações."</string>
@@ -566,6 +574,7 @@
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"SMS"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"Música"</string>
<string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Agenda"</string>
+ <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Não perturbe"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"Atalho de botões de volume"</string>
<string name="battery" msgid="769686279459897127">"Bateria"</string>
<string name="headset" msgid="4485892374984466437">"Fone de ouvido"</string>
@@ -684,6 +693,10 @@
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"O Wi-Fi está desativado"</string>
<string name="bt_is_off" msgid="7436344904889461591">"Bluetooth desativado"</string>
+ <string name="dnd_is_off" msgid="3185706903793094463">"O recurso Não perturbe está desativado"</string>
+ <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"O recurso Não perturbe foi ativado por uma regra automática (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"O recurso Não perturbe foi ativado por um app (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"O recurso Não perturbe foi ativado por uma regra automática ou app."</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"Apps sendo executados em segundo plano"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"Tocar para ver detalhes sobre a bateria e o uso de dados"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Desativar os dados móveis?"</string>
@@ -708,6 +721,8 @@
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(trabalho)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"Chamada telefônica"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(por <xliff:g id="APPLICATION_NAME_S_">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_label" msgid="3385241594101496292">"(<xliff:g id="ATTRIBUTION_LABEL">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_proxy_label" msgid="1111829599659403249">"(<xliff:g id="ATTRIBUTION_LABEL">%1$s</xliff:g> • <xliff:g id="PROXY_LABEL">%2$s</xliff:g>)"</string>
<string name="privacy_type_camera" msgid="7974051382167078332">"câmera"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"localização"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"microfone"</string>
@@ -806,6 +821,9 @@
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(sem conexão)"</string>
<string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Não foi possível mudar. Toque para tentar novamente."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Parear novo dispositivo"</string>
+ <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Abra o app para transmitir esta sessão."</string>
+ <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"App desconhecido"</string>
+ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Parar transmissão"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Número da versão"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Número da versão copiado para a área de transferência."</string>
<string name="basic_status" msgid="2315371112182658176">"Conversa aberta"</string>
@@ -839,6 +857,7 @@
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Veja mensagens recentes, chamadas perdidas e atualizações de status"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Conversa"</string>
+ <string name="paused_by_dnd" msgid="7856941866433556428">"Pausado pelo Não perturbe"</string>
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> enviou uma mensagem: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> enviou uma imagem"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> atualizou o status: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
@@ -877,8 +896,7 @@
<item quantity="one"><xliff:g id="COUNT_1">%s</xliff:g> app ativo</item>
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> apps ativos</item>
</plurals>
- <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
- <skip />
+ <string name="fgs_dot_content_description" msgid="2865071539464777240">"Nova informação"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Apps ativos"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Parar"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Parado"</string>
@@ -886,14 +904,15 @@
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Copiado"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Do app <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Dispensar cópia da IU"</string>
- <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
- <skip />
- <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
- <skip />
- <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
- <skip />
- <!-- no translation found for add (81036585205287996) -->
- <skip />
- <!-- no translation found for manage_users (1823875311934643849) -->
- <skip />
+ <string name="clipboard_edit_text_description" msgid="805254383912962103">"Editar texto copiado"</string>
+ <string name="clipboard_edit_image_description" msgid="8904857948976041306">"Editar imagem copiada"</string>
+ <string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Enviar para dispositivo próximo"</string>
+ <string name="add" msgid="81036585205287996">"Adicionar"</string>
+ <string name="manage_users" msgid="1823875311934643849">"Gerenciar usuários"</string>
+ <string name="drag_split_not_supported" msgid="4326847447699729722">"Esta notificação não tem suporte para ser arrastada para a tela dividida."</string>
+ <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi-Fi indisponível"</string>
+ <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Modo de prioridade"</string>
+ <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarme definido"</string>
+ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"A câmera e o microfone estão desativados"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notificação}one{# notificação}other{# notificações}}"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index d520d509edf6..f57aa7195b84 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -20,14 +20,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4811759950673118541">"UI sistem"</string>
- <string name="battery_low_title" msgid="6891106956328275225">"Este posibil ca bateria să se descarce în curând"</string>
+ <string name="battery_low_title" msgid="5319680173344341779">"Activați Economisirea bateriei?"</string>
+ <string name="battery_low_description" msgid="3282977755476423966">"Mai aveți <xliff:g id="PERCENTAGE">%s</xliff:g> din baterie. Economisirea bateriei activează Tema întunecată, restricționează activitatea în fundal și amână notificările."</string>
+ <string name="battery_low_intro" msgid="5148725009653088790">"Economisirea bateriei activează Tema întunecată, restricționează activitatea în fundal și amână notificările."</string>
<string name="battery_low_percent_format" msgid="4276661262843170964">"Procent rămas din baterie: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="invalid_charger_title" msgid="938685362320735167">"Nu se poate realiza încărcarea prin USB"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"Folosiți încărcătorul livrat împreună cu dispozitivul"</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Activați economisirea bateriei?"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Despre Economisirea bateriei"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Activați"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"Activați economisirea bateriei"</string>
+ <string name="battery_saver_start_action" msgid="8353766979886287140">"Activați"</string>
+ <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Nu, mulțumesc"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Rotire automată a ecranului"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"Permiteți <xliff:g id="APPLICATION">%1$s</xliff:g> să acceseze <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
<string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Permiteți accesul aplicației <xliff:g id="APPLICATION">%1$s</xliff:g> la <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nPermisiunea de înregistrare nu a fost acordată aplicației, dar aceasta poate să înregistreze conținut audio prin intermediul acestui dispozitiv USB."</string>
@@ -128,6 +131,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Chip autentificat"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Confirmat"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Atingeți Confirmați pentru a finaliza"</string>
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"S-a deblocat cu ajutorul feței. Apăsați pentru a continua."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Autentificat"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Folosiți PIN-ul"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Folosiți modelul"</string>
@@ -181,6 +185,7 @@
<string name="accessibility_desc_close" msgid="8293708213442107755">"Închideți"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"niciun sunet"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"numai alarme"</string>
+ <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"Nu deranja."</string>
<string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"Bluetooth."</string>
<string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"Conexiunea prin Bluetooth este activată."</string>
<string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"Alarmă setată pentru <xliff:g id="TIME">%s</xliff:g>."</string>
@@ -206,6 +211,7 @@
<string name="dessert_case" msgid="9104973640704357717">"Vitrina cu dulciuri"</string>
<string name="start_dreams" msgid="9131802557946276718">"Economizor de ecran"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
+ <string name="quick_settings_dnd_label" msgid="7728690179108024338">"Nu deranja"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Niciun dispozitiv conectat disponibil"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Nivelul bateriei: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
@@ -351,6 +357,7 @@
<string name="notification_section_header_alerting" msgid="5581175033680477651">"Notificări"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Conversații"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Ștergeți toate notificările silențioase"</string>
+ <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Notificări întrerupte prin „Nu deranja”"</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"Începeți acum"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Nicio notificare"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Dispozitivul este gestionat de unul dintre părinți"</string>
@@ -455,8 +462,8 @@
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Deblocați pentru a folosi"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"A apărut o problemă la preluarea cardurilor. Încercați din nou mai târziu"</string>
<string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Setările ecranului de blocare"</string>
- <string name="qr_code_scanner_title" msgid="5660820608548306581">"Cod QR"</string>
- <string name="qr_code_scanner_description" msgid="7937603775306661863">"Atingeți pentru a scana"</string>
+ <!-- no translation found for qr_code_scanner_title (5290201053875420785) -->
+ <skip />
<string name="status_bar_work" msgid="5238641949837091056">"Profil de serviciu"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Mod Avion"</string>
<string name="zen_alarm_warning" msgid="7844303238486849503">"Nu veți auzi următoarea alarmă <xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -494,6 +501,8 @@
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"&lt;b&gt;Stare:&lt;/b&gt; clasificată mai jos"</string>
<string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"Se afișează în partea de sus a notificărilor pentru conversații și ca fotografie de profil pe ecranul de blocare"</string>
<string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"Se afișează în partea de sus a notificărilor pentru conversații și ca fotografie de profil pe ecranul de blocare, apare ca un balon"</string>
+ <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"Se afișează în partea de sus a notificărilor pentru conversații și ca fotografie de profil pe ecranul de blocare, întrerupe funcția Nu deranja"</string>
+ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Se afișează în partea de sus a notificărilor pentru conversații și ca fotografie de profil pe ecranul de blocare, apare ca un balon, întrerupe funcția Nu deranja"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritate"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> nu acceptă funcții pentru conversații"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Aceste notificări nu pot fi modificate."</string>
@@ -571,6 +580,7 @@
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"SMS"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"Muzică"</string>
<string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Calendar"</string>
+ <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Nu deranja"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"Comandă rapidă din butoanele de volum"</string>
<string name="battery" msgid="769686279459897127">"Baterie"</string>
<string name="headset" msgid="4485892374984466437">"Set căști-microfon"</string>
@@ -689,6 +699,10 @@
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"Conexiunea Wi-Fi este dezactivată"</string>
<string name="bt_is_off" msgid="7436344904889461591">"Funcția Bluetooth este dezactivată"</string>
+ <string name="dnd_is_off" msgid="3185706903793094463">"Funcția Nu deranja este dezactivată"</string>
+ <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"Funcția Nu deranja a fost activată de o regulă automată (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"Funcția Nu deranja a fost activată de o aplicație (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"Funcția Nu deranja a fost activată de o regulă automată sau de o aplicație."</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"Aplicațiile rulează în fundal"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"Atingeți pentru mai multe detalii privind bateria și utilizarea datelor"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Dezactivați datele mobile?"</string>
@@ -713,6 +727,8 @@
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(serviciu)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"Apel telefonic"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(prin <xliff:g id="APPLICATION_NAME_S_">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_label" msgid="3385241594101496292">"(<xliff:g id="ATTRIBUTION_LABEL">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_proxy_label" msgid="1111829599659403249">"(<xliff:g id="ATTRIBUTION_LABEL">%1$s</xliff:g> • <xliff:g id="PROXY_LABEL">%2$s</xliff:g>)"</string>
<string name="privacy_type_camera" msgid="7974051382167078332">"cameră foto"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"locație"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"microfon"</string>
@@ -812,6 +828,9 @@
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(deconectat)"</string>
<string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Nu se poate comuta. Atingeți pentru a încerca din nou."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Asociați un nou dispozitiv"</string>
+ <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Pentru a proiecta această sesiune, deschideți aplicația."</string>
+ <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Aplicație necunoscută"</string>
+ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Nu mai proiectați"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Numărul versiunii"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Numărul versiunii s-a copiat în clipboard."</string>
<string name="basic_status" msgid="2315371112182658176">"Deschideți conversația"</string>
@@ -845,6 +864,7 @@
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Vedeți mesaje recente, apeluri pierdute și actualizări de stare"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Conversație"</string>
+ <string name="paused_by_dnd" msgid="7856941866433556428">"Întrerupt de Nu deranja"</string>
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> a trimis un mesaj: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> a trimis o imagine"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> are o nouă stare: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
@@ -884,8 +904,7 @@
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> de aplicații active</item>
<item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> aplicație activă</item>
</plurals>
- <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
- <skip />
+ <string name="fgs_dot_content_description" msgid="2865071539464777240">"Informații noi"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Aplicații active"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Opriți"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Oprită"</string>
@@ -896,8 +915,12 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Editați textul copiat"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Editați imaginea copiată"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Trimiteți către un dispozitiv din apropiere"</string>
- <!-- no translation found for add (81036585205287996) -->
- <skip />
- <!-- no translation found for manage_users (1823875311934643849) -->
- <skip />
+ <string name="add" msgid="81036585205287996">"Adăugați"</string>
+ <string name="manage_users" msgid="1823875311934643849">"Gestionați utilizatorii"</string>
+ <string name="drag_split_not_supported" msgid="4326847447699729722">"Notificarea nu acceptă tragerea pe ecranul împărțit."</string>
+ <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi indisponibil"</string>
+ <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Modul Prioritate"</string>
+ <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarmă setată"</string>
+ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Camera și microfonul sunt dezactivate"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notificare}few{# notificări}other{# de notificări}}"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 310a87e1a6da..de09d7680330 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -20,14 +20,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4811759950673118541">"Интерфейс системы"</string>
- <string name="battery_low_title" msgid="6891106956328275225">"Батарея скоро разрядится"</string>
+ <string name="battery_low_title" msgid="5319680173344341779">"Включить режим энергосбережения?"</string>
+ <string name="battery_low_description" msgid="3282977755476423966">"Уровень заряда батареи: <xliff:g id="PERCENTAGE">%s</xliff:g>. В режиме энергосбережения включается тёмная тема, ограничиваются фоновые процессы и приостанавливается показ уведомлений."</string>
+ <string name="battery_low_intro" msgid="5148725009653088790">"В режиме энергосбережения включается тёмная тема, ограничиваются фоновые процессы и приостанавливается показ уведомлений."</string>
<string name="battery_low_percent_format" msgid="4276661262843170964">"Осталось: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="invalid_charger_title" msgid="938685362320735167">"Невозможно выполнить зарядку через USB"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"Используйте зарядное устройство из комплекта."</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Включить режим энергосбережения?"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"О режиме энергосбережения"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Включить"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"Включить режим энергосбережения"</string>
+ <string name="battery_saver_start_action" msgid="8353766979886287140">"Включить"</string>
+ <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Нет"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Автоповорот экрана"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"Предоставить приложению \"<xliff:g id="APPLICATION">%1$s</xliff:g>\" доступ к устройству \"<xliff:g id="USB_DEVICE">%2$s</xliff:g>\"?"</string>
<string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Предоставить приложению \"<xliff:g id="APPLICATION">%1$s</xliff:g>\" доступ к устройству \"<xliff:g id="USB_DEVICE">%2$s</xliff:g>\"?\nПриложению не разрешено вести запись, однако с помощью этого USB-устройства оно может записывать звук."</string>
@@ -128,6 +131,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Лицо распознано"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Подтверждено"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Нажмите \"Подтвердить\""</string>
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Сработало распознавание лица. Нажмите, чтобы продолжить."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Аутентификация выполнена"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"PIN-код"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Использовать графический ключ"</string>
@@ -181,6 +185,7 @@
<string name="accessibility_desc_close" msgid="8293708213442107755">"Закрыть"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"полная тишина"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"только будильник"</string>
+ <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"Не беспокоить."</string>
<string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"Bluetooth."</string>
<string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"Модуль Bluetooth включен."</string>
<string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"Будильник установлен на <xliff:g id="TIME">%s</xliff:g>"</string>
@@ -207,6 +212,7 @@
<string name="dessert_case" msgid="9104973640704357717">"Коробка со сладостями"</string>
<string name="start_dreams" msgid="9131802557946276718">"Заставка"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
+ <string name="quick_settings_dnd_label" msgid="7728690179108024338">"Не беспокоить"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Нет доступных сопряженных устройств"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Заряд: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
@@ -354,6 +360,7 @@
<string name="notification_section_header_alerting" msgid="5581175033680477651">"Уведомления"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Разговоры"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Отклонить все беззвучные уведомления"</string>
+ <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"В режиме \"Не беспокоить\" уведомления заблокированы"</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"Начать"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Нет уведомлений"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Устройством управляет один из родителей."</string>
@@ -458,8 +465,8 @@
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Разблокировать для использования"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Не удалось получить информацию о картах. Повторите попытку позже."</string>
<string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Настройки заблокированного экрана"</string>
- <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR-код"</string>
- <string name="qr_code_scanner_description" msgid="7937603775306661863">"Нажмите, чтобы отсканировать код"</string>
+ <!-- no translation found for qr_code_scanner_title (5290201053875420785) -->
+ <skip />
<string name="status_bar_work" msgid="5238641949837091056">"Рабочий профиль"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Режим полета"</string>
<string name="zen_alarm_warning" msgid="7844303238486849503">"Следующий будильник: <xliff:g id="WHEN">%1$s</xliff:g>. Звук отключен."</string>
@@ -497,6 +504,8 @@
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"&lt;b&gt;Статус:&lt;/b&gt; уровень важности понижен"</string>
<string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"Появляется в верхней части уведомлений о сообщениях, а также в качестве фото профиля на заблокированном экране"</string>
<string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"Появляется в верхней части уведомлений о сообщениях, в виде всплывающего чата, а также в качестве фото профиля на заблокированном экране."</string>
+ <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"Появляется в верхней части уведомлений о сообщениях, а также в качестве фото профиля на заблокированном экране, прерывает режим \"Не беспокоить\"."</string>
+ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Появляется в верхней части уведомлений о сообщениях, в виде всплывающего чата, а также в качестве фото профиля на заблокированном экране, прерывает режим \"Не беспокоить\"."</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Приоритет"</string>
<string name="no_shortcut" msgid="8257177117568230126">"Приложение \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" не поддерживает функции разговоров."</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Эти уведомления нельзя изменить."</string>
@@ -576,6 +585,7 @@
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"SMS"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"Музыка"</string>
<string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Календарь"</string>
+ <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Не беспокоить"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"Кнопки регулировки громкости"</string>
<string name="battery" msgid="769686279459897127">"Батарея"</string>
<string name="headset" msgid="4485892374984466437">"Гарнитура"</string>
@@ -694,6 +704,10 @@
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"Модуль Wi-Fi отключен"</string>
<string name="bt_is_off" msgid="7436344904889461591">"Модуль Bluetooth отключен"</string>
+ <string name="dnd_is_off" msgid="3185706903793094463">"Режим \"Не беспокоить\" отключен"</string>
+ <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"Режим \"Не беспокоить\" был включен специальным правилом (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"Режим \"Не беспокоить\" был включен приложением (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"Режим \"Не беспокоить\" был включен специальным правилом или приложением."</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"Приложения, работающие в фоновом режиме"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"Нажмите, чтобы проверить энергопотребление и трафик"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Отключить мобильный Интернет?"</string>
@@ -718,6 +732,8 @@
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(работа)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"Телефонный звонок"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(через приложение \"<xliff:g id="APPLICATION_NAME_S_">%s</xliff:g>\")"</string>
+ <string name="ongoing_privacy_dialog_attribution_label" msgid="3385241594101496292">"(<xliff:g id="ATTRIBUTION_LABEL">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_proxy_label" msgid="1111829599659403249">"(<xliff:g id="ATTRIBUTION_LABEL">%1$s</xliff:g> • <xliff:g id="PROXY_LABEL">%2$s</xliff:g>)"</string>
<string name="privacy_type_camera" msgid="7974051382167078332">"камера"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"местоположение"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"микрофон"</string>
@@ -818,6 +834,9 @@
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(нет подключения)"</string>
<string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Не удается переключиться. Нажмите, чтобы повторить попытку."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Подключить новое устройство"</string>
+ <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Чтобы начать трансляцию сеанса, откройте приложение"</string>
+ <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Неизвестное приложение"</string>
+ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Остановить трансляцию"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Номер сборки"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Номер сборки скопирован в буфер обмена."</string>
<string name="basic_status" msgid="2315371112182658176">"Открытый чат"</string>
@@ -851,6 +870,7 @@
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Будьте в курсе последних сообщений, пропущенных вызовов и обновлений статуса."</string>
<string name="people_tile_title" msgid="6589377493334871272">"Чат"</string>
+ <string name="paused_by_dnd" msgid="7856941866433556428">"Приостановлено в режиме \"Не беспокоить\""</string>
<string name="new_notification_text_content_description" msgid="2915029960094389291">"Пользователь <xliff:g id="NAME">%1$s</xliff:g> отправил сообщение: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"Пользователь <xliff:g id="NAME">%1$s</xliff:g> отправил изображение"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"Пользователь <xliff:g id="NAME">%1$s</xliff:g> обновил статус: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
@@ -891,8 +911,7 @@
<item quantity="many"><xliff:g id="COUNT_1">%s</xliff:g> активных приложений</item>
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> активного приложения</item>
</plurals>
- <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
- <skip />
+ <string name="fgs_dot_content_description" msgid="2865071539464777240">"Новая информация"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Активные приложения"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Остановить"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Остановлено"</string>
@@ -900,14 +919,15 @@
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Скопировано."</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Из приложения \"<xliff:g id="APPNAME">%1$s</xliff:g>\""</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Закрыть меню копирования"</string>
- <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
- <skip />
- <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
- <skip />
- <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
- <skip />
- <!-- no translation found for add (81036585205287996) -->
- <skip />
- <!-- no translation found for manage_users (1823875311934643849) -->
- <skip />
+ <string name="clipboard_edit_text_description" msgid="805254383912962103">"Изменить скопированный текст"</string>
+ <string name="clipboard_edit_image_description" msgid="8904857948976041306">"Изменить скопированное изображение"</string>
+ <string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Отправить на устройство поблизости"</string>
+ <string name="add" msgid="81036585205287996">"Добавить"</string>
+ <string name="manage_users" msgid="1823875311934643849">"Управление пользователями"</string>
+ <string name="drag_split_not_supported" msgid="4326847447699729722">"Это уведомление нельзя перетаскивать между частями разделенного экрана."</string>
+ <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Сеть Wi‑Fi недоступна"</string>
+ <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Режим приоритета"</string>
+ <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Будильник установлен"</string>
+ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Камера и микрофон отключены"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# уведомление}one{# уведомление}few{# уведомления}many{# уведомлений}other{# уведомления}}"</string>
</resources>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index e730bb06b222..cdb0896a3fab 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -20,14 +20,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4811759950673118541">"පද්ධති UI"</string>
- <string name="battery_low_title" msgid="6891106956328275225">"බැටරිය ඉක්මනින් අවසන් විය හැකිය"</string>
+ <string name="battery_low_title" msgid="5319680173344341779">"බැටරි සුරැකුම ක්‍රියාත්මක කරන්නද?"</string>
+ <string name="battery_low_description" msgid="3282977755476423966">"ඔබට බැටරිය <xliff:g id="PERCENTAGE">%s</xliff:g> ඉතිරිව ඇත. බැටරි සුරැකුම අඳුරු තේමාව ක්‍රියාත්මක කරයි, පසුබිම් ක්‍රියාකාරකම සීමා කරයි, සහ දැනුම්දීම් ප්‍රමාද කරයි."</string>
+ <string name="battery_low_intro" msgid="5148725009653088790">"බැටරි සුරැකුම අඳුරු තේමාව ක්‍රියාත්මක කරයි, පසුබිම් ක්‍රියාකාරකම සීමා කරයි, සහ දැනුම්දීම් ප්‍රමාද කරයි."</string>
<string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> ඉතිරිව තිබේ"</string>
<string name="invalid_charger_title" msgid="938685362320735167">"USB හරහා ආරෝපණය කළ නොහැකිය"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"ඔබේ උපාංගය සමඟ පැමිණි ආරෝපකය භාවිත කරන්න"</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"බැටරි සුරැකුම ක්‍රියාත්මක කරන්නද?"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"බැටරි සුරැකුම ගැන"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"ක්‍රියාත්මක කරන්න"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"බැටරි සුරැකුම ක්‍රියාත්මක කරන්න"</string>
+ <string name="battery_saver_start_action" msgid="8353766979886287140">"ක්‍රියාත්මක කරන්න"</string>
+ <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"එපා ස්තුතියි"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"ස්වයංක්‍රීයව-භ්‍රමණය වන තිරය"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"<xliff:g id="APPLICATION">%1$s</xliff:g> හට <xliff:g id="USB_DEVICE">%2$s</xliff:g> වෙත පිවිසීමට ඉඩ දෙන්නද?"</string>
<string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"<xliff:g id="APPLICATION">%1$s</xliff:g> වෙත ප්‍රවේශ වීමට <xliff:g id="USB_DEVICE">%2$s</xliff:g> හට ඉඩ දෙන්නද?\n මෙම යෙදුමට පටිගත කිරීම් අවසරයක් ලබා දී නොමැති නමුත් මෙම USB උපාංගය හරහා ශ්‍රව්‍ය ග්‍රහණය කර ගත හැකිය."</string>
@@ -128,6 +131,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"මුහුණ සත්‍යාපන කළා"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"තහවුරු කළා"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"සම්පූර්ණ කිරීමට තහවුරු කරන්න තට්ටු කර."</string>
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"ඔබගේ මුහුණෙන් අගුලු හරින ලදී. ඉදිරියට යාමට ඔබන්න."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"සත්‍යාපනය විය"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"PIN භාවිත කරන්න"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"රටාව භාවිත කරන්න"</string>
@@ -181,6 +185,7 @@
<string name="accessibility_desc_close" msgid="8293708213442107755">"වසන්න"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"සම්පූර්ණ නිහඬතාව"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"එලාම පමණි"</string>
+ <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"බාධා නොකරන්න."</string>
<string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"බ්ලූටූත්."</string>
<string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"බ්ලූටූත් ක්‍රියාත්මකයි."</string>
<string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"<xliff:g id="TIME">%s</xliff:g> සඳහා සීනුව සකස් කර ඇත."</string>
@@ -205,6 +210,7 @@
<string name="dessert_case" msgid="9104973640704357717">"අතුරුපස අවස්තාව"</string>
<string name="start_dreams" msgid="9131802557946276718">"තිර සුරැකුම"</string>
<string name="ethernet_label" msgid="2203544727007463351">"ඊතර නෙට්"</string>
+ <string name="quick_settings_dnd_label" msgid="7728690179108024338">"බාධා නොකරන්න"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"බ්ලූටූත්"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"යුගල කළ උපාංග නොතිබේ"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"බැටරිය <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
@@ -348,6 +354,7 @@
<string name="notification_section_header_alerting" msgid="5581175033680477651">"දැනුම් දීම්"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"සංවාද"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"සියලු නිහඬ දැනුම්දීම් හිස් කරන්න"</string>
+ <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"බාධා නොකරන්න මගින් විරාම කරන ලද දැනුම්දීම්"</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"දැන් අරඹන්න"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"දැනුම්දීම් නැත"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"මෙම උපාංගය ඔබගේ මාපියන්ගෙන් අයකු විසින් කළමනාකරණය කෙරේ"</string>
@@ -452,8 +459,8 @@
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"භාවිත කිරීමට අගුලු හරින්න"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"ඔබගේ කාඩ්පත ලබා ගැනීමේ ගැටලුවක් විය, කරුණාකර පසුව නැවත උත්සාහ කරන්න"</string>
<string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"අගුලු තිර සැකසීම්"</string>
- <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR කේතය"</string>
- <string name="qr_code_scanner_description" msgid="7937603775306661863">"ස්කෑන් කිරීමට තට්ටු කරන්න"</string>
+ <!-- no translation found for qr_code_scanner_title (5290201053875420785) -->
+ <skip />
<string name="status_bar_work" msgid="5238641949837091056">"කාර්යාල පැතිකඩ"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"ගුවන්යානා ප්‍රකාරය"</string>
<string name="zen_alarm_warning" msgid="7844303238486849503">"ඔබට ඔබේ ඊළඟ එලාමය <xliff:g id="WHEN">%1$s</xliff:g> නොඇසෙනු ඇත"</string>
@@ -491,6 +498,8 @@
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"&lt;b&gt;තත්ත්වය:&lt;/b&gt; පහළට ශ්‍රේණිගත කරන ලදි"</string>
<string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"සංවාද දැනුම්දීම්වල ඉහළින්ම සහ අගුලු තිරයේ ඇති පැතිකඩ පින්තූරයක් ලෙස පෙන්වයි"</string>
<string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"සංවාද දැනුම්දීම්වල ඉහළින්ම සහ අගුලු තිරයේ ඇති පැතිකඩ පින්තූරයක් ලෙස පෙන්වයි, බුබුළක් ලෙස දිස් වේ"</string>
+ <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"සංවාද දැනුම්දීම්වල ඉහළින්ම සහ අගුලු තිරයේ ඇති පැතිකඩ පින්තූරයක් ලෙස පෙන්වයි, බාධා නොකරන්න සඳහා බාධා කරයි"</string>
+ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"සංවාද දැනුම්දීම්වල ඉහළින්ම සහ අගුලු තිරයේ ඇති පැතිකඩ පින්තූරයක් ලෙස පෙන්වයි, බුබුළක් ලෙස දිස් වේ, බාධා නොකරන්න සඳහා බාධා කරයි"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"ප්‍රමුඛතාව"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> සංවාද විශේෂාංගවලට සහාය නොදක්වයි"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"මෙම දැනුම්දීම් වෙනස් කළ නොහැක."</string>
@@ -566,6 +575,7 @@
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"SMS"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"සංගීතය"</string>
<string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"දින දර්ශනය"</string>
+ <string name="volume_and_do_not_disturb" msgid="502044092739382832">"බාධා නොකරන්න"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"හඩ පරිමා බොත්තම් කෙටිමග"</string>
<string name="battery" msgid="769686279459897127">"බැටරිය"</string>
<string name="headset" msgid="4485892374984466437">"හෙඩ්සෙට්"</string>
@@ -684,6 +694,10 @@
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"Wi-Fi ක්‍රියා විරහිතයි"</string>
<string name="bt_is_off" msgid="7436344904889461591">"බ්ලූටූත් ක්‍රියා විරහිතයි"</string>
+ <string name="dnd_is_off" msgid="3185706903793094463">"බාධා නොකරන්න ක්‍රියා විරහිතයි"</string>
+ <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"ස්වයංක්‍රිය රීතියක් මගින් බාධා නොකරන්න ක්‍රියාත්මක කරන ලදී (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"යෙදුමක් මගින් බාධා නොකරන්න ක්‍රියාත්මක කරන ලදී (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"ස්වයංක්‍රිය රීතියක් හෝ යෙදුමක් මගින් බාධා නොකරන්න ක්‍රියාත්මක කරන ලදී."</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"පසුබිමින් ධාවනය වන යෙදුම්"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"බැටරි හා දත්ත භාවිතය පිළිබඳව විස්තර සඳහා තට්ටු කරන්න"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"ජංගම දත්ත ක්‍රියාවිරහිත කරන්නද?"</string>
@@ -708,6 +722,8 @@
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"කාර්යාලය"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"දුරකථන ඇමතුම"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(<xliff:g id="APPLICATION_NAME_S_">%s</xliff:g> හරහා)"</string>
+ <string name="ongoing_privacy_dialog_attribution_label" msgid="3385241594101496292">"(<xliff:g id="ATTRIBUTION_LABEL">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_proxy_label" msgid="1111829599659403249">"(<xliff:g id="ATTRIBUTION_LABEL">%1$s</xliff:g> • <xliff:g id="PROXY_LABEL">%2$s</xliff:g>)"</string>
<string name="privacy_type_camera" msgid="7974051382167078332">"කැමරාව"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"ස්ථානය"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"මයික්‍රෝෆෝනය"</string>
@@ -806,6 +822,9 @@
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(විසන්ධි විය)"</string>
<string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"මාරු කිරීමට නොහැකිය. නැවත උත්සාහ කිරීමට තට්ටු කරන්න."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"නව උපාංගය යුගල කරන්න"</string>
+ <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"මෙම සැසිය විකාශය කිරීමට, කරුණාකර යෙදුම විවෘත කරන්න."</string>
+ <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"නොදන්නා යෙදුම"</string>
+ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"විකාශය නවතන්න"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"නිමැවුම් අංකය"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"නිමැවුම් අංකය පසුරු පුවරුවට පිටපත් කරන ලදි."</string>
<string name="basic_status" msgid="2315371112182658176">"සංවාදය විවෘත කරන්න"</string>
@@ -839,6 +858,7 @@
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"මෑත පණිවිඩ, මඟ හැරුණු ඇමතුම් සහ තත්ත්ව යාවත්කාලීන කිරීම් බලන්න"</string>
<string name="people_tile_title" msgid="6589377493334871272">"සංවාදය"</string>
+ <string name="paused_by_dnd" msgid="7856941866433556428">"බාධා නොකිරීම මගින් විරාම කර ඇත"</string>
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> පණිවිඩයක් එවා ඇත: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> රූපයක් යවන ලදී"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> හට තත්ත්ව යාවත්කාලීනයක් ඇත: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
@@ -877,8 +897,7 @@
<item quantity="one">සක්‍රිය යෙදුම් <xliff:g id="COUNT_1">%s</xliff:g></item>
<item quantity="other">සක්‍රිය යෙදුම් <xliff:g id="COUNT_1">%s</xliff:g></item>
</plurals>
- <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
- <skip />
+ <string name="fgs_dot_content_description" msgid="2865071539464777240">"නව තොරතුරු"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"සක්‍රිය යෙදුම්"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"නවත්වන්න"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"නවත්වන ලදි"</string>
@@ -886,14 +905,15 @@
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"පිටපත් කරන ලදි"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"<xliff:g id="APPNAME">%1$s</xliff:g> සිට"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Dismiss copy UI"</string>
- <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
- <skip />
- <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
- <skip />
- <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
- <skip />
- <!-- no translation found for add (81036585205287996) -->
- <skip />
- <!-- no translation found for manage_users (1823875311934643849) -->
- <skip />
+ <string name="clipboard_edit_text_description" msgid="805254383912962103">"පිටපත් කළ පෙළ සංස්කරණය කරන්න"</string>
+ <string name="clipboard_edit_image_description" msgid="8904857948976041306">"පිටපත් කළ රූපය සංස්කරණය කරන්න"</string>
+ <string name="clipboard_send_nearby_description" msgid="4629769637846717650">"අවට උපාංගය වෙත යවන්න"</string>
+ <string name="add" msgid="81036585205287996">"එක් කරන්න"</string>
+ <string name="manage_users" msgid="1823875311934643849">"පරිශීලකයන් කළමනාකරණය කරන්න"</string>
+ <string name="drag_split_not_supported" msgid="4326847447699729722">"මෙම දැනුම්දීම බෙදුම් තිරය වෙත ඇද ගෙන යාමට සහාය නොදක්වයි."</string>
+ <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi ලබා ගත නොහැකිය"</string>
+ <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"ප්‍රමුඛතා ප්‍රකාරය"</string>
+ <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"සීනුව සකසන ලදි"</string>
+ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"කැමරාව සහ මයික් ක්‍රියාවිරහිතයි"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{දැනුම්දීම් #ක්}one{දැනුම්දීම් #ක්}other{දැනුම්දීම් #ක්}}"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index a3bbe44a3272..5e29c9399777 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -20,14 +20,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4811759950673118541">"UI systému"</string>
- <string name="battery_low_title" msgid="6891106956328275225">"Batéria sa môže čoskoro minúť"</string>
+ <string name="battery_low_title" msgid="5319680173344341779">"Chcete zapnúť šetrič batérie?"</string>
+ <string name="battery_low_description" msgid="3282977755476423966">"Zostáva vám <xliff:g id="PERCENTAGE">%s</xliff:g> batérie. Šetrič batérie zapne tmavý motív, obmedzí aktivity na pozadí a odloží upozornenia."</string>
+ <string name="battery_low_intro" msgid="5148725009653088790">"Šetrič batérie zapne tmavý motív, obmedzí aktivity na pozadí a odloží upozornenia."</string>
<string name="battery_low_percent_format" msgid="4276661262843170964">"Zostáva <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="invalid_charger_title" msgid="938685362320735167">"Nedá sa nabíjať cez USB"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"Použite nabíjačku dodanú so zariadením"</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Zapnúť šetrič batérie?"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Šetrič batérie"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Zapnúť"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"Zapnúť šetrič batérie"</string>
+ <string name="battery_saver_start_action" msgid="8353766979886287140">"Zapnúť"</string>
+ <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Nie, vďaka"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Automatické otočenie obrazovky"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"Povoliť aplikácii <xliff:g id="APPLICATION">%1$s</xliff:g> prístup k zariadeniu <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
<string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Povoliť aplikácii <xliff:g id="APPLICATION">%1$s</xliff:g> pristupovať k zariadeniu <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nTejto aplikácii nebolo udelené povolenie na nahrávanie, môže však snímať zvuk cez toto zariadenie USB."</string>
@@ -128,6 +131,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Tvár bola overená"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Potvrdené"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Overenie dokončíte klepnutím na Potvrdiť"</string>
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Odomkli ste svojou tvárou. Pokračujte stlačením."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Overené"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Použiť PIN"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Použiť vzor"</string>
@@ -181,6 +185,7 @@
<string name="accessibility_desc_close" msgid="8293708213442107755">"Zavrieť"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"úplné ticho"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"iba budíky"</string>
+ <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"Režim bez vyrušení."</string>
<string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"Bluetooth"</string>
<string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"Rozhranie Bluetooth je zapnuté."</string>
<string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"Budík nastavený na <xliff:g id="TIME">%s</xliff:g>."</string>
@@ -207,6 +212,7 @@
<string name="dessert_case" msgid="9104973640704357717">"Pult s dezertami"</string>
<string name="start_dreams" msgid="9131802557946276718">"Šetrič obrazovky"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
+ <string name="quick_settings_dnd_label" msgid="7728690179108024338">"Režim bez vyrušení"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Nie sú k dispozícii žiadne spárované zariadenia"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Batéria: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
@@ -354,6 +360,7 @@
<string name="notification_section_header_alerting" msgid="5581175033680477651">"Upozornenia"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Konverzácie"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Vymazať všetky tiché upozornenia"</string>
+ <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Upozornenia sú pozastavené režimom bez vyrušení"</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"Spustiť"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Žiadne upozornenia"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Toto zariadenie spravuje tvoj rodič"</string>
@@ -458,8 +465,7 @@
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Odomknúť a použiť"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Pri načítavaní kariet sa vyskytol problém. Skúste to neskôr."</string>
<string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Nastavenia uzamknutej obrazovky"</string>
- <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR kód"</string>
- <string name="qr_code_scanner_description" msgid="7937603775306661863">"Ak chcete skenovať, klepnite"</string>
+ <string name="qr_code_scanner_title" msgid="5290201053875420785">"Skenovanie QR kódu"</string>
<string name="status_bar_work" msgid="5238641949837091056">"Pracovný profil"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Režim v lietadle"</string>
<string name="zen_alarm_warning" msgid="7844303238486849503">"Váš budík o <xliff:g id="WHEN">%1$s</xliff:g> sa nespustí"</string>
@@ -497,6 +503,8 @@
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"&lt;b&gt;Stav:&lt;/b&gt; Preradené nižšie"</string>
<string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"Zobrazuje sa v hornej časti upozornení konverzácie a ako profilová fotka na uzamknutej obrazovke"</string>
<string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"Zobrazuje sa ako bublina v hornej časti upozornení konverzácie a profilová fotka na uzamknutej obrazovke"</string>
+ <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"Zobrazuje sa v hornej časti upozornení konverzácie a ako profilová fotka na uzamknutej obrazovke, preruší režim bez vyrušení"</string>
+ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Zobrazuje sa ako bublina v hornej časti upozornení konverzácie a profilová fotka na uzamknutej obrazovke, preruší režim bez vyrušení"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Priorita"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> nepodporuje funkcie konverzácie"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Tieto upozornenia sa nedajú upraviť."</string>
@@ -576,6 +584,7 @@
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"SMS"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"Hudba"</string>
<string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Kalendár"</string>
+ <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Režim bez vyrušení"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"Skratka tlačidiel hlasitosti"</string>
<string name="battery" msgid="769686279459897127">"Batéria"</string>
<string name="headset" msgid="4485892374984466437">"Náhlavná súprava"</string>
@@ -694,6 +703,10 @@
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"Pripojenie Wi‑Fi je vypnuté"</string>
<string name="bt_is_off" msgid="7436344904889461591">"Rozhranie Bluetooth je vypnuté"</string>
+ <string name="dnd_is_off" msgid="3185706903793094463">"Režim bez vyrušení je vypnutý"</string>
+ <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"Režim bez vyrušení bol zapnutý automatickým pravidlom (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"Režim bez vyrušení bol zapnutý aplikáciou (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"Režim bez vyrušení bol zapnutý automatickým pravidlom alebo aplikáciou."</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"Aplikácie sú spustené na pozadí"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"Klepnutím zobrazíte podrobnosti o batérii a spotrebe dát"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Chcete vypnúť mobilné dáta?"</string>
@@ -718,6 +731,8 @@
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(práca)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"Telefonický hovor"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(prostredníctvom aplikácie <xliff:g id="APPLICATION_NAME_S_">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_label" msgid="3385241594101496292">"(<xliff:g id="ATTRIBUTION_LABEL">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_proxy_label" msgid="1111829599659403249">"(<xliff:g id="ATTRIBUTION_LABEL">%1$s</xliff:g> • <xliff:g id="PROXY_LABEL">%2$s</xliff:g>)"</string>
<string name="privacy_type_camera" msgid="7974051382167078332">"fotoaparát"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"poloha"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofón"</string>
@@ -818,6 +833,9 @@
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(odpojené)"</string>
<string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Nedá sa prepnúť. Zopakujte klepnutím."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Spárovať nové zariadenie"</string>
+ <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Ak chcete túto reláciu prenášať, otvorte aplikáciu."</string>
+ <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Neznáma aplikácia"</string>
+ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Zastaviť prenos"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Číslo zostavy"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Číslo zostavy bolo skopírované do schránky."</string>
<string name="basic_status" msgid="2315371112182658176">"Otvorená konverzácia"</string>
@@ -851,6 +869,7 @@
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Pozrite si nedávne správy, zmeškané hovory a aktualizácie stavu"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Konverzácia"</string>
+ <string name="paused_by_dnd" msgid="7856941866433556428">"Pozastavené režimom bez vyrušení"</string>
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> poslal(a) správu: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> poslal(a) obrázok"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> má aktualizáciu statusu: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
@@ -891,8 +910,7 @@
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> aktívnych aplikácií</item>
<item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> aktívna aplikácia</item>
</plurals>
- <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
- <skip />
+ <string name="fgs_dot_content_description" msgid="2865071539464777240">"Nové informácie"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Aktívne aplikácie"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Ukončiť"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Zastavená"</string>
@@ -903,8 +921,12 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Upraviť skopírovaný text"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Upraviť skopírovaný obrázok"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Odoslať do zariadenia v okolí"</string>
- <!-- no translation found for add (81036585205287996) -->
- <skip />
- <!-- no translation found for manage_users (1823875311934643849) -->
- <skip />
+ <string name="add" msgid="81036585205287996">"Pridať"</string>
+ <string name="manage_users" msgid="1823875311934643849">"Spravovať používateľov"</string>
+ <string name="drag_split_not_supported" msgid="4326847447699729722">"Toto upozornenie nepodporuje presun na rozdelenú obrazovku."</string>
+ <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi nie je k dispozícii"</string>
+ <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Režim priority"</string>
+ <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Budík je nastavený"</string>
+ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Kamera a mikrofón sú vypnuté"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# upozornenie}few{# upozornenia}many{# notifications}other{# upozornení}}"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index d657277431ca..cf9cb1c84212 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -20,14 +20,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4811759950673118541">"Sistemski uporabniški vmesnik"</string>
- <string name="battery_low_title" msgid="6891106956328275225">"Baterija bo morda kmalu izpraznjena"</string>
+ <string name="battery_low_title" msgid="5319680173344341779">"Želite vklopiti varčevanje z energijo baterije?"</string>
+ <string name="battery_low_description" msgid="3282977755476423966">"Preostala napolnjenost baterije: <xliff:g id="PERCENTAGE">%s</xliff:g>. Funkcija varčevanja z energijo baterije vklopi temno temo, omeji dejavnost v ozadju in prikazuje obvestila z zakasnitvijo."</string>
+ <string name="battery_low_intro" msgid="5148725009653088790">"Funkcija varčevanja z energijo baterije vklopi temno temo, omeji dejavnost v ozadju in prikazuje obvestila z zakasnitvijo."</string>
<string name="battery_low_percent_format" msgid="4276661262843170964">"Še <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="invalid_charger_title" msgid="938685362320735167">"Ni mogoče polniti prek USB-ja"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"Uporabite polnilnik, ki je bil priložen napravi"</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Želite vklopiti varčevanje z baterijo?"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"O varčevanju z energijo baterije"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Vklopi"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"Vklop varčevanja z baterijo"</string>
+ <string name="battery_saver_start_action" msgid="8353766979886287140">"Vklopi"</string>
+ <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Ne, hvala"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Samodejno zasukaj zaslon"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"Ali aplikaciji <xliff:g id="APPLICATION">%1$s</xliff:g> dovolite dostop do dodatka USB <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
<string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Ali aplikaciji <xliff:g id="APPLICATION">%1$s</xliff:g> dovolite dostop do naprave <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nTa aplikacija sicer nima dovoljenja za snemanje, vendar bi lahko zajemala zvok prek te naprave USB."</string>
@@ -128,6 +131,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Pristnost obraza je potrjena"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Potrjeno"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Za dokončanje se dotaknite »Potrdite«"</string>
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Odklenili ste z obrazom. Pritisnite za nadaljevanje."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Preverjena pristnost"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Uporabi kodo PIN"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Uporabi vzorec"</string>
@@ -181,6 +185,7 @@
<string name="accessibility_desc_close" msgid="8293708213442107755">"Zapri"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"popolna tišina"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"samo alarmi"</string>
+ <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"Ne moti."</string>
<string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"Bluetooth"</string>
<string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"Bluetooth je vklopljen."</string>
<string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"Alarm je nastavljen čez: <xliff:g id="TIME">%s</xliff:g>."</string>
@@ -207,6 +212,7 @@
<string name="dessert_case" msgid="9104973640704357717">"Vitrina za sladice"</string>
<string name="start_dreams" msgid="9131802557946276718">"Ohranjeval. zaslona"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
+ <string name="quick_settings_dnd_label" msgid="7728690179108024338">"Ne moti"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Na voljo ni nobene seznanjene naprave"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Baterija na <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
@@ -354,6 +360,7 @@
<string name="notification_section_header_alerting" msgid="5581175033680477651">"Obvestila"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Pogovori"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Brisanje vseh tihih obvestil"</string>
+ <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Prikazovanje obvestil je začasno zaustavljeno z načinom »ne moti«"</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"Začni zdaj"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Ni obvestil"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"To napravo upravlja tvoj starš"</string>
@@ -458,8 +465,8 @@
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Odklenite za uporabo"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Pri pridobivanju kartic je prišlo do težave. Poskusite znova pozneje."</string>
<string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Nastavitve zaklepanja zaslona"</string>
- <string name="qr_code_scanner_title" msgid="5660820608548306581">"Koda QR"</string>
- <string name="qr_code_scanner_description" msgid="7937603775306661863">"Dotaknite se za optično branje"</string>
+ <!-- no translation found for qr_code_scanner_title (5290201053875420785) -->
+ <skip />
<string name="status_bar_work" msgid="5238641949837091056">"Profil za Android Work"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Način za letalo"</string>
<string name="zen_alarm_warning" msgid="7844303238486849503">"Naslednjega alarma ob <xliff:g id="WHEN">%1$s</xliff:g> ne boste slišali"</string>
@@ -497,6 +504,8 @@
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"&lt;b&gt;Stanje:&lt;/b&gt; Uvrščeno nižje"</string>
<string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"Prikaz na vrhu razdelka z obvestili za pogovor in kot profilna slika na zaklenjenem zaslonu"</string>
<string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"Prikaz v obliki oblačka na vrhu razdelka z obvestili za pogovor in kot profilna slika na zaklenjenem zaslonu."</string>
+ <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"Prikaz na vrhu razdelka z obvestili za pogovor in kot profilna slika na zaklenjenem zaslonu, preglasitev načina Ne moti."</string>
+ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Prikaz v obliki oblačka na vrhu razdelka z obvestili za pogovor in kot profilna slika na zaklenjenem zaslonu, preglasitev načina Ne moti."</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prednostno"</string>
<string name="no_shortcut" msgid="8257177117568230126">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> ne podpira pogovornih funkcij."</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Za ta obvestila ni mogoče spremeniti nastavitev."</string>
@@ -576,6 +585,7 @@
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"Sporočila SMS"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"Glasba"</string>
<string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Koledar"</string>
+ <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Ne moti"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"Bližnjica z gumboma za glasnost"</string>
<string name="battery" msgid="769686279459897127">"Baterija"</string>
<string name="headset" msgid="4485892374984466437">"Slušalke z mikrofonom"</string>
@@ -694,6 +704,10 @@
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"Wi-Fi je izklopljen"</string>
<string name="bt_is_off" msgid="7436344904889461591">"Bluetooth je izklopljen"</string>
+ <string name="dnd_is_off" msgid="3185706903793094463">"Način »ne moti« je izklopljen"</string>
+ <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"Samodejno pravilo (<xliff:g id="ID_1">%s</xliff:g>) je vklopilo način »ne moti«."</string>
+ <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"Aplikacija (<xliff:g id="ID_1">%s</xliff:g>) je vklopila način »ne moti«."</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"Način »ne moti« je bil vklopljen zaradi samodejnega pravila ali aplikacije."</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"Aplikacije, ki se izvajajo v ozadju"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"Dotaknite se za prikaz podrobnosti porabe baterije in prenosa podatkov"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Želite izklopiti prenos podatkov v mobilnih omrežjih?"</string>
@@ -718,6 +732,8 @@
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(za delo)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"Telefonski klic"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(prek aplikacije <xliff:g id="APPLICATION_NAME_S_">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_label" msgid="3385241594101496292">"(<xliff:g id="ATTRIBUTION_LABEL">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_proxy_label" msgid="1111829599659403249">"(<xliff:g id="ATTRIBUTION_LABEL">%1$s</xliff:g> • <xliff:g id="PROXY_LABEL">%2$s</xliff:g>)"</string>
<string name="privacy_type_camera" msgid="7974051382167078332">"fotoaparat"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"lokacijo"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofon"</string>
@@ -818,6 +834,9 @@
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(povezava je prekinjena)"</string>
<string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Preklop ni mogoč. Če želite poskusiti znova, se dotaknite."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Seznanitev nove naprave"</string>
+ <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Če želite predvajati to sejo, odprite aplikacijo."</string>
+ <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Neznana aplikacija"</string>
+ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Ustavi predvajanje"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Delovna različica"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Delovna različica je bila kopirana v odložišče."</string>
<string name="basic_status" msgid="2315371112182658176">"Odprt pogovor"</string>
@@ -851,6 +870,7 @@
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"Več kot <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Ogled nedavnih sporočil, neodgovorjenih klicev in posodobitev stanj"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Pogovor"</string>
+ <string name="paused_by_dnd" msgid="7856941866433556428">"To je začasno zaustavil način »ne moti«."</string>
<string name="new_notification_text_content_description" msgid="2915029960094389291">"Oseba <xliff:g id="NAME">%1$s</xliff:g> je poslala sporočilo: <xliff:g id="NOTIFICATION">%2$s</xliff:g>."</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"Oseba <xliff:g id="NAME">%1$s</xliff:g> je poslala sliko."</string>
<string name="new_status_content_description" msgid="6046637888641308327">"Oseba <xliff:g id="NAME">%1$s</xliff:g> je posodobila stanje: <xliff:g id="STATUS">%2$s</xliff:g>."</string>
@@ -891,8 +911,7 @@
<item quantity="few"><xliff:g id="COUNT_1">%s</xliff:g> aktivne aplikacije</item>
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> aktivnih aplikacij</item>
</plurals>
- <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
- <skip />
+ <string name="fgs_dot_content_description" msgid="2865071539464777240">"Nove informacije"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Aktivne aplikacije"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Ustavi"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Ustavljeno"</string>
@@ -903,8 +922,12 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Uredi kopirano besedilo"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Uredi kopirano sliko"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Pošlji v napravo v bližini"</string>
- <!-- no translation found for add (81036585205287996) -->
- <skip />
- <!-- no translation found for manage_users (1823875311934643849) -->
- <skip />
+ <string name="add" msgid="81036585205287996">"Dodaj"</string>
+ <string name="manage_users" msgid="1823875311934643849">"Upravljanje uporabnikov"</string>
+ <string name="drag_split_not_supported" msgid="4326847447699729722">"To obvestilo ne podpira vlečenja v razdeljen zaslon."</string>
+ <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi ni na voljo."</string>
+ <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Prednostni način"</string>
+ <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarm je nastavljen."</string>
+ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Fotoaparat in mikrofon sta izklopljena."</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# obvestilo}one{# obvestilo}two{# obvestili}few{# obvestila}other{# obvestil}}"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index f8ba65af9300..fcf886818d42 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -20,14 +20,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4811759950673118541">"Ndërfaqja e përdoruesit të sistemit"</string>
- <string name="battery_low_title" msgid="6891106956328275225">"Bateria mund të mbarojë së shpejti"</string>
+ <string name="battery_low_title" msgid="5319680173344341779">"Të aktivizohet \"Kursyesi i baterisë\"?"</string>
+ <string name="battery_low_description" msgid="3282977755476423966">"Ke <xliff:g id="PERCENTAGE">%s</xliff:g> bateri të mbetur. \"Kursyesi i baterisë\" aktivizon \"Temën e errët\", kufizon aktivitetet në sfond dhe vonon njoftimet."</string>
+ <string name="battery_low_intro" msgid="5148725009653088790">"\"Kursyesi i baterisë\" aktivizon \"Temën e errët\", kufizon aktivitetet në sfond dhe vonon njoftimet."</string>
<string name="battery_low_percent_format" msgid="4276661262843170964">"Ka mbetur edhe <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="invalid_charger_title" msgid="938685362320735167">"Nuk mund të ngarkohet përmes USB-së"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"Përdor karikuesin që ke marrë me pajisjen"</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Të aktivizohet \"Kursyesi i baterisë\"?"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Rreth \"Kursyesit të baterisë\""</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Aktivizo"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"Aktivizo \"Kursyesin e baterisë\""</string>
+ <string name="battery_saver_start_action" msgid="8353766979886287140">"Aktivizo"</string>
+ <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Jo, faleminderit"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Rrotullimi automatik i ekranit"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"Të lejohet <xliff:g id="APPLICATION">%1$s</xliff:g> të ketë qasje te <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
<string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Dëshiron të lejosh që <xliff:g id="APPLICATION">%1$s</xliff:g> të ketë qasje te <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nKëtij aplikacioni nuk i është dhënë leje për regjistrim, por mund të regjistrojë audio përmes kësaj pajisjeje USB."</string>
@@ -128,6 +131,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Fytyra u vërtetua"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Konfirmuar"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Trokit \"Konfirmo\" për ta përfunduar"</string>
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Shkyçur nga fytyra jote. Shtyp për të vazhduar."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"U vërtetua"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Përdor kodin PIN"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Përdor motivin"</string>
@@ -181,6 +185,7 @@
<string name="accessibility_desc_close" msgid="8293708213442107755">"Mbylle"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"heshtje e plotë"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"vetëm alarmet"</string>
+ <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"Mos shqetëso."</string>
<string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"Bluetooth-i."</string>
<string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"\"Bluetooth-i\" është i aktivizuar."</string>
<string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"Alarmi u caktua për në <xliff:g id="TIME">%s</xliff:g>."</string>
@@ -205,6 +210,7 @@
<string name="dessert_case" msgid="9104973640704357717">"\"Kutia e ëmbëlsirës\""</string>
<string name="start_dreams" msgid="9131802557946276718">"Mbrojtësi i ekranit"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Eternet"</string>
+ <string name="quick_settings_dnd_label" msgid="7728690179108024338">"Mos shqetëso"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Nuk ofrohet për përdorim asnjë pajisje e çiftuar"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> bateri"</string>
@@ -348,6 +354,7 @@
<string name="notification_section_header_alerting" msgid="5581175033680477651">"Njoftimet"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Bisedat"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Pastro të gjitha njoftimet në heshtje"</string>
+ <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Njoftimet janë vendosur në pauzë nga modaliteti \"Mos shqetëso\""</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"Fillo tani"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Asnjë njoftim"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Kjo pajisje menaxhohet nga prindi yt"</string>
@@ -452,8 +459,8 @@
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Shkyçe për ta përdorur"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Pati një problem me marrjen e kartave të tua. Provo përsëri më vonë"</string>
<string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Cilësimet e ekranit të kyçjes"</string>
- <string name="qr_code_scanner_title" msgid="5660820608548306581">"Kodi QR"</string>
- <string name="qr_code_scanner_description" msgid="7937603775306661863">"Trokit për të skanuar"</string>
+ <!-- no translation found for qr_code_scanner_title (5290201053875420785) -->
+ <skip />
<string name="status_bar_work" msgid="5238641949837091056">"Profili i punës"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Modaliteti i aeroplanit"</string>
<string name="zen_alarm_warning" msgid="7844303238486849503">"Nuk do ta dëgjosh alarmin e radhës në <xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -491,6 +498,8 @@
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"&lt;b&gt;Statusi:&lt;/b&gt; Renditur më poshtë"</string>
<string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"Shfaqet në krye të njoftimeve të bisedës dhe si fotografia e profilit në ekranin e kyçjes"</string>
<string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"Shfaqet në krye të njoftimeve të bisedës, shfaqet si fotografia e profilit në ekranin e kyçjes dhe shfaqet si flluskë"</string>
+ <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"Shfaqet në krye të njoftimeve të bisedës, shfaqet si fotografia e profilit në ekranin e kyçjes dhe ndërpret modalitetin \"Mos shqetëso\""</string>
+ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Shfaqet në krye të njoftimeve të bisedës dhe si fotografia e profilit në ekranin e kyçjes, shfaqet si flluskë dhe ndërpret modalitetin \"Mos shqetëso\""</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Me përparësi"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> nuk mbështet veçoritë e bisedës"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Këto njoftime nuk mund të modifikohen."</string>
@@ -566,6 +575,7 @@
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"SMS"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"Muzikë"</string>
<string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Kalendari"</string>
+ <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Mos shqetëso"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"Shkurtorja e butonave të volumit"</string>
<string name="battery" msgid="769686279459897127">"Bateria"</string>
<string name="headset" msgid="4485892374984466437">"Kufjet me mikrofon"</string>
@@ -684,6 +694,10 @@
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g> <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"Wi-Fi është joaktiv"</string>
<string name="bt_is_off" msgid="7436344904889461591">"Bluetooth-i është joaktiv"</string>
+ <string name="dnd_is_off" msgid="3185706903793094463">"Modaliteti \"Mos shqetëso\" është joaktiv"</string>
+ <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"Modaliteti \"Mos shqetëso\" është aktivizuar nga një rregull automatik (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"Modaliteti \"Mos shqetëso\" është aktivizuar nga një aplikacion (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"Modaliteti \"Mos shqetëso\" është aktivizuar nga një rregull automatik ose një aplikacion."</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"Aplikacionet që ekzekutohen në sfond"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"Trokit për detaje mbi baterinë dhe përdorimin e të dhënave"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Të çaktivizohen të dhënat celulare?"</string>
@@ -708,6 +722,8 @@
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(puna)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"Telefonata"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(nëpërmjet <xliff:g id="APPLICATION_NAME_S_">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_label" msgid="3385241594101496292">"(<xliff:g id="ATTRIBUTION_LABEL">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_proxy_label" msgid="1111829599659403249">"(<xliff:g id="ATTRIBUTION_LABEL">%1$s</xliff:g> • <xliff:g id="PROXY_LABEL">%2$s</xliff:g>)"</string>
<string name="privacy_type_camera" msgid="7974051382167078332">"kamerën"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"vendndodhjen"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofonin"</string>
@@ -806,6 +822,9 @@
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(shkëputur)"</string>
<string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Nuk mund të ndërrohet. Trokit për të provuar përsëri."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Çifto pajisjen e re"</string>
+ <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Hap aplikacionin për të transmetuar këtë seancë."</string>
+ <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Aplikacion i panjohur"</string>
+ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Ndalo transmetimin"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Numri i ndërtimit"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Numri i ndërtimit u kopjua te kujtesa e fragmenteve"</string>
<string name="basic_status" msgid="2315371112182658176">"Hap bisedën"</string>
@@ -839,6 +858,7 @@
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"Mbi <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Shiko mesazhet e fundit, telefonatat e humbura dhe përditësimet e statusit"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Biseda"</string>
+ <string name="paused_by_dnd" msgid="7856941866433556428">"Vendosur në pauzë nga \"Mos shqetëso\""</string>
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> dërgoi një mesazh: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> dërgoi një imazh"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> ka një përditësim të statusit: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
@@ -877,8 +897,7 @@
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> aplikacione aktive</item>
<item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> aplikacion aktiv</item>
</plurals>
- <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
- <skip />
+ <string name="fgs_dot_content_description" msgid="2865071539464777240">"Informacion i ri"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Aplikacionet aktive"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Ndalo"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Ndaluar"</string>
@@ -886,14 +905,15 @@
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"U kopjua"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Nga <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Hiq kopjen e ndërfaqes së përdoruesit"</string>
- <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
- <skip />
- <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
- <skip />
- <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
- <skip />
- <!-- no translation found for add (81036585205287996) -->
- <skip />
- <!-- no translation found for manage_users (1823875311934643849) -->
- <skip />
+ <string name="clipboard_edit_text_description" msgid="805254383912962103">"Modifiko tekstin e kopjuar"</string>
+ <string name="clipboard_edit_image_description" msgid="8904857948976041306">"Modifiko imazhin e kopjuar"</string>
+ <string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Dërgo te pajisja në afërsi"</string>
+ <string name="add" msgid="81036585205287996">"Shto"</string>
+ <string name="manage_users" msgid="1823875311934643849">"Menaxho përdoruesit"</string>
+ <string name="drag_split_not_supported" msgid="4326847447699729722">"Ky njoftim nuk mbështet zvarritjen në \"Ekranin e ndarë\"."</string>
+ <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi nuk ofrohet"</string>
+ <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Modaliteti \"Me përparësi\""</string>
+ <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarmi është caktuar"</string>
+ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Kamera dhe mikrofoni janë joaktivë"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# njoftim}other{# njoftime}}"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 5d89cf1d3e6c..1025552b613d 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -20,14 +20,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4811759950673118541">"UI система"</string>
- <string name="battery_low_title" msgid="6891106956328275225">"Батерија ће се можда ускоро испразнити"</string>
+ <string name="battery_low_title" msgid="5319680173344341779">"Желите ли да укључите Уштеду батерије?"</string>
+ <string name="battery_low_description" msgid="3282977755476423966">"Преостали ниво напуњености батерије је <xliff:g id="PERCENTAGE">%s</xliff:g>. Уштеда батерије укључује Тамну тему, ограничава активности у позадини и одлаже обавештења."</string>
+ <string name="battery_low_intro" msgid="5148725009653088790">"Уштеда батерије укључује Тамну тему, ограничава активности у позадини и одлаже обавештења."</string>
<string name="battery_low_percent_format" msgid="4276661262843170964">"Још <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="invalid_charger_title" msgid="938685362320735167">"Пуњење преко USB-а није успело"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"Користите пуњач који сте добили уз уређај"</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Желите да укључите Уштеду батерије?"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"О Уштеди батерије"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Укључи"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"Укључи Уштеду батерије"</string>
+ <string name="battery_saver_start_action" msgid="8353766979886287140">"Укључи"</string>
+ <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Не, хвала"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Аутоматско ротирање екрана"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"Желите ли да дозволите да <xliff:g id="APPLICATION">%1$s</xliff:g> приступа уређају <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
<string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Желите ли да дозволите да <xliff:g id="APPLICATION">%1$s</xliff:g> приступа уређају <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nОва апликација нема дозволу за снимање, али би могла да снима звук помоћу овог USB уређаја."</string>
@@ -128,6 +131,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Лице је потврђено"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Потврђено"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Додирните Потврди да бисте завршили"</string>
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Откључали сте лицем. Притисните да бисте наставили."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Идентитет је потврђен"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Користите PIN"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Користите шаблон"</string>
@@ -181,6 +185,7 @@
<string name="accessibility_desc_close" msgid="8293708213442107755">"Затвори"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"потпуна тишина"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"само аларми"</string>
+ <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"Не узнемиравај."</string>
<string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"Bluetooth."</string>
<string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"Bluetooth је укључен."</string>
<string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"Аларм је подешен за <xliff:g id="TIME">%s</xliff:g>."</string>
@@ -206,6 +211,7 @@
<string name="dessert_case" msgid="9104973640704357717">"Витрина са посластицама"</string>
<string name="start_dreams" msgid="9131802557946276718">"Чувар екрана"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Етернет"</string>
+ <string name="quick_settings_dnd_label" msgid="7728690179108024338">"Не узнемиравај"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Није доступан ниједан упарени уређај"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Ниво батерије је <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
@@ -351,6 +357,7 @@
<string name="notification_section_header_alerting" msgid="5581175033680477651">"Обавештења"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Конверзације"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Обришите сва нечујна обавештења"</string>
+ <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Обавештења су паузирана режимом Не узнемиравај"</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"Започни"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Нема обавештења"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Овим уређајем управља родитељ"</string>
@@ -455,8 +462,7 @@
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Откључај ради коришћења"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Дошло је до проблема при преузимању картица. Пробајте поново касније"</string>
<string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Подешавања закључаног екрана"</string>
- <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR кôд"</string>
- <string name="qr_code_scanner_description" msgid="7937603775306661863">"Додирните да бисте скенирали"</string>
+ <string name="qr_code_scanner_title" msgid="5290201053875420785">"Скенирајте QR кôд"</string>
<string name="status_bar_work" msgid="5238641949837091056">"Пословни профил"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Режим рада у авиону"</string>
<string name="zen_alarm_warning" msgid="7844303238486849503">"Нећете чути следећи аларм у <xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -494,6 +500,8 @@
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"&lt;b&gt;Статус:&lt;/b&gt; Рангирано ниже"</string>
<string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"Приказује се у врху обавештења о конверзацијама и као слика профила на закључаном екрану"</string>
<string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"Приказује се у врху обавештења о конверзацијама и као слика профила на закључаном екрану, појављује се као облачић"</string>
+ <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"Приказује се у врху обавештења о конверзацијама и као слика профила на закључаном екрану, прекида режим Не узнемиравај"</string>
+ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Приказује се у врху обавештења о конверзацијама и као слика профила на закључаном екрану, појављује се као облачић, прекида режим Не узнемиравај"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Приоритет"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> не подржава функције конверзације"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Ова обавештења не могу да се мењају."</string>
@@ -571,6 +579,7 @@
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"SMS"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"Музика"</string>
<string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Календар"</string>
+ <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Не узнемиравај"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"Пречица за дугмад за јачину звука"</string>
<string name="battery" msgid="769686279459897127">"Батерија"</string>
<string name="headset" msgid="4485892374984466437">"Наглавне слушалице"</string>
@@ -689,6 +698,10 @@
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"WiFi је искључен"</string>
<string name="bt_is_off" msgid="7436344904889461591">"Bluetooth је искључен"</string>
+ <string name="dnd_is_off" msgid="3185706903793094463">"Режим Не узнемиравај је искључен"</string>
+ <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"Аутоматско правило (<xliff:g id="ID_1">%s</xliff:g>) је укључило режим Не узнемиравај."</string>
+ <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"Апликација (<xliff:g id="ID_1">%s</xliff:g>) је укључила режим Не узнемиравај."</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"Аутоматско правило или апликација су укључили режим Не узнемиравај."</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"Апликације покренуте у позадини"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"Додирните за детаље о батерији и потрошњи података"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Желите да искључите мобилне податке?"</string>
@@ -713,6 +726,8 @@
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(посао)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"Телефонски позив"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(преко: <xliff:g id="APPLICATION_NAME_S_">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_label" msgid="3385241594101496292">"(<xliff:g id="ATTRIBUTION_LABEL">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_proxy_label" msgid="1111829599659403249">"(<xliff:g id="ATTRIBUTION_LABEL">%1$s</xliff:g> • <xliff:g id="PROXY_LABEL">%2$s</xliff:g>)"</string>
<string name="privacy_type_camera" msgid="7974051382167078332">"камеру"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"локацију"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"микрофон"</string>
@@ -812,6 +827,9 @@
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(веза је прекинута)"</string>
<string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Пребацивање није успело. Пробајте поново."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Упари нови уређај"</string>
+ <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Да бисте пребацивали ову сесију, отворите апликацију."</string>
+ <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Непозната апликација"</string>
+ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Заустави пребацивање"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Број верзије"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Број верзије је копиран у привремену меморију."</string>
<string name="basic_status" msgid="2315371112182658176">"Отворите конверзацију"</string>
@@ -845,6 +863,7 @@
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Погледајте недавне поруке, пропуштене позиве и ажурирања статуса"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Конверзација"</string>
+ <string name="paused_by_dnd" msgid="7856941866433556428">"Паузирано режимом Не узнемиравај"</string>
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> је послао/ла поруку: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> шаље слику"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> има ажурирање статуса: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
@@ -884,8 +903,7 @@
<item quantity="few"><xliff:g id="COUNT_1">%s</xliff:g> активне апликације</item>
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> активних апликација</item>
</plurals>
- <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
- <skip />
+ <string name="fgs_dot_content_description" msgid="2865071539464777240">"Нове информације"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Активне апликације"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Заустави"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Заустављено"</string>
@@ -893,14 +911,15 @@
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Копирано је"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Из: <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Одбаци копирање корисничког интерфејса"</string>
- <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
- <skip />
- <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
- <skip />
- <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
- <skip />
- <!-- no translation found for add (81036585205287996) -->
- <skip />
- <!-- no translation found for manage_users (1823875311934643849) -->
- <skip />
+ <string name="clipboard_edit_text_description" msgid="805254383912962103">"Измените копирани текст"</string>
+ <string name="clipboard_edit_image_description" msgid="8904857948976041306">"Измените копирану слику"</string>
+ <string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Пошаљи на уређај у близини"</string>
+ <string name="add" msgid="81036585205287996">"Додај"</string>
+ <string name="manage_users" msgid="1823875311934643849">"Управљаjте корисницима"</string>
+ <string name="drag_split_not_supported" msgid="4326847447699729722">"Ово обавештење не подржава превлачење на подељени екран."</string>
+ <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"WiFi није доступан"</string>
+ <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Приоритетни режим"</string>
+ <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Аларм је подешен"</string>
+ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Камера и микрофон су искључени"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# обавештење}one{# обавештење}few{# обавештења}other{# обавештења}}"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index b9a3ab106fcd..ed89872724ba 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -20,14 +20,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4811759950673118541">"Gränssnitt"</string>
- <string name="battery_low_title" msgid="6891106956328275225">"Batteriet kan ta slut snart"</string>
+ <string name="battery_low_title" msgid="5319680173344341779">"Vill du aktivera batterisparläget?"</string>
+ <string name="battery_low_description" msgid="3282977755476423966">"<xliff:g id="PERCENTAGE">%s</xliff:g> av batteriet återstår. I batterisparläget aktiveras Mörkt tema, bakgrundsaktivitet begränsas och aviseringar skjuts upp."</string>
+ <string name="battery_low_intro" msgid="5148725009653088790">"I batterisparläget aktiveras Mörkt tema, bakgrundsaktivitet begränsas och aviseringar skjuts upp."</string>
<string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> kvar"</string>
<string name="invalid_charger_title" msgid="938685362320735167">"Det går inte att ladda via USB"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"Använd laddaren som följde med enheten."</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Vill du aktivera batterisparläget?"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Om batterisparläget"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Aktivera"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"Aktivera batterisparläget"</string>
+ <string name="battery_saver_start_action" msgid="8353766979886287140">"Aktivera"</string>
+ <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Nej tack"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Rotera skärmen automatiskt"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"Vill du ge <xliff:g id="APPLICATION">%1$s</xliff:g> åtkomst till <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
<string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Vill du ge <xliff:g id="APPLICATION">%1$s</xliff:g> åtkomst till <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nAppen har inte fått inspelningsbehörighet men kan spela in ljud via denna USB-enhet."</string>
@@ -128,6 +131,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Ansiktet har autentiserats"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Bekräftat"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Slutför genom att trycka på Bekräfta"</string>
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Låstes upp med ansiktet. Tryck för att fortsätta."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Autentiserad"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Använd pinkod"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Använd mönster"</string>
@@ -181,6 +185,7 @@
<string name="accessibility_desc_close" msgid="8293708213442107755">"Stäng"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"helt tyst"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"endast alarm"</string>
+ <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"Stör ej."</string>
<string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"Bluetooth"</string>
<string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"Bluetooth på."</string>
<string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"Alarmet ringer <xliff:g id="TIME">%s</xliff:g>."</string>
@@ -205,6 +210,7 @@
<string name="dessert_case" msgid="9104973640704357717">"Dessertdisken"</string>
<string name="start_dreams" msgid="9131802557946276718">"Skärmsläckare"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
+ <string name="quick_settings_dnd_label" msgid="7728690179108024338">"Stör ej"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Det finns inga kopplade enheter tillgängliga"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> batteri"</string>
@@ -348,6 +354,7 @@
<string name="notification_section_header_alerting" msgid="5581175033680477651">"Aviseringar"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Konversationer"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Rensa alla ljudlösa aviseringar"</string>
+ <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Aviseringar har pausats via Stör ej"</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"Starta nu"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Inga aviseringar"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Den här enheten hanteras av din förälder"</string>
@@ -452,8 +459,8 @@
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Lås upp för att använda"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Det gick inte att hämta dina kort. Försök igen senare."</string>
<string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Inställningar för låsskärm"</string>
- <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR-kod"</string>
- <string name="qr_code_scanner_description" msgid="7937603775306661863">"Tryck för att skanna"</string>
+ <!-- no translation found for qr_code_scanner_title (5290201053875420785) -->
+ <skip />
<string name="status_bar_work" msgid="5238641949837091056">"Jobbprofil"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Flygplansläge"</string>
<string name="zen_alarm_warning" msgid="7844303238486849503">"Nästa alarm, kl. <xliff:g id="WHEN">%1$s</xliff:g>, kommer inte att höras"</string>
@@ -491,6 +498,8 @@
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"&lt;b&gt;Status:&lt;/b&gt; Sänkt"</string>
<string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"Visas högst upp i konversationsaviseringarna och som profilbild på låsskärmen"</string>
<string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"Visas högst upp i konversationsaviseringarna och som profilbild på låsskärmen, visas som bubbla"</string>
+ <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"Visas högst upp i konversationsaviseringarna och som profilbild på låsskärmen, åsidosätter Stör ej"</string>
+ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Visas högst upp i konversationsaviseringarna och som profilbild på låsskärmen, visas som bubbla, åsidosätter Stör ej"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritet"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> har inte stöd för konversationsfunktioner"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Det går inte att ändra de här aviseringarna."</string>
@@ -566,6 +575,7 @@
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"Sms"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"Musik"</string>
<string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Kalender"</string>
+ <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Stör ej"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"Genväg till volymknappar"</string>
<string name="battery" msgid="769686279459897127">"Batteri"</string>
<string name="headset" msgid="4485892374984466437">"Headset"</string>
@@ -684,6 +694,10 @@
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g> <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"wifi är inaktiverat"</string>
<string name="bt_is_off" msgid="7436344904889461591">"Bluetooth är inaktiverat"</string>
+ <string name="dnd_is_off" msgid="3185706903793094463">"Stör ej är inaktiverat"</string>
+ <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"Stör ej aktiverades via en automatisk regel (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"Stör ej aktiverades via en app (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"Stör ej aktiverades via en automatisk regel eller en app."</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"Appar körs i bakgrunden"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"Tryck för information om batteri- och dataanvändning"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Vill du inaktivera mobildata?"</string>
@@ -708,6 +722,8 @@
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(jobb)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"Telefonsamtal"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(via <xliff:g id="APPLICATION_NAME_S_">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_label" msgid="3385241594101496292">"(<xliff:g id="ATTRIBUTION_LABEL">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_proxy_label" msgid="1111829599659403249">"(<xliff:g id="ATTRIBUTION_LABEL">%1$s</xliff:g> • <xliff:g id="PROXY_LABEL">%2$s</xliff:g>)"</string>
<string name="privacy_type_camera" msgid="7974051382167078332">"kamera"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"plats"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofon"</string>
@@ -806,6 +822,9 @@
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(frånkopplad)"</string>
<string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Misslyckat byte. Tryck och försök igen."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Parkoppla en ny enhet"</string>
+ <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Öppna appen om du vill casta den här sessionen."</string>
+ <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Okänd app"</string>
+ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Sluta casta"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Versionsnummer"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Versionsnumret har kopierats till urklipp."</string>
<string name="basic_status" msgid="2315371112182658176">"Öppen konversation"</string>
@@ -839,6 +858,7 @@
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"över <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Se de senaste meddelandena, missade samtal och statusuppdateringar"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Konversation"</string>
+ <string name="paused_by_dnd" msgid="7856941866433556428">"Pausad av Stör ej"</string>
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> skickade ett meddelande: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> skickade en bild"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> har gjort en statusuppdatering: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
@@ -877,8 +897,7 @@
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> aktiva appar</item>
<item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> aktiv app</item>
</plurals>
- <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
- <skip />
+ <string name="fgs_dot_content_description" msgid="2865071539464777240">"Ny information"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Aktiva appar"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Stoppa"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Stoppad"</string>
@@ -886,14 +905,15 @@
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Kopierades"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Från <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Stäng användargränssnittet för kopiering"</string>
- <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
- <skip />
- <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
- <skip />
- <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
- <skip />
- <!-- no translation found for add (81036585205287996) -->
- <skip />
- <!-- no translation found for manage_users (1823875311934643849) -->
- <skip />
+ <string name="clipboard_edit_text_description" msgid="805254383912962103">"Redigera kopierad text"</string>
+ <string name="clipboard_edit_image_description" msgid="8904857948976041306">"Redigera kopierad bild"</string>
+ <string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Skicka till enhet i närheten"</string>
+ <string name="add" msgid="81036585205287996">"Lägg till"</string>
+ <string name="manage_users" msgid="1823875311934643849">"Hantera användare"</string>
+ <string name="drag_split_not_supported" msgid="4326847447699729722">"Det går inte att dra den här aviseringen till delad skärm."</string>
+ <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wifi är inte tillgängligt"</string>
+ <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Prioritetsläge"</string>
+ <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarmet är aktiverat"</string>
+ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Kameran och mikrofonen är avstängda"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# avisering}other{# aviseringar}}"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 803a2b56067c..2f184a1a7ee2 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -20,14 +20,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4811759950673118541">"Kiolesura"</string>
- <string name="battery_low_title" msgid="6891106956328275225">"Chaji inaweza kuisha hivi karibuni"</string>
+ <string name="battery_low_title" msgid="5319680173344341779">"Ungependa Kuwasha Kiokoa Betri?"</string>
+ <string name="battery_low_description" msgid="3282977755476423966">"Umebakiza asilimia <xliff:g id="PERCENTAGE">%s</xliff:g> ya betri. Kiokoa Betri kinawasha Mandhari meusi, kinazuia shughuli za chinichini na kuchelewesha arifa."</string>
+ <string name="battery_low_intro" msgid="5148725009653088790">"Kiokoa Betri kinawasha Mandhari meusi, kinazuia shughuli za chinichini na kuchelewesha arifa."</string>
<string name="battery_low_percent_format" msgid="4276661262843170964">"Imebakisha <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="invalid_charger_title" msgid="938685362320735167">"Haiwezi kuchaji kupitia USB"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"Tumia chaja ambayo ilikuja na kifaa chako"</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Ungependa Kuwasha Kiokoa Betri?"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Kuhusu Kiokoa betri"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Washa"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"Washa Kiokoa Betri"</string>
+ <string name="battery_saver_start_action" msgid="8353766979886287140">"Washa"</string>
+ <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Hapana"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Skrini ijizungushe kiotomatiki"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"Ungependa kuruhusu <xliff:g id="APPLICATION">%1$s</xliff:g> ifikie <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
<string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Ungependa kuruhusu <xliff:g id="APPLICATION">%1$s</xliff:g> ifikie <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nProgramu hii haijapewa ruhusa ya kurekodi lakini inaweza kurekodi sauti kupitia kifaa hiki cha USB."</string>
@@ -128,6 +131,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Uso umethibitishwa"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Imethibitishwa"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Gusa Thibitisha ili ukamilishe"</string>
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Imefunguliwa kwa kutumia uso wako. Bonyeza ili uendelee."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Umethibitishwa"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Tumia PIN"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Tumia mchoro"</string>
@@ -181,6 +185,7 @@
<string name="accessibility_desc_close" msgid="8293708213442107755">"Funga"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"kimya kabisa"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"kengele pekee"</string>
+ <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"Usinisumbue."</string>
<string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"Bluetooth"</string>
<string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"Bluetooth imewashwa."</string>
<string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"Kengele imewashwa na italia <xliff:g id="TIME">%s</xliff:g>."</string>
@@ -205,6 +210,7 @@
<string name="dessert_case" msgid="9104973640704357717">"Sanduku la Vitindamlo"</string>
<string name="start_dreams" msgid="9131802557946276718">"Taswira ya skrini"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
+ <string name="quick_settings_dnd_label" msgid="7728690179108024338">"Usinisumbue"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Hakuna vifaa vilivyooanishwa vinavyopatikana"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Chaji ya betri ni <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
@@ -348,6 +354,7 @@
<string name="notification_section_header_alerting" msgid="5581175033680477651">"Arifa"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Mazungumzo"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Futa arifa zote zisizo na sauti"</string>
+ <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Kipengele cha Usinisumbue kimesitisha arifa"</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"Anza sasa"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Hakuna arifa"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Kifaa hiki kinadhibitiwa na mzazi wako"</string>
@@ -452,8 +459,8 @@
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Fungua ili utumie"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Hitilafu imetokea wakati wa kuleta kadi zako, tafadhali jaribu tena baadaye"</string>
<string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Mipangilio ya kufunga skrini"</string>
- <string name="qr_code_scanner_title" msgid="5660820608548306581">"Msimbo wa QR"</string>
- <string name="qr_code_scanner_description" msgid="7937603775306661863">"Gusa ili uchanganue"</string>
+ <!-- no translation found for qr_code_scanner_title (5290201053875420785) -->
+ <skip />
<string name="status_bar_work" msgid="5238641949837091056">"Wasifu wa kazini"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Hali ya ndegeni"</string>
<string name="zen_alarm_warning" msgid="7844303238486849503">"Hutasikia kengele yako inayofuata ya saa <xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -491,6 +498,8 @@
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"&lt;b&gt;Hali:&lt;/b&gt; Imeorodheshwa Katika Nafasi ya Chini"</string>
<string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"Huonyeshwa kwenye sehemu ya juu ya arifa za mazungumzo na kama picha ya wasifu kwenye skrini iliyofungwa"</string>
<string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"Huonyeshwa kwenye sehemu ya juu ya arifa za mazungumzo na kama picha ya wasifu kwenye skrini iliyofungwa. Huonekana kama kiputo"</string>
+ <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"Huonyeshwa kwenye sehemu ya juu ya arifa za mazungumzo na kama picha ya wasifu kwenye skrini iliyofungwa. Hukatiza kipengele cha Usinisumbue"</string>
+ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Huonyeshwa kwenye sehemu ya juu ya arifa za mazungumzo na kama picha ya wasifu kwenye skrini iliyofungwa. Huonekana kama kiputo na hukatiza kipengele cha Usinisumbue"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Kipaumbele"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> haitumii vipengele vya mazungumzo"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Arifa hizi haziwezi kubadilishwa."</string>
@@ -566,6 +575,7 @@
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"SMS"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"Muziki"</string>
<string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Kalenda"</string>
+ <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Usinisumbue"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"Njia ya mkato ya vitufe vya sauti"</string>
<string name="battery" msgid="769686279459897127">"Betri"</string>
<string name="headset" msgid="4485892374984466437">"Vifaa vya sauti"</string>
@@ -684,6 +694,10 @@
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"Wi-Fi imezimwa"</string>
<string name="bt_is_off" msgid="7436344904889461591">"Bluetooth imezimwa"</string>
+ <string name="dnd_is_off" msgid="3185706903793094463">"Kipengele cha Usinisumbue kimezimwa"</string>
+ <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"Kipengele cha Usinisumbue kimewashwa na sheria ya kiotomatiki <xliff:g id="ID_1">%s</xliff:g>."</string>
+ <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"Kipengele cha usinisumbue kimewashwa na programu (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"Kipengele cha Usinisumbue kimewashwa na sheria ya kiotomatiki au programu."</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"Programu zinatumika chinichini"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"Gusa ili upate maelezo kuhusu betri na matumizi ya data"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Ungependa kuzima data ya mtandao wa simu?"</string>
@@ -708,6 +722,8 @@
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(kazini)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"Simu"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(kupitia <xliff:g id="APPLICATION_NAME_S_">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_label" msgid="3385241594101496292">"(<xliff:g id="ATTRIBUTION_LABEL">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_proxy_label" msgid="1111829599659403249">"(<xliff:g id="ATTRIBUTION_LABEL">%1$s</xliff:g> • <xliff:g id="PROXY_LABEL">%2$s</xliff:g>)"</string>
<string name="privacy_type_camera" msgid="7974051382167078332">"kamera"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"mahali"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"maikrofoni"</string>
@@ -806,6 +822,9 @@
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(imetenganishwa)"</string>
<string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Imeshindwa kubadilisha. Gusa ili ujaribu tena."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Oanisha kifaa kipya"</string>
+ <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Ili utume kipindi hiki, tafadhali fungua programu."</string>
+ <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Programu isiyojulikana"</string>
+ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Acha kutuma"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Nambari ya muundo"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Nambari ya muundo imewekwa kwenye ubao wa kunakili."</string>
<string name="basic_status" msgid="2315371112182658176">"Fungua mazungumzo"</string>
@@ -839,6 +858,7 @@
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Angalia ujumbe wa hivi majuzi, simu ambazo hukujibu na taarifa za hali"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Mazungumzo"</string>
+ <string name="paused_by_dnd" msgid="7856941866433556428">"Imesimamishwa na kipengele cha Usinisumbue"</string>
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> ametuma ujumbe: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> ametuma picha"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> ana taarifa kuhusu hali: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
@@ -877,8 +897,7 @@
<item quantity="other">Programu <xliff:g id="COUNT_1">%s</xliff:g> zinatumika</item>
<item quantity="one">Programu <xliff:g id="COUNT_0">%s</xliff:g> inatumika</item>
</plurals>
- <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
- <skip />
+ <string name="fgs_dot_content_description" msgid="2865071539464777240">"Maelezo mapya"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Programu zinazotumika"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Simamisha"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Imesimamishwa"</string>
@@ -886,14 +905,15 @@
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Imenakiliwa"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Kutoka <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Ondoa kiolesura cha nakala"</string>
- <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
- <skip />
- <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
- <skip />
- <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
- <skip />
- <!-- no translation found for add (81036585205287996) -->
- <skip />
- <!-- no translation found for manage_users (1823875311934643849) -->
- <skip />
+ <string name="clipboard_edit_text_description" msgid="805254383912962103">"Badilisha maandishi yaliyonakiliwa"</string>
+ <string name="clipboard_edit_image_description" msgid="8904857948976041306">"Badilisha picha iliyonakiliwa"</string>
+ <string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Tuma kwenye kifaa kilicho karibu"</string>
+ <string name="add" msgid="81036585205287996">"Weka"</string>
+ <string name="manage_users" msgid="1823875311934643849">"Dhibiti watumiaji"</string>
+ <string name="drag_split_not_supported" msgid="4326847447699729722">"Arifa hii hairuhusu kuburuta kwenye Skrini iliyogawanyika."</string>
+ <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi-Fi haipatikani"</string>
+ <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Hali ya kipaumbele"</string>
+ <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Kengele imewekwa"</string>
+ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Kamera na maikrofoni zimezimwa"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{Arifa #}other{Arifa #}}"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sw600dp-land/dimens.xml b/packages/SystemUI/res/values-sw600dp-land/dimens.xml
index 4f95811b21b3..740697ba98af 100644
--- a/packages/SystemUI/res/values-sw600dp-land/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp-land/dimens.xml
@@ -22,6 +22,8 @@
<dimen name="ambient_indication_margin_bottom">115dp</dimen>
<dimen name="lock_icon_margin_bottom">60dp</dimen>
+ <dimen name="qs_media_session_height_expanded">172dp</dimen>
+
<!-- margin from keyguard status bar to clock. For split shade it should be
keyguard_split_shade_top_margin - status_bar_header_height_keyguard = 8dp -->
<dimen name="keyguard_clock_top_margin">8dp</dimen>
@@ -34,17 +36,56 @@
<item name="controls_task_view_width_percentage" translatable="false" format="float" type="dimen">0.45</item>
<dimen name="controls_task_view_right_margin">8dp</dimen>
- <!-- Distance that the full shade transition takes in order for qs to fully transition to the
- shade -->
- <dimen name="lockscreen_shade_qs_transition_distance">200dp</dimen>
+ <dimen name="split_shade_header_height">42dp</dimen>
+ <dimen name="status_bar_header_height_keyguard">42dp</dimen>
- <!-- Distance that the full shade transition takes in order for scrim to fully transition to
- the shade (in alpha) -->
- <dimen name="lockscreen_shade_scrim_transition_distance">200dp</dimen>
+ <!-- Distance that the full shade transition takes in order to complete by tapping on a button
+ like "expand". -->
+ <dimen name="lockscreen_shade_transition_by_tap_distance">200dp</dimen>
+
+ <!-- Distance that the full shade transition takes in order to complete. -->
+ <dimen name="lockscreen_shade_full_transition_distance">200dp</dimen>
<!-- Distance that the full shade transition takes in order for media to fully transition to
- the shade -->
+ the shade -->
<dimen name="lockscreen_shade_media_transition_distance">200dp</dimen>
- <dimen name="notification_panel_margin_horizontal">12dp</dimen>
+ <!-- Distance that the full shade transition takes in order for scrim to fully transition to
+ the shade (in alpha) -->
+ <dimen name="lockscreen_shade_scrim_transition_distance">80dp</dimen>
+
+ <!-- The notifications scrim transition should start when the other scrims' transition is at
+ 95%. -->
+ <dimen name="lockscreen_shade_notifications_scrim_transition_delay">76dp</dimen>
+
+ <!-- The notifications scrim transition duration is 66.6% of the duration of the other scrims'
+ transition. -->
+ <dimen name="lockscreen_shade_notifications_scrim_transition_distance">53.28dp</dimen>
+
+ <!-- Distance that the full shade transition takes in order for the keyguard content on
+ NotificationPanelViewController to fully fade (e.g. Clock & Smartspace) -->
+ <dimen name="lockscreen_shade_npvc_keyguard_content_alpha_transition_distance">80dp</dimen>
+
+ <!-- Distance that the full shade transition takes in order for the notification shell to fully
+ expand. -->
+ <dimen name="lockscreen_shade_notif_shelf_transition_distance">@dimen/lockscreen_shade_full_transition_distance</dimen>
+
+ <!-- Distance that the full shade transition takes in order for the Quick Settings to fully
+ fade and expand. -->
+ <dimen name="lockscreen_shade_qs_transition_distance">@dimen/lockscreen_shade_full_transition_distance</dimen>
+
+ <!-- Distance that the full shade transition takes in order for depth of the wallpaper to fully
+ change.
+ On split-shade, there should be no depth effect, so setting the value to 0. -->
+ <dimen name="lockscreen_shade_depth_controller_transition_distance">0dp</dimen>
+
+ <!-- Distance that the full shade transition takes in order for the UDFPS Keyguard View to fully
+ fade. -->
+ <dimen name="lockscreen_shade_udfps_keyguard_transition_distance">@dimen/lockscreen_shade_full_transition_distance</dimen>
+
+ <!-- Used for StatusBar to know that a transition is in progress. At the moment it only checks
+ whether the progress is > 0, therefore this value is not very important. -->
+ <dimen name="lockscreen_shade_status_bar_transition_distance">@dimen/lockscreen_shade_full_transition_distance</dimen>
+
+ <dimen name="notification_panel_margin_horizontal">24dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/values-sw600dp-port/dimens.xml b/packages/SystemUI/res/values-sw600dp-port/dimens.xml
index c9906053b4cb..f5c0509dbf5b 100644
--- a/packages/SystemUI/res/values-sw600dp-port/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp-port/dimens.xml
@@ -15,7 +15,7 @@
~ limitations under the License.
-->
<resources>
- <dimen name="notification_panel_margin_horizontal">60dp</dimen>
+ <dimen name="notification_panel_margin_horizontal">48dp</dimen>
<dimen name="status_view_margin_horizontal">62dp</dimen>
<dimen name="keyguard_clock_top_margin">40dp</dimen>
<dimen name="keyguard_status_view_bottom_margin">40dp</dimen>
diff --git a/packages/SystemUI/res/values-sw720dp-land/dimens.xml b/packages/SystemUI/res/values-sw720dp-land/dimens.xml
index 71c195896051..bdd704936594 100644
--- a/packages/SystemUI/res/values-sw720dp-land/dimens.xml
+++ b/packages/SystemUI/res/values-sw720dp-land/dimens.xml
@@ -23,5 +23,8 @@
<dimen name="keyguard_split_shade_top_margin">72dp</dimen>
- <dimen name="notification_panel_margin_horizontal">24dp</dimen>
+ <dimen name="split_shade_header_height">56dp</dimen>
+ <dimen name="status_bar_header_height_keyguard">56dp</dimen>
+
+ <dimen name="qs_media_session_height_expanded">184dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/values-sw720dp-port/dimens.xml b/packages/SystemUI/res/values-sw720dp-port/dimens.xml
index e5f502f95290..44f8f3aee9ab 100644
--- a/packages/SystemUI/res/values-sw720dp-port/dimens.xml
+++ b/packages/SystemUI/res/values-sw720dp-port/dimens.xml
@@ -21,8 +21,11 @@
for different hardware and product builds. -->
<resources>
<dimen name="status_view_margin_horizontal">124dp</dimen>
- <dimen name="notification_panel_margin_horizontal">120dp</dimen>
<dimen name="keyguard_clock_top_margin">80dp</dimen>
<dimen name="keyguard_status_view_bottom_margin">80dp</dimen>
<dimen name="bouncer_user_switcher_y_trans">90dp</dimen>
+
+ <dimen name="notification_panel_margin_horizontal">96dp</dimen>
+ <dimen name="notification_side_paddings">40dp</dimen>
+ <dimen name="notification_section_divider_height">16dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index 094559fb7a53..cd40c79f15bc 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -20,14 +20,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4811759950673118541">"சாதனத்தின் UI"</string>
- <string name="battery_low_title" msgid="6891106956328275225">"பேட்டரி விரைவில் தீர்ந்துவிடக்கூடும்"</string>
+ <string name="battery_low_title" msgid="5319680173344341779">"பேட்டரி சேமிப்பானை இயக்கவா?"</string>
+ <string name="battery_low_description" msgid="3282977755476423966">"<xliff:g id="PERCENTAGE">%s</xliff:g> பேட்டரி மீதமுள்ளது. பேட்டரி சேமிப்பான் அம்சம் டார்க் தீமை இயக்கும், அத்துடன் பின்னணிச் செயல்பாடுகளைக் கட்டுப்படுத்தி, அறிவிப்புகளைத் தாமதப்படுத்தும்."</string>
+ <string name="battery_low_intro" msgid="5148725009653088790">"பேட்டரி சேமிப்பான் அம்சம் டார்க் தீமை இயக்கும், அத்துடன் பின்னணிச் செயல்பாடுகளைக் கட்டுப்படுத்தி, அறிவிப்புகளைத் தாமதப்படுத்தும்."</string>
<string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> உள்ளது"</string>
<string name="invalid_charger_title" msgid="938685362320735167">"USB மூலம், சார்ஜ் செய்ய முடியாது"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"உங்கள் சாதனத்துடன் வழங்கப்பட்ட சார்ஜரைப் பயன்படுத்தவும்"</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"பேட்டரி சேமிப்பானை ஆன் செய்யவா?"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"பேட்டரி சேமிப்பான்- ஓர் அறிமுகம்"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"இயக்கு"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"பேட்டரி சேமிப்பானை ஆன் செய்"</string>
+ <string name="battery_saver_start_action" msgid="8353766979886287140">"இயக்கு"</string>
+ <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"வேண்டாம்"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"திரையைத் தானாகச் சுழற்று"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"<xliff:g id="USB_DEVICE">%2$s</xliff:g>ஐ அணுக, <xliff:g id="APPLICATION">%1$s</xliff:g> ஆப்ஸை அனுமதிக்கவா?"</string>
<string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"<xliff:g id="USB_DEVICE">%2$s</xliff:g>ஐப் பயன்படுத்த <xliff:g id="APPLICATION">%1$s</xliff:g>ஐ அனுமதிக்கவா?\nஇந்த ஆப்ஸிற்கு ரெக்கார்டு செய்வதற்கான அனுமதி வழங்கப்படவில்லை, எனினும் இந்த USB சாதனம் மூலம் ஆடியோவைப் பதிவுசெய்யும்."</string>
@@ -128,6 +131,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"முகம் அங்கீகரிக்கப்பட்டது"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"உறுதிப்படுத்தப்பட்டது"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"முடிக்க \'உறுதிப்படுத்துக\' என்பதை தட்டவும்"</string>
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"முகத்தை வைத்து அன்லாக் செய்யப்பட்டது. திறக்க அழுத்தவும்."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"அங்கீகரிக்கப்பட்டது"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"பின்னைப் பயன்படுத்து"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"பேட்டர்னைப் பயன்படுத்து"</string>
@@ -181,6 +185,7 @@
<string name="accessibility_desc_close" msgid="8293708213442107755">"மூடு"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"முழு அமைதி"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"அலாரங்கள் மட்டும்"</string>
+ <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"தொந்தரவு செய்ய வேண்டாம்."</string>
<string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"புளூடூத்."</string>
<string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"புளூடூத் இயக்கத்தில்."</string>
<string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"<xliff:g id="TIME">%s</xliff:g> மணிக்கு அலாரம் அமைக்கப்பட்டது."</string>
@@ -205,6 +210,7 @@
<string name="dessert_case" msgid="9104973640704357717">"இனிப்பு வடிவங்கள்"</string>
<string name="start_dreams" msgid="9131802557946276718">"ஸ்கிரீன் சேவர்"</string>
<string name="ethernet_label" msgid="2203544727007463351">"ஈதர்நெட்"</string>
+ <string name="quick_settings_dnd_label" msgid="7728690179108024338">"தொந்தரவு செய்ய வேண்டாம்"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"புளூடூத்"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"இணைக்கப்பட்ட சாதனங்கள் இல்லை"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> பேட்டரி"</string>
@@ -348,6 +354,7 @@
<string name="notification_section_header_alerting" msgid="5581175033680477651">"அறிவிப்புகள்"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"உரையாடல்கள்"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"சைலன்ட் அறிவிப்புகள் அனைத்தையும் அழிக்கும்"</string>
+ <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"\'தொந்தரவு செய்ய வேண்டாம்\' அம்சத்தின் மூலம் அறிவிப்புகள் இடைநிறுத்தப்பட்டுள்ளன"</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"இப்போது தொடங்கு"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"அறிவிப்புகள் இல்லை"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"இந்தச் சாதனம் உங்கள் பெற்றோரால் நிர்வகிக்கப்படுகிறது"</string>
@@ -401,10 +408,10 @@
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"முடக்கும்"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"ஆப்ஸ் பின் செய்யப்பட்டது"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"பொருத்தியதை அகற்றும் வரை இதைக் காட்சியில் வைக்கும். அகற்ற, முந்தையது மற்றும் மேலோட்டப் பார்வையைத் தொட்டுப் பிடிக்கவும்."</string>
- <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"இதற்கான பின்னை அகற்றும் வரை, இந்தப் பயன்முறை செயல்பாட்டிலேயே இருக்கும். அகற்றுவதற்கு, முந்தையது மற்றும் முகப்புப் பொத்தான்களைத் தொட்டுப் பிடிக்கவும்."</string>
+ <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"இதற்கான பின்னை அகற்றும் வரை, இந்தப் பயன்முறை செயல்பாட்டிலேயே இருக்கும். அகற்றுவதற்கு, முந்தையது மற்றும் முகப்பு பட்டன்களைத் தொட்டுப் பிடிக்கவும்."</string>
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"பின் செய்திருப்பதை அகற்றும் வரை இதைச் செயல்பாட்டில் வைத்திருக்கும். அதை அகற்றுவதற்கு மேல்நோக்கி ஸ்வைப் செய்து பிடித்திருக்கவும்."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"பொருத்தியதை அகற்றும் வரை இதைக் காட்சியில் வைக்கும். அகற்ற, மேலோட்டப் பார்வையைத் தொட்டுப் பிடிக்கவும்."</string>
- <string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"இதற்கான பின்னை அகற்றும் வரை, இந்தப் பயன்முறை செயல்பாட்டிலேயே இருக்கும். அகற்றுவதற்கு, முகப்புப் பொத்தானைத் தொட்டுப் பிடிக்கவும்."</string>
+ <string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"இதற்கான பின்னை அகற்றும் வரை, இந்தப் பயன்முறை செயல்பாட்டிலேயே இருக்கும். அகற்றுவதற்கு, முகப்புப் பட்டனைத் தொட்டுப் பிடிக்கவும்."</string>
<string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"தனிப்பட்ட தரவு அணுகப்படக்கூடும் (தொடர்புகள், மின்னஞ்சலின் உள்ளடக்கம் போன்றவை)."</string>
<string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"பின் செய்யப்பட்டிருக்கும் ஆப்ஸ் பிற ஆப்ஸைத் திறக்கக்கூடும்."</string>
<string name="screen_pinning_toast" msgid="8177286912533744328">"இந்த ஆப்ஸைப் பின்னிலிருந்து அகற்ற, \'பின்செல்\' மற்றும் \'மேலோட்டப் பார்வை\' பட்டன்களைத் தொட்டுப் பிடித்திருக்கவும்"</string>
@@ -452,8 +459,7 @@
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"பயன்படுத்துவதற்கு அன்லாக் செய்க"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"உங்கள் கார்டுகளின் விவரங்களைப் பெறுவதில் சிக்கல் ஏற்பட்டது, பிறகு முயலவும்"</string>
<string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"பூட்டுத் திரை அமைப்புகள்"</string>
- <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR குறியீடு"</string>
- <string name="qr_code_scanner_description" msgid="7937603775306661863">"ஸ்கேன் செய்யத் தட்டவும்"</string>
+ <string name="qr_code_scanner_title" msgid="5290201053875420785">"QR குறியீட்டை ஸ்கேன் செய்தல்"</string>
<string name="status_bar_work" msgid="5238641949837091056">"பணிக் கணக்கு"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"விமானப் பயன்முறை"</string>
<string name="zen_alarm_warning" msgid="7844303238486849503">"அடுத்த அலாரத்தை <xliff:g id="WHEN">%1$s</xliff:g> மணிக்கு கேட்க மாட்டீர்கள்"</string>
@@ -491,6 +497,8 @@
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"&lt;b&gt;நிலை:&lt;/b&gt; முக்கியத்துவம் குறைக்கப்பட்டது"</string>
<string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"உரையாடல் அறிவிப்புகளின் மேற்பகுதியில் காட்டப்படும், திரை பூட்டப்பட்டிருக்கும்போது சுயவிவரப் படமாகக் காட்டப்படும்"</string>
<string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"உரையாடல் அறிவிப்புகளின் மேற்பகுதியில் காட்டப்படும், திரை பூட்டப்பட்டிருக்கும்போது சுயவிவரப் படமாகக் காட்டப்படும், குமிழாகத் தோன்றும்"</string>
+ <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"உரையாடல் அறிவிப்புகளின் மேற்பகுதியில் காட்டப்படும், திரை பூட்டப்பட்டிருக்கும்போது சுயவிவரப் படமாகக் காட்டப்படும், தொந்தரவு செய்ய வேண்டாம் அம்சம் இயக்கப்பட்டிருக்கும்போதும் காட்டப்படும்"</string>
+ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"உரையாடல் அறிவிப்புகளின் மேற்பகுதியில் காட்டப்படும், திரை பூட்டப்பட்டிருக்கும்போது சுயவிவரப் படமாகக் காட்டப்படும், குமிழாகத் தோன்றும், தொந்தரவு செய்ய வேண்டாம் அம்சம் இயக்கப்பட்டிருக்கும்போதும் காட்டப்படும்"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"முன்னுரிமை"</string>
<string name="no_shortcut" msgid="8257177117568230126">"உரையாடல் அம்சங்களை <xliff:g id="APP_NAME">%1$s</xliff:g> ஆதரிக்காது"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"இந்த அறிவிப்புகளை மாற்ற இயலாது."</string>
@@ -566,6 +574,7 @@
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"SMS"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"மியூசிக்"</string>
<string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Calendar"</string>
+ <string name="volume_and_do_not_disturb" msgid="502044092739382832">"தொந்தரவு செய்ய வேண்டாம்"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"ஒலியளவுப் பொத்தான்களுக்கான ஷார்ட்கட்"</string>
<string name="battery" msgid="769686279459897127">"பேட்டரி"</string>
<string name="headset" msgid="4485892374984466437">"ஹெட்செட்"</string>
@@ -684,6 +693,10 @@
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"வைஃபை முடக்கத்தில் உள்ளது"</string>
<string name="bt_is_off" msgid="7436344904889461591">"புளூடூத் முடக்கத்தில் உள்ளது"</string>
+ <string name="dnd_is_off" msgid="3185706903793094463">"\"தொந்தரவு செய்ய வேண்டாம்\" முடக்கத்தில் உள்ளது"</string>
+ <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"\"தொந்தரவு செய்ய வேண்டாம்\" எனும் பயன்முறையை, தானியங்கு விதி (<xliff:g id="ID_1">%s</xliff:g>) இயக்கியுள்ளது."</string>
+ <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"\"தொந்தரவு செய்ய வேண்டாம்\" எனும் பயன்முறையை, ஆப்ஸ் (<xliff:g id="ID_1">%s</xliff:g>) இயக்கியுள்ளது."</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"\"தொந்தரவு செய்ய வேண்டாம்\" எனும் பயன்முறையை, தானியங்கு விதி அல்லது ஆப்ஸ் இயக்கியுள்ளது."</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"பின்னணியில் இயங்கும் ஆப்ஸ்"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"பேட்டரி மற்றும் டேட்டா உபயோக விவரங்களைக் காண, தட்டவும்"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"மொபைல் டேட்டாவை ஆஃப் செய்யவா?"</string>
@@ -708,6 +721,8 @@
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(பணி)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"மொபைல் அழைப்பு"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(<xliff:g id="APPLICATION_NAME_S_">%s</xliff:g> மூலம்)"</string>
+ <string name="ongoing_privacy_dialog_attribution_label" msgid="3385241594101496292">"(<xliff:g id="ATTRIBUTION_LABEL">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_proxy_label" msgid="1111829599659403249">"(<xliff:g id="ATTRIBUTION_LABEL">%1$s</xliff:g> • <xliff:g id="PROXY_LABEL">%2$s</xliff:g>)"</string>
<string name="privacy_type_camera" msgid="7974051382167078332">"கேமரா"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"இருப்பிடம்"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"மைக்ரோஃபோன்"</string>
@@ -806,6 +821,9 @@
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(துண்டிக்கப்பட்டது)"</string>
<string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"இணைக்க முடியவில்லை. மீண்டும் முயல தட்டவும்."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"புதிய சாதனத்தை இணைத்தல்"</string>
+ <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"இந்த அமர்வை அலைபரப்ப ஆப்ஸைத் திறங்கள்."</string>
+ <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"அறியப்படாத ஆப்ஸ்"</string>
+ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"அலைபரப்புவதை நிறுத்து"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"பதிப்பு எண்"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"பதிப்பு எண் கிளிப்போர்டுக்கு நகலெடுக்கப்பட்டது."</string>
<string name="basic_status" msgid="2315371112182658176">"திறந்தநிலை உரையாடல்"</string>
@@ -839,6 +857,7 @@
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"சமீபத்திய மெசேஜ்களையும் தவறிய அழைப்புகளையும் ஸ்டேட்டஸ் அப்டேட்களையும் பார்க்கலாம்"</string>
<string name="people_tile_title" msgid="6589377493334871272">"உரையாடல்"</string>
+ <string name="paused_by_dnd" msgid="7856941866433556428">"தொந்தரவு செய்ய வேண்டாம் அம்சத்தால் இடைநிறுத்தப்பட்டது"</string>
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> ஒரு மெசேஜ் அனுப்பியுள்ளார்: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> ஒரு படம் அனுப்பியுள்ளார்"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> புதிய ஸ்டேட்டஸ் வைத்துள்ளார்: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
@@ -877,8 +896,7 @@
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> ஆப்ஸ் செயலில் உள்ளன</item>
<item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> ஆப்ஸ் செயலில் உள்ளது</item>
</plurals>
- <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
- <skip />
+ <string name="fgs_dot_content_description" msgid="2865071539464777240">"புதிய தகவல்கள்"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"செயலிலுள்ள ஆப்ஸ்"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"நிறுத்து"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"இயங்கவில்லை"</string>
@@ -889,8 +907,12 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"நகலெடுத்த வார்த்தைகளைத் திருத்து"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"நகலெடுத்த படத்தைத் திருத்து"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"அருகிலுள்ள சாதனத்திற்கு அனுப்பு"</string>
- <!-- no translation found for add (81036585205287996) -->
- <skip />
- <!-- no translation found for manage_users (1823875311934643849) -->
- <skip />
+ <string name="add" msgid="81036585205287996">"சேர்"</string>
+ <string name="manage_users" msgid="1823875311934643849">"பயனர்களை நிர்வகித்தல்"</string>
+ <string name="drag_split_not_supported" msgid="4326847447699729722">"பிரிக்கப்பட்ட திரைக்குள் இந்த அறிவிப்பை இழுத்துவிட முடியாது."</string>
+ <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"வைஃபை கிடைக்கவில்லை"</string>
+ <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"முன்னுரிமைப் பயன்முறை"</string>
+ <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"அலாரம் அமைக்கப்பட்டுள்ளது"</string>
+ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"கேமராவும் மைக்கும் ஆஃப் செய்யப்பட்டுள்ளன"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# அறிவிப்பு}other{# அறிவிப்புகள்}}"</string>
</resources>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index 59e8ef4a6e87..222da19a7254 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -20,14 +20,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4811759950673118541">"సిస్టమ్ UI"</string>
- <string name="battery_low_title" msgid="6891106956328275225">"బ్యాటరీ త్వరలో ఖాళీ అవ్వచ్చు"</string>
+ <string name="battery_low_title" msgid="5319680173344341779">"బ్యాటరీ సేవర్‌ను ఆన్ చేయాలా?"</string>
+ <string name="battery_low_description" msgid="3282977755476423966">"మీకు <xliff:g id="PERCENTAGE">%s</xliff:g> బ్యాటరీ మిగిలి ఉంది. బ్యాటరీ సేవర్ ముదురు రంగు రూపాన్ని ఆన్ చేస్తుంది, బ్యాక్‌గ్రౌండ్ యాక్టివిటీని పరిమితం చేస్తుంది, అలాగే నోటిఫికేషన్‌లను ఆలస్యంగా పంపిస్తుంది."</string>
+ <string name="battery_low_intro" msgid="5148725009653088790">"బ్యాటరీ సేవర్ ముదురు రంగు రూపాన్ని ఆన్ చేస్తుంది, బ్యాక్‌గ్రౌండ్ యాక్టివిటీని పరిమితం చేస్తుంది, అలాగే నోటిఫికేషన్‌లను ఆలస్యంగా పంపిస్తుంది."</string>
<string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> మిగిలి ఉంది"</string>
<string name="invalid_charger_title" msgid="938685362320735167">"USB ద్వారా ఛార్జ్ చేయలేరు"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"మీ పరికరంతో వచ్చిన ఛార్జర్‌ను ఉపయోగించండి"</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"బ్యాటరీ సేవర్‌ను ఆన్ చేయాలా?"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"బ్యాటరీ సేవర్ గురించి"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"ఆన్ చేయి"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"బ్యాటరీ సేవర్‌ను ఆన్ చేయండి"</string>
+ <string name="battery_saver_start_action" msgid="8353766979886287140">"ఆన్ చేయండి"</string>
+ <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"వద్దు, ధన్యవాదాలు"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"స్క్రీన్ ఆటో-రొటేట్‌"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"<xliff:g id="USB_DEVICE">%2$s</xliff:g>ని యాక్సెస్ చేయడానికి <xliff:g id="APPLICATION">%1$s</xliff:g>ని అనుమతించాలా?"</string>
<string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"<xliff:g id="USB_DEVICE">%2$s</xliff:g>యాక్సెస్ చేయడానికి <xliff:g id="APPLICATION">%1$s</xliff:g>ను అనుమతించాలా?\nఈ యాప్‌నకు రికార్డ్ చేసే అనుమతి మంజూరు చేయబడలేదు, కానీ ఈ USB పరికరం ద్వారా ఆడియోను క్యాప్చర్ చేయగలదు."</string>
@@ -128,6 +131,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"ముఖం ప్రామాణీకరించబడింది"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"నిర్ధారించబడింది"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"పూర్తి చేయడానికి \"నిర్ధారించు\" నొక్కండి"</string>
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"మీ ముఖం ద్వారా అన్‌లాక్ చేయబడింది. కొనసాగించడానికి నొక్కండి."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"ప్రామాణీకరించబడింది"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"పిన్‌ను ఉపయోగించు"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"ఆకృతిని ఉపయోగించు"</string>
@@ -181,6 +185,7 @@
<string name="accessibility_desc_close" msgid="8293708213442107755">"మూసివేస్తుంది"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"మొత్తం నిశ్శబ్దం"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"అలారాలు మాత్రమే"</string>
+ <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"అంతరాయం కలిగించవద్దు."</string>
<string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"బ్లూటూత్."</string>
<string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"బ్లూటూత్ ఆన్‌లో ఉంది."</string>
<string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"<xliff:g id="TIME">%s</xliff:g>కి అలారం సెట్ చేయబడింది."</string>
@@ -205,6 +210,7 @@
<string name="dessert_case" msgid="9104973640704357717">"డెజర్ట్ కేస్"</string>
<string name="start_dreams" msgid="9131802557946276718">"స్క్రీన్ సేవర్"</string>
<string name="ethernet_label" msgid="2203544727007463351">"ఈథర్‌నెట్"</string>
+ <string name="quick_settings_dnd_label" msgid="7728690179108024338">"అంతరాయం కలిగించవద్దు"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"బ్లూటూత్"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"జత చేసిన పరికరాలు ఏవీ అందుబాటులో లేవు"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> బ్యాటరీ"</string>
@@ -289,7 +295,7 @@
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"స్థూలదృష్టిని టోగుల్ చేయి"</string>
<string name="zen_priority_introduction" msgid="3159291973383796646">"మీరు పేర్కొనే అలారాలు, రిమైండర్‌లు, ఈవెంట్‌లు మరియు కాలర్‌ల నుండి మినహా మరే ఇతర ధ్వనులు మరియు వైబ్రేషన్‌లతో మీకు అంతరాయం కలగదు. మీరు ఇప్పటికీ సంగీతం, వీడియోలు మరియు గేమ్‌లతో సహా మీరు ప్లే చేయడానికి ఎంచుకున్నవి ఏవైనా వింటారు."</string>
<string name="zen_alarms_introduction" msgid="3987266042682300470">"అలారాలు నుండి మినహా మరే ఇతర ధ్వనులు మరియు వైబ్రేషన్‌లతో మీకు అంతరాయం కలగదు. మీరు ఇప్పటికీ సంగీతం, వీడియోలు మరియు గేమ్‌లతో సహా మీరు ప్లే చేయడానికి ఎంచుకున్నవి ఏవైనా వింటారు."</string>
- <string name="zen_priority_customize_button" msgid="4119213187257195047">"అనుకూలీకరించు"</string>
+ <string name="zen_priority_customize_button" msgid="4119213187257195047">"అనుకూలంగా మార్చండి"</string>
<string name="zen_silence_introduction_voice" msgid="853573681302712348">"ఇది అలారాలు, సంగీతం, వీడియోలు మరియు గేమ్‌లతో సహా అన్ని ధ్వనులు మరియు వైబ్రేషన్‌లను బ్లాక్ చేస్తుంది. మీరు ఇప్పటికీ ఫోన్ కాల్స్‌ చేయగలుగుతారు."</string>
<string name="zen_silence_introduction" msgid="6117517737057344014">"ఇది అలారాలు, సంగీతం, వీడియోలు మరియు గేమ్‌లతో సహా అన్ని ధ్వనులు మరియు వైబ్రేషన్‌లను బ్లాక్ చేస్తుంది."</string>
<string name="notification_tap_again" msgid="4477318164947497249">"తెరవడానికి మళ్లీ నొక్కండి"</string>
@@ -348,6 +354,7 @@
<string name="notification_section_header_alerting" msgid="5581175033680477651">"నోటిఫికేషన్‌లు"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"సంభాషణలు"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"అన్ని నిశ్శబ్ద నోటిఫికేషన్‌లను క్లియర్ చేస్తుంది"</string>
+ <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"అంతరాయం కలిగించవద్దు ద్వారా నోటిఫికేషన్‌లు పాజ్ చేయబడ్డాయి"</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"ఇప్పుడే ప్రారంభించు"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"నోటిఫికేషన్‌లు లేవు"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"ఈ పరికరాన్ని మీ తల్లి/తండ్రి మేనేజ్ చేస్తున్నారు"</string>
@@ -452,8 +459,8 @@
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"ఉపయోగించడానికి అన్‌లాక్ చేయండి"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"మీ కార్డ్‌లను పొందడంలో సమస్య ఉంది, దయచేసి తర్వాత మళ్లీ ట్రై చేయండి"</string>
<string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"లాక్ స్క్రీన్ సెట్టింగ్‌లు"</string>
- <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR కోడ్"</string>
- <string name="qr_code_scanner_description" msgid="7937603775306661863">"స్కాన్ చేయడానికి ట్యాప్ చేయండి"</string>
+ <!-- no translation found for qr_code_scanner_title (5290201053875420785) -->
+ <skip />
<string name="status_bar_work" msgid="5238641949837091056">"ఆఫీస్ ప్రొఫైల్‌"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"ఎయిర్‌ప్లేన్ మోడ్"</string>
<string name="zen_alarm_warning" msgid="7844303238486849503">"మీరు <xliff:g id="WHEN">%1$s</xliff:g> సెట్ చేసిన మీ తర్వాత అలారం మీకు వినిపించదు"</string>
@@ -491,6 +498,8 @@
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"&lt;b&gt;స్టేటస్:&lt;/b&gt; తక్కువ ర్యాంక్‌కు సర్దుబాటు చేయబడింది"</string>
<string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"సంభాషణ నోటిఫికేషన్‌ల ఎగువున, లాక్ స్క్రీన్‌లో ప్రొఫైల్ ఫోటో‌గా చూపిస్తుంది"</string>
<string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"సంభాషణ నోటిఫికేషన్‌ల ఎగువున, లాక్ స్క్రీన్‌లో ప్రొఫైల్ ఫోటో‌గా చూపిస్తుంది, బబుల్‌గా కనిపిస్తుంది"</string>
+ <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"సంభాషణ నోటిఫికేషన్‌ల ఎగువున, లాక్ స్క్రీన్‌లో ప్రొఫైల్ ఫోటో‌గా చూపిస్తుంది, \'అంతరాయం కలిగించవద్దు\'ను అంతరాయం కలిగిస్తుంది"</string>
+ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"సంభాషణ నోటిఫికేషన్‌ల ఎగువున, లాక్ స్క్రీన్‌లో ప్రొఫైల్ ఫోటో‌గా చూపిస్తుంది, బబుల్‌గా కనిపిస్తుంది, \'అంతరాయం కలిగించవద్దు\'ను అంతరాయం కలిగిస్తుంది"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"ప్రాధాన్యత"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> సంభాషణ ఫీచర్‌లను సపోర్ట్ చేయదు"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"ఈ నోటిఫికేషన్‌లను సవరించడం వీలుపడదు."</string>
@@ -566,6 +575,7 @@
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"SMS"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"మ్యూజిక్"</string>
<string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Calendar"</string>
+ <string name="volume_and_do_not_disturb" msgid="502044092739382832">"అంతరాయం కలిగించవద్దు"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"వాల్యూమ్ బటన్‌ల షార్ట్‌కట్"</string>
<string name="battery" msgid="769686279459897127">"బ్యాటరీ"</string>
<string name="headset" msgid="4485892374984466437">"హెడ్‌సెట్"</string>
@@ -684,6 +694,10 @@
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"Wi-Fi ఆఫ్‌లో ఉంది"</string>
<string name="bt_is_off" msgid="7436344904889461591">"బ్లూటూత్ ఆఫ్‌లో ఉంది"</string>
+ <string name="dnd_is_off" msgid="3185706903793094463">"అంతరాయం కలిగించవద్దు ఆఫ్‌లో ఉంది"</string>
+ <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"ఆటోమేటిక్‌ నియమం (<xliff:g id="ID_1">%s</xliff:g>) ద్వారా అంతరాయం కలిగించవద్దు ఆన్ చేయబడింది."</string>
+ <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"యాప్ (<xliff:g id="ID_1">%s</xliff:g>) ద్వారా అంతరాయం కలిగించవద్దు ఆన్ చేయబడింది."</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"ఆటోమేటిక్‌ నియమం లేదా యాప్ ద్వారా అంతరాయం కలిగించవద్దు ఆన్ చేయబడింది."</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"నేపథ్యంలో అమలు అవుతున్న ఆప్‌లు"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"బ్యాటరీ మరియు డేటా వినియోగ వివరాల కోసం నొక్కండి"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"మొబైల్ డేటాను ఆఫ్ చేయాలా?"</string>
@@ -708,6 +722,8 @@
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(ఆఫీస్)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"ఫోన్ కాల్"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(<xliff:g id="APPLICATION_NAME_S_">%s</xliff:g> ద్వారా)"</string>
+ <string name="ongoing_privacy_dialog_attribution_label" msgid="3385241594101496292">"(<xliff:g id="ATTRIBUTION_LABEL">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_proxy_label" msgid="1111829599659403249">"(<xliff:g id="ATTRIBUTION_LABEL">%1$s</xliff:g> • <xliff:g id="PROXY_LABEL">%2$s</xliff:g>)"</string>
<string name="privacy_type_camera" msgid="7974051382167078332">"కెమెరా"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"లొకేషన్"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"మైక్రోఫోన్"</string>
@@ -806,6 +822,9 @@
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(డిస్కనెక్ట్ అయ్యింది)"</string>
<string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"స్విచ్ చేయడం సాధ్యం కాదు. మళ్ళీ ట్రై చేయడానికి ట్యాప్ చేయండి."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"కొత్త పరికరాన్ని పెయిర్ చేయండి"</string>
+ <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"ఈ సెషన్‌ను ప్రసారం చేయడానికి, దయచేసి యాప్‌ను తెరవండి."</string>
+ <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"తెలియని యాప్"</string>
+ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"ప్రసారాన్ని ఆపివేయండి"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"బిల్డ్ నంబర్"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"బిల్డ్ నంబర్, క్లిప్‌బోర్డ్‌కు కాపీ చేయబడింది."</string>
<string name="basic_status" msgid="2315371112182658176">"సంభాషణను తెరవండి"</string>
@@ -839,6 +858,7 @@
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"ఇటీవలి మెసేజ్‌లు, మిస్స్‌డ్‌ కాల్స్‌, అలాగే స్టేటస్ అప్‌డేట్‌లను చూడండి"</string>
<string name="people_tile_title" msgid="6589377493334871272">"సంభాషణ"</string>
+ <string name="paused_by_dnd" msgid="7856941866433556428">"అంతరాయం కలిగించవద్దు ద్వారా పాజ్ చేయబడింది"</string>
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> మెసేజ్‌ను పంపారు: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> ఇమేజ్‌ను పంపారు"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g>, స్టేటస్‌ను గురించిన అప్‌డేట్‌ను కలిగి ఉన్నారు: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
@@ -877,8 +897,7 @@
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> యాక్టివ్‌గా ఉన్న యాప్‌లు</item>
<item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> యాక్టివ్‌గా ఉన్న యాప్</item>
</plurals>
- <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
- <skip />
+ <string name="fgs_dot_content_description" msgid="2865071539464777240">"కొత్త సమాచారం"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"యాక్టివ్‌గా ఉన్న యాప్‌లు"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"ఆపివేయండి"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"ఆపివేయబడింది"</string>
@@ -889,8 +908,12 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"కాపీ చేసిన టెక్స్ట్‌ను ఎడిట్ చేయండి"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"కాపీ చేసిన ఇమేజ్‌లను ఎడిట్ చేయండి"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"సమీపంలోని పరికరానికి పంపండి"</string>
- <!-- no translation found for add (81036585205287996) -->
- <skip />
- <!-- no translation found for manage_users (1823875311934643849) -->
- <skip />
+ <string name="add" msgid="81036585205287996">"జోడించండి"</string>
+ <string name="manage_users" msgid="1823875311934643849">"యూజర్‌లను మేనేజ్ చేయండి"</string>
+ <string name="drag_split_not_supported" msgid="4326847447699729722">"ఈ నోటిఫికేషన్ స్ప్లిట్‌స్క్రీన్‌కు లాగడానికి సపోర్ట్ చేయదు."</string>
+ <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi అందుబాటులో లేదు"</string>
+ <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"ముఖ్యమైన ఫైల్స్ మోడ్"</string>
+ <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"అలారం సెట్ చేశాను"</string>
+ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"కెమెరా, మైక్ ఆఫ్‌లో ఉన్నాయి"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# నోటిఫికేషన్}other{# నోటిఫికేషన్‌లు}}"</string>
</resources>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index a20744794360..120d87077454 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -20,14 +20,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4811759950673118541">"อินเทอร์เฟซผู้ใช้ของระบบ"</string>
- <string name="battery_low_title" msgid="6891106956328275225">"แบตเตอรี่อาจหมดเร็วๆ นี้"</string>
+ <string name="battery_low_title" msgid="5319680173344341779">"เปิดโหมดประหยัดแบตเตอรี่ใช่ไหม"</string>
+ <string name="battery_low_description" msgid="3282977755476423966">"คุณมีแบตเตอรี่เหลืออยู่ <xliff:g id="PERCENTAGE">%s</xliff:g> โหมดประหยัดแบตเตอรี่จะเปิดธีมมืด จำกัดกิจกรรมในเบื้องหลัง และหน่วงเวลาการแจ้งเตือน"</string>
+ <string name="battery_low_intro" msgid="5148725009653088790">"โหมดประหยัดแบตเตอรี่จะเปิดธีมมืด จำกัดกิจกรรมในเบื้องหลัง และหน่วงเวลาการแจ้งเตือน"</string>
<string name="battery_low_percent_format" msgid="4276661262843170964">"เหลืออีก <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="invalid_charger_title" msgid="938685362320735167">"ชาร์จผ่าน USB ไม่ได้"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"ใช้ที่ชาร์จที่ให้มาพร้อมกับอุปกรณ์"</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"เปิดโหมดประหยัดแบตเตอรี่ใช่ไหม"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"เกี่ยวกับโหมดประหยัดแบตเตอรี่"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"เปิด"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"เปิดโหมดประหยัดแบตเตอรี่"</string>
+ <string name="battery_saver_start_action" msgid="8353766979886287140">"เปิด"</string>
+ <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"ไม่เป็นไร"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"หมุนหน้าจออัตโนมัติ"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"อนุญาตให้ <xliff:g id="APPLICATION">%1$s</xliff:g> เข้าถึง <xliff:g id="USB_DEVICE">%2$s</xliff:g> ไหม"</string>
<string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"อนุญาตให้ <xliff:g id="APPLICATION">%1$s</xliff:g> เข้าถึง <xliff:g id="USB_DEVICE">%2$s</xliff:g> ไหม\nแอปนี้ไม่ได้รับอนุญาตให้อัดเสียงแต่จะอัดเสียงผ่านอุปกรณ์ USB นี้ได้"</string>
@@ -128,6 +131,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"ตรวจสอบสิทธิ์ใบหน้าแล้ว"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"ยืนยันแล้ว"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"แตะยืนยันเพื่อดำเนินการให้เสร็จสมบูรณ์"</string>
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"ปลดล็อกโดยใช้ใบหน้าแล้ว กดเพื่อดำเนินการต่อ"</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"ตรวจสอบสิทธิ์แล้ว"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"ใช้ PIN"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"ใช้รูปแบบ"</string>
@@ -181,6 +185,7 @@
<string name="accessibility_desc_close" msgid="8293708213442107755">"ปิด"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"ปิดเสียงทั้งหมด"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"เฉพาะปลุกเท่านั้น"</string>
+ <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"ห้ามรบกวน"</string>
<string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"บลูทูธ"</string>
<string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"บลูทูธเปิดอยู่"</string>
<string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"ตั้งเวลาปลุกไว้ที่ <xliff:g id="TIME">%s</xliff:g>"</string>
@@ -205,6 +210,7 @@
<string name="dessert_case" msgid="9104973640704357717">"ชั้นแสดงของหวาน"</string>
<string name="start_dreams" msgid="9131802557946276718">"โปรแกรมรักษาหน้าจอ"</string>
<string name="ethernet_label" msgid="2203544727007463351">"อีเทอร์เน็ต"</string>
+ <string name="quick_settings_dnd_label" msgid="7728690179108024338">"ห้ามรบกวน"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"บลูทูธ"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"ไม่มีอุปกรณ์ที่จับคู่ที่สามารถใช้ได้"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"แบตเตอรี่ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
@@ -348,6 +354,7 @@
<string name="notification_section_header_alerting" msgid="5581175033680477651">"การแจ้งเตือน"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"การสนทนา"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"ล้างการแจ้งเตือนแบบไม่มีเสียงทั้งหมด"</string>
+ <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"หยุดการแจ้งเตือนชั่วคราวโดย \"ห้ามรบกวน\""</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"เริ่มเลย"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"ไม่มีการแจ้งเตือน"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"อุปกรณ์นี้จัดการโดยผู้ปกครอง"</string>
@@ -452,8 +459,8 @@
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"ปลดล็อกเพื่อใช้"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"เกิดปัญหาในการดึงข้อมูลบัตรของคุณ โปรดลองอีกครั้งในภายหลัง"</string>
<string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"การตั้งค่าหน้าจอล็อก"</string>
- <string name="qr_code_scanner_title" msgid="5660820608548306581">"คิวอาร์โค้ด"</string>
- <string name="qr_code_scanner_description" msgid="7937603775306661863">"แตะเพื่อสแกน"</string>
+ <!-- no translation found for qr_code_scanner_title (5290201053875420785) -->
+ <skip />
<string name="status_bar_work" msgid="5238641949837091056">"โปรไฟล์งาน"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"โหมดบนเครื่องบิน"</string>
<string name="zen_alarm_warning" msgid="7844303238486849503">"คุณจะไม่ได้ยินเสียงปลุกครั้งถัดไปในเวลา <xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -491,6 +498,8 @@
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"&lt;b&gt;สถานะ:&lt;/b&gt; อันดับต่ำลง"</string>
<string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"แสดงที่ด้านบนของการแจ้งเตือนการสนทนาและเป็นรูปโปรไฟล์บนหน้าจอล็อก"</string>
<string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"แสดงที่ด้านบนของการแจ้งเตือนการสนทนาและเป็นรูปโปรไฟล์บนหน้าจอล็อก ปรากฏเป็นบับเบิล"</string>
+ <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"แสดงที่ด้านบนของการแจ้งเตือนการสนทนาและเป็นรูปโปรไฟล์บนหน้าจอล็อก แสดงในโหมดห้ามรบกวน"</string>
+ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"แสดงที่ด้านบนของการแจ้งเตือนการสนทนาและเป็นรูปโปรไฟล์บนหน้าจอล็อก ปรากฏเป็นบับเบิล แสดงในโหมดห้ามรบกวน"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"สำคัญ"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> ไม่รองรับฟีเจอร์การสนทนา"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"แก้ไขการแจ้งเตือนเหล่านี้ไม่ได้"</string>
@@ -566,6 +575,7 @@
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"SMS"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"เพลง"</string>
<string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"ปฏิทิน"</string>
+ <string name="volume_and_do_not_disturb" msgid="502044092739382832">"ห้ามรบกวน"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"ทางลัดปุ่มปรับระดับเสียง"</string>
<string name="battery" msgid="769686279459897127">"แบตเตอรี่"</string>
<string name="headset" msgid="4485892374984466437">"ชุดหูฟัง"</string>
@@ -684,6 +694,10 @@
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g> <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"Wi-Fi ปิดอยู่"</string>
<string name="bt_is_off" msgid="7436344904889461591">"บลูทูธปิดอยู่"</string>
+ <string name="dnd_is_off" msgid="3185706903793094463">"\"ห้ามรบกวน\" ปิดอยู่"</string>
+ <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"มีการเปิด \"ห้ามรบกวน\" โดยกฎอัตโนมัติ (<xliff:g id="ID_1">%s</xliff:g>)"</string>
+ <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"มีการเปิด \"ห้ามรบกวน\" โดยแอป (<xliff:g id="ID_1">%s</xliff:g>)"</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"มีการเปิด \"ห้ามรบกวน\" โดยกฎอัตโนมัติหรือแอป"</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"แอปที่กำลังทำงานในเบื้องหลัง"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"แตะเพื่อดูรายละเอียดเกี่ยวกับแบตเตอรี่และปริมาณการใช้อินเทอร์เน็ต"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"ปิดอินเทอร์เน็ตมือถือไหม"</string>
@@ -708,6 +722,8 @@
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(ที่ทำงาน)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"การโทร"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(ผ่านทาง <xliff:g id="APPLICATION_NAME_S_">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_label" msgid="3385241594101496292">"(<xliff:g id="ATTRIBUTION_LABEL">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_proxy_label" msgid="1111829599659403249">"(<xliff:g id="ATTRIBUTION_LABEL">%1$s</xliff:g> • <xliff:g id="PROXY_LABEL">%2$s</xliff:g>)"</string>
<string name="privacy_type_camera" msgid="7974051382167078332">"กล้องถ่ายรูป"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"ตำแหน่ง"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"ไมโครโฟน"</string>
@@ -806,6 +822,9 @@
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(ยกเลิกการเชื่อมต่อแล้ว)"</string>
<string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"เปลี่ยนไม่ได้ แตะเพื่อลองอีกครั้ง"</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"จับคู่อุปกรณ์ใหม่"</string>
+ <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"โปรดเปิดแอปหากต้องการแคสต์เซสชันนี้"</string>
+ <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"แอปที่ไม่รู้จัก"</string>
+ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"หยุดแคสต์"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"หมายเลขบิลด์"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"คัดลอกหมายเลขบิลด์ไปยังคลิปบอร์ดแล้ว"</string>
<string name="basic_status" msgid="2315371112182658176">"เปิดการสนทนา"</string>
@@ -839,6 +858,7 @@
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"ดูข้อความล่าสุด สายที่ไม่ได้รับ และการอัปเดตสถานะ"</string>
<string name="people_tile_title" msgid="6589377493334871272">"การสนทนา"</string>
+ <string name="paused_by_dnd" msgid="7856941866433556428">"หยุดชั่วคราวโดยฟีเจอร์ห้ามรบกวน"</string>
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> ส่งข้อความ: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> ส่งรูปภาพ"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> มีการอัปเดตสถานะ: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
@@ -867,7 +887,7 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi จะไม่เชื่อมต่ออัตโนมัติในตอนนี้"</string>
<string name="see_all_networks" msgid="3773666844913168122">"ดูทั้งหมด"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"ตัดการเชื่อมต่ออีเทอร์เน็ตเพื่อสลับเครือข่าย"</string>
- <string name="wifi_scan_notify_message" msgid="3753839537448621794">"เพื่อปรับปรุงประสบการณ์การใช้อุปกรณ์ แอปและบริการต่างๆ จะยังคงสแกนหาเครือข่าย Wi‑Fi ได้ทุกเมื่อแม้ว่า Wi‑Fi จะปิดอยู่ คุณเปลี่ยนตัวเลือกนี้ได้ในการตั้งค่าการสแกนหา Wi-Fi "<annotation id="link">"เปลี่ยน"</annotation></string>
+ <string name="wifi_scan_notify_message" msgid="3753839537448621794">"เพื่อปรับปรุงประสบการณ์การใช้อุปกรณ์ แอปและบริการต่างๆ จะยังคงสแกนหาเครือข่าย Wi‑Fi ได้ทุกเมื่อแม้ว่า Wi‑Fi จะปิดอยู่ คุณเปลี่ยนตัวเลือกนี้ได้ในการตั้งค่าการสแกนหา Wi-Fi "<annotation id="link">"เปลี่ยนการตั้งค่า"</annotation></string>
<string name="turn_off_airplane_mode" msgid="8425587763226548579">"ปิดโหมดบนเครื่องบิน"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> ต้องการเพิ่มชิ้นส่วนต่อไปนี้ในการตั้งค่าด่วน"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"เพิ่มชิ้นส่วน"</string>
@@ -877,8 +897,7 @@
<item quantity="other">มี <xliff:g id="COUNT_1">%s</xliff:g> แอปที่ใช้งานอยู่</item>
<item quantity="one">มี <xliff:g id="COUNT_0">%s</xliff:g> แอปที่ใช้งานอยู่</item>
</plurals>
- <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
- <skip />
+ <string name="fgs_dot_content_description" msgid="2865071539464777240">"ข้อมูลใหม่"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"แอปที่ใช้งานอยู่"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"หยุด"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"หยุดแล้ว"</string>
@@ -886,14 +905,15 @@
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"คัดลอกแล้ว"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"จาก <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"ปิด UI การคัดลอก"</string>
- <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
- <skip />
- <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
- <skip />
- <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
- <skip />
- <!-- no translation found for add (81036585205287996) -->
- <skip />
- <!-- no translation found for manage_users (1823875311934643849) -->
- <skip />
+ <string name="clipboard_edit_text_description" msgid="805254383912962103">"แก้ไขข้อความที่คัดลอก"</string>
+ <string name="clipboard_edit_image_description" msgid="8904857948976041306">"แก้ไขรูปภาพที่คัดลอก"</string>
+ <string name="clipboard_send_nearby_description" msgid="4629769637846717650">"ส่งไปยังอุปกรณ์ที่อยู่ใกล้เคียง"</string>
+ <string name="add" msgid="81036585205287996">"เพิ่ม"</string>
+ <string name="manage_users" msgid="1823875311934643849">"จัดการผู้ใช้"</string>
+ <string name="drag_split_not_supported" msgid="4326847447699729722">"การแจ้งเตือนนี้ไม่รองรับการลากเพื่อแบ่งหน้าจอ"</string>
+ <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"ใช้ Wi‑Fi ไม่ได้"</string>
+ <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"โหมดลำดับความสำคัญ"</string>
+ <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"ตั้งปลุกแล้ว"</string>
+ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"กล้องและไมค์ปิดอยู่"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{การแจ้งเตือน # รายการ}other{การแจ้งเตือน # รายการ}}"</string>
</resources>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index db9c788037f9..4d5655c191d6 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -20,14 +20,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4811759950673118541">"UI ng System"</string>
- <string name="battery_low_title" msgid="6891106956328275225">"Malapit nang maubos ang baterya"</string>
+ <string name="battery_low_title" msgid="5319680173344341779">"I-on ang Pantipid ng Baterya?"</string>
+ <string name="battery_low_description" msgid="3282977755476423966">"<xliff:g id="PERCENTAGE">%s</xliff:g> na lang ang natitira sa iyong baterya. Ino-on ng Pantipid ng Baterya ang Madilim na tema, pinaghihigpitan nito ang aktibidad sa background, at inaantala nito ang mga notification."</string>
+ <string name="battery_low_intro" msgid="5148725009653088790">"Ino-on ng Pantipid ng Baterya ang Madilim na tema, pinaghihigpitan nito ang aktibidad sa background, at inaantala nito ang mga notification."</string>
<string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> na lang ang natitira"</string>
<string name="invalid_charger_title" msgid="938685362320735167">"Hindi makapag-charge sa pamamagitan ng USB"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"Gamitin ang charger na kasama ng iyong device"</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"I-on ang Pantipid ng Baterya?"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Tungkol sa Pantipid ng Baterya"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"I-on"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"I-on ang Pantipid ng Baterya"</string>
+ <string name="battery_saver_start_action" msgid="8353766979886287140">"I-on"</string>
+ <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Huwag na lang"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"I-auto rotate ang screen"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"Payagan ang <xliff:g id="APPLICATION">%1$s</xliff:g> na ma-access ang <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
<string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Payagan ang <xliff:g id="APPLICATION">%1$s</xliff:g> na i-access ang <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nHindi nabigyan ng pahintulot ang app na ito para mag-record pero nakakapag-capture ito ng audio sa pamamagitan ng USB device na ito."</string>
@@ -128,6 +131,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Na-authenticate ang mukha"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Nakumpirma"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"I-tap ang Kumpirmahin para kumpletuhin"</string>
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Na-unlock gamit ang mukha mo. Pindutin para magpatuloy."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Na-authenticate"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Gumamit ng PIN"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Gumamit ng pattern"</string>
@@ -181,6 +185,7 @@
<string name="accessibility_desc_close" msgid="8293708213442107755">"Isara"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"ganap na katahimikan"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"mga alarm lang"</string>
+ <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"Huwag Istorbohin."</string>
<string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"Bluetooth."</string>
<string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"Naka-on ang Bluetooth."</string>
<string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"Nakatakda ang alarm nang <xliff:g id="TIME">%s</xliff:g>."</string>
@@ -205,6 +210,7 @@
<string name="dessert_case" msgid="9104973640704357717">"Dessert Case"</string>
<string name="start_dreams" msgid="9131802557946276718">"Screen saver"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
+ <string name="quick_settings_dnd_label" msgid="7728690179108024338">"Huwag Istorbohin"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Walang available na mga magkapares na device"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> na baterya"</string>
@@ -348,6 +354,7 @@
<string name="notification_section_header_alerting" msgid="5581175033680477651">"Mga Notification"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Mga Pag-uusap"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"I-clear ang lahat ng silent na notification"</string>
+ <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Mga notification na na-pause ng Huwag Istorbohin"</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"Magsimula ngayon"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Walang mga notification"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Pinapamahalaan ng magulang mo itong device"</string>
@@ -452,8 +459,8 @@
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"I-unlock para magamit"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Nagkaproblema sa pagkuha ng iyong mga card, pakisubukan ulit sa ibang pagkakataon"</string>
<string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Mga setting ng lock screen"</string>
- <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR code"</string>
- <string name="qr_code_scanner_description" msgid="7937603775306661863">"I-tap para i-scan"</string>
+ <!-- no translation found for qr_code_scanner_title (5290201053875420785) -->
+ <skip />
<string name="status_bar_work" msgid="5238641949837091056">"Profile sa trabaho"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Airplane mode"</string>
<string name="zen_alarm_warning" msgid="7844303238486849503">"Hindi mo maririnig ang iyong susunod na alarm ng <xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -491,6 +498,8 @@
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"&lt;b&gt;Status:&lt;/b&gt; Na-rank nang Mas Mababa"</string>
<string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"Makikita sa itaas ng mga notification ng pag-uusap at bilang larawan sa profile sa lock screen"</string>
<string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"Makikita sa itaas ng mga notification ng pag-uusap at bilang larawan sa profile sa lock screen, lumalabas bilang bubble"</string>
+ <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"Makikita sa itaas ng mga notification ng pag-uusap at bilang larawan sa profile sa lock screen, naaabala ang Huwag Istorbohin"</string>
+ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Makikita sa itaas ng mga notification ng pag-uusap at bilang larawan sa profile sa lock screen, lumalabas bilang bubble, naaabala ang Huwag Istorbohin"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Priyoridad"</string>
<string name="no_shortcut" msgid="8257177117568230126">"Hindi sinusuportahan ng <xliff:g id="APP_NAME">%1$s</xliff:g> ang mga feature ng pag-uusap"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Hindi puwedeng baguhin ang mga notification na ito."</string>
@@ -566,6 +575,7 @@
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"SMS"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"Music"</string>
<string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Kalendaryo"</string>
+ <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Huwag Istorbohin"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"Shortcut ng mga button ng volume"</string>
<string name="battery" msgid="769686279459897127">"Baterya"</string>
<string name="headset" msgid="4485892374984466437">"Headset"</string>
@@ -684,6 +694,10 @@
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"Naka-off ang Wi-Fi"</string>
<string name="bt_is_off" msgid="7436344904889461591">"Naka-off ang Bluetooth"</string>
+ <string name="dnd_is_off" msgid="3185706903793094463">"Naka-off ang Huwag Istorbohin"</string>
+ <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"Na-on ang Huwag Istorbohin dahil sa isang awtomatikong panuntunan (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"Na-on ang Huwag Istorbohin dahil sa isang app (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"Na-on ang Huwag Istorbohin dahil sa isang awtomatikong panuntunan o app."</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"Tumatakbo ang mga app sa background"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"I-tap para sa mga detalye tungkol sa paggamit ng baterya at data"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"I-off ang mobile data?"</string>
@@ -708,6 +722,8 @@
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(trabaho)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"Tawag sa telepono"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(sa pamamagitan ng <xliff:g id="APPLICATION_NAME_S_">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_label" msgid="3385241594101496292">"(<xliff:g id="ATTRIBUTION_LABEL">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_proxy_label" msgid="1111829599659403249">"(<xliff:g id="ATTRIBUTION_LABEL">%1$s</xliff:g> • <xliff:g id="PROXY_LABEL">%2$s</xliff:g>)"</string>
<string name="privacy_type_camera" msgid="7974051382167078332">"camera"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"lokasyon"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"mikropono"</string>
@@ -806,6 +822,9 @@
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(nadiskonekta)"</string>
<string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Hindi makalipat. I-tap para subukan ulit."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Magpares ng bagong device"</string>
+ <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Para ma-cast ang session na ito, buksan ang app."</string>
+ <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Hindi kilalang app"</string>
+ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Ihinto ang pag-cast"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Numero ng build"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Nakopya sa clipboard ang numero ng build."</string>
<string name="basic_status" msgid="2315371112182658176">"Buksan ang pag-uusap"</string>
@@ -839,6 +858,7 @@
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Tingnan ang mga kamakailang mensahe, hindi nasagot na tawag, at update sa status"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Pag-uusap"</string>
+ <string name="paused_by_dnd" msgid="7856941866433556428">"Na-pause ng Huwag Istorbohin"</string>
<string name="new_notification_text_content_description" msgid="2915029960094389291">"Nagpadala si <xliff:g id="NAME">%1$s</xliff:g> ng mensahe: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"Nagpadala si <xliff:g id="NAME">%1$s</xliff:g> ng larawan"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"May update sa status si <xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
@@ -877,8 +897,7 @@
<item quantity="one"><xliff:g id="COUNT_1">%s</xliff:g> aktibong app</item>
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> na aktibong app</item>
</plurals>
- <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
- <skip />
+ <string name="fgs_dot_content_description" msgid="2865071539464777240">"Bagong impormasyon"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Mga aktibong app"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Ihinto"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Inihinto"</string>
@@ -886,14 +905,15 @@
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Nakopya"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Mula sa <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"I-dismiss ang UI ng pagkopya"</string>
- <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
- <skip />
- <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
- <skip />
- <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
- <skip />
- <!-- no translation found for add (81036585205287996) -->
- <skip />
- <!-- no translation found for manage_users (1823875311934643849) -->
- <skip />
+ <string name="clipboard_edit_text_description" msgid="805254383912962103">"I-edit ang kinopyang text"</string>
+ <string name="clipboard_edit_image_description" msgid="8904857948976041306">"I-edit ang kinopyang larawan"</string>
+ <string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Ipadala sa kalapit na device"</string>
+ <string name="add" msgid="81036585205287996">"Magdagdag"</string>
+ <string name="manage_users" msgid="1823875311934643849">"Pamahalaan ang mga user"</string>
+ <string name="drag_split_not_supported" msgid="4326847447699729722">"Hindi sinusuportahan ng notification na ito ang pag-drag sa Splitscreen."</string>
+ <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Hindi available ang Wi‑Fi"</string>
+ <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Priority mode"</string>
+ <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Nakatakda ang alarm"</string>
+ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Naka-off ang camera at mikropono"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notification}one{# notification}other{# na notification}}"</string>
</resources>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 308af4f3cb3a..170d582f8583 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -20,14 +20,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4811759950673118541">"Sistem Arayüzü"</string>
- <string name="battery_low_title" msgid="6891106956328275225">"Pil kısa süre sonra bitebilir"</string>
+ <string name="battery_low_title" msgid="5319680173344341779">"Pil Tasarrufu açılsın mı?"</string>
+ <string name="battery_low_description" msgid="3282977755476423966">"<xliff:g id="PERCENTAGE">%s</xliff:g> piliniz kaldı. Pil Tasarrufu, koyu temayı açıp arka plan etkinliğini kısıtlar ve bildirimleri geciktirir."</string>
+ <string name="battery_low_intro" msgid="5148725009653088790">"Pil Tasarrufu, koyu temayı açıp arka plan etkinliğini kısıtlar ve bildirimleri geciktirir."</string>
<string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> kaldı"</string>
<string name="invalid_charger_title" msgid="938685362320735167">"USB ile şarj edilemiyor"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"Cihazınızla birlikte gelen şarj cihazını kullanın"</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Pil Tasarrufu açılsın mı?"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Pil Tasarrufu hakkında"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Aç"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"Pil Tasarrufu\'nu aç"</string>
+ <string name="battery_saver_start_action" msgid="8353766979886287140">"Aç"</string>
+ <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Hayır, teşekkürler"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Ekranı otomatik döndür"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"<xliff:g id="APPLICATION">%1$s</xliff:g> uygulamasının <xliff:g id="USB_DEVICE">%2$s</xliff:g> cihazına erişmesine izin verilsin mi?"</string>
<string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"<xliff:g id="APPLICATION">%1$s</xliff:g> uygulamasının <xliff:g id="USB_DEVICE">%2$s</xliff:g> cihazına erişmesine izin verilsin mi?\nBu uygulamaya kayıt izni verilmemiş ancak bu USB cihazı aracılığıyla sesleri yakalayabilir."</string>
@@ -128,6 +131,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Yüz kimliği doğrulandı"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Onaylandı"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Tamamlamak için Onayla\'ya dokunun"</string>
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Kilit, yüzünüzle açıldı. Devam etmek için basın."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Kimliği Doğrulandı"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"PIN kullan"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Deseni kullan"</string>
@@ -181,6 +185,7 @@
<string name="accessibility_desc_close" msgid="8293708213442107755">"Kapat"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"tamamen sessiz"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"yalnızca alarmlar"</string>
+ <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"Rahatsız Etmeyin."</string>
<string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"Bluetooth."</string>
<string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"Bluetooth açık."</string>
<string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"Alarm saati: <xliff:g id="TIME">%s</xliff:g>."</string>
@@ -205,6 +210,7 @@
<string name="dessert_case" msgid="9104973640704357717">"Tatlı Kutusu"</string>
<string name="start_dreams" msgid="9131802557946276718">"Ekran koruyucu"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
+ <string name="quick_settings_dnd_label" msgid="7728690179108024338">"Rahatsız Etmeyin"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Kullanılabilir eşlenmiş cihaz yok"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Pil düzeyi <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
@@ -348,6 +354,7 @@
<string name="notification_section_header_alerting" msgid="5581175033680477651">"Bildirimler"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Görüşmeler"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Sessiz bildirimlerin tümünü temizle"</string>
+ <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Bildirimler, Rahatsız Etmeyin özelliği tarafından duraklatıldı"</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"Şimdi başlat"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Bildirim yok"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Bu cihaz ebeveyniniz tarafından yönetiliyor"</string>
@@ -452,8 +459,8 @@
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Kullanmak için kilidi aç"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Kartlarınız alınırken bir sorun oluştu. Lütfen daha sonra tekrar deneyin"</string>
<string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Kilit ekranı ayarları"</string>
- <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR kodu"</string>
- <string name="qr_code_scanner_description" msgid="7937603775306661863">"Taramak için dokunun"</string>
+ <!-- no translation found for qr_code_scanner_title (5290201053875420785) -->
+ <skip />
<string name="status_bar_work" msgid="5238641949837091056">"İş profili"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Uçak modu"</string>
<string name="zen_alarm_warning" msgid="7844303238486849503">"<xliff:g id="WHEN">%1$s</xliff:g> olarak ayarlanmış bir sonraki alarmınızı duymayacaksınız"</string>
@@ -491,6 +498,8 @@
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"&lt;b&gt;Durum:&lt;/b&gt; Daha Düşük Sıralandı"</string>
<string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"Görüşme bildirimlerinin üstünde ve kilit ekranında profil resmi olarak gösterilir"</string>
<string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"Görüşme bildirimlerinin üstünde ve kilit ekranında profil resmi olarak gösterilir, baloncuk olarak görünür"</string>
+ <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"Görüşme bildirimlerinin üstünde ve kilit ekranında profil resmi olarak gösterilir, Rahatsız Etmeyin\'i kesintiye uğratır"</string>
+ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Görüşme bildirimlerinin üstünde ve kilit ekranında profil resmi olarak gösterilir, baloncuk olarak görünür, Rahatsız Etmeyin\'i kesintiye uğratır"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Öncelikli"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g>, sohbet özelliklerini desteklemiyor"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Bu bildirimler değiştirilemez."</string>
@@ -566,6 +575,7 @@
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"SMS"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"Müzik"</string>
<string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Takvim"</string>
+ <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Rahatsız Etmeyin"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"Ses düğmeleri kısayolu"</string>
<string name="battery" msgid="769686279459897127">"Pil"</string>
<string name="headset" msgid="4485892374984466437">"Mikrofonlu kulaklık"</string>
@@ -684,6 +694,10 @@
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>, <xliff:g id="CARRIER_NAME">%1$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"Kablosuz bağlantı kapalı"</string>
<string name="bt_is_off" msgid="7436344904889461591">"Bluetooth kapalı"</string>
+ <string name="dnd_is_off" msgid="3185706903793094463">"Rahatsız Etmeyin kapalı"</string>
+ <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"Rahatsız Etmeyin ayarı bir otomatik kural (<xliff:g id="ID_1">%s</xliff:g>) tarafından açıldı."</string>
+ <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"Rahatsız Etmeyin ayarı bir uygulama (<xliff:g id="ID_1">%s</xliff:g>) tarafından açıldı."</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"Rahatsız Etmeyin ayarı bir otomatik kural veya uygulama tarafından açıldı."</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"Arka planda çalışan uygulamalar"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"Pil ve veri kullanımı ile ilgili ayrıntılar için dokunun"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Mobil veri kapatılsın mı?"</string>
@@ -708,6 +722,8 @@
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(iş)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"Sesli arama"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(<xliff:g id="APPLICATION_NAME_S_">%s</xliff:g> aracılığıyla)"</string>
+ <string name="ongoing_privacy_dialog_attribution_label" msgid="3385241594101496292">"(<xliff:g id="ATTRIBUTION_LABEL">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_proxy_label" msgid="1111829599659403249">"(<xliff:g id="ATTRIBUTION_LABEL">%1$s</xliff:g> • <xliff:g id="PROXY_LABEL">%2$s</xliff:g>)"</string>
<string name="privacy_type_camera" msgid="7974051382167078332">"kamera"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"konum"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofon"</string>
@@ -806,6 +822,9 @@
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(bağlantı kesildi)"</string>
<string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Geçiş yapılamıyor. Tekrar denemek için dokunun."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Yeni cihaz eşle"</string>
+ <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Bu oturumu yayınlamak için lütfen uygulamayı açın."</string>
+ <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Bilinmeyen uygulama"</string>
+ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Yayını durdur"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Derleme numarası"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Derleme numarası panoya kopyalandı."</string>
<string name="basic_status" msgid="2315371112182658176">"Görüşmeyi aç"</string>
@@ -839,6 +858,7 @@
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Yeni mesajları, cevapsız aramaları ve durum güncellemelerini görün"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Görüşme"</string>
+ <string name="paused_by_dnd" msgid="7856941866433556428">"Rahatsız Etmeyin özelliği tarafından duraklatıldı"</string>
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> bir mesaj gönderdi: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> bir resim gönderdi"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g>, durumunu güncelledi: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
@@ -877,8 +897,7 @@
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> etkin uygulama</item>
<item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> etkin uygulama</item>
</plurals>
- <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
- <skip />
+ <string name="fgs_dot_content_description" msgid="2865071539464777240">"Yeni bilgi"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Etkin uygulamalar"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Durdur"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Durduruldu"</string>
@@ -886,14 +905,15 @@
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Kopyalandı"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"<xliff:g id="APPNAME">%1$s</xliff:g> uygulamasından"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Kopyalanan kullanıcı arayüzünü kapat"</string>
- <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
- <skip />
- <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
- <skip />
- <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
- <skip />
- <!-- no translation found for add (81036585205287996) -->
- <skip />
- <!-- no translation found for manage_users (1823875311934643849) -->
- <skip />
+ <string name="clipboard_edit_text_description" msgid="805254383912962103">"Kopyalanan metni düzenle"</string>
+ <string name="clipboard_edit_image_description" msgid="8904857948976041306">"Kopyalanan resmi düzenle"</string>
+ <string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Yakındaki cihaza gönder"</string>
+ <string name="add" msgid="81036585205287996">"Ekle"</string>
+ <string name="manage_users" msgid="1823875311934643849">"Kullanıcıları yönet"</string>
+ <string name="drag_split_not_supported" msgid="4326847447699729722">"Bu bildirim, bölünmüş ekrana sürüklenmeyi desteklemiyor."</string>
+ <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Kablosuz kullanılamıyor"</string>
+ <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Öncelik modu"</string>
+ <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarm kuruldu"</string>
+ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Kamera ve mikrofon kapalı"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# bildirim}other{# bildirim}}"</string>
</resources>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 01610607154e..87ea462dfb25 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -20,14 +20,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4811759950673118541">"Інтерфейс системи"</string>
- <string name="battery_low_title" msgid="6891106956328275225">"Акумулятор може невдовзі розрядитися"</string>
+ <string name="battery_low_title" msgid="5319680173344341779">"Увімкнути режим енергозбереження?"</string>
+ <string name="battery_low_description" msgid="3282977755476423966">"У вас залишилося <xliff:g id="PERCENTAGE">%s</xliff:g> заряду акумулятора. У режимі енергозбереження вмикається Темна тема, обмежуються дії у фоновому режимі та затримуються сповіщення."</string>
+ <string name="battery_low_intro" msgid="5148725009653088790">"У режимі енергозбереження вмикається Темна тема, обмежуються дії у фоновому режимі та затримуються сповіщення."</string>
<string name="battery_low_percent_format" msgid="4276661262843170964">"Залишилося <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="invalid_charger_title" msgid="938685362320735167">"Не вдається зарядити через USB"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"Використовуйте зарядний пристрій, який входить у комплект пристрою"</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Увімкнути режим енергозбереження?"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Про режим енергозбереження"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Увімкнути"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"Увімкнути режим енергозбереження"</string>
+ <string name="battery_saver_start_action" msgid="8353766979886287140">"Увімкнути"</string>
+ <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Ні, дякую"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Автообертання екрана"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"Надати додатку <xliff:g id="APPLICATION">%1$s</xliff:g> доступ до такого аксесуара: <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
<string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Надати додатку <xliff:g id="APPLICATION">%1$s</xliff:g> доступ до <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nЦей додаток не має дозволу на записування звуку, але може фіксувати його через цей USB-пристрій."</string>
@@ -128,6 +131,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Обличчя автентифіковано"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Підтверджено"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Щоб завершити, натисніть \"Підтвердити\""</string>
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Розблоковано: фейсконтроль. Натисніть, щоб продовжити."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Автентифіковано"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Ввести PIN-код"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Намалювати ключ"</string>
@@ -181,6 +185,7 @@
<string name="accessibility_desc_close" msgid="8293708213442107755">"Закрити"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"без сигналів"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"лише будильники"</string>
+ <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"Не турбувати."</string>
<string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"Bluetooth."</string>
<string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"Bluetooth увімк."</string>
<string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"Сигнал установлено на <xliff:g id="TIME">%s</xliff:g>."</string>
@@ -207,6 +212,7 @@
<string name="dessert_case" msgid="9104973640704357717">"Вітрина десертів"</string>
<string name="start_dreams" msgid="9131802557946276718">"Заставка"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
+ <string name="quick_settings_dnd_label" msgid="7728690179108024338">"Не турбувати"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Немає спарених пристроїв"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> заряду акумулятора"</string>
@@ -354,6 +360,7 @@
<string name="notification_section_header_alerting" msgid="5581175033680477651">"Сповіщення"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Розмови"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Очистити всі беззвучні сповіщення"</string>
+ <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Режим \"Не турбувати\" призупинив сповіщення"</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"Почати зараз"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Сповіщень немає"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Цим пристроєм керує батько або мати"</string>
@@ -458,8 +465,8 @@
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Розблокувати, щоб використовувати"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Не вдалось отримати ваші картки. Повторіть спробу пізніше."</string>
<string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Параметри блокування екрана"</string>
- <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR-код"</string>
- <string name="qr_code_scanner_description" msgid="7937603775306661863">"Натисніть, щоб сканувати"</string>
+ <!-- no translation found for qr_code_scanner_title (5290201053875420785) -->
+ <skip />
<string name="status_bar_work" msgid="5238641949837091056">"Робочий профіль"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Режим польоту"</string>
<string name="zen_alarm_warning" msgid="7844303238486849503">"Наступний сигнал о <xliff:g id="WHEN">%1$s</xliff:g> не пролунає"</string>
@@ -497,6 +504,8 @@
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"&lt;b&gt;Статус&lt;/b&gt;: пріоритет знижено"</string>
<string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"З’являється вгорі сповіщень про розмови та як зображення профілю на заблокованому екрані"</string>
<string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"З’являється вгорі сповіщень про розмови та як зображення профілю на заблокованому екрані, показується у вигляді спливаючої підказки"</string>
+ <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"З’являється вгорі сповіщень про розмови та як зображення профілю на заблокованому екрані, показується навіть у режимі \"Не турбувати\""</string>
+ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"З’являється вгорі сповіщень про розмови та як зображення профілю на заблокованому екрані, відображається як спливаючий чат, перериває режим \"Не турбувати\""</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Пріоритет"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> не підтримує функції розмов"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Ці сповіщення не можна змінити."</string>
@@ -576,6 +585,7 @@
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"SMS"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"Музика"</string>
<string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Календар"</string>
+ <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Не турбувати"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"Кнопки гучності на корпусі"</string>
<string name="battery" msgid="769686279459897127">"Акумулятор"</string>
<string name="headset" msgid="4485892374984466437">"Гарнітура"</string>
@@ -694,6 +704,10 @@
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"Wi-Fi вимкнено"</string>
<string name="bt_is_off" msgid="7436344904889461591">"Bluetooth вимкнено"</string>
+ <string name="dnd_is_off" msgid="3185706903793094463">"Режим \"Не турбувати\" вимкнено"</string>
+ <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"Автоматичне правило ввімкнуло режим \"Не турбувати\" (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"Додаток увімкнув режим \"Не турбувати\" (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"Автоматичне правило або додаток увімкнули режим \"Не турбувати\"."</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"Додатки, які працюють у фоновому режимі"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"Торкніться, щоб перевірити використання акумулятора й трафік"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Вимкнути мобільний Інтернет?"</string>
@@ -718,6 +732,8 @@
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(робота)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"Телефонний дзвінок"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(через <xliff:g id="APPLICATION_NAME_S_">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_label" msgid="3385241594101496292">"(<xliff:g id="ATTRIBUTION_LABEL">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_proxy_label" msgid="1111829599659403249">"(<xliff:g id="ATTRIBUTION_LABEL">%1$s</xliff:g> • <xliff:g id="PROXY_LABEL">%2$s</xliff:g>)"</string>
<string name="privacy_type_camera" msgid="7974051382167078332">"камера"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"місце"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"мікрофон"</string>
@@ -818,6 +834,9 @@
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(від’єднано)"</string>
<string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Не вдалося змінити підключення. Натисніть, щоб повторити спробу."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Підключити новий пристрій"</string>
+ <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Щоб транслювати цей сеанс, відкрийте додаток."</string>
+ <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Невідомий додаток"</string>
+ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Припинити трансляцію"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Номер складання"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Номер складання скопійовано в буфер обміну."</string>
<string name="basic_status" msgid="2315371112182658176">"Відкрита розмова"</string>
@@ -851,6 +870,7 @@
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Переглядайте останні повідомлення, пропущені виклики й оновлення статусу"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Розмова"</string>
+ <string name="paused_by_dnd" msgid="7856941866433556428">"Призупинено функцією \"Не турбувати\""</string>
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> надсилає повідомлення: \"<xliff:g id="NOTIFICATION">%2$s</xliff:g>\""</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> надсилає зображення"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> публікує новий статус: \"<xliff:g id="STATUS">%2$s</xliff:g>\""</string>
@@ -891,8 +911,7 @@
<item quantity="many"><xliff:g id="COUNT_1">%s</xliff:g> активних додатків</item>
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> активного додатка</item>
</plurals>
- <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
- <skip />
+ <string name="fgs_dot_content_description" msgid="2865071539464777240">"Нова інформація"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Активні додатки"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Зупинити"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Зупинено"</string>
@@ -900,14 +919,15 @@
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Скопійовано"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"З додатка <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Закрити вікно копіювання"</string>
- <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
- <skip />
- <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
- <skip />
- <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
- <skip />
- <!-- no translation found for add (81036585205287996) -->
- <skip />
- <!-- no translation found for manage_users (1823875311934643849) -->
- <skip />
+ <string name="clipboard_edit_text_description" msgid="805254383912962103">"Редагувати скопійований текст"</string>
+ <string name="clipboard_edit_image_description" msgid="8904857948976041306">"Редагувати скопійоване зображення"</string>
+ <string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Надіслати на пристрій поблизу"</string>
+ <string name="add" msgid="81036585205287996">"Додати"</string>
+ <string name="manage_users" msgid="1823875311934643849">"Керувати користувачами"</string>
+ <string name="drag_split_not_supported" msgid="4326847447699729722">"Це сповіщення не підтримує режим розділеного екрана."</string>
+ <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Мережа Wi-Fi недоступна"</string>
+ <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Режим пріоритету"</string>
+ <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Будильник установлено"</string>
+ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Камеру й мікрофон вимкнено"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# сповіщення}one{# сповіщення}few{# сповіщення}many{# сповіщень}other{# сповіщення}}"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index ce492dd71fb4..cb1cbddfa0a9 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -20,14 +20,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4811759950673118541">"‏سسٹم UI"</string>
- <string name="battery_low_title" msgid="6891106956328275225">"بیٹری جلد ہی ختم ہو سکتی ہے"</string>
+ <string name="battery_low_title" msgid="5319680173344341779">"بیٹری سیور آن کریں؟"</string>
+ <string name="battery_low_description" msgid="3282977755476423966">"آپ کے پاس <xliff:g id="PERCENTAGE">%s</xliff:g> بیٹری باقی ہے۔ بیٹری سیور گہری تھیم کو آن، پس منظر کی سرگرمی کو محدود اور اطلاعات میں تاخیر کرتی ہے۔"</string>
+ <string name="battery_low_intro" msgid="5148725009653088790">"بیٹری سیور گہری تھیم کو آن، پس منظر کی سرگرمی کو محدود اور اطلاعات میں تاخیر کرتی ہے۔"</string>
<string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> باقی ہے"</string>
<string name="invalid_charger_title" msgid="938685362320735167">"‏USB کے ذریعے چارج نہیں کر سکتے"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"اپنے آلہ کے ساتھ ملنے والے چارجر کا استعمال کریں"</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"بیٹری سیور آن کریں؟"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"بیٹری سیور کے بارے میں"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"آن کریں"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"بیٹری سیور آن کریں"</string>
+ <string name="battery_saver_start_action" msgid="8353766979886287140">"آن کریں"</string>
+ <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"نہیں شکریہ"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"سکرین کو خودکار طور پر گھمائیں"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"<xliff:g id="APPLICATION">%1$s</xliff:g> کو <xliff:g id="USB_DEVICE">%2$s</xliff:g> تک رسائی حاصل کرنے کی اجازت دیں؟"</string>
<string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"‏<xliff:g id="APPLICATION">%1$s</xliff:g> کو <xliff:g id="USB_DEVICE">%2$s</xliff:g> تک رسائی دیں؟\nاس ایپ کو ریکارڈ کی اجازت عطا نہیں کی گئی ہے مگر اس USB آلہ سے کیپچر کر سکتے ہیں۔"</string>
@@ -128,6 +131,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"چہرے کی تصدیق ہو گئی"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"تصدیق شدہ"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"مکمل کرنے کیلئے \'تصدیق کریں\' تھپتھپائیں"</string>
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"آپ کے چہرے سے غیر مقفل کیا گیا جاری رکھنے کے لیے دبائیں"</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"تصدیق کردہ"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"‏PIN استعمال کریں"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"پیٹرن کا استعمال کریں"</string>
@@ -181,6 +185,7 @@
<string name="accessibility_desc_close" msgid="8293708213442107755">"بند کریں"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"مکمل خاموشی"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"صرف الارمز"</string>
+ <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"ڈسٹرب نہ کریں۔"</string>
<string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"بلوٹوتھ۔"</string>
<string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"بلوٹوتھ آن ہے۔"</string>
<string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"الارم <xliff:g id="TIME">%s</xliff:g> کیلئے سیٹ ہے۔"</string>
@@ -205,6 +210,7 @@
<string name="dessert_case" msgid="9104973640704357717">"ڈیزرٹ کیس"</string>
<string name="start_dreams" msgid="9131802557946276718">"اسکرین سیور"</string>
<string name="ethernet_label" msgid="2203544727007463351">"ایتھرنیٹ"</string>
+ <string name="quick_settings_dnd_label" msgid="7728690179108024338">"ڈسٹرب نہ کریں"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"بلوٹوتھ"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"کوئی جوڑا بنائے ہوئے آلات دستیاب نہیں ہیں"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> بیٹری"</string>
@@ -348,6 +354,7 @@
<string name="notification_section_header_alerting" msgid="5581175033680477651">"اطلاعات"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"گفتگوئیں"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"سبھی خاموش اطلاعات کو صاف کریں"</string>
+ <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"\'ڈسٹرب نہ کریں\' کے ذریعے اطلاعات کو موقوف کیا گیا"</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"ابھی شروع کریں"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"کوئی اطلاعات نہیں ہیں"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"یہ آلہ آپ کے والدین کے زیر انتظام ہے"</string>
@@ -452,8 +459,8 @@
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"استعمال کرنے کے لیے غیر مقفل کریں"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"آپ کے کارڈز حاصل کرنے میں ایک مسئلہ درپیش تھا، براہ کرم بعد میں دوبارہ کوشش کریں"</string>
<string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"مقفل اسکرین کی ترتیبات"</string>
- <string name="qr_code_scanner_title" msgid="5660820608548306581">"‏QR کوڈ"</string>
- <string name="qr_code_scanner_description" msgid="7937603775306661863">"اسکین کرنے کے لیے تھپتھپائیں"</string>
+ <!-- no translation found for qr_code_scanner_title (5290201053875420785) -->
+ <skip />
<string name="status_bar_work" msgid="5238641949837091056">"دفتری پروفائل"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"ہوائی جہاز وضع"</string>
<string name="zen_alarm_warning" msgid="7844303238486849503">"آپ کو <xliff:g id="WHEN">%1$s</xliff:g> بجے اپنا اگلا الارم سنائی نہیں دے گا"</string>
@@ -491,6 +498,8 @@
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"‏&lt;b&gt;اسٹیٹس:&lt;/b&gt; کو کم درجہ دیا گیا"</string>
<string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"یہ گفتگو کی اطلاعات کے اوپری حصّے پر اور مقفل اسکرین پر پروفائل کی تصویر کے بطور دکھائی دیتا ہے"</string>
<string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"یہ گفتگو کی اطلاعات کے اوپری حصّے پر اور مقفل اسکرین پر پروفائل کی تصویر کے بطور دکھائی دیتا ہے، بلبلے کے بطور ظاہر ہوتا ہے"</string>
+ <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"یہ گفتگو کی اطلاعات کے اوپری حصّے پر اور مقفل اسکرین پر پروفائل کی تصویر کے بطور دکھائی دیتا ہے، \'ڈسٹرب نہ کریں\' میں مداخلت کرتا ہے"</string>
+ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"یہ گفتگو کی اطلاعات کے اوپری حصّے پر اور مقفل اسکرین پر پروفائل کی تصویر کے بطور دکھائی دیتا ہے، بلبلے کے بطور ظاہر ہوتا ہے، \'ڈسٹرب نہ کریں\' میں مداخلت کرتا ہے"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"ترجیح"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> ایپ گفتگو کی خصوصیات کو سپورٹ نہیں کرتی ہے"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"ان اطلاعات کی ترمیم نہیں کی جا سکتی۔"</string>
@@ -566,6 +575,7 @@
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"SMS"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"موسیقی"</string>
<string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"کیلنڈر"</string>
+ <string name="volume_and_do_not_disturb" msgid="502044092739382832">"ڈسٹرب نہ کریں"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"والیوم بٹنز کے شارٹ کٹ"</string>
<string name="battery" msgid="769686279459897127">"بیٹری"</string>
<string name="headset" msgid="4485892374984466437">"ہیڈ سیٹ"</string>
@@ -684,6 +694,10 @@
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>، <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"‏Wi-Fi آف ہے"</string>
<string name="bt_is_off" msgid="7436344904889461591">"بلوٹوتھ آف ہے"</string>
+ <string name="dnd_is_off" msgid="3185706903793094463">"\'ڈسٹرب نہ کریں\' آف ہے"</string>
+ <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"\'ڈسٹرب نہ کریں\' کسی خودکار اصول (<xliff:g id="ID_1">%s</xliff:g>) کے ذریعہ آن ہو گیا تھا۔"</string>
+ <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"\'ڈسٹرب نہ کریں\' کسی ایپ (<xliff:g id="ID_1">%s</xliff:g>) کے ذریعہ آن ہو گیا تھا۔"</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"\'ڈسٹرب نہ کریں\' کسی خودکار اصول یا ایپ کے ذریعے آن ہو گیا تھا۔"</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"ایپس پس منظر میں چل رہی ہیں"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"بیٹری اور ڈیٹا استعمال کے بارے میں تفصیلات کے لیے تھپتھپائیں"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"موبائل ڈیٹا آف کریں؟"</string>
@@ -708,6 +722,8 @@
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(دفتر)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"فون کال"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(<xliff:g id="APPLICATION_NAME_S_">%s</xliff:g> کے ذریعے)"</string>
+ <string name="ongoing_privacy_dialog_attribution_label" msgid="3385241594101496292">"(<xliff:g id="ATTRIBUTION_LABEL">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_proxy_label" msgid="1111829599659403249">"(<xliff:g id="ATTRIBUTION_LABEL">%1$s</xliff:g> • <xliff:g id="PROXY_LABEL">%2$s</xliff:g>)"</string>
<string name="privacy_type_camera" msgid="7974051382167078332">"کیمرا"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"مقام"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"مائیکروفون"</string>
@@ -806,6 +822,9 @@
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(غیر منسلک ہے)"</string>
<string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"سوئچ نہیں کر سکتے۔ دوبارہ کوشش کرنے کے لیے تھپتھپائیں۔"</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"نئے آلہ کا جوڑا بنائیں"</string>
+ <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"اس سیشن کو کاسٹ کرنے کیلئے، براہ کرم ایپ کھولیں۔"</string>
+ <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"نامعلوم ایپ"</string>
+ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"کاسٹ کرنا بند کریں"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"بلڈ نمبر"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"بلڈ نمبر کلپ بورڈ میں کاپی ہو گیا۔"</string>
<string name="basic_status" msgid="2315371112182658176">"گفتگو کھولیں"</string>
@@ -839,6 +858,7 @@
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"+<xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="people_tile_description" msgid="8154966188085545556">"حالیہ پیغامات، چھوٹی ہوئی کالز اور اسٹیٹس اپ ڈیٹس دیکھیں"</string>
<string name="people_tile_title" msgid="6589377493334871272">"گفتگو"</string>
+ <string name="paused_by_dnd" msgid="7856941866433556428">"\'ڈسٹرب نہ کریں\' کے ذریعے موقوف کیا گیا"</string>
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> نے ایک پیغام بھیجا: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> نے ایک تصویر بھیجی"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> نے اسٹیٹس کو اپ ڈیٹ کر دیا ہے: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
@@ -877,8 +897,7 @@
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> فعال ایپس</item>
<item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> فعال ایپ</item>
</plurals>
- <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
- <skip />
+ <string name="fgs_dot_content_description" msgid="2865071539464777240">"نئی معلومات"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"فعال ایپس"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"روکیں"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"رکی ہوئی ہے"</string>
@@ -889,8 +908,12 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"کاپی کردہ ٹیکسٹ میں ترمیم کریں"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"کاپی کردہ تصویر میں ترمیم کریں"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"قریبی آلے کو بھیجیں"</string>
- <!-- no translation found for add (81036585205287996) -->
- <skip />
- <!-- no translation found for manage_users (1823875311934643849) -->
- <skip />
+ <string name="add" msgid="81036585205287996">"شامل کریں"</string>
+ <string name="manage_users" msgid="1823875311934643849">"صارفین کا نظم کریں"</string>
+ <string name="drag_split_not_supported" msgid="4326847447699729722">"یہ اطلاع اسپلٹ اسکرین کو گھسیٹنے کو سپورٹ نہیں کرتا ہے۔"</string>
+ <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"‏Wi-Fi دستیاب نہیں ہے"</string>
+ <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"ترجیحی وضع"</string>
+ <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"الارم سیٹ ہوگیا"</string>
+ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"کیمرا اور مائیک آف ہیں"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# اطلاع}other{# اطلاعات}}"</string>
</resources>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index 6d6c3714fcdc..1128b297a56f 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -20,14 +20,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4811759950673118541">"Tizim interfeysi"</string>
- <string name="battery_low_title" msgid="6891106956328275225">"Batareya tez orada tugaydi"</string>
+ <string name="battery_low_title" msgid="5319680173344341779">"Quvvat tejash funksiyasi yoqilsinmi?"</string>
+ <string name="battery_low_description" msgid="3282977755476423966">"<xliff:g id="PERCENTAGE">%s</xliff:g> batareya quvvati qoldi. Quvvat tejash funksiyasi Tungi mavzuni yoqadi va fondagi faollikni cheklaydi. Buning natijasida bildirishnomalar kechikishi mumkin."</string>
+ <string name="battery_low_intro" msgid="5148725009653088790">"Quvvat tejash funksiyasi Tungi mavzuni yoqadi va fondagi faollikni cheklaydi. Buning natijasida bildirishnomalar kechikishi mumkin."</string>
<string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> qoldi"</string>
<string name="invalid_charger_title" msgid="938685362320735167">"USB orqali quvvatlash imkonsiz"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"Qurilmangiz bilan kelgan quvvatlash moslamasidan foydalaning"</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Quvvat tejash yoqilsinmi?"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Quvvat tejash funksiyasi haqida"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Yoqish"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"Quvvat tejash funksiyasini yoqing"</string>
+ <string name="battery_saver_start_action" msgid="8353766979886287140">"Yoqish"</string>
+ <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Kerak emas"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Ekranning avtomatik burilishi"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"<xliff:g id="APPLICATION">%1$s</xliff:g> ilovasiga <xliff:g id="USB_DEVICE">%2$s</xliff:g> qurilmasidan foydalanishga ruxsat berilsinmi?"</string>
<string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"<xliff:g id="APPLICATION">%1$s</xliff:g> ilovasiga <xliff:g id="USB_DEVICE">%2$s</xliff:g> qurilmasidan foydalanish uchun ruxsat berilsinmi?\nBu ilovaga yozib olish ruxsati berilmagan, lekin shu USB orqali ovozlarni yozib olishi mumkin."</string>
@@ -128,6 +131,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Yuzingiz aniqlandi"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Tasdiqlangan"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Tasdiqlash uchun tegining"</string>
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Yuz bilan ochildi. Davom etish uchun bosing."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Tasdiqlandi"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"PIN kod kiritish"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Grafik kalitdan foydalanish"</string>
@@ -181,6 +185,7 @@
<string name="accessibility_desc_close" msgid="8293708213442107755">"Yopish"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"jimjitlik"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"faqat signallar"</string>
+ <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"Bezovta qilinmasin."</string>
<string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"Bluetooth."</string>
<string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"Bluetooth yoqilgan."</string>
<string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"Signal <xliff:g id="TIME">%s</xliff:g> da chalinadi."</string>
@@ -205,6 +210,7 @@
<string name="dessert_case" msgid="9104973640704357717">"Dessert Case"</string>
<string name="start_dreams" msgid="9131802557946276718">"Ekran lavhasi"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
+ <string name="quick_settings_dnd_label" msgid="7728690179108024338">"Bezovta qilinmasin"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Ulangan qurilmalar topilmadi"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Batareya quvvati: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
@@ -348,6 +354,7 @@
<string name="notification_section_header_alerting" msgid="5581175033680477651">"Bildirishnomalar"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Suhbatlar"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Barcha sokin bildirishnomalarni tozalash"</string>
+ <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Bezovta qilinmasin rejimida bildirishnomalar pauza qilinadi"</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"Boshlash"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Bildirishnomalar yo‘q"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Bu qurilmani ota-onangiz boshqaradi"</string>
@@ -452,8 +459,8 @@
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Foydalanish uchun qulfdan chiqarish"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Bildirgilarni yuklashda xatolik yuz berdi, keyinroq qaytadan urining"</string>
<string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Qulflangan ekran sozlamalari"</string>
- <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR kod"</string>
- <string name="qr_code_scanner_description" msgid="7937603775306661863">"Skanerlash uchun bosing"</string>
+ <!-- no translation found for qr_code_scanner_title (5290201053875420785) -->
+ <skip />
<string name="status_bar_work" msgid="5238641949837091056">"Ish profili"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Parvoz rejimi"</string>
<string name="zen_alarm_warning" msgid="7844303238486849503">"Keyingi signal (<xliff:g id="WHEN">%1$s</xliff:g>) chalinmaydi"</string>
@@ -491,6 +498,8 @@
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"&lt;b&gt;Holati:&lt;/b&gt; Quyi darajaga tushirildi"</string>
<string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"Suhbat bildirishnomalari tepasida va ekran qulfida profil rasmi sifatida chiqariladi"</string>
<string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"Suhbat bildirishnomalari tepasida va ekran qulfida profil rasmi sifatida chiqariladi, bulutcha sifatida chiqadi"</string>
+ <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"Suhbat bildirishnomalari tepasida va ekran qulfida profil rasmi sifatida chiqariladi, Bezovta qilinmasin rejimini bekor qiladi"</string>
+ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Suhbat bildirishnomalari tepasida va ekran qulfida profil rasmi sifatida chiqariladi, bulutcha sifatida chiqadi, Bezovta qilinmasin rejimini bekor qiladi"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Muhim"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> ilovasida suhbat funksiyalari ishlamaydi"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Bu bildirishnomalarni tahrirlash imkonsiz."</string>
@@ -566,6 +575,7 @@
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"SMS"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"Musiqa"</string>
<string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Taqvim"</string>
+ <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Bezovta qilinmasin"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"Ovoz balandligini boshqarish tugmalari"</string>
<string name="battery" msgid="769686279459897127">"Batareya"</string>
<string name="headset" msgid="4485892374984466437">"Audio moslama"</string>
@@ -684,6 +694,10 @@
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"Wi-Fi o‘chiq"</string>
<string name="bt_is_off" msgid="7436344904889461591">"Bluetooth o‘chiq"</string>
+ <string name="dnd_is_off" msgid="3185706903793094463">"Bezovta qilinmasin rejimi o‘chiq"</string>
+ <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"Bezovta qilinmasin rejimi avtomatik qoida (<xliff:g id="ID_1">%s</xliff:g>) tomonidan yoqilgan."</string>
+ <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"Bezovta qilinmasin rejimi ilova (<xliff:g id="ID_1">%s</xliff:g>) tomonidan yoqilgan."</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"Bezovta qilinmasin rejimi ilova yoki avtomatik qoida tomonidan yoqilgan."</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"Fonda ishlayotgan ilovalar"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"Batareya va trafik sarfi tafsilotlari uchun ustiga bosing"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Mobil internet uzilsinmi?"</string>
@@ -708,6 +722,8 @@
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(ish)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"Telefon chaqiruvi"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(<xliff:g id="APPLICATION_NAME_S_">%s</xliff:g> orqali)"</string>
+ <string name="ongoing_privacy_dialog_attribution_label" msgid="3385241594101496292">"(<xliff:g id="ATTRIBUTION_LABEL">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_proxy_label" msgid="1111829599659403249">"(<xliff:g id="ATTRIBUTION_LABEL">%1$s</xliff:g> • <xliff:g id="PROXY_LABEL">%2$s</xliff:g>)"</string>
<string name="privacy_type_camera" msgid="7974051382167078332">"kamera"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"joylashuv"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofon"</string>
@@ -806,6 +822,9 @@
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(uzildi)"</string>
<string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Xatolik. Qayta urinish uchun bosing."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Yangi qurilmani ulash"</string>
+ <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Bu seansni translatsiya qilish uchun ilovani oching."</string>
+ <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Notanish ilova"</string>
+ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Toʻxtatish"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Nashr raqami"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Nashr raqami vaqtinchalik xotiraga nusxalandi."</string>
<string name="basic_status" msgid="2315371112182658176">"Suhbatni ochish"</string>
@@ -839,6 +858,7 @@
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Oxirgi xabarlar, javobsiz chaqiruvlar va holat yangilanishlari"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Suhbat"</string>
+ <string name="paused_by_dnd" msgid="7856941866433556428">"Bezovta qilinmasin rejimi pauza qildi"</string>
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> xabar yubordi: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> rasm yubordi"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> ahvolini yangiladi: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
@@ -877,8 +897,7 @@
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> ta faol ilova</item>
<item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> ta faol ilova</item>
</plurals>
- <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
- <skip />
+ <string name="fgs_dot_content_description" msgid="2865071539464777240">"Yangi axborot"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Faol ilovalar"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Stop"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Toʻxtatildi"</string>
@@ -886,14 +905,15 @@
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Nusxa olindi"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Manba: <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"UI nusxasini bekor qilish"</string>
- <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
- <skip />
- <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
- <skip />
- <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
- <skip />
- <!-- no translation found for add (81036585205287996) -->
- <skip />
- <!-- no translation found for manage_users (1823875311934643849) -->
- <skip />
+ <string name="clipboard_edit_text_description" msgid="805254383912962103">"Nusxa olingan matnni tahrirlash"</string>
+ <string name="clipboard_edit_image_description" msgid="8904857948976041306">"Nusxa olingan rasmni tahrirlash"</string>
+ <string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Yaqin-atrofdagi qurilmaga yuborish"</string>
+ <string name="add" msgid="81036585205287996">"Kiritish"</string>
+ <string name="manage_users" msgid="1823875311934643849">"Foydalanuvchilarni boshqarish"</string>
+ <string name="drag_split_not_supported" msgid="4326847447699729722">"Bu bildirishnoma ikkiga ajratilgan ekranda ishlamaydi."</string>
+ <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi ishlamayapti"</string>
+ <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Imtiyozli rejim"</string>
+ <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Signal oʻrnatildi"</string>
+ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Kamera va mikrofon yoqilmagan"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# ta bildirishnoma}other{# ta bildirishnoma}}"</string>
</resources>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 5d69e030b194..068127b17e98 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -20,14 +20,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4811759950673118541">"Giao diện người dùng hệ thống"</string>
- <string name="battery_low_title" msgid="6891106956328275225">"Có thể sắp hết pin"</string>
+ <string name="battery_low_title" msgid="5319680173344341779">"Bật Trình tiết kiệm pin?"</string>
+ <string name="battery_low_description" msgid="3282977755476423966">"Bạn còn <xliff:g id="PERCENTAGE">%s</xliff:g> pin. Trình tiết kiệm pin sẽ bật Giao diện tối, giới hạn hoạt động trong nền và trì hoãn thông báo."</string>
+ <string name="battery_low_intro" msgid="5148725009653088790">"Trình tiết kiệm pin sẽ bật Giao diện tối, giới hạn hoạt động trong nền và trì hoãn thông báo."</string>
<string name="battery_low_percent_format" msgid="4276661262843170964">"Còn lại <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="invalid_charger_title" msgid="938685362320735167">"Không thể sạc qua USB"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"Sử dụng bộ sạc đi kèm với thiết bị"</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Bật trình tiết kiệm pin?"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Giới thiệu về Trình tiết kiệm pin"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Bật"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"Bật trình tiết kiệm pin"</string>
+ <string name="battery_saver_start_action" msgid="8353766979886287140">"Bật"</string>
+ <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Không, cảm ơn"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Tự động xoay màn hình"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"Cho phép <xliff:g id="APPLICATION">%1$s</xliff:g> truy cập <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
<string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Cho phép <xliff:g id="APPLICATION">%1$s</xliff:g> truy cập vào <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nỨng dụng này chưa được cấp quyền ghi âm nhưng vẫn có thể ghi âm thông qua thiết bị USB này."</string>
@@ -128,6 +131,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Đã xác thực khuôn mặt"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Ðã xác nhận"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Nhấn vào Xác nhận để hoàn tất"</string>
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Đã mở khoá bằng khuôn mặt bạn. Hãy nhấn để tiếp tục."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Đã xác thực"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Dùng mã PIN"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Dùng hình mở khóa"</string>
@@ -181,6 +185,7 @@
<string name="accessibility_desc_close" msgid="8293708213442107755">"Đóng"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"hoàn toàn tắt tiếng"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"chỉ chuông báo"</string>
+ <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"Không làm phiền."</string>
<string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"Bluetooth."</string>
<string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"Bluetooth bật."</string>
<string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"Báo thức được đặt cho <xliff:g id="TIME">%s</xliff:g>."</string>
@@ -205,6 +210,7 @@
<string name="dessert_case" msgid="9104973640704357717">"Tủ trưng bày bánh ngọt"</string>
<string name="start_dreams" msgid="9131802557946276718">"Trình bảo vệ m.hình"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
+ <string name="quick_settings_dnd_label" msgid="7728690179108024338">"Không làm phiền"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Không có thiết bị nào được ghép nối"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> pin"</string>
@@ -348,6 +354,7 @@
<string name="notification_section_header_alerting" msgid="5581175033680477651">"Thông báo"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Cuộc trò chuyện"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Xóa tất cả thông báo im lặng"</string>
+ <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Chế độ Không làm phiền đã tạm dừng thông báo"</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"Bắt đầu ngay"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Không có thông báo nào"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Thiết bị này do cha mẹ của bạn quản lý"</string>
@@ -452,8 +459,8 @@
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Mở khóa để sử dụng"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Đã xảy ra sự cố khi tải thẻ của bạn. Vui lòng thử lại sau"</string>
<string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Cài đặt màn hình khóa"</string>
- <string name="qr_code_scanner_title" msgid="5660820608548306581">"Mã QR"</string>
- <string name="qr_code_scanner_description" msgid="7937603775306661863">"Nhấn để quét"</string>
+ <!-- no translation found for qr_code_scanner_title (5290201053875420785) -->
+ <skip />
<string name="status_bar_work" msgid="5238641949837091056">"Hồ sơ công việc"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Chế độ máy bay"</string>
<string name="zen_alarm_warning" msgid="7844303238486849503">"Bạn sẽ không nghe thấy báo thức tiếp theo lúc <xliff:g id="WHEN">%1$s</xliff:g> của mình"</string>
@@ -491,6 +498,8 @@
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"&lt;b&gt;Trạng thái:&lt;/b&gt; Đã giảm mức độ quan trọng"</string>
<string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"Hiện ở đầu phần thông báo cuộc trò chuyện và ở dạng ảnh hồ sơ trên màn hình khóa"</string>
<string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"Hiện ở đầu phần thông báo cuộc trò chuyện và ở dạng ảnh hồ sơ trên màn hình khóa, xuất hiện ở dạng bong bóng"</string>
+ <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"Hiện ở đầu phần thông báo cuộc trò chuyện và ở dạng ảnh hồ sơ trên màn hình khóa, làm gián đoạn chế độ Không làm phiền"</string>
+ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Hiện ở đầu phần thông báo cuộc trò chuyện và ở dạng ảnh hồ sơ trên màn hình khóa, xuất hiện ở dạng bong bóng, làm gián đoạn chế độ Không làm phiền"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Mức độ ưu tiên"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> không hỗ trợ các tính năng trò chuyện"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Không thể sửa đổi các thông báo này."</string>
@@ -566,6 +575,7 @@
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"SMS"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"Âm nhạc"</string>
<string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Lịch"</string>
+ <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Không làm phiền"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"Phím tắt các nút âm lượng"</string>
<string name="battery" msgid="769686279459897127">"Pin"</string>
<string name="headset" msgid="4485892374984466437">"Tai nghe"</string>
@@ -684,6 +694,10 @@
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"Wi-Fi tắt"</string>
<string name="bt_is_off" msgid="7436344904889461591">"Bluetooth tắt"</string>
+ <string name="dnd_is_off" msgid="3185706903793094463">"Không làm phiền tắt"</string>
+ <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"Không làm phiền đã được một quy tắc tự động (<xliff:g id="ID_1">%s</xliff:g>) bật."</string>
+ <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"Không làm phiền đã được một ứng dụng (<xliff:g id="ID_1">%s</xliff:g>) bật."</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"Không làm phiền đã được một quy tắc tự động hoặc ứng dụng bật."</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"Ứng dụng đang chạy trong nền"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"Nhấn để biết chi tiết về mức sử dụng dữ liệu và pin"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Tắt dữ liệu di động?"</string>
@@ -708,6 +722,8 @@
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(công việc)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"Cuộc gọi điện thoại"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(thông qua <xliff:g id="APPLICATION_NAME_S_">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_label" msgid="3385241594101496292">"(<xliff:g id="ATTRIBUTION_LABEL">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_proxy_label" msgid="1111829599659403249">"(<xliff:g id="ATTRIBUTION_LABEL">%1$s</xliff:g> • <xliff:g id="PROXY_LABEL">%2$s</xliff:g>)"</string>
<string name="privacy_type_camera" msgid="7974051382167078332">"máy ảnh"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"vị trí"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"micrô"</string>
@@ -806,6 +822,9 @@
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(đã ngắt kết nối)"</string>
<string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Không thể chuyển đổi. Hãy nhấn để thử lại."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Ghép nối thiết bị mới"</string>
+ <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Vui lòng mở ứng dụng để truyền phiên này."</string>
+ <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Ứng dụng không xác định"</string>
+ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Dừng truyền"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Số bản dựng"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Đã sao chép số bản dựng vào bảng nhớ tạm."</string>
<string name="basic_status" msgid="2315371112182658176">"Mở cuộc trò chuyện"</string>
@@ -839,6 +858,7 @@
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"Hơn <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Xem các tin nhắn, cuộc gọi nhỡ và thông tin cập nhật trạng thái gần đây"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Cuộc trò chuyện"</string>
+ <string name="paused_by_dnd" msgid="7856941866433556428">"Đã tạm dừng do chế độ Không làm phiền"</string>
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> đã gửi một tin nhắn: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> đã gửi một hình ảnh"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> đã cập nhật trạng thái: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
@@ -877,8 +897,7 @@
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> ứng dụng đang hoạt động</item>
<item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> ứng dụng đang hoạt động</item>
</plurals>
- <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
- <skip />
+ <string name="fgs_dot_content_description" msgid="2865071539464777240">"Thông tin mới"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Ứng dụng đang hoạt động"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Dừng"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Đã dừng"</string>
@@ -886,14 +905,15 @@
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Đã sao chép"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"Từ <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"Đóng giao diện người dùng sao chép"</string>
- <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
- <skip />
- <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
- <skip />
- <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
- <skip />
- <!-- no translation found for add (81036585205287996) -->
- <skip />
- <!-- no translation found for manage_users (1823875311934643849) -->
- <skip />
+ <string name="clipboard_edit_text_description" msgid="805254383912962103">"Chỉnh sửa văn bản đã sao chép"</string>
+ <string name="clipboard_edit_image_description" msgid="8904857948976041306">"Chỉnh sửa hình ảnh đã sao chép"</string>
+ <string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Gửi đến thiết bị ở gần"</string>
+ <string name="add" msgid="81036585205287996">"Thêm"</string>
+ <string name="manage_users" msgid="1823875311934643849">"Quản lý người dùng"</string>
+ <string name="drag_split_not_supported" msgid="4326847447699729722">"Thông báo này không hỗ trợ thao tác kéo để Chia đôi màn hình."</string>
+ <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Không có Wi‑Fi"</string>
+ <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Chế độ ưu tiên"</string>
+ <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Đã đặt chuông báo"</string>
+ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Máy ảnh và micrô đang tắt"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# thông báo}other{# thông báo}}"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index f03290709a48..b5671e6df9e7 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -20,14 +20,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4811759950673118541">"系统界面"</string>
- <string name="battery_low_title" msgid="6891106956328275225">"电池电量可能很快就要耗尽"</string>
+ <string name="battery_low_title" msgid="5319680173344341779">"要开启省电模式吗?"</string>
+ <string name="battery_low_description" msgid="3282977755476423966">"您的电池还剩 <xliff:g id="PERCENTAGE">%s</xliff:g> 的电量。省电模式会开启深色主题,限制后台活动并将通知延迟。"</string>
+ <string name="battery_low_intro" msgid="5148725009653088790">"省电模式会开启深色主题,限制后台活动并将通知延迟。"</string>
<string name="battery_low_percent_format" msgid="4276661262843170964">"剩余<xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="invalid_charger_title" msgid="938685362320735167">"无法通过 USB 充电"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"使用设备随附的充电器"</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"要开启省电模式吗?"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"关于省电模式"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"开启"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"开启省电模式"</string>
+ <string name="battery_saver_start_action" msgid="8353766979886287140">"开启"</string>
+ <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"不用了"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"自动旋转屏幕"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"要允许<xliff:g id="APPLICATION">%1$s</xliff:g>访问<xliff:g id="USB_DEVICE">%2$s</xliff:g>吗?"</string>
<string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"是否允许<xliff:g id="APPLICATION">%1$s</xliff:g>访问<xliff:g id="USB_DEVICE">%2$s</xliff:g>?\n此应用未获得录音权限,但能通过此 USB 设备录制音频。"</string>
@@ -128,6 +131,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"面孔身份验证成功"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"已确认"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"点按“确认”即可完成"</string>
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"已通过面孔识别解锁。点按即可继续。"</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"已经过身份验证"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"使用 PIN 码"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"使用图案"</string>
@@ -181,6 +185,7 @@
<string name="accessibility_desc_close" msgid="8293708213442107755">"关闭"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"完全静音"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"仅限闹钟"</string>
+ <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"勿扰。"</string>
<string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"蓝牙。"</string>
<string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"蓝牙开启。"</string>
<string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"闹钟已设置为:<xliff:g id="TIME">%s</xliff:g>。"</string>
@@ -205,6 +210,7 @@
<string name="dessert_case" msgid="9104973640704357717">"甜品盒"</string>
<string name="start_dreams" msgid="9131802557946276718">"屏保"</string>
<string name="ethernet_label" msgid="2203544727007463351">"有线网络"</string>
+ <string name="quick_settings_dnd_label" msgid="7728690179108024338">"勿扰"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"蓝牙"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"没有可用的配对设备"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> 的电量"</string>
@@ -348,6 +354,7 @@
<string name="notification_section_header_alerting" msgid="5581175033680477651">"通知"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"对话"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"清除所有无声通知"</string>
+ <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"勿扰模式暂停的通知"</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"立即开始"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"没有通知"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"此设备由您的家长管理"</string>
@@ -452,8 +459,8 @@
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"解锁设备即可使用"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"获取您的卡片时出现问题,请稍后重试"</string>
<string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"锁定屏幕设置"</string>
- <string name="qr_code_scanner_title" msgid="5660820608548306581">"二维码"</string>
- <string name="qr_code_scanner_description" msgid="7937603775306661863">"点按即可扫描"</string>
+ <!-- no translation found for qr_code_scanner_title (5290201053875420785) -->
+ <skip />
<string name="status_bar_work" msgid="5238641949837091056">"工作资料"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"飞行模式"</string>
<string name="zen_alarm_warning" msgid="7844303238486849503">"您在<xliff:g id="WHEN">%1$s</xliff:g>将不会听到下次闹钟响铃"</string>
@@ -491,6 +498,8 @@
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"&lt;b&gt;状态&lt;/b&gt;:已调低顺序"</string>
<string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"显示在对话通知顶部(屏幕锁定时显示为个人资料照片)"</string>
<string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"以气泡形式显示在对话通知顶部(屏幕锁定时显示为个人资料照片)"</string>
+ <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"显示在对话通知顶部(屏幕锁定时显示为个人资料照片),并且会中断勿扰模式"</string>
+ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"以气泡形式显示在对话通知顶部(屏幕锁定时显示为个人资料照片),并且会中断勿扰模式"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"优先"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g>不支持对话功能"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"无法修改这些通知。"</string>
@@ -566,6 +575,7 @@
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"短信"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"音乐"</string>
<string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"日历"</string>
+ <string name="volume_and_do_not_disturb" msgid="502044092739382832">"勿扰"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"音量按钮快捷键"</string>
<string name="battery" msgid="769686279459897127">"电池"</string>
<string name="headset" msgid="4485892374984466437">"耳机"</string>
@@ -684,6 +694,10 @@
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>,<xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"WLAN 已关闭"</string>
<string name="bt_is_off" msgid="7436344904889461591">"蓝牙已关闭"</string>
+ <string name="dnd_is_off" msgid="3185706903793094463">"“勿扰”模式已关闭"</string>
+ <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"某个自动规则(<xliff:g id="ID_1">%s</xliff:g>)已开启勿扰模式。"</string>
+ <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"某个应用(<xliff:g id="ID_1">%s</xliff:g>)已开启勿扰模式。"</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"某个自动规则或应用已开启勿扰模式。"</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"在后台运行的应用"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"点按即可详细了解电量和流量消耗情况"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"要关闭移动数据网络吗?"</string>
@@ -708,6 +722,8 @@
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(工作)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"电话"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(通过“<xliff:g id="APPLICATION_NAME_S_">%s</xliff:g>”)"</string>
+ <string name="ongoing_privacy_dialog_attribution_label" msgid="3385241594101496292">"(<xliff:g id="ATTRIBUTION_LABEL">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_proxy_label" msgid="1111829599659403249">"(<xliff:g id="ATTRIBUTION_LABEL">%1$s</xliff:g> • <xliff:g id="PROXY_LABEL">%2$s</xliff:g>)"</string>
<string name="privacy_type_camera" msgid="7974051382167078332">"相机"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"位置信息"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"麦克风"</string>
@@ -806,6 +822,9 @@
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(已断开连接)"</string>
<string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"无法切换。点按即可重试。"</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"与新设备配对"</string>
+ <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"如需投射此会话,请打开相关应用。"</string>
+ <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"未知应用"</string>
+ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"停止投射"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"版本号"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"已将版本号复制到剪贴板。"</string>
<string name="basic_status" msgid="2315371112182658176">"开放式对话"</string>
@@ -839,6 +858,7 @@
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"查看近期的消息、未接电话和状态更新"</string>
<string name="people_tile_title" msgid="6589377493334871272">"对话"</string>
+ <string name="paused_by_dnd" msgid="7856941866433556428">"勿扰模式已暂停通知"</string>
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g>发送了一条消息:<xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g>发送了一张图片"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g>更新了状态:<xliff:g id="STATUS">%2$s</xliff:g>"</string>
@@ -877,8 +897,7 @@
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> 个使用中的应用</item>
<item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> 个使用中的应用</item>
</plurals>
- <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
- <skip />
+ <string name="fgs_dot_content_description" msgid="2865071539464777240">"新信息"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"使用中的应用"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"停止"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"已停止"</string>
@@ -886,14 +905,15 @@
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"已复制"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"来自<xliff:g id="APPNAME">%1$s</xliff:g>"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"关闭复制界面"</string>
- <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
- <skip />
- <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
- <skip />
- <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
- <skip />
- <!-- no translation found for add (81036585205287996) -->
- <skip />
- <!-- no translation found for manage_users (1823875311934643849) -->
- <skip />
+ <string name="clipboard_edit_text_description" msgid="805254383912962103">"修改所复制的文字"</string>
+ <string name="clipboard_edit_image_description" msgid="8904857948976041306">"编辑所复制的图片"</string>
+ <string name="clipboard_send_nearby_description" msgid="4629769637846717650">"发送到附近的设备"</string>
+ <string name="add" msgid="81036585205287996">"添加"</string>
+ <string name="manage_users" msgid="1823875311934643849">"管理用户"</string>
+ <string name="drag_split_not_supported" msgid="4326847447699729722">"此通知不支持拖动到分屏中。"</string>
+ <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"WLAN 已关闭"</string>
+ <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"优先模式"</string>
+ <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"闹钟已设置"</string>
+ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"摄像头和麦克风已关闭"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# 条通知}other{# 条通知}}"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index dbb4ffc85d38..718d5e1f7e5e 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -20,14 +20,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4811759950673118541">"系統使用者介面"</string>
- <string name="battery_low_title" msgid="6891106956328275225">"電池電量可能即將耗盡"</string>
+ <string name="battery_low_title" msgid="5319680173344341779">"要開啟「省電模式」嗎?"</string>
+ <string name="battery_low_description" msgid="3282977755476423966">"剩餘 <xliff:g id="PERCENTAGE">%s</xliff:g> 電量。「省電模式」會開啟深色主題背景、限制背景活動,並延遲顯示通知。"</string>
+ <string name="battery_low_intro" msgid="5148725009653088790">"「省電模式」會開啟深色主題背景、限制背景活動,並延遲顯示通知。"</string>
<string name="battery_low_percent_format" msgid="4276661262843170964">"剩餘 <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="invalid_charger_title" msgid="938685362320735167">"無法透過 USB 充電"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"使用裝置隨附的充電器"</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"要開啟省電模式嗎?"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"關於「省電模式」"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"開啟"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"開啟省電模式"</string>
+ <string name="battery_saver_start_action" msgid="8353766979886287140">"開啟"</string>
+ <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"不用了,謝謝"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"自動旋轉螢幕"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"要允許「<xliff:g id="APPLICATION">%1$s</xliff:g>」存取「<xliff:g id="USB_DEVICE">%2$s</xliff:g>」嗎?"</string>
<string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"要允許「<xliff:g id="APPLICATION">%1$s</xliff:g>」存取「<xliff:g id="USB_DEVICE">%2$s</xliff:g>」嗎?\n此應用程式尚未獲授予錄音權限,但可透過此 USB 裝置記錄音訊。"</string>
@@ -128,6 +131,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"臉孔已經驗證"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"已確認"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"輕按 [確定] 以完成"</string>
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"您已使用面孔解鎖。按下即可繼續操作。"</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"驗證咗"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"使用 PIN"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"使用圖案"</string>
@@ -181,6 +185,7 @@
<string name="accessibility_desc_close" msgid="8293708213442107755">"關閉"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"完全靜音"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"只限鬧鐘"</string>
+ <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"請勿騷擾。"</string>
<string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"藍牙。"</string>
<string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"藍牙已開啟。"</string>
<string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"鬧鐘已設定為:<xliff:g id="TIME">%s</xliff:g>。"</string>
@@ -205,6 +210,7 @@
<string name="dessert_case" msgid="9104973640704357717">"Dessert Case"</string>
<string name="start_dreams" msgid="9131802557946276718">"螢幕保護程式"</string>
<string name="ethernet_label" msgid="2203544727007463351">"以太網"</string>
+ <string name="quick_settings_dnd_label" msgid="7728690179108024338">"請勿騷擾"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"藍牙"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"找不到配對的裝置"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"電量:<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
@@ -348,6 +354,7 @@
<string name="notification_section_header_alerting" msgid="5581175033680477651">"通知"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"對話"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"清除所有靜音通知"</string>
+ <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"「請勿騷擾」模式已將通知暫停"</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"立即開始"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"沒有通知"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"此裝置由您的家長管理"</string>
@@ -452,8 +459,8 @@
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"解鎖即可使用"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"擷取資訊卡時發生問題,請稍後再試。"</string>
<string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"上鎖畫面設定"</string>
- <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR 碼"</string>
- <string name="qr_code_scanner_description" msgid="7937603775306661863">"輕按即可掃瞄"</string>
+ <!-- no translation found for qr_code_scanner_title (5290201053875420785) -->
+ <skip />
<string name="status_bar_work" msgid="5238641949837091056">"工作設定檔"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"飛行模式"</string>
<string name="zen_alarm_warning" msgid="7844303238486849503">"您不會<xliff:g id="WHEN">%1$s</xliff:g>聽到鬧鐘"</string>
@@ -491,6 +498,8 @@
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"&lt;b&gt;狀態:&lt;/b&gt;已調低次序"</string>
<string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"顯示在對話通知頂部 (在上鎖畫面會顯示為個人檔案相片)"</string>
<string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"以對話氣泡形式顯示在對話通知頂部 (在上鎖畫面會顯示為個人檔案相片)"</string>
+ <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"顯示在對話通知頂部 (在上鎖畫面會顯示為個人檔案相片),並會中斷「請勿打擾」模式"</string>
+ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"以對話氣泡形式顯示在對話通知頂部 (在上鎖畫面會顯示為個人檔案相片),並會中斷「請勿打擾」模式"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"優先"</string>
<string name="no_shortcut" msgid="8257177117568230126">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」不支援對話功能"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"無法修改這些通知。"</string>
@@ -566,6 +575,7 @@
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"短訊"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"音樂"</string>
<string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"日曆"</string>
+ <string name="volume_and_do_not_disturb" msgid="502044092739382832">"請勿騷擾"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"音量按鈕快速鍵"</string>
<string name="battery" msgid="769686279459897127">"電池"</string>
<string name="headset" msgid="4485892374984466437">"耳機"</string>
@@ -684,6 +694,10 @@
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>,<xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"Wi-Fi 已關閉"</string>
<string name="bt_is_off" msgid="7436344904889461591">"藍牙已關閉"</string>
+ <string name="dnd_is_off" msgid="3185706903793094463">"「請勿騷擾」已關閉"</string>
+ <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"「<xliff:g id="ID_1">%s</xliff:g>」自動規則已開啟「請勿騷擾」功能。"</string>
+ <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"「<xliff:g id="ID_1">%s</xliff:g>」應用程式已開啟「請勿騷擾」功能。"</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"某個自動規則或應用程式已開啟「請勿騷擾」功能。"</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"正在背景中執行的應用程式"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"輕按即可查看電池和數據用量詳情"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"要關閉流動數據嗎?"</string>
@@ -708,6 +722,8 @@
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(公司)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"電話"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(透過「<xliff:g id="APPLICATION_NAME_S_">%s</xliff:g>」)"</string>
+ <string name="ongoing_privacy_dialog_attribution_label" msgid="3385241594101496292">"(<xliff:g id="ATTRIBUTION_LABEL">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_proxy_label" msgid="1111829599659403249">"(<xliff:g id="ATTRIBUTION_LABEL">%1$s</xliff:g> • <xliff:g id="PROXY_LABEL">%2$s</xliff:g>)"</string>
<string name="privacy_type_camera" msgid="7974051382167078332">"相機"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"位置"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"麥克風"</string>
@@ -806,6 +822,9 @@
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(已中斷連線)"</string>
<string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"無法切換,輕按即可重試。"</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"配對新裝置"</string>
+ <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"如要投放此工作階段,請開啟應用程式。"</string>
+ <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"不明應用程式"</string>
+ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"停止投放"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"版本號碼"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"版本號碼已複製到剪貼簿。"</string>
<string name="basic_status" msgid="2315371112182658176">"開啟對話"</string>
@@ -839,6 +858,7 @@
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"查看最近的訊息、未接來電和狀態更新"</string>
<string name="people_tile_title" msgid="6589377493334871272">"對話"</string>
+ <string name="paused_by_dnd" msgid="7856941866433556428">"「請勿騷擾」已暫停通知"</string>
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g>傳送了訊息:<xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g>傳送了圖片"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g>有狀態更新:<xliff:g id="STATUS">%2$s</xliff:g>"</string>
@@ -877,8 +897,7 @@
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> 個使用中的應用程式</item>
<item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> 個使用中的應用程式</item>
</plurals>
- <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
- <skip />
+ <string name="fgs_dot_content_description" msgid="2865071539464777240">"新資料"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"使用中的應用程式"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"停止"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"已停止"</string>
@@ -886,14 +905,15 @@
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"已複製"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"來自「<xliff:g id="APPNAME">%1$s</xliff:g>」"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"關閉剪貼簿使用者介面"</string>
- <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
- <skip />
- <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
- <skip />
- <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
- <skip />
- <!-- no translation found for add (81036585205287996) -->
- <skip />
- <!-- no translation found for manage_users (1823875311934643849) -->
- <skip />
+ <string name="clipboard_edit_text_description" msgid="805254383912962103">"編輯已複製的文字"</string>
+ <string name="clipboard_edit_image_description" msgid="8904857948976041306">"編輯已複製的圖片"</string>
+ <string name="clipboard_send_nearby_description" msgid="4629769637846717650">"傳送至附近的裝置"</string>
+ <string name="add" msgid="81036585205287996">"新增"</string>
+ <string name="manage_users" msgid="1823875311934643849">"管理使用者"</string>
+ <string name="drag_split_not_supported" msgid="4326847447699729722">"此通知無法拖曳到分割螢幕中。"</string>
+ <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi 已關閉"</string>
+ <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"優先模式"</string>
+ <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"已設定鬧鐘"</string>
+ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"相機和麥克風已關閉"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# 則通知}other{# 則通知}}"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index d7185a489e4b..dcb74b30a6cd 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -20,14 +20,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4811759950673118541">"系統 UI"</string>
- <string name="battery_low_title" msgid="6891106956328275225">"電池電力可能很快就會耗盡"</string>
+ <string name="battery_low_title" msgid="5319680173344341779">"要開啟省電模式嗎?"</string>
+ <string name="battery_low_description" msgid="3282977755476423966">"電池電量還剩 <xliff:g id="PERCENTAGE">%s</xliff:g>。省電模式會開啟深色主題、限制背景活動,並延遲顯示通知。"</string>
+ <string name="battery_low_intro" msgid="5148725009653088790">"省電模式會開啟深色主題、限制背景活動,並延遲顯示通知。"</string>
<string name="battery_low_percent_format" msgid="4276661262843170964">"僅剩 <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="invalid_charger_title" msgid="938685362320735167">"無法透過 USB 充電"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"使用裝置隨附的充電器"</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"要開啟省電模式嗎?"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"關於省電模式"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"開啟"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"開啟省電模式"</string>
+ <string name="battery_saver_start_action" msgid="8353766979886287140">"開啟"</string>
+ <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"不用了,謝謝"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"自動旋轉螢幕"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"要允許「<xliff:g id="APPLICATION">%1$s</xliff:g>」存取「<xliff:g id="USB_DEVICE">%2$s</xliff:g>」嗎?"</string>
<string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"要允許「<xliff:g id="APPLICATION">%1$s</xliff:g>」存取「<xliff:g id="USB_DEVICE">%2$s</xliff:g>」嗎?\n這個應用程式未取得錄製權限,但可以透過這部 USB 裝置錄製音訊。"</string>
@@ -128,6 +131,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"臉孔驗證成功"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"確認完畢"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"輕觸 [確認] 完成驗證設定"</string>
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"你已用自己的臉解鎖裝置,按下即可繼續操作。"</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"已通過驗證"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"使用 PIN 碼"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"使用解鎖圖案"</string>
@@ -181,6 +185,7 @@
<string name="accessibility_desc_close" msgid="8293708213442107755">"關閉"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"完全靜音"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"僅限鬧鐘"</string>
+ <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"零打擾。"</string>
<string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"藍牙。"</string>
<string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"藍牙已開啟。"</string>
<string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"鬧鐘已設定為:<xliff:g id="TIME">%s</xliff:g>。"</string>
@@ -205,6 +210,7 @@
<string name="dessert_case" msgid="9104973640704357717">"Dessert Case"</string>
<string name="start_dreams" msgid="9131802557946276718">"螢幕保護程式"</string>
<string name="ethernet_label" msgid="2203544727007463351">"乙太網路"</string>
+ <string name="quick_settings_dnd_label" msgid="7728690179108024338">"零打擾"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"藍牙"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"找不到配對的裝置"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"電量:<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
@@ -348,6 +354,7 @@
<string name="notification_section_header_alerting" msgid="5581175033680477651">"通知"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"對話"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"清除所有靜音通知"</string>
+ <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"「零打擾」模式已將通知設為暫停"</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"立即開始"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"沒有通知"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"這個裝置是由你的家長管理"</string>
@@ -452,8 +459,8 @@
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"解鎖即可使用"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"擷取卡片時發生問題,請稍後再試"</string>
<string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"螢幕鎖定設定"</string>
- <string name="qr_code_scanner_title" msgid="5660820608548306581">"QR 圖碼"</string>
- <string name="qr_code_scanner_description" msgid="7937603775306661863">"輕觸即可掃描"</string>
+ <!-- no translation found for qr_code_scanner_title (5290201053875420785) -->
+ <skip />
<string name="status_bar_work" msgid="5238641949837091056">"工作資料夾"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"飛航模式"</string>
<string name="zen_alarm_warning" msgid="7844303238486849503">"你不會聽到下一個<xliff:g id="WHEN">%1$s</xliff:g> 的鬧鐘"</string>
@@ -491,6 +498,8 @@
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"&lt;b&gt;狀態:&lt;/b&gt;已調降順序"</string>
<string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"顯示在對話通知頂端 (螢幕鎖定時會顯示為個人資料相片)"</string>
<string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"以對話框的形式顯示在對話通知頂端 (螢幕鎖定時會顯示為個人資料相片)"</string>
+ <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"顯示在對話通知頂端 (螢幕鎖定時會顯示為個人資料相片),並會中斷「零打擾」模式"</string>
+ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"以對話框的形式顯示在對話通知頂端 (螢幕鎖定時會顯示為個人資料相片),並會中斷「零打擾」模式"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"優先"</string>
<string name="no_shortcut" msgid="8257177117568230126">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」不支援對話功能"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"無法修改這些通知。"</string>
@@ -566,6 +575,7 @@
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"簡訊"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"音樂"</string>
<string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"日曆"</string>
+ <string name="volume_and_do_not_disturb" msgid="502044092739382832">"零打擾"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"音量按鈕快速鍵"</string>
<string name="battery" msgid="769686279459897127">"電池"</string>
<string name="headset" msgid="4485892374984466437">"耳機"</string>
@@ -684,6 +694,10 @@
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>,<xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"Wi-Fi 已關閉"</string>
<string name="bt_is_off" msgid="7436344904889461591">"藍牙已關閉"</string>
+ <string name="dnd_is_off" msgid="3185706903793094463">"零打擾模式已關閉"</string>
+ <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"「<xliff:g id="ID_1">%s</xliff:g>」自動規則已將零打擾模式開啟。"</string>
+ <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"「<xliff:g id="ID_1">%s</xliff:g>」應用程式已將零打擾模式開啟。"</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"某個自動規則或應用程式已將零打擾模式開啟。"</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"在背景執行的應用程式"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"輕觸即可查看電池和數據用量詳情"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"要關閉行動數據嗎?"</string>
@@ -708,6 +722,8 @@
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(工作)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"電話"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(透過「<xliff:g id="APPLICATION_NAME_S_">%s</xliff:g>」)"</string>
+ <string name="ongoing_privacy_dialog_attribution_label" msgid="3385241594101496292">"(<xliff:g id="ATTRIBUTION_LABEL">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_proxy_label" msgid="1111829599659403249">"(<xliff:g id="ATTRIBUTION_LABEL">%1$s</xliff:g> • <xliff:g id="PROXY_LABEL">%2$s</xliff:g>)"</string>
<string name="privacy_type_camera" msgid="7974051382167078332">"相機"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"位置"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"麥克風"</string>
@@ -806,6 +822,9 @@
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(連線中斷)"</string>
<string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"無法切換,輕觸即可重試。"</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"配對新裝置"</string>
+ <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"如要投放這個工作階段,請開啟應用程式。"</string>
+ <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"不明的應用程式"</string>
+ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"停止投放"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"版本號碼"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"已將版本號碼複製到剪貼簿。"</string>
<string name="basic_status" msgid="2315371112182658176">"開放式對話"</string>
@@ -839,6 +858,7 @@
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"查看最近的訊息、未接來電和狀態更新"</string>
<string name="people_tile_title" msgid="6589377493334871272">"對話"</string>
+ <string name="paused_by_dnd" msgid="7856941866433556428">"零打擾模式已將通知暫停"</string>
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g>傳送了一則訊息:<xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g>傳送了一張圖片"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g>更新了狀態:<xliff:g id="STATUS">%2$s</xliff:g>"</string>
@@ -877,8 +897,7 @@
<item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> 個使用中的應用程式</item>
<item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> 個使用中的應用程式</item>
</plurals>
- <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
- <skip />
+ <string name="fgs_dot_content_description" msgid="2865071539464777240">"新資訊"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"使用中的應用程式"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"停止"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"已停止"</string>
@@ -886,14 +905,15 @@
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"已複製"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"來自「<xliff:g id="APPNAME">%1$s</xliff:g>」"</string>
<string name="clipboard_dismiss_description" msgid="7544573092766945657">"關閉剪貼簿 UI"</string>
- <!-- no translation found for clipboard_edit_text_description (805254383912962103) -->
- <skip />
- <!-- no translation found for clipboard_edit_image_description (8904857948976041306) -->
- <skip />
- <!-- no translation found for clipboard_send_nearby_description (4629769637846717650) -->
- <skip />
- <!-- no translation found for add (81036585205287996) -->
- <skip />
- <!-- no translation found for manage_users (1823875311934643849) -->
- <skip />
+ <string name="clipboard_edit_text_description" msgid="805254383912962103">"編輯複製的文字"</string>
+ <string name="clipboard_edit_image_description" msgid="8904857948976041306">"編輯複製的圖片"</string>
+ <string name="clipboard_send_nearby_description" msgid="4629769637846717650">"傳送到鄰近裝置"</string>
+ <string name="add" msgid="81036585205287996">"新增"</string>
+ <string name="manage_users" msgid="1823875311934643849">"管理使用者"</string>
+ <string name="drag_split_not_supported" msgid="4326847447699729722">"這項通知無法拖曳到分割畫面中。"</string>
+ <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi 已關閉"</string>
+ <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"優先模式"</string>
+ <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"鬧鐘設定成功"</string>
+ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"已關閉相機和麥克風"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# 則通知}other{# 則通知}}"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 5425b268ba7d..f26ef0efa126 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -20,14 +20,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4811759950673118541">"Uhlelo lwe-UI"</string>
- <string name="battery_low_title" msgid="6891106956328275225">"Ibhethri lingaphela maduze"</string>
+ <string name="battery_low_title" msgid="5319680173344341779">"Vula Isilondolozi Sebhethri?"</string>
+ <string name="battery_low_description" msgid="3282977755476423966">"Usele ngo-<xliff:g id="PERCENTAGE">%s</xliff:g> kwibhethri. Isilondolozi Sebhethri sivula itimu Emnyama, sikhawulela umsebenzi wangemuva, futhi sibambezele izaziso."</string>
+ <string name="battery_low_intro" msgid="5148725009653088790">"Isilondolozi Sebhethri sivula itimu Emnyama, sikhawulela umsebenzi wangemuva, futhi sibambezele izaziso."</string>
<string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> okusele"</string>
<string name="invalid_charger_title" msgid="938685362320735167">"Ayikwazi ukushaja nge-USB"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"Sebenzisa ishaja eze nedivayisi yakho"</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Vula isilondolozi sebhethri?"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Mayelana nesilondolozi sebhethri"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Vula"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"Vula isilondolozi sebhethri"</string>
+ <string name="battery_saver_start_action" msgid="8353766979886287140">"Vula"</string>
+ <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Cha ngiyabonga"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Ukuzulazula kweskrini okuzenzakalelayo"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"Vumela i-<xliff:g id="APPLICATION">%1$s</xliff:g> ukufinyelela i-<xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
<string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Vumela i-<xliff:g id="APPLICATION">%1$s</xliff:g> ukuthi ifinyelele ku-<xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nLolu hlelo lokusebenza alunikeziwe imvume yokurekhoda kodwa lingathatha umsindo ngale divayisi ye-USB."</string>
@@ -128,6 +131,7 @@
<string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Ubuso bufakazelwe ubuqiniso"</string>
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Kuqinisekisiwe"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Thepha okuthi Qinisekisa ukuze uqedele"</string>
+ <string name="biometric_dialog_tap_confirm_with_face" msgid="1597899891472340950">"Ivulwe ngobuso bakho. Cindezela ukuze uqhubeke."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Kugunyaziwe"</string>
<string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Sebenzisa iphinikhodi"</string>
<string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Sebenzisa iphethini"</string>
@@ -181,6 +185,7 @@
<string name="accessibility_desc_close" msgid="8293708213442107755">"Vala"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"ukuthula okuphelele"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"ama-alamu kuphela"</string>
+ <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"Ungaphazamisi"</string>
<string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"I-Bluetooth."</string>
<string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"I-Bluetooth ivuliwe."</string>
<string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"I-alamu isethiwe ngo-<xliff:g id="TIME">%s</xliff:g>."</string>
@@ -205,6 +210,7 @@
<string name="dessert_case" msgid="9104973640704357717">"Isikhwama soswidi"</string>
<string name="start_dreams" msgid="9131802557946276718">"Isigcini sihenqo"</string>
<string name="ethernet_label" msgid="2203544727007463351">"I-Ethernet"</string>
+ <string name="quick_settings_dnd_label" msgid="7728690179108024338">"Ungaphazamisi"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"I-Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Awekho amadivayisi abhanqiwe atholakalayo"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> ibhethri"</string>
@@ -348,6 +354,7 @@
<string name="notification_section_header_alerting" msgid="5581175033680477651">"Izaziso"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Izingxoxo"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Sula zonke izaziso ezithulile"</string>
+ <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Izaziso zimiswe okwesikhashana ukungaphazamisi"</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"Qala manje"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Azikho izaziso"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Le divayisi iphethwe ngumzali wakho"</string>
@@ -452,8 +459,8 @@
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Vula ukuze usebenzise"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"Kube khona inkinga yokuthola amakhadi akho, sicela uzame futhi ngemuva kwesikhathi"</string>
<string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Amasethingi okukhiya isikrini"</string>
- <string name="qr_code_scanner_title" msgid="5660820608548306581">"Ikhodi ye-QR"</string>
- <string name="qr_code_scanner_description" msgid="7937603775306661863">"Thepha ukuze uskene"</string>
+ <!-- no translation found for qr_code_scanner_title (5290201053875420785) -->
+ <skip />
<string name="status_bar_work" msgid="5238641949837091056">"Iphrofayela yomsebenzi"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Imodi yendiza"</string>
<string name="zen_alarm_warning" msgid="7844303238486849503">"Ngeke uzwe i-alamu yakho elandelayo ngo-<xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -491,6 +498,8 @@
<string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"&lt;b&gt;Isimo:&lt;/b&gt; Silinganiselwe phansi"</string>
<string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"Ivela phezu kwezaziso zengxoxo nanjengesithombe sephrofayela esikrinini sokukhiya"</string>
<string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"Ivela phezu kwezaziso zengxoxo futhi njengesithombe sephrofayela esikrinini sokukhiya, ivela njengebhamuza"</string>
+ <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"Ivela phezu kwezaziso zengxoxo futhi njengesithombe sephrofayela esikrinini sokukhiya, ukuphazamisa okuthi Ungaphazamisi"</string>
+ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Ivela phezu kwezaziso zengxoxo futhi njengesithombe sephrofayela esikrinini sokukhiya, ivela njengebhamuza, ukuphazamisa okuthi Ungaphazamisi"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Okubalulekile"</string>
<string name="no_shortcut" msgid="8257177117568230126">"I-<xliff:g id="APP_NAME">%1$s</xliff:g> ayisekeli izici zengxoxo"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Lezi zaziso azikwazi ukushintshwa."</string>
@@ -566,6 +575,7 @@
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"I-SMS"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"Umculo"</string>
<string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Ikhalenda"</string>
+ <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Ungaphazamisi"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"Izinqamuleli zezinkinobho zevolomu"</string>
<string name="battery" msgid="769686279459897127">"Ibhethri"</string>
<string name="headset" msgid="4485892374984466437">"Ama-earphone"</string>
@@ -684,6 +694,10 @@
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"I-<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"I-Wi-Fi ivaliwe"</string>
<string name="bt_is_off" msgid="7436344904889461591">"I-Bluetooth ivaliwe"</string>
+ <string name="dnd_is_off" msgid="3185706903793094463">"Ungaphazamisi kuvaliwe"</string>
+ <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"Okuthi ungaphazamisi kuvulwe umthetho ozenzakalelayo (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"Okuthi ungaphazamisi kuvulwe uhlelo lokusebenza (<xliff:g id="ID_1">%s</xliff:g>)."</string>
+ <string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"Okuthi ungaphazamisi kuvulwe umthetho ozenzakalelayo noma uhlelo lokusebenza."</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"Izinhlelo zokusebenza zisebenza ngasemuva"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"Thepha ngemininingwane ekusetshenzisweni kwebhethri nedatha"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Vala idatha yeselula?"</string>
@@ -708,6 +722,8 @@
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(umsebenzi)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"Ikholi yefoni"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(kuya ku-<xliff:g id="APPLICATION_NAME_S_">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_label" msgid="3385241594101496292">"(<xliff:g id="ATTRIBUTION_LABEL">%s</xliff:g>)"</string>
+ <string name="ongoing_privacy_dialog_attribution_proxy_label" msgid="1111829599659403249">"(<xliff:g id="ATTRIBUTION_LABEL">%1$s</xliff:g> • <xliff:g id="PROXY_LABEL">%2$s</xliff:g>)"</string>
<string name="privacy_type_camera" msgid="7974051382167078332">"ikhamera"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"indawo"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"imakrofoni"</string>
@@ -806,6 +822,9 @@
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(inqamukile)"</string>
<string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Akukwazi ukushintsha. Thepha ukuze uzame futhi."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Bhangqa idivayisi entsha"</string>
+ <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Ukuze usakaze le seshini, sicela uvule i-app."</string>
+ <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"I-app engaziwa"</string>
+ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Misa ukusakaza"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Yakha inombolo"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Yakha inombolo ekopishelwe kubhodi yokunamathisela."</string>
<string name="basic_status" msgid="2315371112182658176">"Vula ingxoxo"</string>
@@ -839,6 +858,7 @@
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"Bona imiyalezo yakamuva, amakholi akuphuthile, nezibuyekezo zesimo"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Ingxoxo"</string>
+ <string name="paused_by_dnd" msgid="7856941866433556428">"Kumiswe okuthi Ungaphazamisi"</string>
<string name="new_notification_text_content_description" msgid="2915029960094389291">"U-<xliff:g id="NAME">%1$s</xliff:g> uthumele umlayezo: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"U-<xliff:g id="NAME">%1$s</xliff:g> uthumele isithombe"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"U-<xliff:g id="NAME">%1$s</xliff:g> unesibuyekezo sesimo: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
@@ -877,8 +897,7 @@
<item quantity="one">ama-app asebenzayo angu-<xliff:g id="COUNT_1">%s</xliff:g></item>
<item quantity="other">ama-app asebenzayo angu-<xliff:g id="COUNT_1">%s</xliff:g></item>
</plurals>
- <!-- no translation found for fgs_dot_content_description (2865071539464777240) -->
- <skip />
+ <string name="fgs_dot_content_description" msgid="2865071539464777240">"Ulwazi olusha"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Ama-app asebenzayo"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Misa"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Imisiwe"</string>
@@ -889,8 +908,12 @@
<string name="clipboard_edit_text_description" msgid="805254383912962103">"Hlela umbhalo okopishiwe"</string>
<string name="clipboard_edit_image_description" msgid="8904857948976041306">"Hlela umfanekiso okopishiwe"</string>
<string name="clipboard_send_nearby_description" msgid="4629769637846717650">"Thumela kudivayisi eseduze"</string>
- <!-- no translation found for add (81036585205287996) -->
- <skip />
- <!-- no translation found for manage_users (1823875311934643849) -->
- <skip />
+ <string name="add" msgid="81036585205287996">"Faka"</string>
+ <string name="manage_users" msgid="1823875311934643849">"Phatha abasebenzisi"</string>
+ <string name="drag_split_not_supported" msgid="4326847447699729722">"Lesi saziso asikusekeli ukuhudulela ku-Splitscreen."</string>
+ <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"I-Wi-Fi ayitholakali"</string>
+ <string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Imodi ebalulekile"</string>
+ <string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"I-alamu isethiwe"</string>
+ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Ikhamera nemakrofoni kuvaliwe"</string>
+ <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{Isaziso esingu-#}one{Izaziso ezingu-#}other{Izaziso ezingu-#}}"</string>
</resources>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index dc7470081da2..49fc8482712a 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -52,7 +52,7 @@
(e.g. cannot be switched to) -->
<color name="kg_user_switcher_restricted_avatar_icon_color">@color/GM2_grey_600</color>
<!-- Color of background circle of user avatars in keyguard user switcher -->
- <color name="kg_user_switcher_avatar_background">?android:attr/colorBackgroundFloating</color>
+ <color name="user_avatar_color_bg">?android:attr/colorBackgroundFloating</color>
<!-- Icon color for user avatars in user switcher quick settings -->
<color name="qs_user_switcher_avatar_icon_color">#3C4043</color>
@@ -176,10 +176,12 @@
<!-- media output dialog-->
<color name="media_dialog_background" android:lstar="98">@color/material_dynamic_neutral90</color>
- <color name="media_dialog_active_item_main_content">@color/material_dynamic_primary10</color>
- <color name="media_dialog_inactive_item_main_content">@color/material_dynamic_primary40</color>
- <color name="media_dialog_item_status">@color/material_dynamic_primary10</color>
+ <color name="media_dialog_item_main_content">@color/material_dynamic_primary20</color>
<color name="media_dialog_item_background">@color/material_dynamic_secondary95</color>
+ <color name="media_dialog_connected_item_background">@color/material_dynamic_primary90</color>
+ <color name="media_dialog_seekbar_progress">@color/material_dynamic_secondary40</color>
+ <color name="media_dialog_button_background">@color/material_dynamic_primary40</color>
+ <color name="media_dialog_solid_button_text">@color/material_dynamic_neutral95</color>
<!-- controls -->
<color name="control_primary_text">#E6FFFFFF</color>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index a0a876825a6f..9ea361892b32 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -707,4 +707,18 @@
<integer name="complicationFadeInMs">500</integer>
<integer name="complicationRestoreMs">1000</integer>
+
+ <!-- Icons that don't show in a collapsed non-keyguard statusbar -->
+ <string-array name="config_collapsed_statusbar_icon_blocklist" translatable="false">
+ <item>@*android:string/status_bar_volume</item>
+ <item>@*android:string/status_bar_alarm_clock</item>
+ <item>@*android:string/status_bar_call_strength</item>
+ </string-array>
+
+ <!-- Icons that don't show in a collapsed statusbar on keyguard -->
+ <string-array name="config_keyguard_statusbar_icon_blocklist" translatable="false">
+ <item>@*android:string/status_bar_volume</item>
+ <item>@*android:string/status_bar_alarm_clock</item>
+ <item>@*android:string/status_bar_call_strength</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 5a7efca3dece..8f4e11527d95 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -139,7 +139,7 @@
<!-- Height of a heads up notification in the status bar -->
<dimen name="notification_max_heads_up_height_increased">188dp</dimen>
- <!-- Side padding on the lockscreen on the side of notifications -->
+ <!-- Side padding on the side of notifications -->
<dimen name="notification_side_paddings">16dp</dimen>
<!-- padding between the heads up and the statusbar -->
@@ -941,6 +941,9 @@
<!-- Three privacy items. This value must not be exceeded -->
<dimen name="ongoing_appops_chip_max_width">76dp</dimen>
<dimen name="ongoing_appops_dot_diameter">6dp</dimen>
+ <dimen name="ongoing_appops_chip_min_animation_width">10dp</dimen>
+ <dimen name="ongoing_appops_chip_animation_in_status_bar_translation_x">15dp</dimen>
+ <dimen name="ongoing_appops_chip_animation_out_status_bar_translation_x">7dp</dimen>
<!-- Total minimum padding to enforce to ensure that the dot can always show -->
<dimen name="ongoing_appops_dot_min_padding">20dp</dimen>
@@ -979,6 +982,11 @@
<dimen name="qs_media_session_disabled_seekbar_vertical_padding">16dp</dimen>
<dimen name="qs_media_session_height_expanded">184dp</dimen>
<dimen name="qs_media_session_height_collapsed">128dp</dimen>
+ <dimen name="qs_media_seekbar_progress_wavelength">20dp</dimen>
+ <dimen name="qs_media_seekbar_progress_amplitude">1.5dp</dimen>
+ <dimen name="qs_media_seekbar_progress_phase">8dp</dimen>
+ <dimen name="qs_media_seekbar_progress_stroke_width">2dp</dimen>
+ <dimen name="qs_media_session_collapsed_guideline">144dp</dimen>
<!-- Size of Smartspace media recommendations cards in the QSPanel carousel -->
<dimen name="qs_aa_media_rec_album_size_collapsed">72dp</dimen>
@@ -1000,6 +1008,9 @@
<!-- Media tap-to-transfer chip for receiver device -->
<dimen name="media_ttt_chip_size_receiver">100dp</dimen>
<dimen name="media_ttt_icon_size_receiver">95dp</dimen>
+ <!-- Since the generic icon isn't circular, we need to scale it down so it still fits within
+ the circular chip. -->
+ <dimen name="media_ttt_generic_icon_size_receiver">70dp</dimen>
<!-- Window magnification -->
<dimen name="magnification_border_drag_size">35dp</dimen>
@@ -1122,13 +1133,46 @@
<dimen name="media_output_dialog_title_anim_y_delta">12.5dp</dimen>
<dimen name="media_output_dialog_app_tier_icon_size">20dp</dimen>
- <!-- Distance that the full shade transition takes in order for qs to fully transition to the
- shade -->
- <dimen name="lockscreen_shade_qs_transition_distance">200dp</dimen>
+ <!-- Distance that the full shade transition takes in order to complete by tapping on a button
+ like "expand". -->
+ <dimen name="lockscreen_shade_transition_by_tap_distance">200dp</dimen>
+
+ <!-- Distance that the full shade transition takes in order to complete. -->
+ <dimen name="lockscreen_shade_full_transition_distance">80dp</dimen>
<!-- Distance that the full shade transition takes in order for scrim to fully transition to
the shade (in alpha) -->
- <dimen name="lockscreen_shade_scrim_transition_distance">80dp</dimen>
+ <dimen name="lockscreen_shade_scrim_transition_distance">@dimen/lockscreen_shade_full_transition_distance</dimen>
+
+ <!-- Distance that it takes in order for the notifications scrim fade in to start. -->
+ <dimen name="lockscreen_shade_notifications_scrim_transition_delay">0dp</dimen>
+
+ <!-- Distance that it takes for the notifications scrim to fully fade if after it started. -->
+ <dimen name="lockscreen_shade_notifications_scrim_transition_distance">@dimen/lockscreen_shade_scrim_transition_distance</dimen>
+
+ <!-- Distance that the full shade transition takes in order for the keyguard content on
+ NotificationPanelViewController to fully fade (e.g. Clock & Smartspace) -->
+ <dimen name="lockscreen_shade_npvc_keyguard_content_alpha_transition_distance">@dimen/lockscreen_shade_full_transition_distance</dimen>
+
+ <!-- Distance that the full shade transition takes in order for the notification shelf to fully
+ expand. -->
+ <dimen name="lockscreen_shade_notif_shelf_transition_distance">@dimen/lockscreen_shade_full_transition_distance</dimen>
+
+ <!-- Distance that the full shade transition takes in order for the Quick Settings to fully
+ fade and expand. -->
+ <dimen name="lockscreen_shade_qs_transition_distance">@dimen/lockscreen_shade_full_transition_distance</dimen>
+
+ <!-- Distance that the full shade transition takes in order for depth of the wallpaper to fully
+ change. -->
+ <dimen name="lockscreen_shade_depth_controller_transition_distance">@dimen/lockscreen_shade_full_transition_distance</dimen>
+
+ <!-- Distance that the full shade transition takes in order for the UDFPS Keyguard View to fully
+ fade. -->
+ <dimen name="lockscreen_shade_udfps_keyguard_transition_distance">@dimen/lockscreen_shade_full_transition_distance</dimen>
+
+ <!-- Used for StatusBar to know that a transition is in progress. At the moment it only checks
+ whether the progress is > 0, therefore this value is not very important. -->
+ <dimen name="lockscreen_shade_status_bar_transition_distance">@dimen/lockscreen_shade_full_transition_distance</dimen>
<!-- Distance that the full shade transition takes in order for media to fully transition to
the shade -->
@@ -1335,9 +1379,6 @@
<dimen name="dream_overlay_status_icon_margin">8dp</dimen>
<dimen name="dream_overlay_status_bar_icon_size">
@*android:dimen/status_bar_system_icon_size</dimen>
- <!-- Height of the area at the top of the dream overlay to allow dragging down the notifications
- shade. -->
- <dimen name="dream_overlay_notifications_drag_area_height">100dp</dimen>
<dimen name="dream_overlay_camera_mic_off_indicator_size">8dp</dimen>
<dimen name="dream_overlay_notification_indicator_size">6dp</dimen>
@@ -1347,6 +1388,7 @@
<dimen name="dream_overlay_complication_weather_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>
<!-- The position of the end guide, which dream overlay complications can align their start with
if their end is aligned with the parent end. Represented as the percentage over from the
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 9e1f57bbfa75..6dc6214fec65 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -66,7 +66,10 @@
<string name="battery_saver_confirmation_ok">Turn on</string>
<!-- Battery saver notification action [CHAR LIMIT=NONE]-->
- <string name="battery_saver_start_action">Turn on Battery Saver</string>
+ <string name="battery_saver_start_action">Turn on</string>
+
+ <!-- Battery saver notification dismiss action: Do not turn on battery saver. [CHAR LIMIT=NONE]-->
+ <string name="battery_saver_dismiss_action">No thanks</string>
<!-- Name of the button that links to the Settings app. [CHAR LIMIT=NONE] -->
@@ -1190,10 +1193,7 @@
<string name="wallet_lockscreen_settings_label">Lock screen settings</string>
<!-- QR Code Scanner label, title [CHAR LIMIT=32] -->
- <string name="qr_code_scanner_title">QR code</string>
-
- <!-- QR Code Scanner description [CHAR LIMIT=NONE] -->
- <string name="qr_code_scanner_description">Tap to scan</string>
+ <string name="qr_code_scanner_title">Scan QR code</string>
<!-- Name of the work status bar icon. -->
<string name="status_bar_work">Work profile</string>
@@ -2184,7 +2184,7 @@
<!-- Text informing the user that their media is now playing on this device. [CHAR LIMIT=50] -->
<string name="media_transfer_playing_this_device">Playing on this phone</string>
<!-- Text informing the user that the media transfer has failed because something went wrong. [CHAR LIMIT=50] -->
- <string name="media_transfer_failed">Something went wrong</string>
+ <string name="media_transfer_failed">Something went wrong. Try again.</string>
<!-- Error message indicating that a control timed out while waiting for an update [CHAR_LIMIT=30] -->
<string name="controls_error_timeout">Inactive, check app</string>
@@ -2223,6 +2223,8 @@
<string name="media_output_dialog_launch_app_text">To cast this session, please open the app.</string>
<!-- App name when can't get app name [CHAR LIMIT=60] -->
<string name="media_output_dialog_unknown_launch_app_name">Unknown app</string>
+ <!-- Button text for stopping casting [CHAR LIMIT=60] -->
+ <string name="media_output_dialog_button_stop_casting">Stop casting</string>
<!-- Label for clip data when copying the build number off QS [CHAR LIMIT=NONE]-->
@@ -2425,8 +2427,6 @@
<string name="dream_overlay_status_bar_priority_mode">Priority mode</string>
<!-- Content description for the alarm set icon in the dream overlay status bar [CHAR LIMIT=NONE] -->
<string name="dream_overlay_status_bar_alarm_set">Alarm set</string>
- <!-- Content description for the assistant guest mode enabled icon in the dream overlay status bar [CHAR LIMIT=NONE] -->
- <string name="dream_overlay_status_bar_assistant_guest_mode_enabled">Assistant guest mode enabled</string>
<!-- Content description for the camera and mic off icon in the dream overlay status bar [CHAR LIMIT=NONE] -->
<string name="dream_overlay_status_bar_camera_mic_off">Camera and mic are off</string>
<!-- Content description for the notifications indicator icon in the dream overlay status bar [CHAR LIMIT=NONE] -->
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index f2eaa75496e8..f5c1382b9ae9 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -486,7 +486,7 @@
<style name="MediaOutputItemInactiveTitle">
<item name="android:textSize">16sp</item>
- <item name="android:textColor">@color/media_dialog_inactive_item_main_content</item>
+ <item name="android:textColor">@color/media_dialog_item_main_content</item>
</style>
<style name="TunerSettings" parent="@android:style/Theme.DeviceDefault.Settings">
@@ -590,6 +590,7 @@
<style name="MediaPlayer.ProgressBar" parent="@android:style/Widget.ProgressBar.Horizontal">
<item name="android:thumbTint">?android:attr/textColorPrimary</item>
+ <item name="android:progressDrawable">@drawable/media_squiggly_progress</item>
<item name="android:progressTint">?android:attr/textColorPrimary</item>
<item name="android:progressBackgroundTint">?android:attr/textColorTertiary</item>
<item name="android:clickable">true</item>
diff --git a/packages/SystemUI/res/xml/media_session_collapsed.xml b/packages/SystemUI/res/xml/media_session_collapsed.xml
index c6e18a6f8740..f00e03116337 100644
--- a/packages/SystemUI/res/xml/media_session_collapsed.xml
+++ b/packages/SystemUI/res/xml/media_session_collapsed.xml
@@ -19,6 +19,13 @@
xmlns:app="http://schemas.android.com/apk/res-auto">
<Constraint
+ android:id="@+id/media_action_barrier"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ app:layout_constraintTop_toBottomOf="@id/media_seamless"
+ app:layout_constraintStart_toEndOf="@id/action_button_guideline" />
+
+ <Constraint
android:id="@+id/album_art"
android:layout_width="match_parent"
android:layout_height="@dimen/qs_media_session_height_collapsed"
@@ -28,33 +35,73 @@
app:layout_constraintBottom_toBottomOf="parent" />
<Constraint
+ android:id="@+id/header_title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="20dp"
+ android:layout_marginStart="@dimen/qs_media_padding"
+ android:layout_marginEnd="@dimen/qs_media_padding"
+ app:layout_constraintEnd_toStartOf="@id/action_button_guideline"
+ app:layout_constrainedWidth="true"
+ app:layout_constraintTop_toBottomOf="@id/icon"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintHorizontal_bias="0" />
+ <Constraint
+ android:id="@+id/header_artist"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="@dimen/qs_media_padding"
+ android:layout_marginTop="0dp"
+ app:layout_constraintEnd_toStartOf="@id/action_button_guideline"
+ app:layout_constrainedWidth="true"
+ app:layout_constraintTop_toBottomOf="@id/header_title"
+ app:layout_constraintStart_toStartOf="@id/header_title"
+ app:layout_constraintVertical_bias="0"
+ app:layout_constraintHorizontal_bias="0" />
+
+ <Constraint
android:id="@+id/actionPlayPause"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_marginEnd="@dimen/qs_media_padding"
- app:layout_constraintStart_toEndOf="@id/actionEnd"
+ android:layout_marginBottom="@dimen/qs_media_padding"
+ app:layout_constraintVertical_bias="1"
app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/media_seamless"
- app:layout_constraintBottom_toBottomOf="parent" />
+ app:layout_constraintStart_toEndOf="@id/media_action_barrier_end" />
+ <!--
+ There will only be 3 action buttons shown at most in this layout (controlled in code).
+ Play/Pause should always be at the end, but the other buttons should remain in the same order
+ when in RTL.
+ This is accomplished by setting two barriers at the start and end of the small buttons,
+ anchored to a guideline set at 3x button width from the end. The text and play/pause button are
+ positioned relative to the barriers, and the small buttons use right/left constraints to stay
+ in the correct order inside the barriers.
+ -->
<Constraint
android:id="@+id/actionPrev"
android:layout_width="48dp"
android:layout_height="48dp"
+ android:layout_marginBottom="@dimen/qs_media_padding"
app:layout_constraintHorizontal_bias="1"
+ app:layout_constraintVertical_bias="1"
app:layout_constraintHorizontal_chainStyle="packed"
- app:layout_constraintStart_toEndOf="@id/header_artist"
- app:layout_constraintEnd_toStartOf="@id/media_progress_bar"
+ app:layout_constraintRight_toLeftOf="@id/media_progress_bar"
app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintTop_toBottomOf="@id/media_seamless" />
+ app:layout_constraintTop_toBottomOf="@id/media_seamless"
+ app:layout_constraintLeft_toRightOf="@id/media_action_barrier" />
<Constraint
android:id="@+id/media_progress_bar"
android:layout_width="0dp"
android:layout_height="wrap_content"
+ android:layout_marginBottom="@dimen/qs_media_padding"
android:visibility="gone"
- app:layout_constraintStart_toEndOf="@id/actionPrev"
- app:layout_constraintEnd_toStartOf="@id/actionNext"
+ app:layout_constraintVertical_bias="1"
+ app:layout_constraintLeft_toRightOf="@id/actionPrev"
+ app:layout_constraintRight_toLeftOf="@id/actionNext"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/media_seamless" />
@@ -62,29 +109,70 @@
android:id="@+id/actionNext"
android:layout_width="48dp"
android:layout_height="48dp"
- app:layout_constraintStart_toEndOf="@id/media_progress_bar"
- app:layout_constraintEnd_toStartOf="@id/actionStart"
+ android:layout_marginBottom="@dimen/qs_media_padding"
+ app:layout_constraintVertical_bias="1"
+ app:layout_constraintLeft_toRightOf="@id/media_progress_bar"
+ app:layout_constraintRight_toLeftOf="@id/action0"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/media_seamless" />
+
+ <Constraint
+ android:id="@+id/action0"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:layout_marginBottom="@dimen/qs_media_padding"
+ android:visibility="gone"
+ app:layout_constraintVertical_bias="1"
+ app:layout_constraintLeft_toRightOf="@id/actionNext"
+ app:layout_constraintRight_toLeftOf="@id/action1"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/media_seamless" />
+
+ <Constraint
+ android:id="@+id/action1"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:layout_marginBottom="@dimen/qs_media_padding"
+ android:visibility="gone"
+ app:layout_constraintVertical_bias="1"
+ app:layout_constraintLeft_toRightOf="@id/action0"
+ app:layout_constraintRight_toLeftOf="@id/action2"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/media_seamless" />
<Constraint
- android:id="@+id/actionStart"
+ android:id="@+id/action2"
android:layout_width="48dp"
android:layout_height="48dp"
+ android:layout_marginBottom="@dimen/qs_media_padding"
android:visibility="gone"
- app:layout_constraintStart_toEndOf="@id/actionNext"
- app:layout_constraintEnd_toStartOf="@id/actionEnd"
+ app:layout_constraintVertical_bias="1"
+ app:layout_constraintLeft_toRightOf="@id/action1"
+ app:layout_constraintRight_toLeftOf="@id/action3"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/media_seamless" />
<Constraint
- android:id="@+id/actionEnd"
+ android:id="@+id/action3"
android:layout_width="48dp"
android:layout_height="48dp"
+ android:layout_marginBottom="@dimen/qs_media_padding"
android:visibility="gone"
- app:layout_constraintStart_toEndOf="@id/actionStart"
- app:layout_constraintEnd_toStartOf="@id/actionPlayPause"
+ app:layout_constraintVertical_bias="1"
+ app:layout_constraintLeft_toRightOf="@id/action2"
+ app:layout_constraintRight_toLeftOf="@id/action4"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/media_seamless" />
-</ConstraintSet> \ No newline at end of file
+ <Constraint
+ android:id="@+id/action4"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:layout_marginBottom="@dimen/qs_media_padding"
+ android:visibility="gone"
+ app:layout_constraintVertical_bias="1"
+ app:layout_constraintLeft_toRightOf="@id/action3"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/media_seamless"
+ app:layout_constraintRight_toLeftOf="@id/media_action_barrier_end" />
+</ConstraintSet>
diff --git a/packages/SystemUI/res/xml/media_session_expanded.xml b/packages/SystemUI/res/xml/media_session_expanded.xml
index 18ec7aa4cab4..10da70447ec0 100644
--- a/packages/SystemUI/res/xml/media_session_expanded.xml
+++ b/packages/SystemUI/res/xml/media_session_expanded.xml
@@ -28,57 +28,118 @@
app:layout_constraintBottom_toBottomOf="parent" />
<Constraint
+ android:id="@+id/header_title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="20dp"
+ android:layout_marginStart="@dimen/qs_media_padding"
+ android:layout_marginEnd="@dimen/qs_media_padding"
+ app:layout_constraintEnd_toStartOf="@id/actionPlayPause"
+ app:layout_constrainedWidth="true"
+ app:layout_constraintTop_toBottomOf="@id/icon"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintHorizontal_bias="0" />
+ <Constraint
+ android:id="@+id/header_artist"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="@dimen/qs_media_padding"
+ android:layout_marginTop="0dp"
+ app:layout_constrainedWidth="true"
+ app:layout_constraintEnd_toStartOf="@id/actionPlayPause"
+ app:layout_constraintBottom_toTopOf="@id/media_action_barrier"
+ app:layout_constraintTop_toBottomOf="@id/header_title"
+ app:layout_constraintStart_toStartOf="@id/header_title"
+ app:layout_constraintVertical_bias="0"
+ app:layout_constraintHorizontal_bias="0" />
+
+ <Constraint
android:id="@+id/actionPlayPause"
android:layout_width="48dp"
android:layout_height="48dp"
+ android:layout_marginStart="@dimen/qs_media_padding"
android:layout_marginEnd="@dimen/qs_media_padding"
+ android:layout_marginBottom="0dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/media_seamless"
- app:layout_constraintBottom_toTopOf="@id/actionEnd" />
+ app:layout_constraintBottom_toBottomOf="@id/header_artist" />
+ <!--
+ The bottom row of action buttons should remain in the same order when RTL, so their constraints
+ are set with right/left instead of start/end.
+ The chain is set to "spread" so that the progress bar can be weighted to fill any empty space.
+ -->
<Constraint
android:id="@+id/actionPrev"
android:layout_width="48dp"
android:layout_height="48dp"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintEnd_toStartOf="@id/media_progress_bar"
+ app:layout_constraintLeft_toLeftOf="parent"
+ app:layout_constraintRight_toLeftOf="@id/media_progress_bar"
app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintTop_toBottomOf="@id/actionPlayPause" />
+ app:layout_constraintTop_toBottomOf="@id/header_artist"
+ app:layout_constraintHorizontal_chainStyle="spread" />
<Constraint
android:id="@+id/media_progress_bar"
android:layout_width="0dp"
- android:layout_height="wrap_content"
- app:layout_constraintStart_toEndOf="@id/actionPrev"
- app:layout_constraintEnd_toStartOf="@id/actionNext"
+ android:layout_height="48dp"
+ app:layout_constraintLeft_toRightOf="@id/actionPrev"
+ app:layout_constraintRight_toLeftOf="@id/actionNext"
app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintTop_toBottomOf="@id/actionPlayPause" />
+ app:layout_constraintTop_toBottomOf="@id/header_artist"
+ app:layout_constraintHorizontal_weight="1" />
<Constraint
android:id="@+id/actionNext"
android:layout_width="48dp"
android:layout_height="48dp"
- app:layout_constraintStart_toEndOf="@id/media_progress_bar"
- app:layout_constraintEnd_toStartOf="@id/actionStart"
+ app:layout_constraintLeft_toRightOf="@id/media_progress_bar"
+ app:layout_constraintRight_toLeftOf="@id/action0"
app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintTop_toBottomOf="@id/actionPlayPause" />
+ app:layout_constraintTop_toBottomOf="@id/header_artist" />
<Constraint
- android:id="@+id/actionStart"
+ android:id="@+id/action0"
android:layout_width="48dp"
android:layout_height="48dp"
- app:layout_constraintStart_toEndOf="@id/actionNext"
- app:layout_constraintEnd_toStartOf="@id/actionEnd"
+ app:layout_constraintLeft_toRightOf="@id/actionNext"
+ app:layout_constraintRight_toLeftOf="@id/action1"
app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintTop_toBottomOf="@id/actionPlayPause" />
+ app:layout_constraintTop_toBottomOf="@id/header_artist" />
<Constraint
- android:id="@+id/actionEnd"
+ android:id="@+id/action1"
android:layout_width="48dp"
android:layout_height="48dp"
- app:layout_constraintStart_toEndOf="@id/actionStart"
- app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintLeft_toRightOf="@id/action0"
+ app:layout_constraintRight_toLeftOf="@id/action2"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/header_artist" />
+
+ <Constraint
+ android:id="@+id/action2"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ app:layout_constraintLeft_toRightOf="@id/action1"
+ app:layout_constraintRight_toLeftOf="@id/action3"
app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintTop_toBottomOf="@id/actionPlayPause" />
+ app:layout_constraintTop_toBottomOf="@id/header_artist" />
-</ConstraintSet> \ No newline at end of file
+ <Constraint
+ android:id="@+id/action3"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ app:layout_constraintLeft_toRightOf="@id/action2"
+ app:layout_constraintRight_toLeftOf="@id/action4"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/header_artist" />
+
+ <Constraint
+ android:id="@+id/action4"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ app:layout_constraintLeft_toRightOf="@id/action3"
+ app:layout_constraintRight_toRightOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/header_artist" />
+</ConstraintSet>
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/UiBackground.java b/packages/SystemUI/shared/src/com/android/systemui/dagger/qualifiers/UiBackground.java
index bf2237aa8c11..bf2237aa8c11 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/UiBackground.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/dagger/qualifiers/UiBackground.java
diff --git a/packages/SystemUI/shared/src/com/android/systemui/flags/Flag.kt b/packages/SystemUI/shared/src/com/android/systemui/flags/Flag.kt
index 6ad91612f99b..19a53091b35c 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/flags/Flag.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/flags/Flag.kt
@@ -24,6 +24,7 @@ import android.os.Parcelable
interface Flag<T> {
val id: Int
+ val teamfood: Boolean
}
interface ParcelableFlag<T> : Flag<T>, Parcelable {
@@ -44,7 +45,8 @@ interface SysPropFlag<T> : Flag<T> {
data class BooleanFlag @JvmOverloads constructor(
override val id: Int,
- override val default: Boolean = false
+ override val default: Boolean = false,
+ override val teamfood: Boolean = false
) : ParcelableFlag<Boolean> {
companion object {
@@ -66,20 +68,25 @@ data class BooleanFlag @JvmOverloads constructor(
}
}
-data class ResourceBooleanFlag constructor(
+data class ResourceBooleanFlag @JvmOverloads constructor(
override val id: Int,
- @BoolRes override val resourceId: Int
+ @BoolRes override val resourceId: Int,
+ override val teamfood: Boolean = false
) : ResourceFlag<Boolean>
-data class SysPropBooleanFlag constructor(
+data class SysPropBooleanFlag @JvmOverloads constructor(
override val id: Int,
override val name: String,
override val default: Boolean = false
-) : SysPropFlag<Boolean>
+) : SysPropFlag<Boolean> {
+ // TODO(b/223379190): Teamfood not supported for sysprop flags yet.
+ override val teamfood: Boolean = false
+}
data class StringFlag @JvmOverloads constructor(
override val id: Int,
- override val default: String = ""
+ override val default: String = "",
+ override val teamfood: Boolean = false
) : ParcelableFlag<String> {
companion object {
@JvmField
@@ -100,14 +107,16 @@ data class StringFlag @JvmOverloads constructor(
}
}
-data class ResourceStringFlag constructor(
+data class ResourceStringFlag @JvmOverloads constructor(
override val id: Int,
- @StringRes override val resourceId: Int
+ @StringRes override val resourceId: Int,
+ override val teamfood: Boolean = false
) : ResourceFlag<String>
data class IntFlag @JvmOverloads constructor(
override val id: Int,
- override val default: Int = 0
+ override val default: Int = 0,
+ override val teamfood: Boolean = false
) : ParcelableFlag<Int> {
companion object {
@@ -129,14 +138,16 @@ data class IntFlag @JvmOverloads constructor(
}
}
-data class ResourceIntFlag constructor(
+data class ResourceIntFlag @JvmOverloads constructor(
override val id: Int,
- @IntegerRes override val resourceId: Int
+ @IntegerRes override val resourceId: Int,
+ override val teamfood: Boolean = false
) : ResourceFlag<Int>
data class LongFlag @JvmOverloads constructor(
override val id: Int,
- override val default: Long = 0
+ override val default: Long = 0,
+ override val teamfood: Boolean = false
) : ParcelableFlag<Long> {
companion object {
@@ -160,7 +171,8 @@ data class LongFlag @JvmOverloads constructor(
data class FloatFlag @JvmOverloads constructor(
override val id: Int,
- override val default: Float = 0f
+ override val default: Float = 0f,
+ override val teamfood: Boolean = false
) : ParcelableFlag<Float> {
companion object {
@@ -182,14 +194,16 @@ data class FloatFlag @JvmOverloads constructor(
}
}
-data class ResourceFloatFlag constructor(
+data class ResourceFloatFlag @JvmOverloads constructor(
override val id: Int,
- override val resourceId: Int
+ override val resourceId: Int,
+ override val teamfood: Boolean = false
) : ResourceFlag<Int>
data class DoubleFlag @JvmOverloads constructor(
override val id: Int,
- override val default: Double = 0.0
+ override val default: Double = 0.0,
+ override val teamfood: Boolean = false
) : ParcelableFlag<Double> {
companion object {
diff --git a/packages/SystemUI/shared/src/com/android/systemui/flags/FlagManager.kt b/packages/SystemUI/shared/src/com/android/systemui/flags/FlagManager.kt
index 149f6e8e7e9e..26e40e1ecad3 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/flags/FlagManager.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/flags/FlagManager.kt
@@ -64,7 +64,7 @@ class FlagManager constructor(
intent.setPackage(RECEIVING_PACKAGE)
return CallbackToFutureAdapter.getFuture {
- completer: CallbackToFutureAdapter.Completer<Any?> ->
+ completer: CallbackToFutureAdapter.Completer<Collection<Flag<*>>> ->
context.sendOrderedBroadcast(intent, null,
object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
@@ -79,7 +79,7 @@ class FlagManager constructor(
}
}, null, Activity.RESULT_OK, "extra data", null)
"QueryingFlags"
- } as ListenableFuture<Collection<Flag<*>>>
+ }
}
/**
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/BitmapUtil.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/BitmapUtil.java
deleted file mode 100644
index 325bcfc622d7..000000000000
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/BitmapUtil.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.shared.recents.utilities;
-
-import android.graphics.Bitmap;
-import android.graphics.ColorSpace;
-import android.graphics.ParcelableColorSpace;
-import android.hardware.HardwareBuffer;
-import android.os.Bundle;
-
-import java.util.Objects;
-
-/**
- * Utils for working with Bitmaps.
- */
-public final class BitmapUtil {
- private static final String KEY_BUFFER = "bitmap_util_buffer";
- private static final String KEY_COLOR_SPACE = "bitmap_util_color_space";
-
- private BitmapUtil(){ }
-
- /**
- * Creates a Bundle that represents the given Bitmap.
- * <p>The Bundle will contain a wrapped version of the Bitmaps HardwareBuffer, so will avoid
- * copies when passing across processes, only pass to processes you trust.
- *
- * <p>Returns a new Bundle rather than modifying an exiting one to avoid key collisions, the
- * returned Bundle should be treated as a standalone object.
- *
- * @param bitmap to convert to bundle
- * @return a Bundle representing the bitmap, should only be parsed by
- * {@link #bundleToHardwareBitmap(Bundle)}
- */
- public static Bundle hardwareBitmapToBundle(Bitmap bitmap) {
- if (bitmap.getConfig() != Bitmap.Config.HARDWARE) {
- throw new IllegalArgumentException(
- "Passed bitmap must have hardware config, found: " + bitmap.getConfig());
- }
-
- // Bitmap assumes SRGB for null color space
- ParcelableColorSpace colorSpace =
- bitmap.getColorSpace() == null
- ? new ParcelableColorSpace(ColorSpace.get(ColorSpace.Named.SRGB))
- : new ParcelableColorSpace(bitmap.getColorSpace());
-
- Bundle bundle = new Bundle();
- bundle.putParcelable(KEY_BUFFER, bitmap.getHardwareBuffer());
- bundle.putParcelable(KEY_COLOR_SPACE, colorSpace);
-
- return bundle;
- }
-
- /**
- * Extracts the Bitmap added to a Bundle with {@link #hardwareBitmapToBundle(Bitmap)} .}
- *
- * <p>This Bitmap contains the HardwareBuffer from the original caller, be careful passing this
- * Bitmap on to any other source.
- *
- * @param bundle containing the bitmap
- * @return a hardware Bitmap
- */
- public static Bitmap bundleToHardwareBitmap(Bundle bundle) {
- if (!bundle.containsKey(KEY_BUFFER) || !bundle.containsKey(KEY_COLOR_SPACE)) {
- throw new IllegalArgumentException("Bundle does not contain a hardware bitmap");
- }
-
- HardwareBuffer buffer = bundle.getParcelable(KEY_BUFFER);
- ParcelableColorSpace colorSpace = bundle.getParcelable(KEY_COLOR_SPACE);
-
- return Bitmap.wrapHardwareBuffer(Objects.requireNonNull(buffer),
- colorSpace.getColorSpace());
- }
-}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityOptionsCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityOptionsCompat.java
index db62f88325dc..e38d2bad11b3 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityOptionsCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityOptionsCompat.java
@@ -17,36 +17,22 @@
package com.android.systemui.shared.system;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
-import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
-import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
import android.app.ActivityOptions;
import android.content.Context;
import android.os.Handler;
-import com.android.systemui.shared.recents.model.Task;
-
/**
* Wrapper around internal ActivityOptions creation.
*/
public abstract class ActivityOptionsCompat {
/**
+ * @Deprecated
* @return ActivityOptions for starting a task in split screen as the primary window.
*/
public static ActivityOptions makeSplitScreenOptions(boolean dockTopLeft) {
- return makeSplitScreenOptions(dockTopLeft, true);
- }
-
- /**
- * @return ActivityOptions for starting a task in split screen.
- */
- public static ActivityOptions makeSplitScreenOptions(boolean dockTopLeft, boolean isPrimary) {
- final ActivityOptions options = ActivityOptions.makeBasic();
- options.setLaunchWindowingMode(isPrimary
- ? WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
- : WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
- return options;
+ return ActivityOptions.makeBasic();
}
/**
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 98e48f64e9e6..b61827a0212c 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
@@ -243,10 +243,15 @@ public class RemoteTransitionCompat implements Parcelable {
boolean merge(TransitionInfo info, SurfaceControl.Transaction t,
RecentsAnimationListener recents) {
ArrayList<TransitionInfo.Change> openingTasks = null;
+ boolean cancelRecents = false;
for (int i = info.getChanges().size() - 1; i >= 0; --i) {
final TransitionInfo.Change change = info.getChanges().get(i);
if (change.getMode() == TRANSIT_OPEN || change.getMode() == TRANSIT_TO_FRONT) {
if (change.getTaskInfo() != null) {
+ if (change.getTaskInfo().topActivityType == ACTIVITY_TYPE_HOME) {
+ // canceling recents animation
+ cancelRecents = true;
+ }
if (openingTasks == null) {
openingTasks = new ArrayList<>();
}
@@ -256,9 +261,11 @@ public class RemoteTransitionCompat implements Parcelable {
}
if (openingTasks == null) return false;
int pauseMatches = 0;
- for (int i = 0; i < openingTasks.size(); ++i) {
- if (mPausingTasks.contains(openingTasks.get(i).getContainer())) {
- ++pauseMatches;
+ if (!cancelRecents) {
+ for (int i = 0; i < openingTasks.size(); ++i) {
+ if (mPausingTasks.contains(openingTasks.get(i).getContainer())) {
+ ++pauseMatches;
+ }
}
}
if (pauseMatches > 0) {
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java
index 85d5de0ea4f6..32299f5643db 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java
@@ -78,10 +78,6 @@ public class WindowManagerWrapper {
public static final int WINDOWING_MODE_MULTI_WINDOW =
WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
- public static final int WINDOWING_MODE_SPLIT_SCREEN_PRIMARY =
- WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
- public static final int WINDOWING_MODE_SPLIT_SCREEN_SECONDARY =
- WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
public static final int WINDOWING_MODE_FREEFORM = WindowConfiguration.WINDOWING_MODE_FREEFORM;
public static final int ITYPE_EXTRA_NAVIGATION_BAR = InsetsState.ITYPE_EXTRA_NAVIGATION_BAR;
diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldSharedComponent.kt b/packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldSharedComponent.kt
index ac62cf9f9d5b..15593ea5f0e4 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldSharedComponent.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldSharedComponent.kt
@@ -22,6 +22,7 @@ import android.hardware.SensorManager
import android.hardware.devicestate.DeviceStateManager
import android.os.Handler
import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.dagger.qualifiers.UiBackground
import com.android.systemui.unfold.config.UnfoldTransitionConfig
import com.android.systemui.unfold.updates.screen.ScreenStatusProvider
import com.android.systemui.unfold.util.UnfoldTransitionATracePrefix
@@ -53,6 +54,7 @@ internal interface UnfoldSharedComponent {
@BindsInstance sensorManager: SensorManager,
@BindsInstance @Main handler: Handler,
@BindsInstance @Main executor: Executor,
+ @BindsInstance @UiBackground backgroundExecutor: Executor,
@BindsInstance @UnfoldTransitionATracePrefix tracingTagPrefix: String,
@BindsInstance contentResolver: ContentResolver = context.contentResolver
): UnfoldSharedComponent
diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldSharedModule.kt b/packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldSharedModule.kt
index 23e4c97fc271..c612995241ef 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldSharedModule.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldSharedModule.kt
@@ -17,6 +17,7 @@
package com.android.systemui.unfold
import android.hardware.SensorManager
+import com.android.systemui.dagger.qualifiers.UiBackground
import com.android.systemui.unfold.config.UnfoldTransitionConfig
import com.android.systemui.unfold.progress.FixedTimingTransitionProgressProvider
import com.android.systemui.unfold.progress.PhysicsBasedUnfoldTransitionProgressProvider
@@ -30,6 +31,7 @@ import com.android.systemui.unfold.util.ScaleAwareTransitionProgressProvider
import dagger.Module
import dagger.Provides
import java.util.Optional
+import java.util.concurrent.Executor
import javax.inject.Singleton
@Module
@@ -67,10 +69,11 @@ class UnfoldSharedModule {
@Provides
fun hingeAngleProvider(
config: UnfoldTransitionConfig,
- sensorManager: SensorManager
+ sensorManager: SensorManager,
+ @UiBackground executor: Executor
): HingeAngleProvider =
if (config.isHingeAngleEnabled) {
- HingeSensorAngleProvider(sensorManager)
+ HingeSensorAngleProvider(sensorManager, executor)
} else {
EmptyHingeAngleProvider
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt b/packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt
index d5d636208747..8e4ff9bc9133 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt
@@ -42,6 +42,7 @@ fun createUnfoldTransitionProgressProvider(
sensorManager: SensorManager,
mainHandler: Handler,
mainExecutor: Executor,
+ backgroundExecutor: Executor,
tracingTagPrefix: String
): UnfoldTransitionProgressProvider =
DaggerUnfoldSharedComponent.factory()
@@ -53,6 +54,7 @@ fun createUnfoldTransitionProgressProvider(
sensorManager,
mainHandler,
mainExecutor,
+ backgroundExecutor,
tracingTagPrefix)
.unfoldTransitionProvider
.orElse(null)
diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/hinge/HingeSensorAngleProvider.kt b/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/hinge/HingeSensorAngleProvider.kt
index a50d852e9b36..c93412b53817 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/hinge/HingeSensorAngleProvider.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/hinge/HingeSensorAngleProvider.kt
@@ -6,21 +6,29 @@ import android.hardware.SensorEventListener
import android.hardware.SensorManager
import android.os.Trace
import androidx.core.util.Consumer
+import java.util.concurrent.Executor
-internal class HingeSensorAngleProvider(private val sensorManager: SensorManager) :
+internal class HingeSensorAngleProvider(
+ private val sensorManager: SensorManager,
+ private val executor: Executor
+) :
HingeAngleProvider {
private val sensorListener = HingeAngleSensorListener()
private val listeners: MutableList<Consumer<Float>> = arrayListOf()
- override fun start() {
+ override fun start() = executor.execute {
Trace.beginSection("HingeSensorAngleProvider#start")
val sensor = sensorManager.getDefaultSensor(Sensor.TYPE_HINGE_ANGLE)
- sensorManager.registerListener(sensorListener, sensor, SensorManager.SENSOR_DELAY_FASTEST)
+ sensorManager.registerListener(
+ sensorListener,
+ sensor,
+ SensorManager.SENSOR_DELAY_FASTEST
+ )
Trace.endSection()
}
- override fun stop() {
+ override fun stop() = executor.execute {
sensorManager.unregisterListener(sensorListener)
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/util/ScopedUnfoldTransitionProgressProvider.kt b/packages/SystemUI/shared/src/com/android/systemui/unfold/util/ScopedUnfoldTransitionProgressProvider.kt
index 7b6791770295..8491f832b740 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/unfold/util/ScopedUnfoldTransitionProgressProvider.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/unfold/util/ScopedUnfoldTransitionProgressProvider.kt
@@ -28,7 +28,7 @@ import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionPr
* If the transition has already started by the moment when the clients are ready to play the
* transition then it will report transition started callback and current animation progress.
*/
-class ScopedUnfoldTransitionProgressProvider
+open class ScopedUnfoldTransitionProgressProvider
@JvmOverloads
constructor(source: UnfoldTransitionProgressProvider? = null) :
UnfoldTransitionProgressProvider, TransitionProgressListener {
diff --git a/packages/SystemUI/src-debug/com/android/systemui/flags/FlagsModule.kt b/packages/SystemUI/src-debug/com/android/systemui/flags/FlagsModule.kt
index adfc87241460..256028417a1d 100644
--- a/packages/SystemUI/src-debug/com/android/systemui/flags/FlagsModule.kt
+++ b/packages/SystemUI/src-debug/com/android/systemui/flags/FlagsModule.kt
@@ -19,11 +19,12 @@ package com.android.systemui.flags
import android.content.Context
import android.os.Handler
import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.flags.FeatureFlagsDebug.ALL_FLAGS
import com.android.systemui.util.settings.SettingsUtilModule
import dagger.Binds
import dagger.Module
import dagger.Provides
-import java.util.function.Supplier
+import javax.inject.Named
@Module(includes = [
SettingsUtilModule::class
@@ -42,6 +43,7 @@ abstract class FlagsModule {
@JvmStatic
@Provides
- fun providesFlagCollector(): Supplier<Map<Int, Flag<*>>>? = null
+ @Named(ALL_FLAGS)
+ fun providesAllFlags(): Map<Int, Flag<*>> = Flags.collectFlags()
}
} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/keyguard/BouncerPanelExpansionCalculator.kt b/packages/SystemUI/src/com/android/keyguard/BouncerPanelExpansionCalculator.kt
new file mode 100644
index 000000000000..497d81f6bdc5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/BouncerPanelExpansionCalculator.kt
@@ -0,0 +1,49 @@
+/*
+ * 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.keyguard
+
+import android.util.MathUtils
+
+object BouncerPanelExpansionCalculator {
+ /**
+ * Scale the alpha/position of the host view.
+ */
+ @JvmStatic
+ fun getHostViewScaledExpansion(fraction: Float): Float {
+ return when {
+ fraction >= 0.9f -> 1f
+ fraction < 0.6 -> 0f
+ else -> (fraction - 0.6f) / 0.3f
+ }
+ }
+
+ /**
+ * Scale the alpha/tint of the back scrim.
+ */
+ @JvmStatic
+ fun getBackScrimScaledExpansion(fraction: Float): Float {
+ return MathUtils.constrain((fraction - 0.9f) / 0.1f, 0f, 1f)
+ }
+
+ /**
+ * This will scale the alpha/position of the clock.
+ */
+ @JvmStatic
+ fun getKeyguardClockScaledExpansion(fraction: Float): Float {
+ return MathUtils.constrain((fraction - 0.7f) / 0.3f, 0f, 1f)
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java b/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java
index c4b02f62f291..458d22efd206 100644
--- a/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java
+++ b/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java
@@ -96,7 +96,7 @@ public class EmergencyButton extends Button {
**/
public void reloadColors() {
int color = Utils.getColorAttrDefaultColor(getContext(),
- android.R.attr.textColorPrimaryInverse);
+ com.android.internal.R.attr.textColorOnAccent);
setTextColor(color);
setBackground(getContext()
.getDrawable(com.android.systemui.R.drawable.kg_emergency_button_background));
@@ -107,10 +107,10 @@ public class EmergencyButton extends Button {
return super.performLongClick();
}
- void updateEmergencyCallButton(boolean isInCall, boolean isVoiceCapable, boolean simLocked) {
+ void updateEmergencyCallButton(boolean isInCall, boolean hasTelephonyRadio, boolean simLocked) {
boolean visible = false;
- if (isVoiceCapable) {
- // Emergency calling requires voice capability.
+ if (hasTelephonyRadio) {
+ // Emergency calling requires a telephony radio.
if (isInCall) {
visible = true; // always show "return to call" if phone is off-hook
} else {
diff --git a/packages/SystemUI/src/com/android/keyguard/EmergencyButtonController.java b/packages/SystemUI/src/com/android/keyguard/EmergencyButtonController.java
index e7215b8ebe49..f28910576073 100644
--- a/packages/SystemUI/src/com/android/keyguard/EmergencyButtonController.java
+++ b/packages/SystemUI/src/com/android/keyguard/EmergencyButtonController.java
@@ -21,6 +21,7 @@ import static com.android.systemui.DejankUtils.whitelistIpcs;
import android.app.ActivityOptions;
import android.app.ActivityTaskManager;
import android.content.Intent;
+import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.os.PowerManager;
import android.os.SystemClock;
@@ -116,7 +117,8 @@ public class EmergencyButtonController extends ViewController<EmergencyButton> {
if (mView != null) {
mView.updateEmergencyCallButton(
mTelecomManager != null && mTelecomManager.isInCall(),
- mTelephonyManager.isVoiceCapable(),
+ getContext().getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_TELEPHONY),
mKeyguardUpdateMonitor.isSimPinVoiceSecure());
}
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java
index 7f456dba6053..eb418ff3b142 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java
@@ -194,9 +194,12 @@ public abstract class KeyguardAbsKeyInputViewController<T extends KeyguardAbsKey
mMessageAreaController.setMessage(mView.getWrongPasswordStringId());
}
mView.resetPasswordText(true /* animate */, false /* announce deletion if no match */);
+ startErrorAnimation();
}
}
+ protected void startErrorAnimation() { /* no-op */ }
+
protected void verifyPasswordAndUnlock() {
if (mDismissing) return; // already verified but haven't been dismissed; don't do it again.
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java
index b6910961bcb4..8c3e066849b9 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java
@@ -37,7 +37,6 @@ import com.android.keyguard.dagger.KeyguardBouncerScope;
import com.android.settingslib.Utils;
import com.android.systemui.R;
import com.android.systemui.plugins.ActivityStarter;
-import com.android.systemui.statusbar.phone.KeyguardBouncer;
import com.android.systemui.util.ViewController;
import java.io.File;
@@ -64,6 +63,7 @@ public class KeyguardHostViewController extends ViewController<KeyguardHostView>
private ActivityStarter.OnDismissAction mDismissAction;
private Runnable mCancelAction;
+ private int mTranslationY;
private final KeyguardUpdateMonitorCallback mUpdateCallback =
new KeyguardUpdateMonitorCallback() {
@@ -322,12 +322,14 @@ public class KeyguardHostViewController extends ViewController<KeyguardHostView>
/**
* Fades and translates in/out the security screen.
+ * Fades in as expansion approaches 0.
+ * Animation duration is between 0.33f and 0.67f of panel expansion fraction.
* @param fraction amount of the screen that should show.
*/
public void setExpansion(float fraction) {
- float alpha = MathUtils.map(KeyguardBouncer.ALPHA_EXPANSION_THRESHOLD, 1, 1, 0, fraction);
- mView.setAlpha(MathUtils.constrain(alpha, 0f, 1f));
- mView.setTranslationY(fraction * mView.getHeight());
+ float scaledFraction = BouncerPanelExpansionCalculator.getHostViewScaledExpansion(fraction);
+ mView.setAlpha(MathUtils.constrain(1 - scaledFraction, 0f, 1f));
+ mView.setTranslationY(scaledFraction * mTranslationY);
}
/**
@@ -490,6 +492,8 @@ public class KeyguardHostViewController extends ViewController<KeyguardHostView>
gravity = resources.getInteger(R.integer.keyguard_host_view_gravity);
}
+ mTranslationY = resources
+ .getDimensionPixelSize(R.dimen.keyguard_host_view_translation_y);
// Android SysUI uses a FrameLayout as the top-level, but Auto uses RelativeLayout.
// We're just changing the gravity here though (which can't be applied to RelativeLayout),
// so only attempt the update if mView is inside a FrameLayout.
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardMessageArea.java b/packages/SystemUI/src/com/android/keyguard/KeyguardMessageArea.java
index 75579b05aeeb..5ab2fd0aff09 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardMessageArea.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardMessageArea.java
@@ -57,7 +57,7 @@ public class KeyguardMessageArea extends TextView implements SecurityMessageDisp
private ColorStateList mDefaultColorState;
private CharSequence mMessage;
private ColorStateList mNextMessageColorState = ColorStateList.valueOf(DEFAULT_COLOR);
- private boolean mBouncerVisible;
+ private boolean mBouncerShowing;
private boolean mAltBouncerShowing;
/**
* Container that wraps the KeyguardMessageArea - may be null if current view hierarchy doesn't
@@ -177,7 +177,7 @@ public class KeyguardMessageArea extends TextView implements SecurityMessageDisp
void update() {
CharSequence status = mMessage;
- setVisibility(TextUtils.isEmpty(status) || (!mBouncerVisible && !mAltBouncerShowing)
+ setVisibility(TextUtils.isEmpty(status) || (!mBouncerShowing && !mAltBouncerShowing)
? INVISIBLE : VISIBLE);
setText(status);
ColorStateList colorState = mDefaultColorState;
@@ -192,8 +192,14 @@ public class KeyguardMessageArea extends TextView implements SecurityMessageDisp
setTextColor(colorState);
}
- public void setBouncerVisible(boolean bouncerVisible) {
- mBouncerVisible = bouncerVisible;
+ /**
+ * Set whether the bouncer is fully showing
+ */
+ public void setBouncerShowing(boolean bouncerShowing) {
+ if (mBouncerShowing != bouncerShowing) {
+ mBouncerShowing = bouncerShowing;
+ update();
+ }
}
/**
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java
index 05318bb0df78..81cc3a933600 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java
@@ -39,12 +39,6 @@ public class KeyguardMessageAreaController extends ViewController<KeyguardMessag
public void onStartedWakingUp() {
mView.setSelected(true);
}
-
- @Override
- public void onKeyguardBouncerChanged(boolean bouncer) {
- mView.setBouncerVisible(bouncer);
- mView.update();
- }
};
private ConfigurationListener mConfigurationListener = new ConfigurationListener() {
@@ -94,6 +88,13 @@ public class KeyguardMessageAreaController extends ViewController<KeyguardMessag
mView.setAltBouncerShowing(showing);
}
+ /**
+ * Set bouncer is fully showing
+ */
+ public void setBouncerShowing(boolean showing) {
+ mView.setBouncerShowing(showing);
+ }
+
public void setMessage(CharSequence s) {
mView.setMessage(s);
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java
index 1efda7edee2f..77044ed33113 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java
@@ -188,14 +188,13 @@ public class KeyguardPINView extends KeyguardPinBasedInputView {
enableClipping(false);
setTranslationY(0);
- AppearAnimationUtils.startTranslationYAnimation(this, 0 /* delay */, 280 /* duration */,
- mDisappearYTranslation, mDisappearAnimationUtils.getInterpolator(),
- getAnimationListener(InteractionJankMonitor.CUJ_LOCKSCREEN_PIN_DISAPPEAR));
DisappearAnimationUtils disappearAnimationUtils = needsSlowUnlockTransition
? mDisappearAnimationUtilsLocked
: mDisappearAnimationUtils;
- disappearAnimationUtils.startAnimation2d(mViews,
- () -> {
+ disappearAnimationUtils.createAnimation(
+ this, 0, 200, mDisappearYTranslation, false,
+ mDisappearAnimationUtils.getInterpolator(), () -> {
+ getAnimationListener(InteractionJankMonitor.CUJ_LOCKSCREEN_PIN_DISAPPEAR);
enableClipping(true);
if (finishRunnable != null) {
finishRunnable.run();
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
index 4723af2760c0..c46e33d9fd53 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
@@ -24,6 +24,9 @@ import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_RESTART;
import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_TIMEOUT;
import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_USER_REQUEST;
+import android.animation.Animator;
+import android.animation.AnimatorSet;
+import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Rect;
import android.util.AttributeSet;
@@ -32,6 +35,10 @@ import android.view.View;
import com.android.internal.widget.LockscreenCredential;
import com.android.systemui.R;
+import com.android.systemui.animation.Interpolators;
+
+import java.util.ArrayList;
+import java.util.List;
/**
* A Pin based Keyguard input view
@@ -188,4 +195,48 @@ public abstract class KeyguardPinBasedInputView extends KeyguardAbsKeyInputView
return getContext().getString(
com.android.internal.R.string.keyguard_accessibility_pin_unlock);
}
+
+ /**
+ * Begins an error animation for this view.
+ **/
+ public void startErrorAnimation() {
+ AnimatorSet animatorSet = new AnimatorSet();
+ List<Animator> animators = new ArrayList();
+ List<View> buttons = new ArrayList<>();
+ for (int i = 1; i <= 9; i++) {
+ buttons.add(mButtons[i]);
+ }
+ buttons.add(mDeleteButton);
+ buttons.add(mButtons[0]);
+ buttons.add(mOkButton);
+
+ int delay = 0;
+ for (int i = 0; i < buttons.size(); i++) {
+ final View button = buttons.get(i);
+ AnimatorSet animateWrapper = new AnimatorSet();
+ animateWrapper.setStartDelay(delay);
+
+ ValueAnimator scaleDownAnimator = ValueAnimator.ofFloat(1f, 0.8f);
+ scaleDownAnimator.setInterpolator(Interpolators.STANDARD);
+ scaleDownAnimator.addUpdateListener(valueAnimator -> {
+ button.setScaleX((float) valueAnimator.getAnimatedValue());
+ button.setScaleY((float) valueAnimator.getAnimatedValue());
+ });
+ scaleDownAnimator.setDuration(50);
+
+ ValueAnimator scaleUpAnimator = ValueAnimator.ofFloat(0.8f, 1f);
+ scaleUpAnimator.setInterpolator(Interpolators.STANDARD);
+ scaleUpAnimator.addUpdateListener(valueAnimator -> {
+ button.setScaleX((float) valueAnimator.getAnimatedValue());
+ button.setScaleY((float) valueAnimator.getAnimatedValue());
+ });
+ scaleUpAnimator.setDuration(617);
+
+ animateWrapper.playSequentially(scaleDownAnimator, scaleUpAnimator);
+ animators.add(animateWrapper);
+ delay += 33;
+ }
+ animatorSet.playTogether(animators);
+ animatorSet.start();
+ }
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java
index 8de4e7b557f3..f7423ed12e68 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java
@@ -133,4 +133,10 @@ public abstract class KeyguardPinBasedInputViewController<T extends KeyguardPinB
void resetState() {
mView.setPasswordEntryEnabled(true);
}
+
+ @Override
+ protected void startErrorAnimation() {
+ super.startErrorAnimation();
+ mView.startErrorAnimation();
+ }
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index af7cf862b6b6..46a883194e25 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -152,6 +152,7 @@ public class KeyguardSecurityContainer extends FrameLayout {
private SwipeListener mSwipeListener;
private ViewMode mViewMode = new DefaultViewMode();
private @Mode int mCurrentMode = MODE_DEFAULT;
+ private int mWidth = -1;
private final WindowInsetsAnimation.Callback mWindowInsetsAnimationCallback =
new WindowInsetsAnimation.Callback(DISPATCH_MODE_STOP) {
@@ -649,9 +650,11 @@ public class KeyguardSecurityContainer extends FrameLayout {
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
- // After a layout pass, we need to re-place the inner bouncer, as our bounds may have
- // changed.
- mViewMode.updateSecurityViewLocation();
+ int width = right - left;
+ if (changed && mWidth != width) {
+ mWidth = width;
+ mViewMode.updateSecurityViewLocation();
+ }
}
@Override
@@ -918,7 +921,7 @@ public class KeyguardSecurityContainer extends FrameLayout {
}
drawable.setTint(iconColor);
- Drawable bg = context.getDrawable(R.drawable.kg_bg_avatar);
+ Drawable bg = context.getDrawable(R.drawable.user_avatar_bg);
bg.setTintBlendMode(BlendMode.DST);
bg.setTint(Utils.getColorAttrDefaultColor(context,
com.android.internal.R.attr.colorSurfaceVariant));
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
index 31f466f0fdf9..087817f0ec81 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
@@ -113,6 +113,22 @@ public class KeyguardStatusView extends GridLayout {
}
}
+ /** Sets a translationY value on every child view except for the media view. */
+ public void setChildrenTranslationYExcludingMediaView(float translationY) {
+ setChildrenTranslationYExcluding(translationY, Set.of(mMediaHostContainer));
+ }
+
+ /** Sets a translationY value on every view except for the views in the provided set. */
+ private void setChildrenTranslationYExcluding(float translationY, Set<View> excludedViews) {
+ for (int i = 0; i < mStatusViewContainer.getChildCount(); i++) {
+ final View child = mStatusViewContainer.getChildAt(i);
+
+ if (!excludedViews.contains(child)) {
+ child.setTranslationY(translationY);
+ }
+ }
+ }
+
public float getChildrenAlphaExcludingSmartSpace() {
return mChildrenAlphaExcludingSmartSpace;
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
index a5fe0efc8887..14c9cb2022bc 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
@@ -20,7 +20,6 @@ import android.graphics.Rect;
import android.util.Slog;
import com.android.keyguard.KeyguardClockSwitch.ClockSize;
-import com.android.systemui.communal.CommunalStateController;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.statusbar.notification.AnimatableProperty;
import com.android.systemui.statusbar.notification.PropertyAnimator;
@@ -63,7 +62,6 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV
KeyguardClockSwitchController keyguardClockSwitchController,
KeyguardStateController keyguardStateController,
KeyguardUpdateMonitor keyguardUpdateMonitor,
- CommunalStateController communalStateController,
ConfigurationController configurationController,
DozeParameters dozeParameters,
KeyguardUnlockAnimationController keyguardUnlockAnimationController,
@@ -75,9 +73,8 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV
mConfigurationController = configurationController;
mDozeParameters = dozeParameters;
mKeyguardStateController = keyguardStateController;
- mKeyguardVisibilityHelper = new KeyguardVisibilityHelper(mView, communalStateController,
- keyguardStateController, dozeParameters, screenOffAnimationController,
- /* animateYPos= */ true, /* visibleOnCommunal= */ false);
+ mKeyguardVisibilityHelper = new KeyguardVisibilityHelper(mView, keyguardStateController,
+ dozeParameters, screenOffAnimationController, /* animateYPos= */ true);
mKeyguardUnlockAnimationController = keyguardUnlockAnimationController;
}
@@ -140,6 +137,13 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV
}
/**
+ * Sets a translationY on the views on the keyguard, except on the media view.
+ */
+ public void setTranslationYExcludingMedia(float translationY) {
+ mView.setChildrenTranslationYExcludingMediaView(translationY);
+ }
+
+ /**
* Set keyguard status view alpha.
*/
public void setAlpha(float alpha) {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 37f45644fa68..74a88bd5f19a 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -52,6 +52,7 @@ import android.content.pm.ResolveInfo;
import android.content.pm.UserInfo;
import android.database.ContentObserver;
import android.hardware.SensorPrivacyManager;
+import android.hardware.biometrics.BiometricFingerprintConstants;
import android.hardware.biometrics.BiometricManager;
import android.hardware.biometrics.BiometricSourceType;
import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback;
@@ -325,7 +326,6 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
private int mActiveMobileDataSubscription = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
private final Executor mBackgroundExecutor;
private SensorPrivacyManager mSensorPrivacyManager;
- private int mFaceAuthUserId;
/**
* Short delay before restarting fingerprint authentication after a successful try. This should
@@ -752,15 +752,13 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
}
}
- private void handleFingerprintAcquired(int acquireInfo) {
+ private void handleFingerprintAcquired(
+ @BiometricFingerprintConstants.FingerprintAcquired int acquireInfo) {
Assert.isMainThread();
- if (acquireInfo != FingerprintManager.FINGERPRINT_ACQUIRED_GOOD) {
- return;
- }
for (int i = 0; i < mCallbacks.size(); i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
- cb.onBiometricAcquired(BiometricSourceType.FINGERPRINT);
+ cb.onBiometricAcquired(BiometricSourceType.FINGERPRINT, acquireInfo);
}
}
}
@@ -960,14 +958,11 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
private void handleFaceAcquired(int acquireInfo) {
Assert.isMainThread();
- if (acquireInfo != FaceManager.FACE_ACQUIRED_GOOD) {
- return;
- }
- if (DEBUG_FACE) Log.d(TAG, "Face acquired");
+ if (DEBUG_FACE) Log.d(TAG, "Face acquired acquireInfo=" + acquireInfo);
for (int i = 0; i < mCallbacks.size(); i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
- cb.onBiometricAcquired(BiometricSourceType.FACE);
+ cb.onBiometricAcquired(BiometricSourceType.FACE, acquireInfo);
}
}
}
@@ -1034,8 +1029,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
boolean cameraPrivacyEnabled = false;
if (mSensorPrivacyManager != null) {
cameraPrivacyEnabled = mSensorPrivacyManager
- .isSensorPrivacyEnabled(SensorPrivacyManager.Sensors.CAMERA,
- mFaceAuthUserId);
+ .isSensorPrivacyEnabled(SensorPrivacyManager.TOGGLE_TYPE_SOFTWARE,
+ SensorPrivacyManager.Sensors.CAMERA);
}
if (msgId == FaceManager.FACE_ERROR_CANCELED
@@ -1491,6 +1486,10 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
@Override
public void onAuthenticationFailed() {
handleFingerprintAuthFailed();
+
+ // TODO(b/225231929): Refactor as needed, add tests, etc.
+ mTrustManager.reportUserRequestedUnlock(
+ KeyguardUpdateMonitor.getCurrentUser(), true);
}
@Override
@@ -2263,7 +2262,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
}
if (shouldTriggerActiveUnlock()) {
- mTrustManager.reportUserRequestedUnlock(KeyguardUpdateMonitor.getCurrentUser());
+ // TODO(b/225231929): Refactor surrounding code to reflect calling of new method
+ mTrustManager.reportUserMayRequestUnlock(KeyguardUpdateMonitor.getCurrentUser());
}
}
@@ -2603,7 +2603,6 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
// This would need to be updated for multi-sensor devices
final boolean supportsFaceDetection = !mFaceSensorProperties.isEmpty()
&& mFaceSensorProperties.get(0).supportsFaceDetection;
- mFaceAuthUserId = userId;
if (isEncryptedOrLockdown(userId) && supportsFaceDetection) {
mFaceManager.detectFace(mFaceCancelSignal, mFaceDetectionCallback, userId);
} else {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
index 8d5603dc1563..ad2053cbc31b 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
@@ -206,8 +206,10 @@ public class KeyguardUpdateMonitorCallback {
* It is guaranteed that either {@link #onBiometricAuthenticated} or
* {@link #onBiometricAuthFailed(BiometricSourceType)} is called after this method eventually.
* @param biometricSourceType
+ * @param acquireInfo see {@link android.hardware.biometrics.BiometricFaceConstants} and
+ * {@link android.hardware.biometrics.BiometricFingerprintConstants}
*/
- public void onBiometricAcquired(BiometricSourceType biometricSourceType) { }
+ public void onBiometricAcquired(BiometricSourceType biometricSourceType, int acquireInfo) { }
/**
* Called when a biometric couldn't be authenticated.
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardVisibilityHelper.java b/packages/SystemUI/src/com/android/keyguard/KeyguardVisibilityHelper.java
index bb608c79a50e..498304b3fc55 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardVisibilityHelper.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardVisibilityHelper.java
@@ -22,7 +22,6 @@ import android.view.View;
import android.view.ViewPropertyAnimator;
import com.android.systemui.animation.Interpolators;
-import com.android.systemui.communal.CommunalStateController;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.notification.AnimatableProperty;
import com.android.systemui.statusbar.notification.PropertyAnimator;
@@ -39,30 +38,24 @@ import com.android.systemui.statusbar.policy.KeyguardStateController;
public class KeyguardVisibilityHelper {
private View mView;
- private final CommunalStateController mCommunalStateController;
private final KeyguardStateController mKeyguardStateController;
private final DozeParameters mDozeParameters;
private final ScreenOffAnimationController mScreenOffAnimationController;
- private final boolean mVisibleOnCommunal;
private boolean mAnimateYPos;
private boolean mKeyguardViewVisibilityAnimating;
private boolean mLastOccludedState = false;
private final AnimationProperties mAnimationProperties = new AnimationProperties();
public KeyguardVisibilityHelper(View view,
- CommunalStateController communalStateController,
KeyguardStateController keyguardStateController,
DozeParameters dozeParameters,
ScreenOffAnimationController screenOffAnimationController,
- boolean animateYPos,
- boolean visibleOnCommunal) {
+ boolean animateYPos) {
mView = view;
- mCommunalStateController = communalStateController;
mKeyguardStateController = keyguardStateController;
mDozeParameters = dozeParameters;
mScreenOffAnimationController = screenOffAnimationController;
mAnimateYPos = animateYPos;
- mVisibleOnCommunal = visibleOnCommunal;
}
public boolean isVisibilityAnimating() {
@@ -81,13 +74,6 @@ public class KeyguardVisibilityHelper {
boolean isOccluded = mKeyguardStateController.isOccluded();
mKeyguardViewVisibilityAnimating = false;
- // If the communal view is showing, hide immediately
- if (!mVisibleOnCommunal && mCommunalStateController.getCommunalViewShowing()) {
- mView.setVisibility(View.GONE);
- mView.setAlpha(1f);
- return;
- }
-
if ((!keyguardFadingAway && oldStatusBarState == KEYGUARD
&& statusBarState != KEYGUARD) || goingToFullShade) {
mKeyguardViewVisibilityAnimating = true;
diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
index 370686a1e682..e36e984380e2 100644
--- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
@@ -211,6 +211,23 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
mDownDetected = false;
updateBurnInOffsets();
updateVisibility();
+
+ updateAccessibility();
+ }
+
+ private void updateAccessibility() {
+ if (mAccessibilityManager.isTouchExplorationEnabled()) {
+ mView.setOnClickListener(
+ new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ onLongPress();
+ }
+ }
+ );
+ } else {
+ mView.setOnClickListener(null);
+ }
}
@Override
@@ -558,7 +575,7 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
switch(event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_HOVER_ENTER:
- if (!mDownDetected) {
+ if (!mDownDetected && mAccessibilityManager.isTouchExplorationEnabled()) {
mVibrator.vibrate(
Process.myUid(),
getContext().getOpPackageName(),
diff --git a/packages/SystemUI/src/com/android/keyguard/NumPadAnimator.java b/packages/SystemUI/src/com/android/keyguard/NumPadAnimator.java
index 00470c0efe35..f925eaa0e40b 100644
--- a/packages/SystemUI/src/com/android/keyguard/NumPadAnimator.java
+++ b/packages/SystemUI/src/com/android/keyguard/NumPadAnimator.java
@@ -73,12 +73,14 @@ class NumPadAnimator {
ValueAnimator expandBackgroundColorAnimator = ValueAnimator.ofObject(new ArgbEvaluator(),
mNormalColor, mHighlightColor);
expandBackgroundColorAnimator.setDuration(EXPAND_COLOR_ANIMATION_MS);
+ expandBackgroundColorAnimator.setInterpolator(Interpolators.LINEAR);
expandBackgroundColorAnimator.addUpdateListener(
animator -> mBackground.setColor((int) animator.getAnimatedValue()));
ValueAnimator expandTextColorAnimator =
ValueAnimator.ofObject(new ArgbEvaluator(),
textColorPrimary, textColorPrimaryInverse);
+ expandTextColorAnimator.setInterpolator(Interpolators.LINEAR);
expandTextColorAnimator.setDuration(EXPAND_COLOR_ANIMATION_MS);
expandTextColorAnimator.addUpdateListener(valueAnimator -> {
if (digitTextView != null) {
@@ -98,6 +100,7 @@ class NumPadAnimator {
anim -> mBackground.setCornerRadius((float) anim.getAnimatedValue()));
ValueAnimator contractBackgroundColorAnimator = ValueAnimator.ofObject(new ArgbEvaluator(),
mHighlightColor, mNormalColor);
+ contractBackgroundColorAnimator.setInterpolator(Interpolators.LINEAR);
contractBackgroundColorAnimator.setStartDelay(CONTRACT_ANIMATION_DELAY_MS);
contractBackgroundColorAnimator.setDuration(CONTRACT_ANIMATION_MS);
contractBackgroundColorAnimator.addUpdateListener(
@@ -106,6 +109,7 @@ class NumPadAnimator {
ValueAnimator contractTextColorAnimator =
ValueAnimator.ofObject(new ArgbEvaluator(), textColorPrimaryInverse,
textColorPrimary);
+ contractTextColorAnimator.setInterpolator(Interpolators.LINEAR);
contractTextColorAnimator.setStartDelay(CONTRACT_ANIMATION_DELAY_MS);
contractTextColorAnimator.setDuration(CONTRACT_ANIMATION_MS);
contractTextColorAnimator.addUpdateListener(valueAnimator -> {
diff --git a/packages/SystemUI/src/com/android/keyguard/NumPadButton.java b/packages/SystemUI/src/com/android/keyguard/NumPadButton.java
index e0d0fc25943b..7b98f2759d80 100644
--- a/packages/SystemUI/src/com/android/keyguard/NumPadButton.java
+++ b/packages/SystemUI/src/com/android/keyguard/NumPadButton.java
@@ -19,6 +19,8 @@ import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.Configuration;
import android.content.res.TypedArray;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.GradientDrawable;
import android.graphics.drawable.VectorDrawable;
import android.util.AttributeSet;
import android.view.MotionEvent;
@@ -37,8 +39,14 @@ public class NumPadButton extends AlphaOptimizedImageButton {
public NumPadButton(Context context, AttributeSet attrs) {
super(context, attrs);
- mAnimator = new NumPadAnimator(context, getBackground().mutate(),
- attrs.getStyleAttribute());
+ Drawable background = getBackground();
+ if (background instanceof GradientDrawable) {
+ mAnimator = new NumPadAnimator(context, background.mutate(),
+ attrs.getStyleAttribute());
+ } else {
+ mAnimator = null;
+ }
+
}
@Override
diff --git a/packages/SystemUI/src/com/android/keyguard/NumPadKey.java b/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
index 88a0bcec0542..5cab547ee435 100644
--- a/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
+++ b/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
@@ -18,6 +18,8 @@ package com.android.keyguard;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.TypedArray;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.GradientDrawable;
import android.os.PowerManager;
import android.os.SystemClock;
import android.util.AttributeSet;
@@ -129,8 +131,13 @@ public class NumPadKey extends ViewGroup {
setContentDescription(mDigitText.getText().toString());
- mAnimator = new NumPadAnimator(context, getBackground().mutate(),
- R.style.NumPadKey, mDigitText);
+ Drawable background = getBackground();
+ if (background instanceof GradientDrawable) {
+ mAnimator = new NumPadAnimator(context, background.mutate(),
+ R.style.NumPadKey, mDigitText);
+ } else {
+ mAnimator = null;
+ }
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java b/packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java
index 5bd620e873b0..7af6f6677f3f 100644
--- a/packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java
+++ b/packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java
@@ -16,6 +16,7 @@ package com.android.systemui;
import android.app.PendingIntent;
import android.content.Intent;
+import android.os.UserHandle;
import android.view.View;
import androidx.annotation.Nullable;
@@ -100,6 +101,15 @@ public class ActivityStarterDelegate implements ActivityStarter {
}
@Override
+ public void startActivity(Intent intent, boolean dismissShade,
+ @Nullable ActivityLaunchAnimator.Controller animationController,
+ boolean showOverLockscreenWhenLocked, UserHandle userHandle) {
+ mActualStarterOptionalLazy.get().ifPresent(
+ starter -> starter.startActivity(intent, dismissShade, animationController,
+ showOverLockscreenWhenLocked, userHandle));
+ }
+
+ @Override
public void startActivity(Intent intent, boolean onlyProvisioned, boolean dismissShade) {
mActualStarterOptionalLazy.get().ifPresent(
starter -> starter.startActivity(intent, onlyProvisioned, dismissShade));
diff --git a/packages/SystemUI/src/com/android/systemui/LatencyTester.java b/packages/SystemUI/src/com/android/systemui/LatencyTester.java
index bc2a1ff24235..7afd43d1cb06 100644
--- a/packages/SystemUI/src/com/android/systemui/LatencyTester.java
+++ b/packages/SystemUI/src/com/android/systemui/LatencyTester.java
@@ -20,6 +20,7 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.hardware.biometrics.BiometricConstants;
import android.hardware.biometrics.BiometricSourceType;
import android.os.Build;
@@ -78,7 +79,8 @@ public class LatencyTester extends CoreStartable {
}
private void fakeWakeAndUnlock(BiometricSourceType type) {
- mBiometricUnlockController.onBiometricAcquired(type);
+ mBiometricUnlockController.onBiometricAcquired(type,
+ BiometricConstants.BIOMETRIC_ACQUIRED_GOOD);
mBiometricUnlockController.onBiometricAuthenticated(
KeyguardUpdateMonitor.getCurrentUser(), type, true /* isStrongBiometric */);
}
diff --git a/packages/SystemUI/src/com/android/systemui/Prefs.java b/packages/SystemUI/src/com/android/systemui/Prefs.java
index 6a60afa8eadf..ff5715c606b6 100644
--- a/packages/SystemUI/src/com/android/systemui/Prefs.java
+++ b/packages/SystemUI/src/com/android/systemui/Prefs.java
@@ -71,7 +71,9 @@ public final class Prefs {
Key.HAS_SEEN_REVERSE_BOTTOM_SHEET,
Key.CONTROLS_STRUCTURE_SWIPE_TOOLTIP_COUNT,
Key.HAS_SEEN_ACCESSIBILITY_FLOATING_MENU_DOCK_TOOLTIP,
- Key.ACCESSIBILITY_FLOATING_MENU_POSITION
+ Key.ACCESSIBILITY_FLOATING_MENU_POSITION,
+ Key.HAS_CLICKED_NUDGE_TO_SETUP_DREAM,
+ Key.HAS_DISMISSED_NUDGE_TO_SETUP_DREAM
})
// TODO: annotate these with their types so {@link PrefsCommandLine} can know how to set them
public @interface Key {
@@ -115,6 +117,8 @@ public final class Prefs {
String HAS_SEEN_ACCESSIBILITY_FLOATING_MENU_DOCK_TOOLTIP =
"HasSeenAccessibilityFloatingMenuDockTooltip";
String ACCESSIBILITY_FLOATING_MENU_POSITION = "AccessibilityFloatingMenuPosition";
+ String HAS_CLICKED_NUDGE_TO_SETUP_DREAM = "HasClickedNudgeToSetupDream";
+ String HAS_DISMISSED_NUDGE_TO_SETUP_DREAM = "HasDismissedNudgeToSetupDream";
}
public static boolean getBoolean(Context context, @Key String key, boolean defaultValue) {
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorHwcLayer.kt b/packages/SystemUI/src/com/android/systemui/ScreenDecorHwcLayer.kt
index 4b868622ce58..1094622a8ef0 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorHwcLayer.kt
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorHwcLayer.kt
@@ -101,10 +101,10 @@ class ScreenDecorHwcLayer(context: Context, displayDecorationSupport: DisplayDec
override fun onAttachedToWindow() {
super.onAttachedToWindow()
+ parent.requestTransparentRegion(this)
if (!DEBUG_COLOR) {
- parent.requestTransparentRegion(this)
+ viewRootImpl.setDisplayDecoration(true)
}
- viewRootImpl.setDisplayDecoration(true)
if (useInvertedAlphaColor) {
paint.set(clearPaint)
@@ -119,12 +119,15 @@ class ScreenDecorHwcLayer(context: Context, displayDecorationSupport: DisplayDec
if (useInvertedAlphaColor) {
canvas.drawColor(bgColor)
}
+
+ // We may clear the color(if useInvertedAlphaColor is true) of the rounded corner rects
+ // before drawing rounded corners. If the cutout happens to be inside one of these rects, it
+ // will be cleared, so we have to draw rounded corners before cutout.
+ drawRoundedCorners(canvas)
// Cutouts are drawn in DisplayCutoutBaseView.onDraw()
super.onDraw(canvas)
- drawRoundedCorners(canvas)
debugTransparentRegionPaint?.let {
- calculateTransparentRect()
canvas.drawRect(transparentRect, it)
}
}
@@ -132,7 +135,16 @@ class ScreenDecorHwcLayer(context: Context, displayDecorationSupport: DisplayDec
override fun gatherTransparentRegion(region: Region?): Boolean {
region?.let {
calculateTransparentRect()
- region.op(transparentRect, Region.Op.INTERSECT)
+ if (DEBUG_COLOR) {
+ // Since we're going to draw a rectangle where the layer would
+ // normally be transparent, treat the transparent region as
+ // empty. We still want this method to be called, though, so
+ // that it calculates the transparent rect at the right time
+ // to match !DEBUG_COLOR.
+ region.setEmpty()
+ } else {
+ region.op(transparentRect, Region.Op.INTERSECT)
+ }
}
// Always return false - views underneath this should always be visible.
return false
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
index ae41cae10bba..2f5292cec909 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
@@ -37,13 +37,11 @@ import android.content.pm.ActivityInfo;
import android.content.res.ColorStateList;
import android.content.res.Configuration;
import android.content.res.Resources;
-import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PixelFormat;
-import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.hardware.display.DisplayManager;
@@ -53,14 +51,12 @@ import android.os.Handler;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.provider.Settings.Secure;
-import android.util.DisplayMetrics;
-import android.util.DisplayUtils;
import android.util.Log;
+import android.util.Size;
import android.view.DisplayCutout;
import android.view.DisplayCutout.BoundsPosition;
import android.view.Gravity;
import android.view.LayoutInflater;
-import android.view.RoundedCorners;
import android.view.View;
import android.view.View.OnLayoutChangeListener;
import android.view.ViewGroup;
@@ -81,6 +77,7 @@ import com.android.systemui.decor.DecorProviderFactory;
import com.android.systemui.decor.DecorProviderKt;
import com.android.systemui.decor.OverlayWindow;
import com.android.systemui.decor.PrivacyDotDecorProviderFactory;
+import com.android.systemui.decor.RoundedCornerResDelegate;
import com.android.systemui.qs.SettingObserver;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.events.PrivacyDotViewController;
@@ -139,11 +136,7 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
// corners. for now it is only supposed when reading the intrinsic size from the drawables with
// mIsRoundedCornerMultipleRadius is set
@VisibleForTesting
- protected Point mRoundedDefault = new Point(0, 0);
- @VisibleForTesting
- protected Point mRoundedDefaultTop = new Point(0, 0);
- @VisibleForTesting
- protected Point mRoundedDefaultBottom = new Point(0, 0);
+ protected RoundedCornerResDelegate mRoundedCornerResDelegate;
@VisibleForTesting
protected OverlayWindow[] mOverlays = null;
@Nullable
@@ -152,17 +145,12 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
ViewGroup mScreenDecorHwcWindow;
@VisibleForTesting
ScreenDecorHwcLayer mScreenDecorHwcLayer;
- private float mDensity;
private WindowManager mWindowManager;
private int mRotation;
private SettingObserver mColorInversionSetting;
private DelayableExecutor mExecutor;
private Handler mHandler;
boolean mPendingRotationChange;
- private boolean mIsRoundedCornerMultipleRadius;
- private Drawable mRoundedCornerDrawable;
- private Drawable mRoundedCornerDrawableTop;
- private Drawable mRoundedCornerDrawableBottom;
@VisibleForTesting
String mDisplayUniqueId;
private int mTintColor = Color.BLACK;
@@ -302,7 +290,8 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
private void startOnScreenDecorationsThread() {
mRotation = mContext.getDisplay().getRotation();
mDisplayUniqueId = mContext.getDisplay().getUniqueId();
- mIsRoundedCornerMultipleRadius = isRoundedCornerMultipleRadius(mContext, mDisplayUniqueId);
+ mRoundedCornerResDelegate = new RoundedCornerResDelegate(mContext.getResources(),
+ mDisplayUniqueId);
mWindowManager = mContext.getSystemService(WindowManager.class);
mDisplayManager = mContext.getSystemService(DisplayManager.class);
mHwcScreenDecorationSupport = mContext.getDisplay().getDisplayDecorationSupport();
@@ -359,8 +348,7 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
final String newUniqueId = mContext.getDisplay().getUniqueId();
if (!Objects.equals(newUniqueId, mDisplayUniqueId)) {
mDisplayUniqueId = newUniqueId;
- mIsRoundedCornerMultipleRadius =
- isRoundedCornerMultipleRadius(mContext, mDisplayUniqueId);
+ mRoundedCornerResDelegate.reloadAll(newUniqueId);
final DisplayDecorationSupport newScreenDecorationSupport =
mContext.getDisplay().getDisplayDecorationSupport();
// When the value of mSupportHwcScreenDecoration is changed, re-setup the whole
@@ -457,9 +445,6 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
if (mIsRegistered) {
return;
}
- DisplayMetrics metrics = new DisplayMetrics();
- mContext.getDisplay().getMetrics(metrics);
- mDensity = metrics.density;
mMainExecutor.execute(() -> mTunerService.addTunable(this, SIZE));
@@ -606,8 +591,8 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
mScreenDecorHwcWindow.addView(mScreenDecorHwcLayer, new FrameLayout.LayoutParams(
MATCH_PARENT, MATCH_PARENT, Gravity.TOP | Gravity.START));
mWindowManager.addView(mScreenDecorHwcWindow, getHwcWindowLayoutParams());
- updateRoundedCornerSize(mRoundedDefault, mRoundedDefaultTop, mRoundedDefaultBottom);
- updateRoundedCornerImageView();
+ updateHwLayerRoundedCornerSize();
+ updateHwLayerRoundedCornerDrawable();
mScreenDecorHwcWindow.getViewTreeObserver().addOnPreDrawListener(
new ValidatingPreDrawListener(mScreenDecorHwcWindow));
}
@@ -640,7 +625,9 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
// update rounded corner view rotation
updateRoundedCornerView(pos, R.id.left, cutout);
updateRoundedCornerView(pos, R.id.right, cutout);
- updateRoundedCornerSize(mRoundedDefault, mRoundedDefaultTop, mRoundedDefaultBottom);
+ updateRoundedCornerSize(
+ mRoundedCornerResDelegate.getTopRoundedSize(),
+ mRoundedCornerResDelegate.getBottomRoundedSize());
updateRoundedCornerImageView();
// update cutout view rotation
@@ -844,7 +831,6 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
pw.println("ScreenDecorations state:");
pw.println(" DEBUG_DISABLE_SCREEN_DECORATIONS:" + DEBUG_DISABLE_SCREEN_DECORATIONS);
- pw.println(" mIsRoundedCornerMultipleRadius:" + mIsRoundedCornerMultipleRadius);
pw.println(" mIsPrivacyDotEnabled:" + isPrivacyDotEnabled());
pw.println(" mPendingRotationChange:" + mPendingRotationChange);
if (mHwcScreenDecorationSupport != null) {
@@ -862,16 +848,12 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
} else {
pw.println(" mScreenDecorHwcLayer: null");
}
- pw.println(" mRoundedDefault(x,y)=(" + mRoundedDefault.x + "," + mRoundedDefault.y + ")");
- pw.println(" mRoundedDefaultTop(x,y)=(" + mRoundedDefaultTop.x + "," + mRoundedDefaultTop.y
- + ")");
- pw.println(" mRoundedDefaultBottom(x,y)=(" + mRoundedDefaultBottom.x + ","
- + mRoundedDefaultBottom.y + ")");
pw.println(" mOverlays(left,top,right,bottom)=("
+ (mOverlays != null && mOverlays[BOUNDS_POSITION_LEFT] != null) + ","
+ (mOverlays != null && mOverlays[BOUNDS_POSITION_TOP] != null) + ","
+ (mOverlays != null && mOverlays[BOUNDS_POSITION_RIGHT] != null) + ","
+ (mOverlays != null && mOverlays[BOUNDS_POSITION_BOTTOM] != null) + ")");
+ mRoundedCornerResDelegate.dump(fd, pw, args);
}
private void updateOrientation() {
@@ -912,119 +894,18 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
// upgrading all of the configs to contain (width, height) pairs. Instead assume that a
// device configured using the single integer config value is okay with drawing the corners
// as a square
- final int newRoundedDefault = RoundedCorners.getRoundedCornerRadius(
- mContext.getResources(), mDisplayUniqueId);
- final int newRoundedDefaultTop = RoundedCorners.getRoundedCornerTopRadius(
- mContext.getResources(), mDisplayUniqueId);
- final int newRoundedDefaultBottom = RoundedCorners.getRoundedCornerBottomRadius(
- mContext.getResources(), mDisplayUniqueId);
-
- final boolean changed = mRoundedDefault.x != newRoundedDefault
- || mRoundedDefaultTop.x != newRoundedDefaultTop
- || mRoundedDefaultBottom.x != newRoundedDefaultBottom;
-
- if (changed) {
- // If config_roundedCornerMultipleRadius set as true, ScreenDecorations respect the
- // (width, height) size of drawable/rounded.xml instead of rounded_corner_radius
- if (mIsRoundedCornerMultipleRadius) {
- mRoundedDefault.set(mRoundedCornerDrawable.getIntrinsicWidth(),
- mRoundedCornerDrawable.getIntrinsicHeight());
- mRoundedDefaultTop.set(mRoundedCornerDrawableTop.getIntrinsicWidth(),
- mRoundedCornerDrawableTop.getIntrinsicHeight());
- mRoundedDefaultBottom.set(mRoundedCornerDrawableBottom.getIntrinsicWidth(),
- mRoundedCornerDrawableBottom.getIntrinsicHeight());
- } else {
- mRoundedDefault.set(newRoundedDefault, newRoundedDefault);
- mRoundedDefaultTop.set(newRoundedDefaultTop, newRoundedDefaultTop);
- mRoundedDefaultBottom.set(newRoundedDefaultBottom, newRoundedDefaultBottom);
- }
+ final Size oldRoundedDefaultTop = mRoundedCornerResDelegate.getTopRoundedSize();
+ final Size oldRoundedDefaultBottom = mRoundedCornerResDelegate.getBottomRoundedSize();
+ mRoundedCornerResDelegate.reloadAll(mDisplayUniqueId);
+ final Size newRoundedDefaultTop = mRoundedCornerResDelegate.getTopRoundedSize();
+ final Size newRoundedDefaultBottom = mRoundedCornerResDelegate.getBottomRoundedSize();
+
+ if (oldRoundedDefaultTop.getWidth() != newRoundedDefaultTop.getWidth()
+ || oldRoundedDefaultBottom.getWidth() != newRoundedDefaultBottom.getWidth()) {
onTuningChanged(SIZE, null);
}
}
- /**
- * Gets whether the rounded corners are multiple radii for current display.
- *
- * Loads the default config {@link R.bool#config_roundedCornerMultipleRadius} if
- * {@link com.android.internal.R.array#config_displayUniqueIdArray} is not set.
- */
- private static boolean isRoundedCornerMultipleRadius(Context context, String displayUniqueId) {
- final Resources res = context.getResources();
- final int index = DisplayUtils.getDisplayUniqueIdConfigIndex(res, displayUniqueId);
- final TypedArray array = res.obtainTypedArray(
- R.array.config_roundedCornerMultipleRadiusArray);
- boolean isMultipleRadius;
- if (index >= 0 && index < array.length()) {
- isMultipleRadius = array.getBoolean(index, false);
- } else {
- isMultipleRadius = res.getBoolean(R.bool.config_roundedCornerMultipleRadius);
- }
- array.recycle();
- return isMultipleRadius;
- }
-
- /**
- * Gets the rounded corner drawable for current display.
- *
- * Loads the default config {@link R.drawable#rounded} if
- * {@link com.android.internal.R.array#config_displayUniqueIdArray} is not set.
- */
- private static Drawable getRoundedCornerDrawable(Context context, String displayUniqueId) {
- final Resources res = context.getResources();
- final int index = DisplayUtils.getDisplayUniqueIdConfigIndex(res, displayUniqueId);
- final TypedArray array = res.obtainTypedArray(R.array.config_roundedCornerDrawableArray);
- Drawable drawable;
- if (index >= 0 && index < array.length()) {
- drawable = array.getDrawable(index);
- } else {
- drawable = context.getDrawable(R.drawable.rounded);
- }
- array.recycle();
- return drawable;
- }
-
- /**
- * Gets the rounded corner top drawable for current display.
- *
- * Loads the default config {@link R.drawable#rounded_corner_top} if
- * {@link com.android.internal.R.array#config_displayUniqueIdArray} is not set.
- */
- private static Drawable getRoundedCornerTopDrawable(Context context, String displayUniqueId) {
- final Resources res = context.getResources();
- final int index = DisplayUtils.getDisplayUniqueIdConfigIndex(res, displayUniqueId);
- final TypedArray array = res.obtainTypedArray(R.array.config_roundedCornerTopDrawableArray);
- Drawable drawable;
- if (index >= 0 && index < array.length()) {
- drawable = array.getDrawable(index);
- } else {
- drawable = context.getDrawable(R.drawable.rounded_corner_top);
- }
- array.recycle();
- return drawable;
- }
-
- /**
- * Gets the rounded corner bottom drawable for current display.
- *
- * Loads the default config {@link R.drawable#rounded_corner_bottom} if
- * {@link com.android.internal.R.array#config_displayUniqueIdArray} is not set.
- */
- private static Drawable getRoundedCornerBottomDrawable(
- Context context, String displayUniqueId) {
- final Resources res = context.getResources();
- final int index = DisplayUtils.getDisplayUniqueIdConfigIndex(res, displayUniqueId);
- final TypedArray array = res.obtainTypedArray(
- R.array.config_roundedCornerBottomDrawableArray);
- Drawable drawable;
- if (index >= 0 && index < array.length()) {
- drawable = array.getDrawable(index);
- } else {
- drawable = context.getDrawable(R.drawable.rounded_corner_bottom);
- }
- array.recycle();
- return drawable;
- }
-
private void updateRoundedCornerView(@BoundsPosition int pos, int id,
@Nullable DisplayCutout cutout) {
final View rounded = mOverlays[pos].getRootView().findViewById(id);
@@ -1085,10 +966,9 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
}
}
private boolean hasRoundedCorners() {
- return mRoundedDefault.x > 0
- || mRoundedDefaultBottom.x > 0
- || mRoundedDefaultTop.x > 0
- || mIsRoundedCornerMultipleRadius;
+ return mRoundedCornerResDelegate.getBottomRoundedSize().getWidth() > 0
+ || mRoundedCornerResDelegate.getTopRoundedSize().getWidth() > 0
+ || mRoundedCornerResDelegate.isMultipleRadius();
}
private boolean isDefaultShownOverlayPos(@BoundsPosition int pos,
@@ -1154,33 +1034,28 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
mExecutor.execute(() -> {
if (mOverlays == null) return;
if (SIZE.equals(key)) {
- Point size = mRoundedDefault;
- Point sizeTop = mRoundedDefaultTop;
- Point sizeBottom = mRoundedDefaultBottom;
if (newValue != null) {
try {
- int s = (int) (Integer.parseInt(newValue) * mDensity);
- size = new Point(s, s);
+ mRoundedCornerResDelegate.updateTuningSizeFactor(
+ Integer.parseInt(newValue));
} catch (Exception e) {
}
}
- updateRoundedCornerSize(size, sizeTop, sizeBottom);
+ updateRoundedCornerSize(
+ mRoundedCornerResDelegate.getTopRoundedSize(),
+ mRoundedCornerResDelegate.getBottomRoundedSize());
}
});
}
private void updateRoundedCornerDrawable() {
- mRoundedCornerDrawable = getRoundedCornerDrawable(mContext, mDisplayUniqueId);
- mRoundedCornerDrawableTop = getRoundedCornerTopDrawable(mContext, mDisplayUniqueId);
- mRoundedCornerDrawableBottom = getRoundedCornerBottomDrawable(mContext, mDisplayUniqueId);
+ mRoundedCornerResDelegate.reloadAll(mDisplayUniqueId);
updateRoundedCornerImageView();
}
private void updateRoundedCornerImageView() {
- final Drawable top = mRoundedCornerDrawableTop != null
- ? mRoundedCornerDrawableTop : mRoundedCornerDrawable;
- final Drawable bottom = mRoundedCornerDrawableBottom != null
- ? mRoundedCornerDrawableBottom : mRoundedCornerDrawable;
+ final Drawable top = mRoundedCornerResDelegate.getTopRoundedDrawable();
+ final Drawable bottom = mRoundedCornerResDelegate.getBottomRoundedDrawable();
if (mScreenDecorHwcLayer != null) {
mScreenDecorHwcLayer.updateRoundedCornerDrawable(top, bottom);
@@ -1205,6 +1080,20 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
}
}
+ private void updateHwLayerRoundedCornerDrawable() {
+ if (mScreenDecorHwcLayer == null) {
+ return;
+ }
+
+ final Drawable topDrawable = mRoundedCornerResDelegate.getTopRoundedDrawable();
+ final Drawable bottomDrawable = mRoundedCornerResDelegate.getBottomRoundedDrawable();
+
+ if (topDrawable == null || bottomDrawable == null) {
+ return;
+ }
+ mScreenDecorHwcLayer.updateRoundedCornerDrawable(topDrawable, bottomDrawable);
+ }
+
@VisibleForTesting
boolean isTopRoundedCorner(@BoundsPosition int pos, int id) {
switch (pos) {
@@ -1224,19 +1113,21 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
}
}
- private void updateRoundedCornerSize(
- Point sizeDefault,
- Point sizeTop,
- Point sizeBottom) {
- if (sizeTop.x == 0) {
- sizeTop = sizeDefault;
- }
- if (sizeBottom.x == 0) {
- sizeBottom = sizeDefault;
+ private void updateHwLayerRoundedCornerSize() {
+ if (mScreenDecorHwcLayer == null) {
+ return;
}
+ final int topWidth = mRoundedCornerResDelegate.getTopRoundedSize().getWidth();
+ final int bottomWidth = mRoundedCornerResDelegate.getBottomRoundedSize().getWidth();
+
+ mScreenDecorHwcLayer.updateRoundedCornerSize(topWidth, bottomWidth);
+ }
+
+ private void updateRoundedCornerSize(Size sizeTop, Size sizeBottom) {
+
if (mScreenDecorHwcLayer != null) {
- mScreenDecorHwcLayer.updateRoundedCornerSize(sizeTop.x, sizeBottom.x);
+ mScreenDecorHwcLayer.updateRoundedCornerSize(sizeTop.getWidth(), sizeBottom.getWidth());
return;
}
@@ -1256,10 +1147,10 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
}
@VisibleForTesting
- protected void setSize(View view, Point pixelSize) {
+ protected void setSize(View view, Size pixelSize) {
LayoutParams params = view.getLayoutParams();
- params.width = pixelSize.x;
- params.height = pixelSize.y;
+ params.width = pixelSize.getWidth();
+ params.height = pixelSize.getHeight();
view.setLayoutParams(params);
}
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
index 3a6165c03e24..031e3781ae9d 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
@@ -27,6 +27,7 @@ import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.res.Configuration;
import android.os.Bundle;
+import android.os.Looper;
import android.os.Process;
import android.os.RemoteException;
import android.os.SystemProperties;
@@ -105,6 +106,10 @@ public class SystemUIApplication extends Application implements
mBootCompleteCache = mSysUIComponent.provideBootCacheImpl();
log.traceEnd();
+ // Enable Looper trace points.
+ // This allows us to see Handler callbacks on traces.
+ Looper.getMainLooper().setTraceTag(Trace.TRACE_TAG_APP);
+
// Set the application theme that is inherited by all services. Note that setting the
// application theme in the manifest does only work for activities. Keep this in sync with
// the theme set there.
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
index 50ca447090b5..807ff21bf47a 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
@@ -254,8 +254,8 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
mMirrorViewGeometryVsyncCallback =
l -> {
- if (isWindowVisible() && mMirrorSurface != null) {
- calculateSourceBounds(mMagnificationFrame, mScale);
+ if (isWindowVisible() && mMirrorSurface != null && calculateSourceBounds(
+ mMagnificationFrame, mScale)) {
// The final destination for the magnification surface should be at 0,0
// since the ViewRootImpl's position will change
mTmpRect.set(0, 0, mMagnificationFrame.width(),
@@ -350,6 +350,7 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
mMirrorWindowControl.destroyControl();
}
mMirrorViewBounds.setEmpty();
+ mSourceBounds.setEmpty();
updateSystemUIStateIfNeeded();
mContext.unregisterComponentCallbacks(this);
}
@@ -728,8 +729,12 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
/**
* Calculates the desired source bounds. This will be the area under from the center of the
* displayFrame, factoring in scale.
+ *
+ * @return {@code true} if the source bounds is changed.
*/
- private void calculateSourceBounds(Rect displayFrame, float scale) {
+ private boolean calculateSourceBounds(Rect displayFrame, float scale) {
+ final Rect oldSourceBounds = mTmpRect;
+ oldSourceBounds.set(mSourceBounds);
int halfWidth = displayFrame.width() / 2;
int halfHeight = displayFrame.height() / 2;
int left = displayFrame.left + (halfWidth - (int) (halfWidth / scale));
@@ -757,6 +762,7 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
mSourceBounds.offsetTo(mSourceBounds.left,
mWindowBounds.height() - mSourceBounds.height());
}
+ return !mSourceBounds.equals(oldSourceBounds);
}
private void calculateMagnificationFrameBoundary() {
@@ -1072,13 +1078,14 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
pw.println("WindowMagnificationController (displayId=" + mDisplayId + "):");
pw.println(" mOverlapWithGestureInsets:" + mOverlapWithGestureInsets);
pw.println(" mScale:" + mScale);
+ pw.println(" mWindowBounds:" + mWindowBounds);
pw.println(" mMirrorViewBounds:" + (isWindowVisible() ? mMirrorViewBounds : "empty"));
pw.println(" mMagnificationFrameBoundary:"
+ (isWindowVisible() ? mMagnificationFrameBoundary : "empty"));
pw.println(" mMagnificationFrame:"
+ (isWindowVisible() ? mMagnificationFrame : "empty"));
pw.println(" mSourceBounds:"
- + (isWindowVisible() ? mSourceBounds : "empty"));
+ + (mSourceBounds.isEmpty() ? "empty" : mSourceBounds));
pw.println(" mSystemGestureTop:" + mSystemGestureTop);
pw.println(" mMagnificationFrameOffsetX:" + mMagnificationFrameOffsetX);
pw.println(" mMagnificationFrameOffsetY:" + mMagnificationFrameOffsetY);
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
index 64c2d2e3858e..c100a0744b85 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
@@ -726,8 +726,8 @@ public class AuthController extends CoreStartable implements CommandQueue.Callba
boolean isCameraPrivacyEnabled = false;
if (error == BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE
- && mSensorPrivacyManager.isSensorPrivacyEnabled(SensorPrivacyManager.Sensors.CAMERA,
- mCurrentDialogArgs.argi1 /* userId */)) {
+ && mSensorPrivacyManager.isSensorPrivacyEnabled(
+ SensorPrivacyManager.TOGGLE_TYPE_SOFTWARE, SensorPrivacyManager.Sensors.CAMERA)) {
isCameraPrivacyEnabled = true;
}
// TODO(b/141025588): Create separate methods for handling hard and soft errors.
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialView.java
index 57ca0f4826e9..2f2ca5b51fbf 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialView.java
@@ -20,7 +20,7 @@ import static android.app.admin.DevicePolicyResources.Strings.SystemUi.BIOMETRIC
import static android.app.admin.DevicePolicyResources.Strings.SystemUi.BIOMETRIC_DIALOG_WORK_PASSWORD_LAST_ATTEMPT;
import static android.app.admin.DevicePolicyResources.Strings.SystemUi.BIOMETRIC_DIALOG_WORK_PATTERN_LAST_ATTEMPT;
import static android.app.admin.DevicePolicyResources.Strings.SystemUi.BIOMETRIC_DIALOG_WORK_PIN_LAST_ATTEMPT;
-import static android.app.admin.DevicePolicyResources.Strings.UNDEFINED;
+import static android.app.admin.DevicePolicyResources.UNDEFINED;
import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -442,7 +442,7 @@ public abstract class AuthCredentialView extends LinearLayout {
private String getLastAttemptBeforeWipeProfileMessage(
@Utils.CredentialType int credentialType) {
- return mDevicePolicyManager.getString(
+ return mDevicePolicyManager.getResources().getString(
getLastAttemptBeforeWipeProfileUpdatableStringId(credentialType),
() -> getLastAttemptBeforeWipeProfileDefaultMessage(credentialType));
}
@@ -495,7 +495,7 @@ public abstract class AuthCredentialView extends LinearLayout {
}
private String getNowWipingMessage(@UserType int userType) {
- return mDevicePolicyManager.getString(
+ return mDevicePolicyManager.getResources().getString(
getNowWipingUpdatableStringId(userType),
() -> getNowWipingDefaultMessage(userType));
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
index 99f27d7f48e7..b811c51c952b 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
@@ -21,6 +21,7 @@ import android.animation.AnimatorListenerAdapter
import android.animation.ValueAnimator
import android.content.Context
import android.graphics.PointF
+import android.hardware.biometrics.BiometricFingerprintConstants
import android.hardware.biometrics.BiometricSourceType
import android.util.DisplayMetrics
import android.util.Log
@@ -39,8 +40,8 @@ import com.android.systemui.statusbar.NotificationShadeWindowController
import com.android.systemui.statusbar.commandline.Command
import com.android.systemui.statusbar.commandline.CommandRegistry
import com.android.systemui.statusbar.phone.BiometricUnlockController
-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.dagger.CentralSurfacesComponent.CentralSurfacesScope
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.statusbar.policy.KeyguardStateController
@@ -115,7 +116,7 @@ class AuthRippleController @Inject constructor(
}
fun showRipple(biometricSourceType: BiometricSourceType?) {
- if (!keyguardUpdateMonitor.isKeyguardVisible ||
+ if (!(keyguardUpdateMonitor.isKeyguardVisible || keyguardUpdateMonitor.isDreaming) ||
keyguardUpdateMonitor.userNeedsStrongAuth()) {
return
}
@@ -257,6 +258,16 @@ class AuthRippleController @Inject constructor(
override fun onBiometricAuthFailed(biometricSourceType: BiometricSourceType?) {
mView.retractRipple()
}
+
+ override fun onBiometricAcquired(
+ biometricSourceType: BiometricSourceType?,
+ acquireInfo: Int
+ ) {
+ if (biometricSourceType == BiometricSourceType.FINGERPRINT &&
+ acquireInfo == BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_PARTIAL) {
+ mView.retractRipple()
+ }
+ }
}
private val configurationChangedListener =
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index 8052c2071d86..975e0c5b32cd 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -16,6 +16,7 @@
package com.android.systemui.biometrics;
+import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_GOOD;
import static android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_KEYGUARD;
import static com.android.internal.util.Preconditions.checkArgument;
@@ -30,6 +31,7 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Point;
import android.graphics.RectF;
+import android.hardware.biometrics.BiometricFingerprintConstants;
import android.hardware.biometrics.SensorLocationInternal;
import android.hardware.display.DisplayManager;
import android.hardware.fingerprint.FingerprintManager;
@@ -47,7 +49,6 @@ import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.Surface;
import android.view.VelocityTracker;
-import android.view.View;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityManager;
@@ -90,7 +91,7 @@ import kotlin.Unit;
* Note that the current architecture is designed so that a single {@link UdfpsController}
* controls/manages all UDFPS sensors. In other words, a single controller is registered with
* {@link com.android.server.biometrics.sensors.fingerprint.FingerprintService}, and interfaces such
- * as {@link FingerprintManager#onPointerDown(int, int, int, float, float)} or
+ * as {@link FingerprintManager#onPointerDown(long, int, int, int, float, float)} or
* {@link IUdfpsOverlayController#showUdfpsOverlay} should all have
* {@code sensorId} parameters.
*/
@@ -141,11 +142,11 @@ public class UdfpsController implements DozeReceiver {
private int mActivePointerId = -1;
// The timestamp of the most recent touch log.
private long mTouchLogTime;
- // Sensor has a good capture for this touch. Do not need to illuminate for this particular
- // touch event anymore. In other words, do not illuminate until user lifts and touches the
- // sensor area again.
+ // Sensor has a capture (good or bad) for this touch. Do not need to illuminate for this
+ // particular touch event anymore. In other words, do not illuminate until user lifts and
+ // touches the sensor area again.
// TODO: We should probably try to make touch/illumination things more of a FSM
- private boolean mGoodCaptureReceived;
+ private boolean mAcquiredReceived;
// The current request from FingerprintService. Null if no current request.
@Nullable UdfpsControllerOverlay mOverlay;
@@ -191,7 +192,7 @@ public class UdfpsController implements DozeReceiver {
public class UdfpsOverlayController extends IUdfpsOverlayController.Stub {
@Override
- public void showUdfpsOverlay(int sensorId, int reason,
+ public void showUdfpsOverlay(long requestId, int sensorId, int reason,
@NonNull IUdfpsOverlayControllerCallback callback) {
mFgExecutor.execute(
() -> UdfpsController.this.showUdfpsOverlay(new UdfpsControllerOverlay(
@@ -201,8 +202,10 @@ public class UdfpsController implements DozeReceiver {
mKeyguardUpdateMonitor, mDialogManager, mDumpManager,
mLockscreenShadeTransitionController, mConfigurationController,
mSystemClock, mKeyguardStateController,
- mUnlockedScreenOffAnimationController, mSensorProps, mHbmProvider,
- reason, callback, UdfpsController.this::onTouch,
+ mUnlockedScreenOffAnimationController, mSensorProps,
+ mHbmProvider, requestId, reason, callback,
+ (view, event, fromUdfpsView) ->
+ onTouch(requestId, event, fromUdfpsView),
mActivityLaunchAnimator)));
}
@@ -221,19 +224,28 @@ public class UdfpsController implements DozeReceiver {
}
@Override
- public void onAcquiredGood(int sensorId) {
- mFgExecutor.execute(() -> {
- if (mOverlay == null) {
- Log.e(TAG, "Null request when onAcquiredGood for sensorId: " + sensorId);
- return;
- }
- mGoodCaptureReceived = true;
- final UdfpsView view = mOverlay.getOverlayView();
- if (view != null) {
- view.stopIllumination();
- }
- mOverlay.onAcquiredGood();
- });
+ public void onAcquired(
+ int sensorId,
+ @BiometricFingerprintConstants.FingerprintAcquired int acquiredInfo
+ ) {
+ if (BiometricFingerprintConstants.shouldTurnOffHbm(acquiredInfo)) {
+ boolean acquiredGood = acquiredInfo == FINGERPRINT_ACQUIRED_GOOD;
+ mFgExecutor.execute(() -> {
+ if (mOverlay == null) {
+ Log.e(TAG, "Null request when onAcquired for sensorId: " + sensorId
+ + " acquiredInfo=" + acquiredInfo);
+ return;
+ }
+ mAcquiredReceived = true;
+ final UdfpsView view = mOverlay.getOverlayView();
+ if (view != null) {
+ view.stopIllumination(); // turn off HBM
+ }
+ if (acquiredGood) {
+ mOverlay.onAcquiredGood();
+ }
+ });
+ }
}
@Override
@@ -307,7 +319,8 @@ public class UdfpsController implements DozeReceiver {
if (mOverlay == null || mOverlay.isHiding()) {
return false;
}
- return onTouch(mOverlay.getOverlayView(), event, false);
+ // TODO(b/225068271): may not be correct but no way to get the id yet
+ return onTouch(mOverlay.getRequestId(), event, false);
}
/**
@@ -331,8 +344,18 @@ public class UdfpsController implements DozeReceiver {
&& getSensorLocation().contains(x, y);
}
- private boolean onTouch(@NonNull View view, @NonNull MotionEvent event, boolean fromUdfpsView) {
- UdfpsView udfpsView = (UdfpsView) view;
+ private boolean onTouch(long requestId, @NonNull MotionEvent event, boolean fromUdfpsView) {
+ if (mOverlay == null) {
+ Log.w(TAG, "ignoring onTouch with null overlay");
+ return false;
+ }
+ if (!mOverlay.matchesRequestId(requestId)) {
+ Log.w(TAG, "ignoring stale touch event: " + requestId + " current: "
+ + mOverlay.getRequestId());
+ return false;
+ }
+
+ final UdfpsView udfpsView = mOverlay.getOverlayView();
final boolean isIlluminationRequested = udfpsView.isIlluminationRequested();
boolean handled = false;
switch (event.getActionMasked()) {
@@ -414,8 +437,8 @@ public class UdfpsController implements DozeReceiver {
"minor: %.1f, major: %.1f, v: %.1f, exceedsVelocityThreshold: %b",
minor, major, v, exceedsVelocityThreshold);
final long sinceLastLog = mSystemClock.elapsedRealtime() - mTouchLogTime;
- if (!isIlluminationRequested && !mGoodCaptureReceived &&
- !exceedsVelocityThreshold) {
+ if (!isIlluminationRequested && !mAcquiredReceived
+ && !exceedsVelocityThreshold) {
final int rawX = (int) event.getRawX();
final int rawY = (int) event.getRawY();
// Default coordinates assume portrait mode.
@@ -442,7 +465,7 @@ public class UdfpsController implements DozeReceiver {
// Do nothing to stay in portrait mode.
}
- onFingerDown(x, y, minor, major);
+ onFingerDown(requestId, x, y, minor, major);
Log.v(TAG, "onTouch | finger down: " + touchInfo);
mTouchLogTime = mSystemClock.elapsedRealtime();
mPowerManager.userActivity(mSystemClock.uptimeMillis(),
@@ -454,7 +477,7 @@ public class UdfpsController implements DozeReceiver {
}
} else {
Log.v(TAG, "onTouch | finger outside");
- onFingerUp(udfpsView);
+ onFingerUp(requestId, udfpsView);
}
}
Trace.endSection();
@@ -471,7 +494,7 @@ public class UdfpsController implements DozeReceiver {
}
Log.v(TAG, "onTouch | finger up");
mAttemptedToDismissKeyguard = false;
- onFingerUp(udfpsView);
+ onFingerUp(requestId, udfpsView);
mFalsingManager.isFalseTouch(UDFPS_AUTHENTICATION);
Trace.endSection();
break;
@@ -573,16 +596,18 @@ public class UdfpsController implements DozeReceiver {
}
/**
- * Play haptic to signal udfps scanning started.
+ * If a11y touchExplorationEnabled, play haptic to signal UDFPS scanning started.
*/
@VisibleForTesting
public void playStartHaptic() {
- mVibrator.vibrate(
- Process.myUid(),
- mContext.getOpPackageName(),
- EFFECT_CLICK,
- "udfps-onStart-click",
- VIBRATION_ATTRIBUTES);
+ if (mAccessibilityManager.isTouchExplorationEnabled()) {
+ mVibrator.vibrate(
+ Process.myUid(),
+ mContext.getOpPackageName(),
+ EFFECT_CLICK,
+ "udfps-onStart-click",
+ VIBRATION_ATTRIBUTES);
+ }
}
@Nullable
@@ -666,7 +691,7 @@ public class UdfpsController implements DozeReceiver {
// Reset the controller back to its starting state.
final UdfpsView oldView = mOverlay.getOverlayView();
if (oldView != null) {
- onFingerUp(oldView);
+ onFingerUp(mOverlay.getRequestId(), oldView);
}
final boolean removed = mOverlay.hide();
if (mKeyguardViewManager.isShowingAlternateAuth()) {
@@ -697,6 +722,8 @@ public class UdfpsController implements DozeReceiver {
return;
}
+ // TODO(b/225068271): this may not be correct but there isn't a way to track it
+ final long requestId = mOverlay != null ? mOverlay.getRequestId() : -1;
mAodInterruptRunnable = () -> {
mIsAodInterruptActive = true;
// Since the sensor that triggers the AOD interrupt doesn't provide
@@ -706,10 +733,10 @@ public class UdfpsController implements DozeReceiver {
mCancelAodTimeoutAction = mFgExecutor.executeDelayed(this::onCancelUdfps,
AOD_INTERRUPT_TIMEOUT_MILLIS);
// using a hard-coded value for major and minor until it is available from the sensor
- onFingerDown(screenX, screenY, minor, major);
+ onFingerDown(requestId, screenX, screenY, minor, major);
};
- if (mScreenOn && mAodInterruptRunnable != null) {
+ if (mScreenOn) {
mAodInterruptRunnable.run();
mAodInterruptRunnable = null;
}
@@ -742,7 +769,7 @@ public class UdfpsController implements DozeReceiver {
*/
void onCancelUdfps() {
if (mOverlay != null && mOverlay.getOverlayView() != null) {
- onFingerUp(mOverlay.getOverlayView());
+ onFingerUp(mOverlay.getRequestId(), mOverlay.getOverlayView());
}
if (!mIsAodInterruptActive) {
return;
@@ -758,12 +785,17 @@ public class UdfpsController implements DozeReceiver {
return mOnFingerDown;
}
- private void onFingerDown(int x, int y, float minor, float major) {
+ private void onFingerDown(long requestId, int x, int y, float minor, float major) {
mExecution.assertIsMainThread();
if (mOverlay == null) {
Log.w(TAG, "Null request in onFingerDown");
return;
}
+ if (!mOverlay.matchesRequestId(requestId)) {
+ Log.w(TAG, "Mismatched fingerDown: " + requestId
+ + " current: " + mOverlay.getRequestId());
+ return;
+ }
if (mOverlay.getAnimationViewController() instanceof UdfpsKeyguardViewController
&& !mStatusBarStateController.isDozing()) {
@@ -778,14 +810,14 @@ public class UdfpsController implements DozeReceiver {
}
}
mOnFingerDown = true;
- mFingerprintManager.onPointerDown(mSensorProps.sensorId, x, y, minor, major);
+ mFingerprintManager.onPointerDown(requestId, mSensorProps.sensorId, x, y, minor, major);
Trace.endAsyncSection("UdfpsController.e2e.onPointerDown", 0);
final UdfpsView view = mOverlay.getOverlayView();
if (view != null) {
Trace.beginAsyncSection("UdfpsController.e2e.startIllumination", 0);
view.startIllumination(() -> {
- mFingerprintManager.onUiReady(mSensorProps.sensorId);
+ mFingerprintManager.onUiReady(requestId, mSensorProps.sensorId);
mLatencyTracker.onActionEnd(LatencyTracker.ACTION_UDFPS_ILLUMINATE);
Trace.endAsyncSection("UdfpsController.e2e.startIllumination", 0);
});
@@ -796,12 +828,12 @@ public class UdfpsController implements DozeReceiver {
}
}
- private void onFingerUp(@NonNull UdfpsView view) {
+ private void onFingerUp(long requestId, @NonNull UdfpsView view) {
mExecution.assertIsMainThread();
mActivePointerId = -1;
- mGoodCaptureReceived = false;
+ mAcquiredReceived = false;
if (mOnFingerDown) {
- mFingerprintManager.onPointerUp(mSensorProps.sensorId);
+ mFingerprintManager.onPointerUp(requestId, mSensorProps.sensorId);
for (Callback cb : mCallbacks) {
cb.onFingerUp();
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt
index 086894d2e670..ee43e932b344 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt
@@ -80,6 +80,7 @@ class UdfpsControllerOverlay(
private val unlockedScreenOffAnimationController: UnlockedScreenOffAnimationController,
private val sensorProps: FingerprintSensorPropertiesInternal,
private var hbmProvider: UdfpsHbmProvider,
+ val requestId: Long,
@ShowReason val requestReason: Int,
private val controllerCallback: IUdfpsOverlayControllerCallback,
private val onTouch: (View, MotionEvent, Boolean) -> Boolean,
@@ -276,6 +277,9 @@ class UdfpsControllerOverlay(
}
}
+ /** Checks if the id is relevant for this overlay. */
+ fun matchesRequestId(id: Long): Boolean = requestId == -1L || requestId == id
+
private fun WindowManager.LayoutParams.updateForLocation(
location: SensorLocationInternal,
animation: UdfpsAnimationViewController<*>?
diff --git a/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastSender.kt b/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastSender.kt
new file mode 100644
index 000000000000..6615f6b0b9eb
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastSender.kt
@@ -0,0 +1,132 @@
+package com.android.systemui.broadcast
+
+import android.annotation.AnyThread
+import android.content.Context
+import android.content.Intent
+import android.os.Bundle
+import android.os.UserHandle
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.util.wakelock.WakeLock
+import java.util.concurrent.Executor
+import javax.inject.Inject
+
+/**
+ * SystemUI master Broadcast sender
+ *
+ * This class dispatches broadcasts on background thread to avoid synchronous call to binder. Use
+ * this class instead of calling [Context.sendBroadcast] directly.
+ */
+@SysUISingleton
+class BroadcastSender @Inject constructor(
+ private val context: Context,
+ private val wakeLockBuilder: WakeLock.Builder,
+ @Background private val bgExecutor: Executor
+) {
+
+ private val WAKE_LOCK_TAG = "SysUI:BroadcastSender"
+ private val WAKE_LOCK_SEND_REASON = "sendInBackground"
+
+ /**
+ * Sends broadcast via [Context.sendBroadcast] on background thread to avoid blocking
+ * synchronous binder call.
+ */
+ @AnyThread
+ fun sendBroadcast(intent: Intent) {
+ sendInBackground {
+ context.sendBroadcast(intent)
+ }
+ }
+
+ /**
+ * Sends broadcast via [Context.sendBroadcast] on background thread to avoid blocking
+ * synchronous binder call.
+ */
+ @AnyThread
+ fun sendBroadcast(intent: Intent, receiverPermission: String?) {
+ sendInBackground {
+ context.sendBroadcast(intent, receiverPermission)
+ }
+ }
+
+ /**
+ * Sends broadcast via [Context.sendBroadcastAsUser] on background thread to avoid blocking
+ * synchronous binder call.
+ */
+ @AnyThread
+ fun sendBroadcastAsUser(intent: Intent, userHandle: UserHandle) {
+ sendInBackground {
+ context.sendBroadcastAsUser(intent, userHandle)
+ }
+ }
+
+ /**
+ * Sends broadcast via [Context.sendBroadcastAsUser] on background thread to avoid blocking
+ * synchronous binder call.
+ */
+ @AnyThread
+ fun sendBroadcastAsUser(intent: Intent, userHandle: UserHandle, receiverPermission: String?) {
+ sendInBackground {
+ context.sendBroadcastAsUser(intent, userHandle, receiverPermission)
+ }
+ }
+
+ /**
+ * Sends broadcast via [Context.sendBroadcastAsUser] on background thread to avoid blocking
+ * synchronous binder call.
+ */
+ @AnyThread
+ fun sendBroadcastAsUser(
+ intent: Intent,
+ userHandle: UserHandle,
+ receiverPermission: String?,
+ options: Bundle?
+ ) {
+ sendInBackground {
+ context.sendBroadcastAsUser(intent, userHandle, receiverPermission, options)
+ }
+ }
+
+ /**
+ * Sends broadcast via [Context.sendBroadcastAsUser] on background thread to avoid blocking
+ * synchronous binder call.
+ */
+ @AnyThread
+ fun sendBroadcastAsUser(
+ intent: Intent,
+ userHandle: UserHandle,
+ receiverPermission: String?,
+ appOp: Int
+ ) {
+ sendInBackground {
+ context.sendBroadcastAsUser(intent, userHandle, receiverPermission, appOp)
+ }
+ }
+
+ /**
+ * Sends [Intent.ACTION_CLOSE_SYSTEM_DIALOGS] broadcast to the system.
+ */
+ @AnyThread
+ fun closeSystemDialogs() {
+ sendInBackground {
+ context.sendBroadcast(Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS))
+ }
+ }
+
+ /**
+ * Dispatches parameter on background executor while holding a wakelock.
+ */
+ private fun sendInBackground(callable: () -> Unit) {
+ val broadcastWakelock = wakeLockBuilder.setTag(WAKE_LOCK_TAG)
+ .setMaxTimeout(5000)
+ .build()
+ broadcastWakelock.acquire(WAKE_LOCK_SEND_REASON)
+ bgExecutor.execute {
+ try {
+ callable.invoke()
+ } finally {
+ broadcastWakelock.release(WAKE_LOCK_SEND_REASON)
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingAnimation.java b/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingAnimation.java
index 508262d4ddec..835025bbfc88 100644
--- a/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingAnimation.java
+++ b/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingAnimation.java
@@ -16,6 +16,8 @@
package com.android.systemui.charging;
+import static com.android.systemui.charging.WirelessChargingLayout.UNKNOWN_BATTERY_LEVEL;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
@@ -76,6 +78,16 @@ public class WirelessChargingAnimation {
}
/**
+ * Creates a charging animation object using mostly default values for non-dozing and unknown
+ * battery level without charging number shown.
+ */
+ public static WirelessChargingAnimation makeChargingAnimationWithNoBatteryLevel(
+ @NonNull Context context, UiEventLogger uiEventLogger) {
+ return makeWirelessChargingAnimation(context, null,
+ UNKNOWN_BATTERY_LEVEL, UNKNOWN_BATTERY_LEVEL, null, false, uiEventLogger);
+ }
+
+ /**
* Show the view for the specified duration.
*/
public void show(long delay) {
diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java
index 56e4d7ec1882..0f937d163f5c 100644
--- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java
@@ -73,6 +73,7 @@ import android.widget.TextView;
import com.android.internal.policy.PhoneWindow;
import com.android.systemui.R;
+import com.android.systemui.screenshot.DraggableConstraintLayout;
import com.android.systemui.screenshot.FloatingWindowUtil;
import com.android.systemui.screenshot.OverlayActionChip;
import com.android.systemui.screenshot.TimeoutHandler;
@@ -166,8 +167,28 @@ public class ClipboardOverlayController {
mRemoteCopyChip = requireNonNull(mView.findViewById(R.id.remote_copy_chip));
mDismissButton = requireNonNull(mView.findViewById(R.id.dismiss_button));
- mView.setOnDismissEndCallback(this::hideImmediate);
- mView.setOnInteractionCallback(mTimeoutHandler::resetTimeout);
+ mView.setCallbacks(new DraggableConstraintLayout.SwipeDismissCallbacks() {
+ @Override
+ public void onInteraction() {
+ mTimeoutHandler.resetTimeout();
+ }
+
+ @Override
+ public void onSwipeDismissInitiated(Animator animator) {
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ super.onAnimationStart(animation);
+ mContainer.animate().alpha(0).start();
+ }
+ });
+ }
+
+ @Override
+ public void onDismissComplete() {
+ hideImmediate();
+ }
+ });
mDismissButton.setOnClickListener(view -> animateOut());
diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/DraggableConstraintLayout.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/DraggableConstraintLayout.java
deleted file mode 100644
index a327809640db..000000000000
--- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/DraggableConstraintLayout.java
+++ /dev/null
@@ -1,140 +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.systemui.clipboardoverlay;
-
-import android.animation.Animator;
-import android.content.Context;
-import android.graphics.Rect;
-import android.util.AttributeSet;
-import android.view.GestureDetector;
-import android.view.MotionEvent;
-import android.view.View;
-
-import androidx.constraintlayout.widget.ConstraintLayout;
-
-import com.android.systemui.R;
-import com.android.systemui.screenshot.SwipeDismissHandler;
-
-import java.util.function.Consumer;
-
-/**
- * ConstraintLayout that is draggable when touched in a specific region
- */
-public class DraggableConstraintLayout extends ConstraintLayout {
- private final SwipeDismissHandler mSwipeDismissHandler;
- private final GestureDetector mSwipeDetector;
- private Consumer<Animator> mOnDismissInitiated;
- private Runnable mOnDismissComplete;
- private Runnable mOnInteraction;
-
- public DraggableConstraintLayout(Context context) {
- this(context, null);
- }
-
- public DraggableConstraintLayout(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public DraggableConstraintLayout(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
-
- mSwipeDismissHandler = new SwipeDismissHandler(mContext, this,
- new SwipeDismissHandler.SwipeDismissCallbacks() {
- @Override
- public void onInteraction() {
- if (mOnInteraction != null) {
- mOnInteraction.run();
- }
- }
-
- @Override
- public void onSwipeDismissInitiated(Animator animator) {
- if (mOnDismissInitiated != null) {
- mOnDismissInitiated.accept(animator);
- }
- }
-
- @Override
- public void onDismissComplete() {
- if (mOnDismissComplete != null) {
- mOnDismissComplete.run();
- }
- }
- });
- setOnTouchListener(mSwipeDismissHandler);
-
- mSwipeDetector = new GestureDetector(mContext,
- new GestureDetector.SimpleOnGestureListener() {
- final Rect mActionsRect = new Rect();
-
- @Override
- public boolean onScroll(
- MotionEvent ev1, MotionEvent ev2, float distanceX, float distanceY) {
- View actionsContainer = findViewById(R.id.actions_container);
- actionsContainer.getBoundsOnScreen(mActionsRect);
- // return true if we aren't in the actions bar, or if we are but it isn't
- // scrollable in the direction of movement
- return !mActionsRect.contains((int) ev2.getRawX(), (int) ev2.getRawY())
- || !actionsContainer.canScrollHorizontally((int) distanceX);
- }
- });
- mSwipeDetector.setIsLongpressEnabled(false);
- }
-
- @Override // View
- protected void onFinishInflate() {
-
- }
-
- @Override
- public boolean onInterceptTouchEvent(MotionEvent ev) {
- if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) {
- mSwipeDismissHandler.onTouch(this, ev);
- }
-
- return mSwipeDetector.onTouchEvent(ev);
- }
-
- /**
- * Dismiss the view, with animation controlled by SwipeDismissHandler
- */
- public void dismiss() {
- mSwipeDismissHandler.dismiss();
- }
-
- /**
- * Set the callback to be run after view is dismissed (before animation; receives animator as
- * input)
- */
- public void setOnDismissStartCallback(Consumer<Animator> callback) {
- mOnDismissInitiated = callback;
- }
-
- /**
- * Set the callback to be run after view is dismissed
- */
- public void setOnDismissEndCallback(Runnable callback) {
- mOnDismissComplete = callback;
- }
-
- /**
- * Set the callback to be run when the view is interacted with (e.g. tapped)
- */
- public void setOnInteractionCallback(Runnable callback) {
- mOnInteraction = callback;
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/CommunalHostView.java b/packages/SystemUI/src/com/android/systemui/communal/CommunalHostView.java
deleted file mode 100644
index 6e2fcd11f643..000000000000
--- a/packages/SystemUI/src/com/android/systemui/communal/CommunalHostView.java
+++ /dev/null
@@ -1,45 +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.systemui.communal;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.widget.FrameLayout;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-/**
- * Container for communal presentation. Containing communal-related view to this parent view allows
- * for aggregate measurement/layout adjustments and capturing said values before the communal views
- * might be available.
- */
-public class CommunalHostView extends FrameLayout {
- public CommunalHostView(@NonNull Context context) {
- this(context, null, 0);
- }
-
- public CommunalHostView(@NonNull Context context,
- @Nullable AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public CommunalHostView(@NonNull Context context, @Nullable AttributeSet attrs,
- int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/CommunalHostViewController.java b/packages/SystemUI/src/com/android/systemui/communal/CommunalHostViewController.java
deleted file mode 100644
index b42838099986..000000000000
--- a/packages/SystemUI/src/com/android/systemui/communal/CommunalHostViewController.java
+++ /dev/null
@@ -1,396 +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.systemui.communal;
-
-import android.annotation.IntDef;
-import android.content.Context;
-import android.util.Log;
-import android.view.View;
-import android.view.ViewGroup;
-
-import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.keyguard.KeyguardUpdateMonitorCallback;
-import com.android.keyguard.KeyguardVisibilityHelper;
-import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.StatusBarState;
-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.notification.stack.StackStateAnimator;
-import com.android.systemui.statusbar.phone.DozeParameters;
-import com.android.systemui.statusbar.phone.ScreenOffAnimationController;
-import com.android.systemui.statusbar.policy.KeyguardStateController;
-import com.android.systemui.util.ViewController;
-
-import com.google.common.util.concurrent.ListenableFuture;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.ref.WeakReference;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.concurrent.Executor;
-
-import javax.inject.Inject;
-
-/**
- * Injectable controller for {@link CommunalHostView}.
- */
-public class CommunalHostViewController extends ViewController<CommunalHostView> {
- private static final String TAG = "CommunalController";
- private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
- private static final String STATE_LIST_FORMAT = "[%s]";
- private static final AnimationProperties COMMUNAL_ANIMATION_PROPERTIES =
- new AnimationProperties().setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
-
- private final Executor mMainExecutor;
- private final CommunalStateController mCommunalStateController;
- private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
- private final KeyguardStateController mKeyguardStateController;
- private final StatusBarStateController mStatusBarStateController;
- private WeakReference<CommunalSource> mCurrentSource;
- private Optional<ShowRequest> mLastRequest = Optional.empty();
- private int mState;
- private float mQsExpansion;
- private float mShadeExpansion;
-
- @Retention(RetentionPolicy.RUNTIME)
- @IntDef({STATE_KEYGUARD_SHOWING, STATE_DOZING, STATE_BOUNCER_SHOWING, STATE_KEYGUARD_OCCLUDED})
- public @interface State {}
-
- private static final int STATE_KEYGUARD_SHOWING = 1 << 0;
- private static final int STATE_DOZING = 1 << 1;
- private static final int STATE_BOUNCER_SHOWING = 1 << 2;
- private static final int STATE_KEYGUARD_OCCLUDED = 1 << 3;
-
- // Only show communal view when keyguard is showing and not dozing.
- private static final int SHOW_COMMUNAL_VIEW_REQUIRED_STATES = STATE_KEYGUARD_SHOWING;
- private static final int SHOW_COMMUNAL_VIEW_INVALID_STATES =
- STATE_DOZING | STATE_KEYGUARD_OCCLUDED;
-
- private final KeyguardVisibilityHelper mKeyguardVisibilityHelper;
-
- private ViewController<? extends View> mCommunalViewController;
-
- private static class ShowRequest {
- private boolean mShouldShow;
- private WeakReference<CommunalSource> mSource;
-
- ShowRequest(boolean shouldShow, WeakReference<CommunalSource> source) {
- mShouldShow = shouldShow;
- mSource = source;
- }
-
- CommunalSource getSource() {
- return mSource != null ? mSource.get() : null;
- }
-
- boolean shouldShow() {
- return mShouldShow;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (!(o instanceof ShowRequest)) return false;
- ShowRequest that = (ShowRequest) o;
- return mShouldShow == that.mShouldShow && Objects.equals(getSource(), that.getSource());
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(mShouldShow, mSource);
- }
- }
-
- private KeyguardUpdateMonitorCallback mKeyguardUpdateCallback =
- new KeyguardUpdateMonitorCallback() {
- @Override
- public void onKeyguardBouncerChanged(boolean bouncer) {
- if (DEBUG) {
- Log.d(TAG, "onKeyguardBouncerChanged:" + bouncer);
- }
-
- setState(STATE_BOUNCER_SHOWING, bouncer);
- }
-
- @Override
- public void onKeyguardOccludedChanged(boolean occluded) {
- if (DEBUG) {
- Log.d(TAG, "onKeyguardOccludedChanged" + occluded);
- }
-
- setState(STATE_KEYGUARD_OCCLUDED, occluded);
- }
- };
-
- private KeyguardStateController.Callback mKeyguardCallback =
- new KeyguardStateController.Callback() {
- @Override
- public void onKeyguardShowingChanged() {
- final boolean isShowing = mKeyguardStateController.isShowing();
- if (DEBUG) {
- Log.d(TAG, "setKeyguardShowing:" + isShowing);
- }
-
- setState(STATE_KEYGUARD_SHOWING, isShowing);
- }
- };
-
- private StatusBarStateController.StateListener mDozeCallback =
- new StatusBarStateController.StateListener() {
- @Override
- public void onDozingChanged(boolean isDozing) {
- if (DEBUG) {
- Log.d(TAG, "setDozing:" + isDozing);
- }
-
- setState(STATE_DOZING, isDozing);
- }
-
- @Override
- public void onStateChanged(int newState) {
- updateCommunalViewOccluded();
- }
- };
-
- @Inject
- protected CommunalHostViewController(@Main Executor mainExecutor,
- CommunalStateController communalStateController,
- KeyguardUpdateMonitor keyguardUpdateMonitor,
- KeyguardStateController keyguardStateController,
- DozeParameters dozeParameters,
- ScreenOffAnimationController screenOffAnimationController,
- StatusBarStateController statusBarStateController, CommunalHostView view) {
- super(view);
- mCommunalStateController = communalStateController;
- mKeyguardUpdateMonitor = keyguardUpdateMonitor;
- mMainExecutor = mainExecutor;
- mKeyguardStateController = keyguardStateController;
- mStatusBarStateController = statusBarStateController;
- mKeyguardVisibilityHelper = new KeyguardVisibilityHelper(mView, communalStateController,
- keyguardStateController, dozeParameters, screenOffAnimationController,
- /* animateYPos= */ false, /* visibleOnCommunal= */ true);
- }
-
- /**
- * Set the visibility of the keyguard status view based on some new state.
- */
- public void setKeyguardStatusViewVisibility(
- int statusBarState,
- boolean keyguardFadingAway,
- boolean goingToFullShade,
- int oldStatusBarState) {
- mKeyguardVisibilityHelper.setViewVisibility(
- statusBarState, keyguardFadingAway, goingToFullShade, oldStatusBarState);
- }
-
- /**
- * Set keyguard status view alpha.
- */
- public void setAlpha(float alpha) {
- if (!mKeyguardVisibilityHelper.isVisibilityAnimating()) {
- mView.setAlpha(alpha);
-
- // Some communal view implementations, such as SurfaceViews, do not behave correctly
- // inheriting the alpha of their parent. Directly set child alpha here to work around
- // this.
- for (int i = mView.getChildCount() - 1; i >= 0; --i) {
- mView.getChildAt(i).setAlpha(alpha);
- }
- }
- }
- @Override
- public void onInit() {
- setState(STATE_KEYGUARD_SHOWING, mKeyguardStateController.isShowing());
- setState(STATE_DOZING, mStatusBarStateController.isDozing());
- }
-
- @Override
- protected void onViewAttached() {
- mKeyguardStateController.addCallback(mKeyguardCallback);
- mStatusBarStateController.addCallback(mDozeCallback);
- mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateCallback);
- }
-
- @Override
- protected void onViewDetached() {
- mKeyguardStateController.removeCallback(mKeyguardCallback);
- mStatusBarStateController.removeCallback(mDozeCallback);
- mKeyguardUpdateMonitor.removeCallback(mKeyguardUpdateCallback);
- }
-
- private void setState(@State int stateFlag, boolean enabled) {
- final int existingState = mState;
- if (DEBUG) {
- Log.d(TAG, "setState flag:" + describeState(stateFlag) + " enabled:" + enabled);
- }
-
- if (enabled) {
- mState |= stateFlag;
- } else {
- mState &= ~stateFlag;
- }
-
- if (DEBUG) {
- Log.d(TAG, "updated state:" + describeState());
- }
-
- if (existingState != mState) {
- showSource();
- }
-
- updateCommunalViewOccluded();
- }
-
- private String describeState(@State int stateFlag) {
- switch(stateFlag) {
- case STATE_DOZING:
- return "dozing";
- case STATE_BOUNCER_SHOWING:
- return "bouncer_showing";
- case STATE_KEYGUARD_SHOWING:
- return "keyguard_showing";
- default:
- return "UNDEFINED_STATE";
- }
- }
-
- private String describeState() {
- StringBuilder stringBuilder = new StringBuilder();
-
- if ((mState & STATE_KEYGUARD_SHOWING) == STATE_KEYGUARD_SHOWING) {
- stringBuilder.append(String.format(STATE_LIST_FORMAT,
- describeState(STATE_KEYGUARD_SHOWING)));
- }
- if ((mState & STATE_DOZING) == STATE_DOZING) {
- stringBuilder.append(String.format(STATE_LIST_FORMAT,
- describeState(STATE_DOZING)));
- }
- if ((mState & STATE_BOUNCER_SHOWING) == STATE_BOUNCER_SHOWING) {
- stringBuilder.append(String.format(STATE_LIST_FORMAT,
- describeState(STATE_BOUNCER_SHOWING)));
- }
-
- return stringBuilder.toString();
- }
-
- private void showSource() {
- final ShowRequest request = new ShowRequest(
- (mState & SHOW_COMMUNAL_VIEW_REQUIRED_STATES) == SHOW_COMMUNAL_VIEW_REQUIRED_STATES
- && (mState & SHOW_COMMUNAL_VIEW_INVALID_STATES) == 0
- && mCurrentSource != null,
- mCurrentSource);
-
- if (mLastRequest.isPresent() && Objects.equals(mLastRequest.get(), request)) {
- return;
- }
-
- mLastRequest = Optional.of(request);
-
- // Make sure all necessary states are present for showing communal and all invalid states
- // are absent
- mMainExecutor.execute(() -> {
- if (DEBUG) {
- Log.d(TAG, "showSource. currentSource:" + request.getSource());
- }
-
- if (request.shouldShow()) {
- mView.removeAllViews();
-
- // Make view visible.
- mView.setVisibility(View.VISIBLE);
-
- final Context context = mView.getContext();
-
- final ListenableFuture<CommunalSource.CommunalViewResult> listenableFuture =
- request.getSource().requestCommunalView(context);
-
- if (listenableFuture == null) {
- Log.e(TAG, "could not request communal view");
- return;
- }
-
- listenableFuture.addListener(() -> {
- try {
- final CommunalSource.CommunalViewResult result = listenableFuture.get();
- result.view.setLayoutParams(new ViewGroup.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.MATCH_PARENT));
- mView.addView(result.view);
-
- mCommunalViewController = result.viewController;
- mCommunalViewController.init();
- } catch (Exception e) {
- Log.e(TAG, "could not obtain communal view through callback:" + e);
- }
- }, mMainExecutor);
- } else {
- mView.removeAllViews();
- mView.setVisibility(View.INVISIBLE);
- mCommunalStateController.setCommunalViewShowing(false);
- }
- });
- }
-
- /**
- * Instructs {@link CommunalHostViewController} to display provided source.
- *
- * @param source The new {@link CommunalSource}, {@code null} if not set.
- */
- public void show(WeakReference<CommunalSource> source) {
- mCurrentSource = source;
- showSource();
- }
-
- /**
- * Update position of the view with an optional animation
- */
- public void updatePosition(int y, boolean animate) {
- PropertyAnimator.setProperty(mView, AnimatableProperty.Y, y, COMMUNAL_ANIMATION_PROPERTIES,
- animate);
- }
-
- /**
- * Invoked when the quick settings is expanded.
- * @param expansionFraction the percentage the QS shade has been expanded.
- */
- public void updateQsExpansion(float expansionFraction) {
- mQsExpansion = expansionFraction;
- updateCommunalViewOccluded();
- }
-
- /**
- * Invoked when the main shade is expanded.
- * @param shadeExpansion the percentage the main shade has expanded.
- */
- public void updateShadeExpansion(float shadeExpansion) {
- mShadeExpansion = shadeExpansion;
- updateCommunalViewOccluded();
- }
-
- private void updateCommunalViewOccluded() {
- final boolean bouncerShowing = (mState & STATE_BOUNCER_SHOWING) == STATE_BOUNCER_SHOWING;
- final int statusBarState = mStatusBarStateController.getState();
- final boolean shadeExpanded = statusBarState == StatusBarState.SHADE
- || statusBarState == StatusBarState.SHADE_LOCKED;
-
- mCommunalStateController.setCommunalViewOccluded(
- bouncerShowing || shadeExpanded || mQsExpansion > 0.0f || mShadeExpansion > 0.0f);
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/CommunalHostViewPositionAlgorithm.java b/packages/SystemUI/src/com/android/systemui/communal/CommunalHostViewPositionAlgorithm.java
deleted file mode 100644
index 424da0b111c5..000000000000
--- a/packages/SystemUI/src/com/android/systemui/communal/CommunalHostViewPositionAlgorithm.java
+++ /dev/null
@@ -1,74 +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.systemui.communal;
-
-import android.util.Log;
-
-import com.android.systemui.statusbar.phone.NotificationPanelViewController;
-
-/**
- * {@link CommunalHostViewPositionAlgorithm} calculates the position of the communal view given
- * input such as the notification panel position.
- */
-public class CommunalHostViewPositionAlgorithm {
- private static final String TAG = "CommunalPositionAlg";
- private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
-
- /**
- * @see NotificationPanelViewController#getExpandedFraction()
- */
- private float mPanelExpansion;
-
- /**
- * Height of {@link CommunalHostView}.
- */
- private int mCommunalHeight;
-
- /**
- * A data container for the result of the position algorithm.
- */
- public static class Result {
- /**
- * The y translation of the clock.
- */
- public int communalY;
- }
-
- /**
- * Sets the conditions under which the result should be calculated from.
- * @param panelExpansion The percentage the keyguard panel has been moved upwards.
- * @param communalHeight The height of the communal panel.
- */
- public void setup(float panelExpansion, int communalHeight) {
- if (DEBUG) {
- Log.d(TAG, "setup. panelExpansion:" + panelExpansion);
- }
- mPanelExpansion = panelExpansion;
- mCommunalHeight = communalHeight;
- }
-
- /**
- * Calculates the position based on factors input through {link {@link #setup(float, int)}}.
- * @param result The resulting calculations.
- */
- public void run(Result result) {
- // The panel expansion relates to the keyguard expansion. At full expansion, the communal
- // view should be aligned at the top (0). Otherwise, it should be shifted offscreen by the
- // unexpanded amount.
- result.communalY = (int) ((1 - mPanelExpansion) * -mCommunalHeight);
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/CommunalSource.java b/packages/SystemUI/src/com/android/systemui/communal/CommunalSource.java
deleted file mode 100644
index 42ecd5c835bb..000000000000
--- a/packages/SystemUI/src/com/android/systemui/communal/CommunalSource.java
+++ /dev/null
@@ -1,105 +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.systemui.communal;
-
-import android.content.Context;
-import android.view.View;
-
-import com.android.systemui.util.ViewController;
-
-import com.google.common.util.concurrent.ListenableFuture;
-
-import java.util.Optional;
-
-/**
- * {@link CommunalSource} defines an interface for working with a source for communal data. Clients
- * may request a communal surface that can be shown within a {@link android.view.SurfaceView}.
- * Callbacks may also be registered to listen to state changes.
- */
-public interface CommunalSource {
- /**
- * {@link Connector} defines an interface for {@link CommunalSource} instances to be generated.
- */
- interface Connector {
- Connection connect(Connection.Callback callback);
- }
-
- /**
- * {@link Connection} defines an interface for an entity which holds the necessary components
- * for establishing and maintaining a connection to the communal source.
- */
- interface Connection {
- /**
- * {@link Callback} defines an interface for clients to be notified when a source is ready
- */
- interface Callback {
- void onSourceEstablished(Optional<CommunalSource> source);
- void onDisconnected();
- }
-
- void disconnect();
- }
-
- /**
- * The {@link Observer} interface specifies an entity which {@link CommunalSource} listeners
- * can be informed of changes to the source, which will require updating. Note that this deals
- * with changes to the source itself, not content which will be updated through the
- * {@link CommunalSource} interface.
- */
- interface Observer {
- interface Callback {
- void onSourceChanged();
- }
-
- void addCallback(Callback callback);
- void removeCallback(Callback callback);
- }
-
- /**
- * {@link CommunalViewResult} is handed back from {@link #requestCommunalView(Context)} and
- * contains the view to be displayed and its associated controller.
- */
- class CommunalViewResult {
- /**
- * The resulting communal view.
- */
- public final View view;
- /**
- * The controller for the communal view.
- */
- public final ViewController<? extends View> viewController;
-
- /**
- * The default constructor for {@link CommunalViewResult}.
- * @param view The communal view.
- * @param viewController The communal view's controller.
- */
- public CommunalViewResult(View view, ViewController<? extends View> viewController) {
- this.view = view;
- this.viewController = viewController;
- }
- }
-
- /**
- * Requests a communal surface that can be displayed inside {@link CommunalHostView}.
- *
- * @param context The {@link View} {@link Context} to build the resulting view from
- * @return A future that can be listened upon for the resulting {@link CommunalViewResult}. The
- * value will be {@code null} in case of a failure.
- */
- ListenableFuture<CommunalViewResult> requestCommunalView(Context context);
-}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/CommunalSourceMonitor.java b/packages/SystemUI/src/com/android/systemui/communal/CommunalSourceMonitor.java
deleted file mode 100644
index 58cf35f2917c..000000000000
--- a/packages/SystemUI/src/com/android/systemui/communal/CommunalSourceMonitor.java
+++ /dev/null
@@ -1,158 +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.systemui.communal;
-
-import static com.android.systemui.communal.dagger.CommunalModule.COMMUNAL_CONDITIONS;
-
-import android.util.Log;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.util.condition.Monitor;
-
-import com.google.android.collect.Lists;
-
-import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.concurrent.Executor;
-
-import javax.inject.Inject;
-import javax.inject.Named;
-
-/**
- * A Monitor for reporting a {@link CommunalSource} presence.
- */
-@SysUISingleton
-public class CommunalSourceMonitor {
- private static final String TAG = "CommunalSourceMonitor";
- private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
-
- // A list of {@link Callback} that have registered to receive updates.
- private final ArrayList<WeakReference<Callback>> mCallbacks = Lists.newArrayList();
- private final Monitor mConditionsMonitor;
- private final Executor mExecutor;
-
- private CommunalSource mCurrentSource;
-
- // Whether all conditions for communal mode to show have been met.
- private boolean mAllCommunalConditionsMet = false;
-
- // Whether the class is currently listening for condition changes.
- private boolean mListeningForConditions = false;
-
- private final Monitor.Callback mConditionsCallback =
- allConditionsMet -> {
- if (mAllCommunalConditionsMet != allConditionsMet) {
- if (DEBUG) Log.d(TAG, "communal conditions changed: " + allConditionsMet);
-
- mAllCommunalConditionsMet = allConditionsMet;
- executeOnSourceAvailableCallbacks();
- }
- };
-
- @VisibleForTesting
- @Inject
- public CommunalSourceMonitor(@Main Executor executor,
- @Named(COMMUNAL_CONDITIONS) Monitor communalConditionsMonitor) {
- mExecutor = executor;
- mConditionsMonitor = communalConditionsMonitor;
- }
-
- /**
- * Sets the current {@link CommunalSource}, informing any callbacks. Any existing
- * {@link CommunalSource} will be disconnected.
- *
- * @param source The new {@link CommunalSource}.
- */
- public void setSource(CommunalSource source) {
- mCurrentSource = source;
-
- if (mAllCommunalConditionsMet) {
- executeOnSourceAvailableCallbacks();
- }
- }
-
- private void executeOnSourceAvailableCallbacks() {
- mExecutor.execute(() -> {
- // If the new source is valid, inform registered Callbacks of its presence.
- Iterator<WeakReference<Callback>> itr = mCallbacks.iterator();
- while (itr.hasNext()) {
- Callback cb = itr.next().get();
- if (cb == null) {
- itr.remove();
- } else {
- cb.onSourceAvailable(
- (mAllCommunalConditionsMet && mCurrentSource != null)
- ? new WeakReference<>(mCurrentSource) : null);
- }
- }
- });
- }
-
- /**
- * Adds a {@link Callback} to receive {@link CommunalSource} updates.
- *
- * @param callback The {@link Callback} to add.
- */
- public void addCallback(Callback callback) {
- mExecutor.execute(() -> {
- mCallbacks.add(new WeakReference<>(callback));
-
- // Inform the callback of any already present CommunalSource.
- if (mAllCommunalConditionsMet && mCurrentSource != null) {
- callback.onSourceAvailable(new WeakReference<>(mCurrentSource));
- }
-
- if (!mListeningForConditions) {
- mConditionsMonitor.addCallback(mConditionsCallback);
- mListeningForConditions = true;
- }
- });
- }
-
- /**
- * Removes the specified {@link Callback} from receive future updates if present.
- *
- * @param callback The {@link Callback} to add.
- */
- public void removeCallback(Callback callback) {
- mExecutor.execute(() -> {
- mCallbacks.removeIf(el -> el.get() == callback);
-
- if (mCallbacks.isEmpty() && mListeningForConditions) {
- mConditionsMonitor.removeCallback(mConditionsCallback);
- mListeningForConditions = false;
- }
- });
- }
-
- /**
- * Interface implemented to be notified when new {@link CommunalSource} become available.
- */
- public interface Callback {
- /**
- * Called when a new {@link CommunalSource} has been registered. This will also be invoked
- * when a {@link Callback} is first registered and a {@link CommunalSource} is already
- * registered.
- *
- * @param source The new {@link CommunalSource}.
- */
- void onSourceAvailable(WeakReference<CommunalSource> source);
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/CommunalSourcePrimer.java b/packages/SystemUI/src/com/android/systemui/communal/CommunalSourcePrimer.java
deleted file mode 100644
index f965431a8001..000000000000
--- a/packages/SystemUI/src/com/android/systemui/communal/CommunalSourcePrimer.java
+++ /dev/null
@@ -1,180 +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.systemui.communal;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.util.Log;
-
-import com.android.systemui.CoreStartable;
-import com.android.systemui.R;
-import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.util.concurrency.DelayableExecutor;
-import com.android.systemui.util.time.SystemClock;
-
-import java.util.Optional;
-
-import javax.inject.Inject;
-
-/**
- * The {@link CommunalSourcePrimer} is responsible for priming SystemUI with a pre-configured
- * Communal source. The SystemUI service binds to the component to retrieve the
- * {@link CommunalSource}. {@link CommunalSourcePrimer} has no effect
- * if there is no pre-defined value.
- */
-@SysUISingleton
-public class CommunalSourcePrimer extends CoreStartable {
- private static final String TAG = "CommunalSourcePrimer";
- private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
-
- private final SystemClock mSystemClock;
- private final DelayableExecutor mMainExecutor;
- private final CommunalSourceMonitor mMonitor;
- private final int mBaseReconnectDelayMs;
- private final int mMaxReconnectAttempts;
- private final int mMinConnectionDuration;
-
- private int mReconnectAttempts = 0;
- private Runnable mCurrentReconnectCancelable;
-
- private final Optional<CommunalSource.Observer> mObserver;
- private final Optional<CommunalSource.Connector> mConnector;
-
- private CommunalSource.Connection mCurrentConnection;
-
- private final Runnable mConnectRunnable = new Runnable() {
- @Override
- public void run() {
- mCurrentReconnectCancelable = null;
- connect();
- }
- };
-
- private final CommunalSource.Observer.Callback mObserverCallback = () -> {
- initiateConnectionAttempt();
- };
-
- @Inject
- public CommunalSourcePrimer(Context context, @Main Resources resources,
- SystemClock clock,
- DelayableExecutor mainExecutor,
- CommunalSourceMonitor monitor,
- Optional<CommunalSource.Connector> connector,
- Optional<CommunalSource.Observer> observer) {
- super(context);
- mSystemClock = clock;
- mMainExecutor = mainExecutor;
- mMonitor = monitor;
- mConnector = connector;
- mObserver = observer;
-
- mMaxReconnectAttempts = resources.getInteger(
- R.integer.config_communalSourceMaxReconnectAttempts);
- mBaseReconnectDelayMs = resources.getInteger(
- R.integer.config_communalSourceReconnectBaseDelay);
- mMinConnectionDuration = resources.getInteger(
- R.integer.config_connectionMinDuration);
- }
-
- @Override
- public void start() {
- }
-
- private void initiateConnectionAttempt() {
- // Reset attempts
- mReconnectAttempts = 0;
- mMonitor.setSource(null);
-
- // The first attempt is always a direct invocation rather than delayed.
- connect();
- }
-
- private void scheduleConnectionAttempt() {
- // always clear cancelable if present.
- if (mCurrentReconnectCancelable != null) {
- mCurrentReconnectCancelable.run();
- mCurrentReconnectCancelable = null;
- }
-
- if (mReconnectAttempts >= mMaxReconnectAttempts) {
- if (DEBUG) {
- Log.d(TAG, "exceeded max connection attempts.");
- }
- return;
- }
-
- final long reconnectDelayMs =
- (long) Math.scalb(mBaseReconnectDelayMs, mReconnectAttempts);
-
- if (DEBUG) {
- Log.d(TAG,
- "scheduling connection attempt in " + reconnectDelayMs + "milliseconds");
- }
-
- mCurrentReconnectCancelable = mMainExecutor.executeDelayed(mConnectRunnable,
- reconnectDelayMs);
-
- mReconnectAttempts++;
- }
-
- @Override
- protected void onBootCompleted() {
- if (mObserver.isPresent()) {
- mObserver.get().addCallback(mObserverCallback);
- }
- initiateConnectionAttempt();
- }
-
- private void connect() {
- if (DEBUG) {
- Log.d(TAG, "attempting to connect to communal source");
- }
-
- if (mCurrentConnection != null) {
- if (DEBUG) {
- Log.d(TAG, "canceling in-flight connection");
- }
- mCurrentConnection.disconnect();
- }
-
- mCurrentConnection = mConnector.get().connect(new CommunalSource.Connection.Callback() {
- private long mStartTime;
-
- @Override
- public void onSourceEstablished(Optional<CommunalSource> optionalSource) {
- mStartTime = mSystemClock.currentTimeMillis();
-
- if (optionalSource.isPresent()) {
- final CommunalSource source = optionalSource.get();
- mMonitor.setSource(source);
- } else {
- scheduleConnectionAttempt();
- }
- }
-
- @Override
- public void onDisconnected() {
- if (mSystemClock.currentTimeMillis() - mStartTime > mMinConnectionDuration) {
- initiateConnectionAttempt();
- } else {
- scheduleConnectionAttempt();
- }
- }
- });
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/CommunalStateController.java b/packages/SystemUI/src/com/android/systemui/communal/CommunalStateController.java
deleted file mode 100644
index c72f5422b1f5..000000000000
--- a/packages/SystemUI/src/com/android/systemui/communal/CommunalStateController.java
+++ /dev/null
@@ -1,125 +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.systemui.communal;
-
-import android.annotation.NonNull;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.statusbar.policy.CallbackController;
-
-import java.util.ArrayList;
-import java.util.Objects;
-
-import javax.inject.Inject;
-
-/**
- * CommunalStateController enables publishing and listening to communal-related state changes.
- */
-@SysUISingleton
-public class CommunalStateController implements
- CallbackController<CommunalStateController.Callback> {
- private final ArrayList<Callback> mCallbacks = new ArrayList<>();
- private boolean mCommunalViewOccluded;
- private boolean mCommunalViewShowing;
-
- /**
- * Callback for communal events.
- */
- public interface Callback {
- /**
- * Called when the visibility of the communal view changes.
- */
- default void onCommunalViewShowingChanged() {
- }
-
- /**
- * Called when the occlusion of the communal view changes.
- */
- default void onCommunalViewOccludedChanged() {
- }
- }
-
- @VisibleForTesting
- @Inject
- public CommunalStateController() {
- }
-
- /**
- * Sets whether the communal view is showing.
- * @param communalViewShowing {@code true} if the view is showing, {@code false} otherwise.
- */
- public void setCommunalViewShowing(boolean communalViewShowing) {
- if (mCommunalViewShowing == communalViewShowing) {
- return;
- }
-
- mCommunalViewShowing = communalViewShowing;
-
- final ArrayList<Callback> callbacks = new ArrayList<>(mCallbacks);
- for (Callback callback : callbacks) {
- callback.onCommunalViewShowingChanged();
- }
- }
-
- /**
- * Sets whether the communal view is occluded (but otherwise still showing).
- * @param communalViewOccluded {@code true} if the view is occluded, {@code false} otherwise.
- */
- public void setCommunalViewOccluded(boolean communalViewOccluded) {
- if (mCommunalViewOccluded == communalViewOccluded) {
- return;
- }
-
- mCommunalViewOccluded = communalViewOccluded;
-
- ArrayList<Callback> callbacks = new ArrayList<>(mCallbacks);
- for (int i = 0; i < callbacks.size(); i++) {
- callbacks.get(i).onCommunalViewOccludedChanged();
- }
- }
-
- /**
- * Returns whether the communal view is showing.
- * @return {@code true} if the view is showing, {@code false} otherwise.
- */
- public boolean getCommunalViewShowing() {
- return mCommunalViewShowing;
- }
-
- /**
- * Returns whether the communal view is occluded.
- * @return {@code true} if the view is occluded, {@code false} otherwise.
- */
- public boolean getCommunalViewOccluded() {
- return mCommunalViewOccluded;
- }
-
- @Override
- public void addCallback(@NonNull Callback callback) {
- Objects.requireNonNull(callback, "Callback must not be null. b/128895449");
- if (!mCallbacks.contains(callback)) {
- mCallbacks.add(callback);
- }
- }
-
- @Override
- public void removeCallback(@NonNull Callback callback) {
- Objects.requireNonNull(callback, "Callback must not be null. b/128895449");
- mCallbacks.remove(callback);
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/PackageObserver.java b/packages/SystemUI/src/com/android/systemui/communal/PackageObserver.java
deleted file mode 100644
index 3d25d126a291..000000000000
--- a/packages/SystemUI/src/com/android/systemui/communal/PackageObserver.java
+++ /dev/null
@@ -1,101 +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.systemui.communal;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.PatternMatcher;
-import android.util.Log;
-
-import com.google.android.collect.Lists;
-
-import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-import java.util.Iterator;
-
-/**
- * {@link PackageObserver} allows for monitoring the system for changes relating to a particular
- * package. This can be used by {@link CommunalSource} clients to detect when a related package
- * has changed and reloading is necessary.
- */
-public class PackageObserver implements CommunalSource.Observer {
- private static final String TAG = "PackageObserver";
- private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
-
- private final ArrayList<WeakReference<Callback>> mCallbacks = Lists.newArrayList();
-
- private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (DEBUG) {
- Log.d(TAG, "package added receiver - onReceive");
- }
-
- final Iterator<WeakReference<Callback>> iter = mCallbacks.iterator();
- while (iter.hasNext()) {
- final Callback callback = iter.next().get();
- if (callback != null) {
- callback.onSourceChanged();
- } else {
- iter.remove();
- }
- }
- }
- };
-
- private final String mPackageName;
- private final Context mContext;
-
- public PackageObserver(Context context, String packageName) {
- mContext = context;
- mPackageName = packageName;
- }
-
- @Override
- public void addCallback(Callback callback) {
- if (DEBUG) {
- Log.d(TAG, "addCallback:" + callback);
- }
- mCallbacks.add(new WeakReference<>(callback));
-
- // Only register for listening to package additions on first callback.
- if (mCallbacks.size() > 1) {
- return;
- }
-
- final IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
- filter.addDataScheme("package");
- filter.addDataSchemeSpecificPart(mPackageName, PatternMatcher.PATTERN_LITERAL);
- // Note that we directly register the receiver here as data schemes are not supported by
- // BroadcastDispatcher.
- mContext.registerReceiver(mReceiver, filter, Context.RECEIVER_EXPORTED);
- }
-
- @Override
- public void removeCallback(Callback callback) {
- if (DEBUG) {
- Log.d(TAG, "removeCallback:" + callback);
- }
- final boolean removed = mCallbacks.removeIf(el -> el.get() == callback);
-
- if (removed && mCallbacks.isEmpty()) {
- mContext.unregisterReceiver(mReceiver);
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/conditions/CommunalSettingCondition.java b/packages/SystemUI/src/com/android/systemui/communal/conditions/CommunalSettingCondition.java
deleted file mode 100644
index 25519d0f96c7..000000000000
--- a/packages/SystemUI/src/com/android/systemui/communal/conditions/CommunalSettingCondition.java
+++ /dev/null
@@ -1,67 +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.systemui.communal.conditions;
-
-import android.database.ContentObserver;
-import android.os.Handler;
-import android.os.UserHandle;
-import android.provider.Settings;
-
-import androidx.annotation.MainThread;
-
-import com.android.systemui.util.condition.Condition;
-import com.android.systemui.util.settings.SecureSettings;
-
-import javax.inject.Inject;
-
-/**
- * Monitors the communal setting, and informs any listeners with updates.
- */
-public class CommunalSettingCondition extends Condition {
- private final SecureSettings mSecureSettings;
- private final ContentObserver mCommunalSettingContentObserver;
-
- @Inject
- public CommunalSettingCondition(@MainThread Handler mainHandler,
- SecureSettings secureSettings) {
- mSecureSettings = secureSettings;
-
- mCommunalSettingContentObserver = new ContentObserver(mainHandler) {
- @Override
- public void onChange(boolean selfChange) {
- final boolean communalSettingEnabled = mSecureSettings.getIntForUser(
- Settings.Secure.COMMUNAL_MODE_ENABLED, 0, UserHandle.USER_SYSTEM) == 1;
- updateCondition(communalSettingEnabled);
- }
- };
- }
-
- @Override
- protected void start() {
- mSecureSettings.registerContentObserverForUser(Settings.Secure.COMMUNAL_MODE_ENABLED,
- false /*notifyForDescendants*/, mCommunalSettingContentObserver,
- UserHandle.USER_SYSTEM);
-
- // Fetches setting immediately.
- mCommunalSettingContentObserver.onChange(false);
- }
-
- @Override
- protected void stop() {
- mSecureSettings.unregisterContentObserver(mCommunalSettingContentObserver);
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/dagger/CommunalModule.java b/packages/SystemUI/src/com/android/systemui/communal/dagger/CommunalModule.java
deleted file mode 100644
index 814b251d08ab..000000000000
--- a/packages/SystemUI/src/com/android/systemui/communal/dagger/CommunalModule.java
+++ /dev/null
@@ -1,125 +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.systemui.communal.dagger;
-
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.res.Resources;
-import android.text.TextUtils;
-
-import androidx.annotation.Nullable;
-
-import com.android.systemui.R;
-import com.android.systemui.communal.CommunalSource;
-import com.android.systemui.communal.PackageObserver;
-import com.android.systemui.communal.conditions.CommunalSettingCondition;
-import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.util.condition.Condition;
-import com.android.systemui.util.condition.Monitor;
-import com.android.systemui.util.condition.dagger.MonitorComponent;
-
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Optional;
-import java.util.Set;
-
-import javax.inject.Named;
-import javax.inject.Provider;
-
-import dagger.Module;
-import dagger.Provides;
-import dagger.multibindings.ElementsIntoSet;
-import dagger.multibindings.IntoMap;
-import dagger.multibindings.StringKey;
-
-/**
- * Dagger Module providing Communal-related functionality.
- */
-@Module(subcomponents = {
- CommunalViewComponent.class,
-})
-public interface CommunalModule {
- String COMMUNAL_CONDITIONS = "communal_conditions";
-
- /** */
- @Provides
- static Optional<CommunalSource.Observer> provideCommunalSourcePackageObserver(
- Context context, @Main Resources resources) {
- final String componentName = resources.getString(R.string.config_communalSourceComponent);
-
- if (TextUtils.isEmpty(componentName)) {
- return Optional.empty();
- }
-
- return Optional.of(new PackageObserver(context,
- ComponentName.unflattenFromString(componentName).getPackageName()));
- }
-
- /**
- * Provides a set of conditions that need to be fulfilled in order for Communal Mode to display.
- */
- @Provides
- @ElementsIntoSet
- @Named(COMMUNAL_CONDITIONS)
- static Set<Condition> provideCommunalConditions(
- CommunalSettingCondition communalSettingCondition) {
- return new HashSet<>(Collections.singletonList(communalSettingCondition));
- }
-
- /**
- * TODO(b/205638389): Remove when there is a base implementation of
- * {@link CommunalSource.Connector}. Currently a place holder to allow a map to be present.
- */
- @Provides
- @IntoMap
- @Nullable
- @StringKey("empty")
- static CommunalSource.Connector provideEmptyCommunalSourceConnector() {
- return null;
- }
-
- /** */
- @Provides
- static Optional<CommunalSource.Connector> provideCommunalSourceConnector(
- @Main Resources resources,
- Map<Class<?>, Provider<CommunalSource.Connector>> connectorCreators) {
- final String className = resources.getString(R.string.config_communalSourceConnector);
-
- if (TextUtils.isEmpty(className)) {
- return Optional.empty();
- }
-
- try {
- Class<?> clazz = Class.forName(className);
- Provider<CommunalSource.Connector> provider = connectorCreators.get(clazz);
- return provider != null ? Optional.of(provider.get()) : Optional.empty();
- } catch (ClassNotFoundException e) {
- return Optional.empty();
- }
- }
-
- /** */
- @Provides
- @Named(COMMUNAL_CONDITIONS)
- static Monitor provideCommunalSourceMonitor(
- @Named(COMMUNAL_CONDITIONS) Set<Condition> communalConditions,
- MonitorComponent.Factory factory) {
- final MonitorComponent component = factory.create(communalConditions, new HashSet<>());
- return component.getMonitor();
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/dagger/CommunalViewComponent.java b/packages/SystemUI/src/com/android/systemui/communal/dagger/CommunalViewComponent.java
deleted file mode 100644
index 3a80a03aecb2..000000000000
--- a/packages/SystemUI/src/com/android/systemui/communal/dagger/CommunalViewComponent.java
+++ /dev/null
@@ -1,38 +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.systemui.communal.dagger;
-
-import com.android.systemui.communal.CommunalHostView;
-import com.android.systemui.communal.CommunalHostViewController;
-
-import dagger.BindsInstance;
-import dagger.Subcomponent;
-
-/**
- * Subcomponent for working with {@link CommunalHostView}.
- */
-@Subcomponent
-public interface CommunalViewComponent {
- /** Simple factory for {@link CommunalViewComponent}. */
- @Subcomponent.Factory
- interface Factory {
- CommunalViewComponent build(@BindsInstance CommunalHostView view);
- }
-
- /** Builds a {@link CommunalHostViewController}. */
- CommunalHostViewController getCommunalHostViewController();
-}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt
index 40662536e57e..f9115b20ca06 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt
@@ -17,10 +17,13 @@
package com.android.systemui.controls.management
import android.content.ComponentName
+import android.content.res.Configuration
+import android.content.res.Resources
import android.graphics.Rect
import android.os.Bundle
import android.service.controls.Control
import android.service.controls.DeviceTypes
+import android.util.TypedValue
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
@@ -32,7 +35,6 @@ import android.widget.TextView
import androidx.core.view.AccessibilityDelegateCompat
import androidx.core.view.ViewCompat
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat
-import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.android.systemui.R
import com.android.systemui.controls.ControlInterface
@@ -56,11 +58,32 @@ class ControlAdapter(
const val TYPE_ZONE = 0
const val TYPE_CONTROL = 1
const val TYPE_DIVIDER = 2
- }
- val spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() {
- override fun getSpanSize(position: Int): Int {
- return if (getItemViewType(position) != TYPE_CONTROL) 2 else 1
+ /**
+ * For low-dp width screens that also employ an increased font scale, adjust the
+ * number of columns. This helps prevent text truncation on these devices.
+ *
+ */
+ @JvmStatic
+ fun findMaxColumns(res: Resources): Int {
+ var maxColumns = res.getInteger(R.integer.controls_max_columns)
+ val maxColumnsAdjustWidth =
+ res.getInteger(R.integer.controls_max_columns_adjust_below_width_dp)
+
+ val outValue = TypedValue()
+ res.getValue(R.dimen.controls_max_columns_adjust_above_font_scale, outValue, true)
+ val maxColumnsAdjustFontScale = outValue.getFloat()
+
+ val config = res.configuration
+ val isPortrait = config.orientation == Configuration.ORIENTATION_PORTRAIT
+ if (isPortrait &&
+ config.screenWidthDp != Configuration.SCREEN_WIDTH_DP_UNDEFINED &&
+ config.screenWidthDp <= maxColumnsAdjustWidth &&
+ config.fontScale >= maxColumnsAdjustFontScale) {
+ maxColumns--
+ }
+
+ return maxColumns
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsEditingActivity.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsEditingActivity.kt
index 6f94943472b1..f611c3ef966d 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsEditingActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsEditingActivity.kt
@@ -195,10 +195,11 @@ class ControlsEditingActivity @Inject constructor(
val margin = resources
.getDimensionPixelSize(R.dimen.controls_card_margin)
val itemDecorator = MarginItemDecorator(margin, margin)
+ val spanCount = ControlAdapter.findMaxColumns(resources)
recyclerView.apply {
this.adapter = adapter
- layoutManager = object : GridLayoutManager(recyclerView.context, 2) {
+ layoutManager = object : GridLayoutManager(recyclerView.context, spanCount) {
// This will remove from the announcement the row corresponding to the divider,
// as it's not something that should be announced.
@@ -210,7 +211,12 @@ class ControlsEditingActivity @Inject constructor(
return if (initial > 0) initial - 1 else initial
}
}.apply {
- spanSizeLookup = adapter.spanSizeLookup
+ spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() {
+ override fun getSpanSize(position: Int): Int {
+ return if (adapter?.getItemViewType(position)
+ != ControlAdapter.TYPE_CONTROL) spanCount else 1
+ }
+ }
}
addItemDecoration(itemDecorator)
}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/StructureAdapter.kt b/packages/SystemUI/src/com/android/systemui/controls/management/StructureAdapter.kt
index cb67454195ec..747bcbe1c229 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/StructureAdapter.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/StructureAdapter.kt
@@ -60,11 +60,17 @@ class StructureAdapter(
val margin = itemView.context.resources
.getDimensionPixelSize(R.dimen.controls_card_margin)
val itemDecorator = MarginItemDecorator(margin, margin)
+ val spanCount = ControlAdapter.findMaxColumns(itemView.resources)
recyclerView.apply {
this.adapter = controlAdapter
- layoutManager = GridLayoutManager(recyclerView.context, 2).apply {
- spanSizeLookup = controlAdapter.spanSizeLookup
+ layoutManager = GridLayoutManager(recyclerView.context, spanCount).apply {
+ spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() {
+ override fun getSpanSize(position: Int): Int {
+ return if (adapter?.getItemViewType(position)
+ != ControlAdapter.TYPE_CONTROL) spanCount else 1
+ }
+ }
}
addItemDecoration(itemDecorator)
}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt
index 5c1d8c3929cb..e53f2673841c 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt
@@ -16,11 +16,11 @@
package com.android.systemui.controls.ui
+import android.annotation.AnyThread
import android.annotation.MainThread
import android.app.Dialog
import android.app.PendingIntent
import android.content.Context
-import android.content.Intent
import android.content.pm.PackageManager
import android.content.pm.ResolveInfo
import android.database.ContentObserver
@@ -35,6 +35,7 @@ import android.service.controls.actions.FloatAction
import android.util.Log
import android.view.HapticFeedbackConstants
import com.android.internal.annotations.VisibleForTesting
+import com.android.systemui.broadcast.BroadcastSender
import com.android.systemui.controls.ControlsMetricsLogger
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main
@@ -53,6 +54,7 @@ class ControlActionCoordinatorImpl @Inject constructor(
private val bgExecutor: DelayableExecutor,
@Main private val uiExecutor: DelayableExecutor,
private val activityStarter: ActivityStarter,
+ private val broadcastSender: BroadcastSender,
private val keyguardStateController: KeyguardStateController,
private val taskViewFactory: Optional<TaskViewFactory>,
private val controlsMetricsLogger: ControlsMetricsLogger,
@@ -199,11 +201,12 @@ class ControlActionCoordinatorImpl @Inject constructor(
false
}
+ @AnyThread
@VisibleForTesting
fun bouncerOrRun(action: Action, authRequired: Boolean) {
if (keyguardStateController.isShowing() && authRequired) {
if (isLocked) {
- context.sendBroadcast(Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS))
+ broadcastSender.closeSystemDialogs()
// pending actions will only run after the control state has been refreshed
pendingAction = action
@@ -233,7 +236,10 @@ class ControlActionCoordinatorImpl @Inject constructor(
// make sure the intent is valid before attempting to open the dialog
if (activities.isNotEmpty() && taskViewFactory.isPresent) {
taskViewFactory.get().create(context, uiExecutor, {
- dialog = DetailDialog(activityContext, it, pendingIntent, cvh).also {
+ dialog = DetailDialog(
+ activityContext, broadcastSender,
+ it, pendingIntent, cvh
+ ).also {
it.setOnDismissListener { _ -> dialog = null }
it.show()
}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
index 59c291cf9e5c..1268250137b8 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
@@ -25,12 +25,10 @@ import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.SharedPreferences
-import android.content.res.Configuration
import android.graphics.drawable.Drawable
import android.graphics.drawable.LayerDrawable
import android.service.controls.Control
import android.util.Log
-import android.util.TypedValue
import android.view.ContextThemeWrapper
import android.view.LayoutInflater
import android.view.View
@@ -51,6 +49,7 @@ import com.android.systemui.controls.CustomIconCache
import com.android.systemui.controls.controller.ControlInfo
import com.android.systemui.controls.controller.ControlsController
import com.android.systemui.controls.controller.StructureInfo
+import com.android.systemui.controls.management.ControlAdapter
import com.android.systemui.controls.management.ControlsEditingActivity
import com.android.systemui.controls.management.ControlsFavoritingActivity
import com.android.systemui.controls.management.ControlsListingController
@@ -386,7 +385,7 @@ class ControlsUiControllerImpl @Inject constructor (
visibility = View.VISIBLE
}
- val maxColumns = findMaxColumns()
+ val maxColumns = ControlAdapter.findMaxColumns(activityContext.resources)
val listView = parent.requireViewById(R.id.global_actions_controls_list) as ViewGroup
var lastRow: ViewGroup = createRow(inflater, listView)
@@ -432,32 +431,6 @@ class ControlsUiControllerImpl @Inject constructor (
}
}
- /**
- * For low-dp width screens that also employ an increased font scale, adjust the
- * number of columns. This helps prevent text truncation on these devices.
- */
- private fun findMaxColumns(): Int {
- val res = activityContext.resources
- var maxColumns = res.getInteger(R.integer.controls_max_columns)
- val maxColumnsAdjustWidth =
- res.getInteger(R.integer.controls_max_columns_adjust_below_width_dp)
-
- val outValue = TypedValue()
- res.getValue(R.dimen.controls_max_columns_adjust_above_font_scale, outValue, true)
- val maxColumnsAdjustFontScale = outValue.getFloat()
-
- val config = res.configuration
- val isPortrait = config.orientation == Configuration.ORIENTATION_PORTRAIT
- if (isPortrait &&
- config.screenWidthDp != Configuration.SCREEN_WIDTH_DP_UNDEFINED &&
- config.screenWidthDp <= maxColumnsAdjustWidth &&
- config.fontScale >= maxColumnsAdjustFontScale) {
- maxColumns--
- }
-
- return maxColumns
- }
-
override fun getPreferredStructure(structures: List<StructureInfo>): StructureInfo {
if (structures.isEmpty()) return EMPTY_STRUCTURE
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt
index dc3d1b52495c..80589a2711cc 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt
@@ -33,6 +33,7 @@ import android.view.WindowManager
import android.widget.ImageView
import com.android.internal.policy.ScreenDecorationsUtils
import com.android.systemui.R
+import com.android.systemui.broadcast.BroadcastSender
import com.android.wm.shell.TaskView
/**
@@ -42,6 +43,7 @@ import com.android.wm.shell.TaskView
*/
class DetailDialog(
val activityContext: Context,
+ val broadcastSender: BroadcastSender,
val taskView: TaskView,
val pendingIntent: PendingIntent,
val cvh: ControlViewHolder
@@ -147,7 +149,7 @@ class DetailDialog(
// startActivity() below is called.
removeDetailTask()
dismiss()
- context.sendBroadcast(Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS))
+ broadcastSender.closeSystemDialogs()
pendingIntent.send()
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/GlobalModule.java b/packages/SystemUI/src/com/android/systemui/dagger/GlobalModule.java
index 18f85196aa0b..620feec8fbb8 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/GlobalModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/GlobalModule.java
@@ -23,10 +23,14 @@ import android.util.DisplayMetrics;
import com.android.internal.logging.UiEventLogger;
import com.android.internal.logging.UiEventLoggerImpl;
import com.android.systemui.dagger.qualifiers.TestHarness;
+import com.android.systemui.dagger.qualifiers.UiBackground;
import com.android.systemui.plugins.PluginsModule;
import com.android.systemui.unfold.UnfoldTransitionModule;
import com.android.systemui.util.concurrency.GlobalConcurrencyModule;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+
import javax.inject.Singleton;
import dagger.Module;
@@ -75,4 +79,16 @@ public class GlobalModule {
static boolean provideIsTestHarness() {
return ActivityManager.isRunningInUserTestHarness();
}
+
+ /**
+ * Provide an Executor specifically for running UI operations on a separate thread.
+ *
+ * Keep submitted runnables short and to the point, just as with any other UI code.
+ */
+ @Provides
+ @Singleton
+ @UiBackground
+ public static Executor provideUiBackgroundExecutor() {
+ return Executors.newSingleThreadExecutor();
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/GlobalRootComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/GlobalRootComponent.java
index a3a45fe7ae40..4f55ba496b6b 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/GlobalRootComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/GlobalRootComponent.java
@@ -27,10 +27,7 @@ import dagger.Component;
* Root component for Dagger injection.
*/
@Singleton
-@Component(modules = {
- GlobalModule.class,
- SysUISubcomponentModule.class,
- WMModule.class})
+@Component(modules = {GlobalModule.class})
public interface GlobalRootComponent {
/**
@@ -45,12 +42,12 @@ public interface GlobalRootComponent {
}
/**
- * Builder for a WMComponent.
+ * Builder for a {@link WMComponent}, which makes it a subcomponent of this class.
*/
WMComponent.Builder getWMComponentBuilder();
/**
- * Builder for a SysUIComponent.
+ * Builder for a {@link SysUIComponent}, which makes it a subcomponent of this class.
*/
SysUIComponent.Builder getSysUIComponent();
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt b/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
index f78929f75b04..a9f340854689 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
@@ -35,6 +35,7 @@ import com.android.systemui.power.PowerUI
import com.android.systemui.recents.Recents
import com.android.systemui.shortcut.ShortcutKeyDispatcher
import com.android.systemui.statusbar.notification.InstantAppNotifier
+import com.android.systemui.statusbar.phone.KeyguardLiftController
import com.android.systemui.theme.ThemeOverlayController
import com.android.systemui.toast.ToastUI
import com.android.systemui.usb.StorageNotification
@@ -198,4 +199,10 @@ abstract class SystemUICoreStartableModule {
@IntoMap
@ClassKey(WMShell::class)
abstract fun bindWMShell(sysui: WMShell): CoreStartable
+
+ /** Inject into KeyguardLiftController. */
+ @Binds
+ @IntoMap
+ @ClassKey(KeyguardLiftController::class)
+ abstract fun bindKeyguardLiftController(sysui: KeyguardLiftController): CoreStartable
} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index 27993010c917..166c2654cbaa 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -32,7 +32,6 @@ import com.android.systemui.assist.AssistModule;
import com.android.systemui.biometrics.UdfpsHbmProvider;
import com.android.systemui.biometrics.dagger.BiometricsModule;
import com.android.systemui.classifier.FalsingModule;
-import com.android.systemui.communal.dagger.CommunalModule;
import com.android.systemui.controls.dagger.ControlsModule;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.demomode.dagger.DemoModeModule;
@@ -49,6 +48,7 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.recents.Recents;
import com.android.systemui.screenshot.dagger.ScreenshotModule;
import com.android.systemui.settings.dagger.SettingsModule;
+import com.android.systemui.smartspace.dagger.SmartspaceModule;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationShadeWindowController;
@@ -66,8 +66,8 @@ import com.android.systemui.statusbar.notification.people.PeopleHubModule;
import com.android.systemui.statusbar.notification.row.dagger.ExpandableNotificationRowComponent;
import com.android.systemui.statusbar.notification.row.dagger.NotificationRowComponent;
import com.android.systemui.statusbar.notification.row.dagger.NotificationShelfComponent;
-import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.phone.CentralSurfaces;
+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;
@@ -106,7 +106,6 @@ import dagger.Provides;
AssistModule.class,
BiometricsModule.class,
ClockModule.class,
- CommunalModule.class,
DreamModule.class,
ControlsModule.class,
DemoModeModule.class,
@@ -121,6 +120,7 @@ import dagger.Provides;
SettingsModule.class,
SettingsUtilModule.class,
SmartRepliesInflationModule.class,
+ SmartspaceModule.class,
StatusBarPolicyModule.class,
StatusBarWindowModule.class,
SysUIConcurrencyModule.class,
diff --git a/packages/SystemUI/src/com/android/systemui/decor/RoundedCornerResDelegate.kt b/packages/SystemUI/src/com/android/systemui/decor/RoundedCornerResDelegate.kt
new file mode 100644
index 000000000000..c817f89c7a9b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/decor/RoundedCornerResDelegate.kt
@@ -0,0 +1,201 @@
+/*
+ * 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.decor
+
+import android.annotation.ArrayRes
+import android.annotation.DrawableRes
+import android.content.res.Resources
+import android.graphics.drawable.Drawable
+import android.util.DisplayUtils
+import android.util.Size
+import android.view.RoundedCorners
+import com.android.systemui.Dumpable
+import com.android.systemui.R
+import java.io.FileDescriptor
+import java.io.PrintWriter
+
+class RoundedCornerResDelegate(
+ private val res: Resources,
+ private var displayUniqueId: String?
+) : Dumpable {
+
+ private val density: Float
+ get() = res.displayMetrics.density
+
+ var isMultipleRadius: Boolean = false
+ private set
+
+ private var roundedDrawable: Drawable? = null
+
+ var topRoundedDrawable: Drawable? = null
+ private set
+
+ var bottomRoundedDrawable: Drawable? = null
+ private set
+
+ private var roundedSize = Size(0, 0)
+
+ var topRoundedSize = Size(0, 0)
+ private set
+
+ var bottomRoundedSize = Size(0, 0)
+ private set
+
+ init {
+ reloadDrawables()
+ reloadMeasures()
+ }
+
+ fun reloadAll(newDisplayUniqueId: String?) {
+ displayUniqueId = newDisplayUniqueId
+ reloadDrawables()
+ reloadMeasures()
+ }
+
+ private fun reloadDrawables() {
+ val configIdx = DisplayUtils.getDisplayUniqueIdConfigIndex(res, displayUniqueId)
+ isMultipleRadius = getIsMultipleRadius(configIdx)
+
+ roundedDrawable = getDrawable(
+ displayConfigIndex = configIdx,
+ arrayResId = R.array.config_roundedCornerDrawableArray,
+ backupDrawableId = R.drawable.rounded
+ )
+ topRoundedDrawable = getDrawable(
+ displayConfigIndex = configIdx,
+ arrayResId = R.array.config_roundedCornerTopDrawableArray,
+ backupDrawableId = R.drawable.rounded_corner_top
+ ) ?: roundedDrawable
+ bottomRoundedDrawable = getDrawable(
+ displayConfigIndex = configIdx,
+ 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) {
+ // 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)
+ }
+
+ roundedSizeFactor ?.let {
+ val length: Int = (it * density).toInt()
+ roundedSize = Size(length, length)
+ }
+
+ if (topRoundedSize.width == 0) {
+ topRoundedSize = roundedSize
+ }
+ if (bottomRoundedSize.width == 0) {
+ bottomRoundedSize = roundedSize
+ }
+ }
+
+ fun updateTuningSizeFactor(factor: Int) {
+ reloadMeasures(factor)
+ }
+
+ /**
+ * Gets whether the rounded corners are multiple radii for current display.
+ *
+ * Loads the default config {@link R.bool#config_roundedCornerMultipleRadius} if
+ * {@link com.android.internal.R.array#config_displayUniqueIdArray} is not set.
+ */
+ private fun getIsMultipleRadius(displayConfigIndex: Int): Boolean {
+ val isMultipleRadius: Boolean
+ res.obtainTypedArray(R.array.config_roundedCornerMultipleRadiusArray).let { array ->
+ isMultipleRadius = if (displayConfigIndex >= 0 && displayConfigIndex < array.length()) {
+ array.getBoolean(displayConfigIndex, false)
+ } else {
+ res.getBoolean(R.bool.config_roundedCornerMultipleRadius)
+ }
+ array.recycle()
+ }
+ return isMultipleRadius
+ }
+
+ private fun getDrawable(
+ displayConfigIndex: Int,
+ @ArrayRes arrayResId: Int,
+ @DrawableRes backupDrawableId: Int
+ ): Drawable? {
+ val drawable: Drawable?
+ res.obtainTypedArray(arrayResId).let { array ->
+ drawable = if (displayConfigIndex >= 0 && displayConfigIndex < array.length()) {
+ array.getDrawable(displayConfigIndex)
+ } else {
+ res.getDrawable(backupDrawableId, null)
+ }
+ array.recycle()
+ }
+ return drawable
+ }
+
+ override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>) {
+ pw.println("RoundedCornerResDelegate state:")
+ pw.println(" isMultipleRadius:$isMultipleRadius")
+ pw.println(" roundedSize(w,h)=(${roundedSize.width},${roundedSize.height})")
+ pw.println(" topRoundedSize(w,h)=(${topRoundedSize.width},${topRoundedSize.height})")
+ pw.println(" bottomRoundedSize(w,h)=(${bottomRoundedSize.width}," +
+ "${bottomRoundedSize.height})")
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
index 0a2e69f943c6..8e1d645d1e97 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
@@ -319,9 +319,10 @@ public class DozeLog implements Dumpable {
/**
* Appends the doze state that was suppressed to the doze event log
* @param suppressedState The {@link DozeMachine.State} that was suppressed
+ * @param reason what suppressed always on
*/
- public void traceAlwaysOnSuppressed(DozeMachine.State suppressedState) {
- mLogger.logAlwaysOnSuppressed(suppressedState);
+ public void traceAlwaysOnSuppressed(DozeMachine.State suppressedState, String reason) {
+ mLogger.logAlwaysOnSuppressed(suppressedState, reason);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt b/packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt
index f3f6be210fed..4c81563e4f93 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt
@@ -267,11 +267,12 @@ class DozeLogger @Inject constructor(
})
}
- fun logAlwaysOnSuppressed(state: DozeMachine.State) {
+ fun logAlwaysOnSuppressed(state: DozeMachine.State, reason: String) {
buffer.log(TAG, INFO, {
str1 = state.name
+ str2 = reason
}, {
- "Always-on state suppressed, suppressed state=$str1"
+ "Always-on state suppressed, suppressed state=$str1 reason=$str2"
})
}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
index ae01f0ad84c7..5779bb307790 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
@@ -358,8 +358,13 @@ public class DozeMachine {
return State.FINISH;
}
if (mDozeHost.isAlwaysOnSuppressed() && requestedState.isAlwaysOn()) {
- Log.i(TAG, "Doze is suppressed. Suppressing state: " + requestedState);
- mDozeLog.traceAlwaysOnSuppressed(requestedState);
+ Log.i(TAG, "Doze is suppressed by an app. Suppressing state: " + requestedState);
+ mDozeLog.traceAlwaysOnSuppressed(requestedState, "app");
+ return State.DOZE;
+ }
+ if (mDozeHost.isPowerSaveActive() && requestedState.isAlwaysOn()) {
+ Log.i(TAG, "Doze is suppressed by battery saver. Suppressing state: " + requestedState);
+ mDozeLog.traceAlwaysOnSuppressed(requestedState, "batterySaver");
return State.DOZE;
}
if ((mState == State.DOZE_AOD_PAUSED || mState == State.DOZE_AOD_PAUSING
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
index b8b4092ccf2f..dfb27eff722b 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
@@ -89,6 +89,7 @@ public class DozeScreenBrightness extends BroadcastReceiver implements DozeMachi
private boolean mPaused = false;
private boolean mScreenOff = false;
private int mLastSensorValue = -1;
+ private DozeMachine.State mState = DozeMachine.State.UNINITIALIZED;
/**
* Debug value used for emulating various display brightness buckets:
@@ -135,6 +136,7 @@ public class DozeScreenBrightness extends BroadcastReceiver implements DozeMachi
@Override
public void transitionTo(DozeMachine.State oldState, DozeMachine.State newState) {
+ mState = newState;
switch (newState) {
case INITIALIZED:
resetBrightnessToDefault();
@@ -262,8 +264,9 @@ public class DozeScreenBrightness extends BroadcastReceiver implements DozeMachi
*/
private int clampToDimBrightnessForScreenOff(int brightness) {
final boolean screenTurningOff =
- mDozeParameters.shouldClampToDimBrightness()
- || mWakefulnessLifecycle.getWakefulness() == WAKEFULNESS_GOING_TO_SLEEP;
+ (mDozeParameters.shouldClampToDimBrightness()
+ || mWakefulnessLifecycle.getWakefulness() == WAKEFULNESS_GOING_TO_SLEEP)
+ && mState == DozeMachine.State.INITIALIZED;
if (screenTurningOff
&& mWakefulnessLifecycle.getLastSleepReason() == GO_TO_SLEEP_REASON_TIMEOUT) {
return Math.max(
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
index 19b0ea1db04e..b06bf89ffdeb 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
@@ -136,6 +136,8 @@ public class DozeService extends DreamService
@Override
public void setDozeScreenState(int state) {
super.setDozeScreenState(state);
- mDozeMachine.onScreenState(state);
+ if (mDozeMachine != null) {
+ mDozeMachine.onScreenState(state);
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSuppressor.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSuppressor.java
index 31d43b5475e0..89f50ad9fc21 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeSuppressor.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSuppressor.java
@@ -166,6 +166,8 @@ public class DozeSuppressor implements DozeMachine.Part {
private DozeHost.Callback mHostCallback = new DozeHost.Callback() {
@Override
public void onPowerSaveChanged(boolean active) {
+ // handles suppression changes, while DozeMachine#transitionPolicy handles gating
+ // transitions to DOZE_AOD
DozeMachine.State nextState = null;
if (mDozeHost.isPowerSaveActive()) {
nextState = DozeMachine.State.DOZE;
@@ -182,6 +184,8 @@ public class DozeSuppressor implements DozeMachine.Part {
@Override
public void onAlwaysOnSuppressedChanged(boolean suppressed) {
+ // handles suppression changes, while DozeMachine#transitionPolicy handles gating
+ // transitions to DOZE_AOD
final DozeMachine.State nextState;
if (mConfig.alwaysOnEnabled(UserHandle.USER_CURRENT) && !suppressed) {
nextState = DozeMachine.State.DOZE_AOD;
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
index 69f15e692065..995df19f64c2 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
@@ -23,8 +23,6 @@ import android.util.MathUtils;
import android.view.View;
import android.view.ViewGroup;
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.R;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dreams.complication.ComplicationHostViewController;
import com.android.systemui.dreams.dagger.DreamOverlayComponent;
@@ -39,9 +37,6 @@ import javax.inject.Named;
*/
@DreamOverlayComponent.DreamOverlayScope
public class DreamOverlayContainerViewController extends ViewController<DreamOverlayContainerView> {
- // The height of the area at the top of the dream overlay to allow dragging down the
- // notifications shade.
- private final int mDreamOverlayNotificationsDragAreaHeight;
private final DreamOverlayStatusBarViewController mStatusBarViewController;
private final ComplicationHostViewController mComplicationHostViewController;
@@ -79,9 +74,6 @@ public class DreamOverlayContainerViewController extends ViewController<DreamOve
super(containerView);
mDreamOverlayContentView = contentView;
mStatusBarViewController = statusBarViewController;
- mDreamOverlayNotificationsDragAreaHeight =
- mView.getResources().getDimensionPixelSize(
- R.dimen.dream_overlay_notifications_drag_area_height);
mComplicationHostViewController = complicationHostViewController;
final View view = mComplicationHostViewController.getView();
@@ -117,11 +109,6 @@ public class DreamOverlayContainerViewController extends ViewController<DreamOve
return mView;
}
- @VisibleForTesting
- int getDreamOverlayNotificationsDragAreaHeight() {
- return mDreamOverlayNotificationsDragAreaHeight;
- }
-
private void updateBurnInOffsets() {
int burnInOffset = mMaxBurnInOffset;
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
index ebc766635733..dfbb0c7c1624 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
@@ -65,6 +65,9 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ
// A reference to the {@link Window} used to hold the dream overlay.
private Window mWindow;
+ // True if the service has been destroyed.
+ private boolean mDestroyed;
+
private final Complication.Host mHost = new Complication.Host() {
@Override
public void requestExitDream() {
@@ -134,6 +137,7 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ
mPreviewComplication.setDreamLabel(null);
mStateController.removeComplication(mPreviewComplication);
mStateController.setPreviewMode(false);
+ mDestroyed = true;
super.onDestroy();
}
@@ -141,6 +145,11 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ
public void onStartDream(@NonNull WindowManager.LayoutParams layoutParams) {
setCurrentState(Lifecycle.State.STARTED);
mExecutor.execute(() -> {
+ if (mDestroyed) {
+ // The task could still be executed after the service has been destroyed. Bail if
+ // that is the case.
+ return;
+ }
mStateController.setShouldShowComplications(shouldShowComplications());
mStateController.setPreviewMode(isPreviewMode());
if (isPreviewMode()) {
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarView.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarView.java
index d2ab61149d26..59a17bad5069 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarView.java
@@ -88,10 +88,6 @@ public class DreamOverlayStatusBarView extends ConstraintLayout {
fetchStatusIconForResId(R.id.dream_overlay_priority_mode));
}
- void showIcon(@StatusIconType int iconType, boolean show) {
- showIcon(iconType, show, null);
- }
-
void showIcon(@StatusIconType int iconType, boolean show, @Nullable String contentDescription) {
View icon = mStatusIcons.get(iconType);
if (icon == null) {
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarViewController.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarViewController.java
index a25a7423770e..761f28c5ac3b 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarViewController.java
@@ -16,6 +16,7 @@
package com.android.systemui.dreams;
+import android.annotation.Nullable;
import android.app.AlarmManager;
import android.content.res.Resources;
import android.hardware.SensorPrivacyManager;
@@ -45,6 +46,7 @@ import com.android.systemui.util.time.DateFormatUtil;
import java.util.Locale;
import java.util.Map;
+import java.util.concurrent.Executor;
import javax.inject.Inject;
@@ -62,6 +64,9 @@ public class DreamOverlayStatusBarViewController extends ViewController<DreamOve
private final IndividualSensorPrivacyController mSensorPrivacyController;
private final NotificationListener mNotificationListener;
private final ZenModeController mZenModeController;
+ private final Executor mMainExecutor;
+
+ private boolean mIsAttached;
private final NetworkRequest mNetworkRequest = new NetworkRequest.Builder()
.clearCapabilities()
@@ -131,6 +136,7 @@ public class DreamOverlayStatusBarViewController extends ViewController<DreamOve
public DreamOverlayStatusBarViewController(
DreamOverlayStatusBarView view,
@Main Resources resources,
+ @Main Executor mainExecutor,
ConnectivityManager connectivityManager,
TouchInsetManager.TouchInsetSession touchInsetSession,
AlarmManager alarmManager,
@@ -141,6 +147,7 @@ public class DreamOverlayStatusBarViewController extends ViewController<DreamOve
ZenModeController zenModeController) {
super(view);
mResources = resources;
+ mMainExecutor = mainExecutor;
mConnectivityManager = connectivityManager;
mTouchInsetSession = touchInsetSession;
mAlarmManager = alarmManager;
@@ -157,6 +164,8 @@ public class DreamOverlayStatusBarViewController extends ViewController<DreamOve
@Override
protected void onViewAttached() {
+ mIsAttached = true;
+
updateNotificationsStatusIcon();
mConnectivityManager.registerNetworkCallback(mNetworkRequest, mNetworkCallback);
@@ -181,6 +190,8 @@ public class DreamOverlayStatusBarViewController extends ViewController<DreamOve
mNextAlarmController.removeCallback(mNextAlarmCallback);
mConnectivityManager.unregisterNetworkCallback(mNetworkCallback);
mTouchInsetSession.clear();
+
+ mIsAttached = false;
}
private void updateWifiUnavailableStatusIcon() {
@@ -189,14 +200,14 @@ public class DreamOverlayStatusBarViewController extends ViewController<DreamOve
mConnectivityManager.getActiveNetwork());
final boolean available = capabilities != null
&& capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI);
- mView.showIcon(DreamOverlayStatusBarView.STATUS_ICON_WIFI_UNAVAILABLE, !available);
+ showIcon(DreamOverlayStatusBarView.STATUS_ICON_WIFI_UNAVAILABLE, !available);
}
private void updateAlarmStatusIcon() {
final AlarmManager.AlarmClockInfo alarm =
mAlarmManager.getNextAlarmClock(UserHandle.USER_CURRENT);
final boolean hasAlarm = alarm != null && alarm.getTriggerTime() > 0;
- mView.showIcon(
+ showIcon(
DreamOverlayStatusBarView.STATUS_ICON_ALARM_SET,
hasAlarm,
hasAlarm ? buildAlarmContentDescription(alarm) : null);
@@ -215,7 +226,7 @@ public class DreamOverlayStatusBarViewController extends ViewController<DreamOve
.isSensorBlocked(SensorPrivacyManager.Sensors.MICROPHONE);
final boolean cameraBlocked = mSensorPrivacyController
.isSensorBlocked(SensorPrivacyManager.Sensors.CAMERA);
- mView.showIcon(
+ showIcon(
DreamOverlayStatusBarView.STATUS_ICON_MIC_CAMERA_DISABLED,
micBlocked && cameraBlocked);
}
@@ -230,7 +241,7 @@ public class DreamOverlayStatusBarViewController extends ViewController<DreamOve
final StatusBarNotification[] notifications =
mNotificationListener.getActiveNotifications();
final int notificationCount = notifications != null ? notifications.length : 0;
- mView.showIcon(
+ showIcon(
DreamOverlayStatusBarView.STATUS_ICON_NOTIFICATIONS,
notificationCount > 0,
notificationCount > 0
@@ -246,8 +257,23 @@ public class DreamOverlayStatusBarViewController extends ViewController<DreamOve
}
private void updatePriorityModeStatusIcon() {
- mView.showIcon(
+ showIcon(
DreamOverlayStatusBarView.STATUS_ICON_PRIORITY_MODE_ON,
mZenModeController.getZen() != Settings.Global.ZEN_MODE_OFF);
}
+
+ private void showIcon(@DreamOverlayStatusBarView.StatusIconType int iconType, boolean show) {
+ showIcon(iconType, show, null);
+ }
+
+ private void showIcon(
+ @DreamOverlayStatusBarView.StatusIconType int iconType,
+ boolean show,
+ @Nullable String contentDescription) {
+ mMainExecutor.execute(() -> {
+ if (mIsAttached) {
+ mView.showIcon(iconType, show, contentDescription);
+ }
+ });
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/SmartSpaceComplication.java b/packages/SystemUI/src/com/android/systemui/dreams/SmartSpaceComplication.java
index a5dcd39264df..a83e006dfa2f 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/SmartSpaceComplication.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/SmartSpaceComplication.java
@@ -17,6 +17,7 @@
package com.android.systemui.dreams;
import android.content.Context;
+import android.os.Parcelable;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
@@ -25,7 +26,10 @@ import com.android.systemui.CoreStartable;
import com.android.systemui.dreams.complication.Complication;
import com.android.systemui.dreams.complication.ComplicationLayoutParams;
import com.android.systemui.dreams.complication.ComplicationViewModel;
-import com.android.systemui.statusbar.lockscreen.LockscreenSmartspaceController;
+import com.android.systemui.dreams.smartspace.DreamsSmartspaceController;
+import com.android.systemui.plugins.BcSmartspaceDataPlugin;
+
+import java.util.List;
import javax.inject.Inject;
@@ -39,10 +43,22 @@ public class SmartSpaceComplication implements Complication {
* SystemUI.
*/
public static class Registrant extends CoreStartable {
- private final LockscreenSmartspaceController mSmartSpaceController;
+ private final DreamsSmartspaceController mSmartSpaceController;
private final DreamOverlayStateController mDreamOverlayStateController;
private final SmartSpaceComplication mComplication;
+ private final BcSmartspaceDataPlugin.SmartspaceTargetListener mSmartspaceListener =
+ new BcSmartspaceDataPlugin.SmartspaceTargetListener() {
+ @Override
+ public void onSmartspaceTargetsUpdated(List<? extends Parcelable> targets) {
+ if (!targets.isEmpty()) {
+ mDreamOverlayStateController.addComplication(mComplication);
+ } else {
+ mDreamOverlayStateController.removeComplication(mComplication);
+ }
+ }
+ };
+
/**
* Default constructor for {@link SmartSpaceComplication}.
*/
@@ -50,7 +66,7 @@ public class SmartSpaceComplication implements Complication {
public Registrant(Context context,
DreamOverlayStateController dreamOverlayStateController,
SmartSpaceComplication smartSpaceComplication,
- LockscreenSmartspaceController smartSpaceController) {
+ DreamsSmartspaceController smartSpaceController) {
super(context);
mDreamOverlayStateController = dreamOverlayStateController;
mComplication = smartSpaceComplication;
@@ -59,32 +75,27 @@ public class SmartSpaceComplication implements Complication {
@Override
public void start() {
- addOrRemoveOverlay();
mDreamOverlayStateController.addCallback(new DreamOverlayStateController.Callback() {
@Override
public void onStateChanged() {
- addOrRemoveOverlay();
+ if (mDreamOverlayStateController.isOverlayActive()) {
+ mSmartSpaceController.addListener(mSmartspaceListener);
+ } else {
+ mSmartSpaceController.removeListener(mSmartspaceListener);
+ }
}
});
}
-
- private void addOrRemoveOverlay() {
- if (mDreamOverlayStateController.isPreviewMode()) {
- mDreamOverlayStateController.removeComplication(mComplication);
- } else if (mSmartSpaceController.isEnabled()) {
- mDreamOverlayStateController.addComplication(mComplication);
- }
- }
}
private static class SmartSpaceComplicationViewHolder implements ViewHolder {
private static final int SMARTSPACE_COMPLICATION_WEIGHT = 10;
- private final LockscreenSmartspaceController mSmartSpaceController;
+ private final DreamsSmartspaceController mSmartSpaceController;
private final Context mContext;
protected SmartSpaceComplicationViewHolder(
Context context,
- LockscreenSmartspaceController smartSpaceController) {
+ DreamsSmartspaceController smartSpaceController) {
mSmartSpaceController = smartSpaceController;
mContext = context;
}
@@ -109,12 +120,12 @@ public class SmartSpaceComplication implements Complication {
}
}
- private final LockscreenSmartspaceController mSmartSpaceController;
+ private final DreamsSmartspaceController mSmartSpaceController;
private final Context mContext;
@Inject
public SmartSpaceComplication(Context context,
- LockscreenSmartspaceController smartSpaceController) {
+ DreamsSmartspaceController smartSpaceController) {
mContext = context;
mSmartSpaceController = smartSpaceController;
}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationHostViewController.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationHostViewController.java
index 62b319bd9e97..4e528bbe9386 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationHostViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationHostViewController.java
@@ -21,6 +21,7 @@ import static com.android.systemui.dreams.complication.dagger.ComplicationModule
import android.graphics.Rect;
import android.graphics.Region;
+import android.util.Log;
import android.view.View;
import androidx.constraintlayout.widget.ConstraintLayout;
@@ -42,6 +43,8 @@ import javax.inject.Named;
* a {@link ComplicationLayoutEngine}.
*/
public class ComplicationHostViewController extends ViewController<ConstraintLayout> {
+ public static final String TAG = "ComplicationHostViewController";
+
private final ComplicationLayoutEngine mLayoutEngine;
private final LifecycleOwner mLifecycleOwner;
private final ComplicationCollectionViewModel mComplicationCollectionViewModel;
@@ -113,6 +116,12 @@ public class ComplicationHostViewController extends ViewController<ConstraintLay
final Complication.ViewHolder viewHolder = complication.getComplication()
.createView(complication);
mComplications.put(id, viewHolder);
+ if (viewHolder.getView().getParent() != null) {
+ Log.e(TAG, "View for complication "
+ + complication.getComplication().getClass()
+ + " already has a parent. Make sure not to reuse complication "
+ + "views!");
+ }
mLayoutEngine.addComplication(id, viewHolder.getView(),
viewHolder.getLayoutParams(), viewHolder.getCategory());
});
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamClockDateComplication.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamClockDateComplication.java
index 6861c7479161..1ca06b25aa9f 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamClockDateComplication.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamClockDateComplication.java
@@ -16,32 +16,32 @@
package com.android.systemui.dreams.complication;
-import static com.android.systemui.dreams.complication.dagger.DreamClockDateComplicationComponent.DreamClockDateComplicationModule.DREAM_CLOCK_DATE_COMPLICATION_LAYOUT_PARAMS;
-import static com.android.systemui.dreams.complication.dagger.DreamClockDateComplicationComponent.DreamClockDateComplicationModule.DREAM_CLOCK_DATE_COMPLICATION_VIEW;
+import static com.android.systemui.dreams.complication.dagger.DreamClockDateComplicationModule.DREAM_CLOCK_DATE_COMPLICATION_LAYOUT_PARAMS;
+import static com.android.systemui.dreams.complication.dagger.DreamClockDateComplicationModule.DREAM_CLOCK_DATE_COMPLICATION_VIEW;
import android.content.Context;
import android.view.View;
import com.android.systemui.CoreStartable;
import com.android.systemui.dreams.DreamOverlayStateController;
-import com.android.systemui.dreams.complication.dagger.DreamClockDateComplicationComponent;
import javax.inject.Inject;
import javax.inject.Named;
+import javax.inject.Provider;
/**
* Clock Date Complication that produce Clock Date view holder.
*/
public class DreamClockDateComplication implements Complication {
- DreamClockDateComplicationComponent.Factory mComponentFactory;
+ private final Provider<DreamClockDateViewHolder> mDreamClockDateViewHolderProvider;
/**
* Default constructor for {@link DreamClockDateComplication}.
*/
@Inject
public DreamClockDateComplication(
- DreamClockDateComplicationComponent.Factory componentFactory) {
- mComponentFactory = componentFactory;
+ Provider<DreamClockDateViewHolder> dreamClockDateViewHolderProvider) {
+ mDreamClockDateViewHolderProvider = dreamClockDateViewHolderProvider;
}
@Override
@@ -54,11 +54,11 @@ public class DreamClockDateComplication implements Complication {
*/
@Override
public ViewHolder createView(ComplicationViewModel model) {
- return mComponentFactory.create().getViewHolder();
+ return mDreamClockDateViewHolderProvider.get();
}
/**
- * {@link CoreStartable} responsbile for registering {@link DreamClockDateComplication} with
+ * {@link CoreStartable} responsible for registering {@link DreamClockDateComplication} with
* SystemUI.
*/
public static class Registrant extends CoreStartable {
@@ -84,7 +84,7 @@ public class DreamClockDateComplication implements Complication {
}
/**
- * ViewHolder to contain value/logic associated with a Clock Date Complication View.
+ * {@link ViewHolder} to contain value/logic associated with {@link DreamClockDateComplication}.
*/
public static class DreamClockDateViewHolder implements ViewHolder {
private final View mView;
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamClockTimeComplication.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamClockTimeComplication.java
index 936767a60233..7f67ecd19175 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamClockTimeComplication.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamClockTimeComplication.java
@@ -16,32 +16,32 @@
package com.android.systemui.dreams.complication;
-import static com.android.systemui.dreams.complication.dagger.DreamClockTimeComplicationComponent.DreamClockTimeComplicationModule.DREAM_CLOCK_TIME_COMPLICATION_LAYOUT_PARAMS;
-import static com.android.systemui.dreams.complication.dagger.DreamClockTimeComplicationComponent.DreamClockTimeComplicationModule.DREAM_CLOCK_TIME_COMPLICATION_VIEW;
+import static com.android.systemui.dreams.complication.dagger.DreamClockTimeComplicationModule.DREAM_CLOCK_TIME_COMPLICATION_LAYOUT_PARAMS;
+import static com.android.systemui.dreams.complication.dagger.DreamClockTimeComplicationModule.DREAM_CLOCK_TIME_COMPLICATION_VIEW;
import android.content.Context;
import android.view.View;
import com.android.systemui.CoreStartable;
import com.android.systemui.dreams.DreamOverlayStateController;
-import com.android.systemui.dreams.complication.dagger.DreamClockTimeComplicationComponent;
import javax.inject.Inject;
import javax.inject.Named;
+import javax.inject.Provider;
/**
* Clock Time Complication that produce Clock Time view holder.
*/
public class DreamClockTimeComplication implements Complication {
- DreamClockTimeComplicationComponent.Factory mComponentFactory;
+ private final Provider<DreamClockTimeViewHolder> mDreamClockTimeViewHolderProvider;
/**
* Default constructor for {@link DreamClockTimeComplication}.
*/
@Inject
public DreamClockTimeComplication(
- DreamClockTimeComplicationComponent.Factory componentFactory) {
- mComponentFactory = componentFactory;
+ Provider<DreamClockTimeViewHolder> dreamClockTimeViewHolderProvider) {
+ mDreamClockTimeViewHolderProvider = dreamClockTimeViewHolderProvider;
}
@Override
@@ -54,11 +54,11 @@ public class DreamClockTimeComplication implements Complication {
*/
@Override
public ViewHolder createView(ComplicationViewModel model) {
- return mComponentFactory.create().getViewHolder();
+ return mDreamClockTimeViewHolderProvider.get();
}
/**
- * {@link CoreStartable} responsbile for registering {@link DreamClockTimeComplication} with
+ * {@link CoreStartable} responsible for registering {@link DreamClockTimeComplication} with
* SystemUI.
*/
public static class Registrant extends CoreStartable {
@@ -84,7 +84,7 @@ public class DreamClockTimeComplication implements Complication {
}
/**
- * ViewHolder to contain value/logic associated with a Clock Time Complication View.
+ * {@link ViewHolder} to contain value/logic associated with {@link DreamClockTimeComplication}.
*/
public static class DreamClockTimeViewHolder implements ViewHolder {
private final View mView;
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamClockDateComplicationComponent.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamClockDateComplicationComponent.java
deleted file mode 100644
index dd7f10c204e1..000000000000
--- a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamClockDateComplicationComponent.java
+++ /dev/null
@@ -1,110 +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.systemui.dreams.complication.dagger;
-
-
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-
-import com.android.internal.util.Preconditions;
-import com.android.systemui.R;
-import com.android.systemui.dreams.complication.ComplicationLayoutParams;
-import com.android.systemui.dreams.complication.DreamClockDateComplication.DreamClockDateViewHolder;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-
-import javax.inject.Named;
-import javax.inject.Scope;
-
-import dagger.Module;
-import dagger.Provides;
-import dagger.Subcomponent;
-
-/**
- * {@link DreamClockDateComplicationComponent} is responsible for generating dependencies
- * surrounding the
- * Clock Date {@link com.android.systemui.dreams.complication.Complication}, such as the layout
- * details.
- */
-@Subcomponent(modules = {
- DreamClockDateComplicationComponent.DreamClockDateComplicationModule.class,
-})
-@DreamClockDateComplicationComponent.DreamClockDateComplicationScope
-public interface DreamClockDateComplicationComponent {
- /**
- * Creates {@link DreamClockDateViewHolder}.
- */
- DreamClockDateViewHolder getViewHolder();
-
- @Documented
- @Retention(RUNTIME)
- @Scope
- @interface DreamClockDateComplicationScope {
- }
-
- /**
- * Generates {@link DreamClockDateComplicationComponent}.
- */
- @Subcomponent.Factory
- interface Factory {
- DreamClockDateComplicationComponent create();
- }
-
- /**
- * Scoped values for {@link DreamClockDateComplicationComponent}.
- */
- @Module
- interface DreamClockDateComplicationModule {
- String DREAM_CLOCK_DATE_COMPLICATION_VIEW = "clock_date_complication_view";
- String DREAM_CLOCK_DATE_COMPLICATION_LAYOUT_PARAMS =
- "clock_date_complication_layout_params";
- // Order weight of insert into parent container
- int INSERT_ORDER_WEIGHT = 2;
-
- /**
- * Provides the complication view.
- */
- @Provides
- @DreamClockDateComplicationScope
- @Named(DREAM_CLOCK_DATE_COMPLICATION_VIEW)
- static View provideComplicationView(LayoutInflater layoutInflater) {
- return Preconditions.checkNotNull(
- layoutInflater.inflate(R.layout.dream_overlay_complication_clock_date,
- null, false),
- "R.layout.dream_overlay_complication_clock_date did not properly inflated");
- }
-
- /**
- * Provides the layout parameters for the complication view.
- */
- @Provides
- @DreamClockDateComplicationScope
- @Named(DREAM_CLOCK_DATE_COMPLICATION_LAYOUT_PARAMS)
- static ComplicationLayoutParams provideLayoutParams() {
- return new ComplicationLayoutParams(0,
- ViewGroup.LayoutParams.WRAP_CONTENT,
- ComplicationLayoutParams.POSITION_BOTTOM
- | ComplicationLayoutParams.POSITION_START,
- ComplicationLayoutParams.DIRECTION_END,
- INSERT_ORDER_WEIGHT);
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamClockDateComplicationModule.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamClockDateComplicationModule.java
new file mode 100644
index 000000000000..eb2fc5d1a93e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamClockDateComplicationModule.java
@@ -0,0 +1,71 @@
+/*
+ * 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.dreams.complication.dagger;
+
+
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.internal.util.Preconditions;
+import com.android.systemui.R;
+import com.android.systemui.dreams.complication.ComplicationLayoutParams;
+import com.android.systemui.dreams.complication.DreamClockDateComplication;
+
+import javax.inject.Named;
+
+import dagger.Module;
+import dagger.Provides;
+
+/**
+ * Module for providing {@link DreamClockDateComplication}.
+ */
+@Module
+public interface DreamClockDateComplicationModule {
+ String DREAM_CLOCK_DATE_COMPLICATION_VIEW = "clock_date_complication_view";
+ String DREAM_CLOCK_DATE_COMPLICATION_LAYOUT_PARAMS =
+ "clock_date_complication_layout_params";
+ // Order weight of insert into parent container
+ //TODO(b/217199227): move to a single location.
+ int INSERT_ORDER_WEIGHT = 2;
+
+ /**
+ * Provides the complication view.
+ */
+ @Provides
+ @Named(DREAM_CLOCK_DATE_COMPLICATION_VIEW)
+ static View provideComplicationView(LayoutInflater layoutInflater) {
+ return Preconditions.checkNotNull(
+ layoutInflater.inflate(R.layout.dream_overlay_complication_clock_date,
+ null, false),
+ "R.layout.dream_overlay_complication_clock_date did not properly inflated");
+ }
+
+ /**
+ * Provides the layout parameters for the complication view.
+ */
+ @Provides
+ @Named(DREAM_CLOCK_DATE_COMPLICATION_LAYOUT_PARAMS)
+ static ComplicationLayoutParams provideLayoutParams() {
+ return new ComplicationLayoutParams(0,
+ ViewGroup.LayoutParams.WRAP_CONTENT,
+ ComplicationLayoutParams.POSITION_BOTTOM
+ | ComplicationLayoutParams.POSITION_START,
+ ComplicationLayoutParams.DIRECTION_END,
+ INSERT_ORDER_WEIGHT);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamClockTimeComplicationComponent.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamClockTimeComplicationComponent.java
deleted file mode 100644
index de11b61f4759..000000000000
--- a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamClockTimeComplicationComponent.java
+++ /dev/null
@@ -1,115 +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.systemui.dreams.complication.dagger;
-
-
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.TextClock;
-
-import com.android.internal.util.Preconditions;
-import com.android.systemui.R;
-import com.android.systemui.dreams.complication.ComplicationLayoutParams;
-import com.android.systemui.dreams.complication.DreamClockTimeComplication.DreamClockTimeViewHolder;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-
-import javax.inject.Named;
-import javax.inject.Scope;
-
-import dagger.Module;
-import dagger.Provides;
-import dagger.Subcomponent;
-
-/**
- * {@link DreamClockTimeComplicationComponent} is responsible for generating dependencies
- * surrounding the
- * Clock Time {@link com.android.systemui.dreams.complication.Complication}, such as the layout
- * details.
- */
-@Subcomponent(modules = {
- DreamClockTimeComplicationComponent.DreamClockTimeComplicationModule.class,
-})
-@DreamClockTimeComplicationComponent.DreamClockTimeComplicationScope
-public interface DreamClockTimeComplicationComponent {
- /**
- * Creates {@link DreamClockTimeViewHolder}.
- */
- DreamClockTimeViewHolder getViewHolder();
-
- @Documented
- @Retention(RUNTIME)
- @Scope
- @interface DreamClockTimeComplicationScope {
- }
-
- /**
- * Generates {@link DreamClockTimeComplicationComponent}.
- */
- @Subcomponent.Factory
- interface Factory {
- DreamClockTimeComplicationComponent create();
- }
-
- /**
- * Scoped values for {@link DreamClockTimeComplicationComponent}.
- */
- @Module
- interface DreamClockTimeComplicationModule {
- String DREAM_CLOCK_TIME_COMPLICATION_VIEW = "clock_time_complication_view";
- String DREAM_CLOCK_TIME_COMPLICATION_LAYOUT_PARAMS =
- "clock_time_complication_layout_params";
- // Order weight of insert into parent container
- int INSERT_ORDER_WEIGHT = 0;
- String TAG_WEIGHT = "'wght' ";
- int WEIGHT = 200;
-
- /**
- * Provides the complication view.
- */
- @Provides
- @DreamClockTimeComplicationScope
- @Named(DREAM_CLOCK_TIME_COMPLICATION_VIEW)
- static View provideComplicationView(LayoutInflater layoutInflater) {
- final TextClock view = Preconditions.checkNotNull((TextClock)
- layoutInflater.inflate(R.layout.dream_overlay_complication_clock_time,
- null, false),
- "R.layout.dream_overlay_complication_clock_time did not properly inflated");
- view.setFontVariationSettings(TAG_WEIGHT + WEIGHT);
- return view;
- }
-
- /**
- * Provides the layout parameters for the complication view.
- */
- @Provides
- @DreamClockTimeComplicationScope
- @Named(DREAM_CLOCK_TIME_COMPLICATION_LAYOUT_PARAMS)
- static ComplicationLayoutParams provideLayoutParams() {
- return new ComplicationLayoutParams(0,
- ViewGroup.LayoutParams.WRAP_CONTENT,
- ComplicationLayoutParams.POSITION_BOTTOM
- | ComplicationLayoutParams.POSITION_START,
- ComplicationLayoutParams.DIRECTION_UP,
- INSERT_ORDER_WEIGHT);
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamClockTimeComplicationModule.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamClockTimeComplicationModule.java
new file mode 100644
index 000000000000..3ad7d3ded749
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamClockTimeComplicationModule.java
@@ -0,0 +1,76 @@
+/*
+ * 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.dreams.complication.dagger;
+
+
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextClock;
+
+import com.android.internal.util.Preconditions;
+import com.android.systemui.R;
+import com.android.systemui.dreams.complication.ComplicationLayoutParams;
+import com.android.systemui.dreams.complication.DreamClockTimeComplication;
+
+import javax.inject.Named;
+
+import dagger.Module;
+import dagger.Provides;
+
+/**
+ * Module for providing {@link DreamClockTimeComplication}.
+ */
+@Module
+public interface DreamClockTimeComplicationModule {
+ String DREAM_CLOCK_TIME_COMPLICATION_VIEW = "clock_time_complication_view";
+ String DREAM_CLOCK_TIME_COMPLICATION_LAYOUT_PARAMS =
+ "clock_time_complication_layout_params";
+ // Order weight of insert into parent container
+ //TODO(b/217199227): move to a single location.
+ int INSERT_ORDER_WEIGHT = 0;
+ String TAG_WEIGHT = "'wght' ";
+ int WEIGHT = 200;
+
+ /**
+ * Provides the complication view.
+ */
+ @Provides
+ @Named(DREAM_CLOCK_TIME_COMPLICATION_VIEW)
+ static View provideComplicationView(LayoutInflater layoutInflater) {
+ final TextClock view = Preconditions.checkNotNull((TextClock)
+ layoutInflater.inflate(R.layout.dream_overlay_complication_clock_time,
+ null, false),
+ "R.layout.dream_overlay_complication_clock_time did not properly inflated");
+ view.setFontVariationSettings(TAG_WEIGHT + WEIGHT);
+ return view;
+ }
+
+ /**
+ * Provides the layout parameters for the complication view.
+ */
+ @Provides
+ @Named(DREAM_CLOCK_TIME_COMPLICATION_LAYOUT_PARAMS)
+ static ComplicationLayoutParams provideLayoutParams() {
+ return new ComplicationLayoutParams(0,
+ ViewGroup.LayoutParams.WRAP_CONTENT,
+ ComplicationLayoutParams.POSITION_BOTTOM
+ | ComplicationLayoutParams.POSITION_START,
+ ComplicationLayoutParams.DIRECTION_UP,
+ INSERT_ORDER_WEIGHT);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/RegisteredComplicationsModule.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/RegisteredComplicationsModule.java
index 8e4fb3783f4a..62a4140c6745 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/RegisteredComplicationsModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/RegisteredComplicationsModule.java
@@ -24,10 +24,12 @@ import dagger.Module;
* Module for all components with corresponding dream layer complications registered in
* {@link SystemUIBinder}.
*/
-@Module(subcomponents = {
- DreamClockTimeComplicationComponent.class,
- DreamClockDateComplicationComponent.class,
- DreamWeatherComplicationComponent.class,
-})
+@Module(includes = {
+ DreamClockDateComplicationModule.class,
+ DreamClockTimeComplicationModule.class,
+ },
+ subcomponents = {
+ DreamWeatherComplicationComponent.class,
+ })
public interface RegisteredComplicationsModule {
}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamModule.java b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamModule.java
index de5b4bb9e520..c7b02cd00e96 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamModule.java
@@ -26,7 +26,7 @@ import dagger.Module;
import dagger.Provides;
/**
- * Dagger Module providing Communal-related functionality.
+ * Dagger Module providing Dream-related functionality.
*/
@Module(includes = {
RegisteredComplicationsModule.class,
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/smartspace/DreamsSmartspaceController.kt b/packages/SystemUI/src/com/android/systemui/dreams/smartspace/DreamsSmartspaceController.kt
new file mode 100644
index 000000000000..4e228a14fc88
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/dreams/smartspace/DreamsSmartspaceController.kt
@@ -0,0 +1,219 @@
+/*
+ * 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.dreams.smartspace
+
+import android.app.smartspace.SmartspaceConfig
+import android.app.smartspace.SmartspaceManager
+import android.app.smartspace.SmartspaceSession
+import android.content.Context
+import android.graphics.Color
+import android.util.Log
+import android.view.View
+import android.view.ViewGroup
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.plugins.BcSmartspaceDataPlugin
+import com.android.systemui.plugins.BcSmartspaceDataPlugin.SmartspaceTargetListener
+import com.android.systemui.plugins.BcSmartspaceDataPlugin.SmartspaceView
+import com.android.systemui.smartspace.SmartspacePrecondition
+import com.android.systemui.smartspace.SmartspaceTargetFilter
+import com.android.systemui.smartspace.dagger.SmartspaceModule.Companion.DREAM_SMARTSPACE_DATA_PLUGIN
+import com.android.systemui.smartspace.dagger.SmartspaceModule.Companion.DREAM_SMARTSPACE_PRECONDITION
+import com.android.systemui.smartspace.dagger.SmartspaceModule.Companion.DREAM_SMARTSPACE_TARGET_FILTER
+import com.android.systemui.smartspace.dagger.SmartspaceViewComponent
+import com.android.systemui.util.concurrency.Execution
+import java.lang.RuntimeException
+import java.util.Optional
+import java.util.concurrent.Executor
+import javax.inject.Inject
+import javax.inject.Named
+
+/**
+ * Controller for managing the smartspace view on the dream
+ */
+@SysUISingleton
+class DreamsSmartspaceController @Inject constructor(
+ private val context: Context,
+ private val smartspaceManager: SmartspaceManager,
+ private val execution: Execution,
+ @Main private val uiExecutor: Executor,
+ private val smartspaceViewComponentFactory: SmartspaceViewComponent.Factory,
+ @Named(DREAM_SMARTSPACE_PRECONDITION) private val precondition: SmartspacePrecondition,
+ @Named(DREAM_SMARTSPACE_TARGET_FILTER)
+ private val optionalTargetFilter: Optional<SmartspaceTargetFilter>,
+ @Named(DREAM_SMARTSPACE_DATA_PLUGIN) optionalPlugin: Optional<BcSmartspaceDataPlugin>
+) {
+ companion object {
+ private const val TAG = "DreamsSmartspaceCtrlr"
+ }
+
+ private var session: SmartspaceSession? = null
+ private val plugin: BcSmartspaceDataPlugin? = optionalPlugin.orElse(null)
+ private var targetFilter: SmartspaceTargetFilter? = optionalTargetFilter.orElse(null)
+
+ // A shadow copy of listeners is maintained to track whether the session should remain open.
+ private var listeners = mutableSetOf<BcSmartspaceDataPlugin.SmartspaceTargetListener>()
+
+ // Smartspace can be used on multiple displays, such as when the user casts their screen
+ private var smartspaceViews = mutableSetOf<SmartspaceView>()
+
+ var preconditionListener = object : SmartspacePrecondition.Listener {
+ override fun onCriteriaChanged() {
+ reloadSmartspace()
+ }
+ }
+
+ init {
+ precondition.addListener(preconditionListener)
+ }
+
+ var filterListener = object : SmartspaceTargetFilter.Listener {
+ override fun onCriteriaChanged() {
+ reloadSmartspace()
+ }
+ }
+
+ init {
+ targetFilter?.addListener(filterListener)
+ }
+
+ var stateChangeListener = object : View.OnAttachStateChangeListener {
+ override fun onViewAttachedToWindow(v: View) {
+ val view = v as SmartspaceView
+ // Until there is dream color matching
+ view.setPrimaryTextColor(Color.WHITE)
+ smartspaceViews.add(view)
+ connectSession()
+ }
+
+ override fun onViewDetachedFromWindow(v: View) {
+ smartspaceViews.remove(v as SmartspaceView)
+
+ if (smartspaceViews.isEmpty()) {
+ disconnect()
+ }
+ }
+ }
+
+ private val sessionListener = SmartspaceSession.OnTargetsAvailableListener { targets ->
+ execution.assertIsMainThread()
+
+ val filteredTargets = targets.filter { targetFilter?.filterSmartspaceTarget(it) ?: true }
+ plugin?.onTargetsAvailable(filteredTargets)
+ }
+
+ /**
+ * Constructs the smartspace view and connects it to the smartspace service.
+ */
+ fun buildAndConnectView(parent: ViewGroup): View? {
+ execution.assertIsMainThread()
+
+ if (!precondition.conditionsMet()) {
+ throw RuntimeException("Cannot build view when not enabled")
+ }
+
+ val view = buildView(parent)
+ connectSession()
+
+ return view
+ }
+
+ private fun buildView(parent: ViewGroup): View? {
+ return if (plugin != null) {
+ var view = smartspaceViewComponentFactory.create(parent, plugin, stateChangeListener)
+ .getView()
+
+ if (view is View) {
+ return view
+ }
+
+ return null
+ } else {
+ null
+ }
+ }
+
+ private fun hasActiveSessionListeners(): Boolean {
+ return smartspaceViews.isNotEmpty() || listeners.isNotEmpty()
+ }
+
+ private fun connectSession() {
+ if (plugin == null || session != null || !hasActiveSessionListeners()) {
+ return
+ }
+
+ if (!precondition.conditionsMet()) {
+ return
+ }
+
+ // TODO(b/217559844): Replace with "dream" session when available.
+ val newSession = smartspaceManager.createSmartspaceSession(
+ SmartspaceConfig.Builder(context, "lockscreen").build())
+ Log.d(TAG, "Starting smartspace session for dream")
+ newSession.addOnTargetsAvailableListener(uiExecutor, sessionListener)
+ this.session = newSession
+
+ plugin.registerSmartspaceEventNotifier {
+ e -> session?.notifySmartspaceEvent(e)
+ }
+
+ reloadSmartspace()
+ }
+
+ /**
+ * Disconnects the smartspace view from the smartspace service and cleans up any resources.
+ */
+ private fun disconnect() {
+ if (hasActiveSessionListeners()) return
+
+ execution.assertIsMainThread()
+
+ if (session == null) {
+ return
+ }
+
+ session?.let {
+ it.removeOnTargetsAvailableListener(sessionListener)
+ it.close()
+ }
+
+ session = null
+
+ plugin?.registerSmartspaceEventNotifier(null)
+ plugin?.onTargetsAvailable(emptyList())
+ Log.d(TAG, "Ending smartspace session for dream")
+ }
+
+ fun addListener(listener: SmartspaceTargetListener) {
+ execution.assertIsMainThread()
+ plugin?.registerListener(listener)
+ listeners.add(listener)
+
+ connectSession()
+ }
+
+ fun removeListener(listener: SmartspaceTargetListener) {
+ execution.assertIsMainThread()
+ plugin?.unregisterListener(listener)
+ listeners.remove(listener)
+ disconnect()
+ }
+
+ private fun reloadSmartspace() {
+ session?.requestSmartspaceUpdate()
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandler.java b/packages/SystemUI/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandler.java
index e140f6b0faa2..b96cee650663 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandler.java
@@ -31,8 +31,8 @@ import android.view.MotionEvent;
import android.view.VelocityTracker;
import com.android.systemui.statusbar.NotificationShadeWindowController;
-import com.android.systemui.statusbar.phone.KeyguardBouncer;
import com.android.systemui.statusbar.phone.CentralSurfaces;
+import com.android.systemui.statusbar.phone.KeyguardBouncer;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.wm.shell.animation.FlingAnimationUtils;
@@ -89,7 +89,7 @@ public class BouncerSwipeTouchHandler implements DreamTouchHandler {
private VelocityTrackerFactory mVelocityTrackerFactory;
private final GestureDetector.OnGestureListener mOnGestureListener =
- new GestureDetector.SimpleOnGestureListener() {
+ new GestureDetector.SimpleOnGestureListener() {
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
float distanceY) {
@@ -134,9 +134,9 @@ public class BouncerSwipeTouchHandler implements DreamTouchHandler {
NotificationShadeWindowController notificationShadeWindowController,
ValueAnimatorCreator valueAnimatorCreator,
VelocityTrackerFactory velocityTrackerFactory,
- @Named(SWIPE_TO_BOUNCER_FLING_ANIMATION_UTILS_CLOSING)
- FlingAnimationUtils flingAnimationUtils,
@Named(SWIPE_TO_BOUNCER_FLING_ANIMATION_UTILS_OPENING)
+ FlingAnimationUtils flingAnimationUtils,
+ @Named(SWIPE_TO_BOUNCER_FLING_ANIMATION_UTILS_CLOSING)
FlingAnimationUtils flingAnimationUtilsClosing,
@Named(SWIPE_TO_BOUNCER_START_REGION) float swipeRegionPercentage) {
mDisplayMetrics = displayMetrics;
@@ -154,13 +154,16 @@ public class BouncerSwipeTouchHandler implements DreamTouchHandler {
public void getTouchInitiationRegion(Region region) {
if (mCentralSurfaces.isBouncerShowing()) {
region.op(new Rect(0, 0, mDisplayMetrics.widthPixels,
- Math.round(mDisplayMetrics.heightPixels * mBouncerZoneScreenPercentage)),
+ Math.round(
+ mDisplayMetrics.heightPixels * mBouncerZoneScreenPercentage)),
Region.Op.UNION);
} else {
region.op(new Rect(0,
- Math.round(mDisplayMetrics.heightPixels * (1 - mBouncerZoneScreenPercentage)),
- mDisplayMetrics.widthPixels,
- mDisplayMetrics.heightPixels),
+ Math.round(
+ mDisplayMetrics.heightPixels
+ * (1 - mBouncerZoneScreenPercentage)),
+ mDisplayMetrics.widthPixels,
+ mDisplayMetrics.heightPixels),
Region.Op.UNION);
}
}
@@ -191,7 +194,7 @@ public class BouncerSwipeTouchHandler implements DreamTouchHandler {
final MotionEvent motionEvent = (MotionEvent) event;
- switch(motionEvent.getAction()) {
+ switch (motionEvent.getAction()) {
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
mTouchSession.pop();
@@ -210,9 +213,8 @@ public class BouncerSwipeTouchHandler implements DreamTouchHandler {
final float velocityVector =
(float) Math.hypot(horizontalVelocity, verticalVelocity);
-
final float expansion = flingRevealsOverlay(verticalVelocity, velocityVector)
- ? KeyguardBouncer.EXPANSION_HIDDEN : KeyguardBouncer.EXPANSION_VISIBLE;
+ ? KeyguardBouncer.EXPANSION_HIDDEN : KeyguardBouncer.EXPANSION_VISIBLE;
flingToExpansion(verticalVelocity, expansion);
if (expansion == KeyguardBouncer.EXPANSION_HIDDEN) {
@@ -236,8 +238,8 @@ public class BouncerSwipeTouchHandler implements DreamTouchHandler {
}
protected boolean flingRevealsOverlay(float velocity, float velocityVector) {
- // Fully expand if the user has expanded the bouncer less than halfway or final velocity was
- // positive, indicating an downward direction.
+ // Fully expand the space above the bouncer, if the user has expanded the bouncer less
+ // than halfway or final velocity was positive, indicating a downward direction.
if (Math.abs(velocityVector) < mFlingAnimationUtils.getMinVelocityPxPerSecond()) {
return mCurrentExpansion > FLING_PERCENTAGE_THRESHOLD;
} else {
@@ -246,17 +248,20 @@ public class BouncerSwipeTouchHandler implements DreamTouchHandler {
}
protected void flingToExpansion(float velocity, float expansion) {
+ // The animation utils deal in pixel units, rather than expansion height.
final float viewHeight = mCentralSurfaces.getDisplayHeight();
final float currentHeight = viewHeight * mCurrentExpansion;
final float targetHeight = viewHeight * expansion;
final ValueAnimator animator = createExpansionAnimator(expansion);
if (expansion == KeyguardBouncer.EXPANSION_HIDDEN) {
- // The animation utils deal in pixel units, rather than expansion height.
- mFlingAnimationUtils.apply(animator, currentHeight, targetHeight, velocity, viewHeight);
+ // Hides the bouncer, i.e., fully expands the space above the bouncer.
+ mFlingAnimationUtilsClosing.apply(animator, currentHeight, targetHeight, velocity,
+ viewHeight);
} else {
- mFlingAnimationUtilsClosing.apply(
- animator, mCurrentExpansion, currentHeight, targetHeight, viewHeight);
+ // Shows the bouncer, i.e., fully collapses the space above the bouncer.
+ mFlingAnimationUtils.apply(
+ animator, currentHeight, targetHeight, velocity, viewHeight);
}
animator.start();
diff --git a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebug.java b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebug.java
index 0c5f7ebb6e16..3335c8d62f46 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebug.java
+++ b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebug.java
@@ -50,9 +50,9 @@ import java.util.Map;
import java.util.Objects;
import java.util.TreeMap;
import java.util.function.Consumer;
-import java.util.function.Supplier;
import javax.inject.Inject;
+import javax.inject.Named;
/**
* Concrete implementation of the a Flag manager that returns default values for debug builds
@@ -66,12 +66,13 @@ import javax.inject.Inject;
@SysUISingleton
public class FeatureFlagsDebug implements FeatureFlags, Dumpable {
private static final String TAG = "SysUIFlags";
+ static final String ALL_FLAGS = "all_flags";
private final FlagManager mFlagManager;
private final SecureSettings mSecureSettings;
private final Resources mResources;
private final SystemPropertiesHelper mSystemProperties;
- private final Supplier<Map<Integer, Flag<?>>> mFlagsCollector;
+ private final Map<Integer, Flag<?>> mAllFlags;
private final Map<Integer, Boolean> mBooleanFlagCache = new TreeMap<>();
private final Map<Integer, String> mStringFlagCache = new TreeMap<>();
private final IStatusBarService mBarService;
@@ -84,13 +85,13 @@ public class FeatureFlagsDebug implements FeatureFlags, Dumpable {
SystemPropertiesHelper systemProperties,
@Main Resources resources,
DumpManager dumpManager,
- @Nullable Supplier<Map<Integer, Flag<?>>> flagsCollector,
+ @Named(ALL_FLAGS) Map<Integer, Flag<?>> allFlags,
IStatusBarService barService) {
mFlagManager = flagManager;
mSecureSettings = secureSettings;
mResources = resources;
mSystemProperties = systemProperties;
- mFlagsCollector = flagsCollector != null ? flagsCollector : Flags::collectFlags;
+ mAllFlags = allFlags;
IntentFilter filter = new IntentFilter();
filter.addAction(ACTION_SET_FLAG);
filter.addAction(ACTION_GET_FLAGS);
@@ -107,7 +108,7 @@ public class FeatureFlagsDebug implements FeatureFlags, Dumpable {
int id = flag.getId();
if (!mBooleanFlagCache.containsKey(id)) {
mBooleanFlagCache.put(id,
- readFlagValue(id, flag.getDefault(), BooleanFlagSerializer.INSTANCE));
+ readFlagValue(id, flag.getDefault()));
}
return mBooleanFlagCache.get(id);
@@ -118,8 +119,7 @@ public class FeatureFlagsDebug implements FeatureFlags, Dumpable {
int id = flag.getId();
if (!mBooleanFlagCache.containsKey(id)) {
mBooleanFlagCache.put(id,
- readFlagValue(id, mResources.getBoolean(flag.getResourceId()),
- BooleanFlagSerializer.INSTANCE));
+ readFlagValue(id, mResources.getBoolean(flag.getResourceId())));
}
return mBooleanFlagCache.get(id);
@@ -129,8 +129,13 @@ public class FeatureFlagsDebug implements FeatureFlags, Dumpable {
public boolean isEnabled(@NonNull SysPropBooleanFlag flag) {
int id = flag.getId();
if (!mBooleanFlagCache.containsKey(id)) {
+ // Use #readFlagValue to get the default. That will allow it to fall through to
+ // teamfood if need be.
mBooleanFlagCache.put(
- id, mSystemProperties.getBoolean(flag.getName(), flag.getDefault()));
+ id,
+ mSystemProperties.getBoolean(
+ flag.getName(),
+ readFlagValue(id, flag.getDefault())));
}
return mBooleanFlagCache.get(id);
@@ -161,6 +166,19 @@ public class FeatureFlagsDebug implements FeatureFlags, Dumpable {
return mStringFlagCache.get(id);
}
+ /** Specific override for Boolean flags that checks against the teamfood list.*/
+ private boolean readFlagValue(int id, boolean defaultValue) {
+ Boolean result = readFlagValueInternal(id, BooleanFlagSerializer.INSTANCE);
+ // Only check for teamfood if the default is false.
+ if (!defaultValue && result == null && id != Flags.TEAMFOOD.getId()) {
+ if (mAllFlags.containsKey(id) && mAllFlags.get(id).getTeamfood()) {
+ return isEnabled(Flags.TEAMFOOD);
+ }
+ }
+
+ return result == null ? defaultValue : result;
+ }
+
@NonNull
private <T> T readFlagValue(int id, @NonNull T defaultValue, FlagSerializer<T> serializer) {
requireNonNull(defaultValue, "defaultValue");
@@ -266,8 +284,7 @@ public class FeatureFlagsDebug implements FeatureFlags, Dumpable {
if (ACTION_SET_FLAG.equals(action)) {
handleSetFlag(intent.getExtras());
} else if (ACTION_GET_FLAGS.equals(action)) {
- Map<Integer, Flag<?>> knownFlagMap = mFlagsCollector.get();
- ArrayList<Flag<?>> flags = new ArrayList<>(knownFlagMap.values());
+ ArrayList<Flag<?>> flags = new ArrayList<>(mAllFlags.values());
// Convert all flags to parcelable flags.
ArrayList<ParcelableFlag<?>> pFlags = new ArrayList<>();
@@ -296,12 +313,11 @@ public class FeatureFlagsDebug implements FeatureFlags, Dumpable {
return;
}
- Map<Integer, Flag<?>> flagMap = mFlagsCollector.get();
- if (!flagMap.containsKey(id)) {
+ if (!mAllFlags.containsKey(id)) {
Log.w(TAG, "Tried to set unknown id: " + id);
return;
}
- Flag<?> flag = flagMap.get(id);
+ Flag<?> flag = mAllFlags.get(id);
if (!extras.containsKey(EXTRA_VALUE)) {
eraseFlag(flag);
@@ -338,13 +354,16 @@ public class FeatureFlagsDebug implements FeatureFlags, Dumpable {
@Nullable
private ParcelableFlag<?> toParcelableFlag(Flag<?> f) {
if (f instanceof BooleanFlag) {
- return new BooleanFlag(f.getId(), isEnabled((BooleanFlag) f));
+ return new BooleanFlag(f.getId(), isEnabled((BooleanFlag) f), f.getTeamfood());
}
if (f instanceof ResourceBooleanFlag) {
- return new BooleanFlag(f.getId(), isEnabled((ResourceBooleanFlag) f));
+ return new BooleanFlag(
+ f.getId(), isEnabled((ResourceBooleanFlag) f), f.getTeamfood());
}
if (f instanceof SysPropBooleanFlag) {
- return new BooleanFlag(f.getId(), isEnabled((SysPropBooleanFlag) f));
+ // TODO(b/223379190): Teamfood not supported for sysprop flags yet.
+ return new BooleanFlag(
+ f.getId(), isEnabled((SysPropBooleanFlag) f), false);
}
// TODO: add support for other flag types.
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.java b/packages/SystemUI/src/com/android/systemui/flags/Flags.java
index bf689e30d2fd..61cfe925f640 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.java
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.java
@@ -16,6 +16,7 @@
package com.android.systemui.flags;
+import com.android.internal.annotations.Keep;
import com.android.systemui.R;
import java.lang.reflect.Field;
@@ -144,7 +145,7 @@ public class Flags {
/***************************************/
// 900 - media
public static final BooleanFlag MEDIA_TAP_TO_TRANSFER = new BooleanFlag(900, true);
- public static final BooleanFlag MEDIA_SESSION_ACTIONS = new BooleanFlag(901, true);
+ public static final BooleanFlag MEDIA_SESSION_ACTIONS = new BooleanFlag(901, false);
public static final BooleanFlag MEDIA_SESSION_LAYOUT = new BooleanFlag(902, true);
public static final BooleanFlag MEDIA_NEARBY_DEVICES = new BooleanFlag(903, true);
public static final BooleanFlag MEDIA_MUTE_AWAIT = new BooleanFlag(904, true);
@@ -154,8 +155,9 @@ public class Flags {
new BooleanFlag(1000, true);
// 1100 - windowing
+ @Keep
public static final SysPropBooleanFlag WM_ENABLE_SHELL_TRANSITIONS =
- new SysPropBooleanFlag(1100, "persist.debug.shell_transit", false);
+ new SysPropBooleanFlag(1100, "persist.wm.debug.shell_transit", false);
// Pay no attention to the reflection behind the curtain.
// ========================== Curtain ==========================
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
index 7a278f786a67..af553c744311 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
@@ -624,7 +624,9 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene
addIfShouldShowAction(tempActions, new LogoutAction());
}
} else if (GLOBAL_ACTION_KEY_EMERGENCY.equals(actionKey)) {
- addIfShouldShowAction(tempActions, new EmergencyDialerAction());
+ if (shouldDisplayEmergency()) {
+ addIfShouldShowAction(tempActions, new EmergencyDialerAction());
+ }
} else {
Log.e(TAG, "Invalid global action key " + actionKey);
}
@@ -704,6 +706,12 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene
}
@VisibleForTesting
+ boolean shouldDisplayEmergency() {
+ // Emergency calling requires a telephony radio.
+ return mHasTelephony;
+ }
+
+ @VisibleForTesting
boolean shouldDisplayBugReport(UserInfo currentUser) {
return mGlobalSettings.getInt(Settings.Global.BUGREPORT_IN_POWER_MENU, 0) != 0
&& (currentUser == null || currentUser.isPrimary());
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index c01d2c316a93..acad30b4276f 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -20,6 +20,7 @@ import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT;
import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER;
import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.NAV_BAR_HANDLE_SHOW_OVER_LOCKSCREEN;
+import static com.android.internal.jank.InteractionJankMonitor.CUJ_LOCKSCREEN_TRANSITION_FROM_AOD;
import static com.android.internal.jank.InteractionJankMonitor.CUJ_LOCKSCREEN_UNLOCK_ANIMATION;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW;
@@ -123,11 +124,11 @@ import com.android.systemui.statusbar.NotificationShadeDepthController;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.phone.BiometricUnlockController;
+import com.android.systemui.statusbar.phone.CentralSurfaces;
import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.NotificationPanelViewController;
import com.android.systemui.statusbar.phone.ScreenOffAnimationController;
-import com.android.systemui.statusbar.phone.CentralSurfaces;
import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.UserSwitcherController;
@@ -1557,6 +1558,7 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable,
public void setOccluded(boolean isOccluded, boolean animate) {
Trace.beginSection("KeyguardViewMediator#setOccluded");
if (DEBUG) Log.d(TAG, "setOccluded " + isOccluded);
+ mInteractionJankMonitor.cancel(CUJ_LOCKSCREEN_TRANSITION_FROM_AOD);
mHandler.removeMessages(SET_OCCLUDED);
Message msg = mHandler.obtainMessage(SET_OCCLUDED, isOccluded ? 1 : 0, animate ? 1 : 0);
mHandler.sendMessage(msg);
@@ -1706,14 +1708,6 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable,
if (DEBUG) Log.d(TAG, "doKeyguard: not showing because lockscreen is off");
return;
}
-
- if (mLockPatternUtils.checkVoldPassword(KeyguardUpdateMonitor.getCurrentUser())) {
- if (DEBUG) Log.d(TAG, "Not showing lock screen since just decrypted");
- // Without this, settings is not enabled until the lock screen first appears
- setShowingLocked(false);
- hideLocked();
- return;
- }
}
if (DEBUG) Log.d(TAG, "doKeyguard: showing the lock screen");
@@ -2813,6 +2807,7 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable,
RemoteAnimationTarget[] apps, RemoteAnimationTarget[] wallpapers,
RemoteAnimationTarget[] nonApps, IRemoteAnimationFinishedCallback finishedCallback) {
Trace.beginSection("KeyguardViewMediator#startKeyguardExitAnimation");
+ mInteractionJankMonitor.cancel(CUJ_LOCKSCREEN_TRANSITION_FROM_AOD);
Message msg = mHandler.obtainMessage(START_KEYGUARD_EXIT_ANIM,
new StartKeyguardExitAnimParams(transit, startTime, fadeoutDuration, apps,
wallpapers, nonApps, finishedCallback));
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivity.java b/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivity.java
index b3371831454b..e6b650b20711 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivity.java
@@ -94,7 +94,7 @@ public class WorkLockActivity extends Activity {
// Blank out the activity. When it is on-screen it will look like a Recents thumbnail with
// redaction switched on.
final DevicePolicyManager dpm = getSystemService(DevicePolicyManager.class);
- String contentDescription = dpm.getString(
+ String contentDescription = dpm.getResources().getString(
WORK_LOCK_ACCESSIBILITY, () -> getString(R.string.accessibility_desc_work_lock));
final View blankView = new View(this);
blankView.setContentDescription(contentDescription);
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
index c69f947f5f3f..71dfa7433c32 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
@@ -16,10 +16,8 @@
package com.android.systemui.keyguard.dagger;
-import android.annotation.Nullable;
import android.app.trust.TrustManager;
import android.content.Context;
-import android.content.pm.PackageManager;
import android.os.PowerManager;
import com.android.internal.jank.InteractionJankMonitor;
@@ -44,18 +42,14 @@ import com.android.systemui.keyguard.DismissCallbackRegistry;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.navigationbar.NavigationModeController;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.NotificationShadeDepthController;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
-import com.android.systemui.statusbar.phone.CentralSurfaces;
import com.android.systemui.statusbar.phone.DozeParameters;
-import com.android.systemui.statusbar.phone.KeyguardLiftController;
import com.android.systemui.statusbar.phone.ScreenOffAnimationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.UserSwitcherController;
import com.android.systemui.util.DeviceConfigProxy;
-import com.android.systemui.util.sensors.AsyncSensorManager;
import java.util.concurrent.Executor;
@@ -133,20 +127,4 @@ public class KeyguardModule {
notificationShadeWindowController,
activityLaunchAnimator);
}
-
- @SysUISingleton
- @Provides
- @Nullable
- static KeyguardLiftController provideKeyguardLiftController(
- Context context,
- StatusBarStateController statusBarStateController,
- AsyncSensorManager asyncSensorManager,
- KeyguardUpdateMonitor keyguardUpdateMonitor,
- DumpManager dumpManager) {
- if (!context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FACE)) {
- return null;
- }
- return new KeyguardLiftController(statusBarStateController, asyncSensorManager,
- keyguardUpdateMonitor, dumpManager);
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
index 831a606e95b2..ffdd5376b12e 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
@@ -54,6 +54,7 @@ import com.android.settingslib.widget.AdaptiveIcon;
import com.android.systemui.R;
import com.android.systemui.animation.ActivityLaunchAnimator;
import com.android.systemui.animation.GhostedViewLaunchAnimatorController;
+import com.android.systemui.broadcast.BroadcastSender;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.media.dialog.MediaOutputDialogFactory;
import com.android.systemui.monet.ColorScheme;
@@ -104,10 +105,18 @@ public class MediaControlPanel {
R.id.action4
};
+ // Buttons to show in small player when using semantic actions
+ private static final List<Integer> SEMANTIC_ACTION_IDS = List.of(
+ R.id.actionPlayPause,
+ R.id.actionPrev,
+ R.id.actionNext
+ );
+
private final SeekBarViewModel mSeekBarViewModel;
private SeekBarObserver mSeekBarObserver;
protected final Executor mBackgroundExecutor;
private final ActivityStarter mActivityStarter;
+ private final BroadcastSender mBroadcastSender;
private Context mContext;
private MediaViewHolder mMediaViewHolder;
@@ -128,7 +137,6 @@ public class MediaControlPanel {
private MediaCarouselController mMediaCarouselController;
private final MediaOutputDialogFactory mMediaOutputDialogFactory;
private final FalsingManager mFalsingManager;
- private final MediaFlags mMediaFlags;
// Used for swipe-to-dismiss logging.
protected boolean mIsImpressed = false;
@@ -142,21 +150,22 @@ public class MediaControlPanel {
*/
@Inject
public MediaControlPanel(Context context, @Background Executor backgroundExecutor,
- ActivityStarter activityStarter, MediaViewController mediaViewController,
- SeekBarViewModel seekBarViewModel, Lazy<MediaDataManager> lazyMediaDataManager,
+ ActivityStarter activityStarter, BroadcastSender broadcastSender,
+ MediaViewController mediaViewController, SeekBarViewModel seekBarViewModel,
+ Lazy<MediaDataManager> lazyMediaDataManager,
MediaOutputDialogFactory mediaOutputDialogFactory,
MediaCarouselController mediaCarouselController,
- FalsingManager falsingManager, MediaFlags mediaFlags, SystemClock systemClock) {
+ FalsingManager falsingManager, SystemClock systemClock) {
mContext = context;
mBackgroundExecutor = backgroundExecutor;
mActivityStarter = activityStarter;
+ mBroadcastSender = broadcastSender;
mSeekBarViewModel = seekBarViewModel;
mMediaViewController = mediaViewController;
mMediaDataManagerLazy = lazyMediaDataManager;
mMediaOutputDialogFactory = mediaOutputDialogFactory;
mMediaCarouselController = mediaCarouselController;
mFalsingManager = falsingManager;
- mMediaFlags = mediaFlags;
mSystemClock = systemClock;
loadDimens();
@@ -495,17 +504,16 @@ public class MediaControlPanel {
List<MediaAction> actionIcons = data.getActions();
List<Integer> actionsWhenCollapsed = data.getActionsToShowInCompact();
- // If the session actions flag is enabled, but we're still using the regular layout, use
- // the session actions anyways
- if (mMediaFlags.areMediaSessionActionsEnabled() && data.getSemanticActions() != null) {
+ // If we got session actions, use those instead
+ if (data.getSemanticActions() != null) {
MediaButton semanticActions = data.getSemanticActions();
actionIcons = new ArrayList<MediaAction>();
- actionIcons.add(semanticActions.getStartCustom());
+ actionIcons.add(semanticActions.getCustom0());
actionIcons.add(semanticActions.getPrevOrCustom());
actionIcons.add(semanticActions.getPlayOrPause());
actionIcons.add(semanticActions.getNextOrCustom());
- actionIcons.add(semanticActions.getEndCustom());
+ actionIcons.add(semanticActions.getCustom1());
actionsWhenCollapsed = new ArrayList<Integer>();
actionsWhenCollapsed.add(1);
@@ -562,6 +570,9 @@ public class MediaControlPanel {
/** Bind elements specific to PlayerSessionViewHolder */
private void bindSessionPlayer(@NonNull MediaData data, String key) {
+ ConstraintSet expandedSet = mMediaViewController.getExpandedLayout();
+ ConstraintSet collapsedSet = mMediaViewController.getCollapsedLayout();
+
// Default colors
int surfaceColor = mBackgroundColor;
int accentPrimary = com.android.settingslib.Utils.getColorAttr(mContext,
@@ -575,25 +586,6 @@ public class MediaControlPanel {
int textTertiary = com.android.settingslib.Utils.getColorAttr(mContext,
com.android.internal.R.attr.textColorTertiary).getDefaultColor();
- // App icon - use launcher icon
- ImageView appIconView = mMediaViewHolder.getAppIcon();
- appIconView.clearColorFilter();
- try {
- Drawable icon = mContext.getPackageManager().getApplicationIcon(
- data.getPackageName());
- appIconView.setImageDrawable(icon);
- } catch (PackageManager.NameNotFoundException e) {
- Log.w(TAG, "Cannot find icon for package " + data.getPackageName(), e);
- // Fall back to notification icon
- if (data.getAppIcon() != null) {
- appIconView.setImageIcon(data.getAppIcon());
- } else {
- appIconView.setImageResource(R.drawable.ic_music_note);
- }
- int color = mContext.getColor(R.color.material_dynamic_secondary10);
- appIconView.setColorFilter(color);
- }
-
// Album art
ColorScheme colorScheme = null;
ImageView albumView = mMediaViewHolder.getAlbumView();
@@ -640,6 +632,25 @@ public class MediaControlPanel {
ColorStateList.valueOf(surfaceColor));
mMediaViewHolder.getPlayer().setBackgroundTintList(bgColorList);
+ // App icon - use notification icon
+ ImageView appIconView = mMediaViewHolder.getAppIcon();
+ appIconView.clearColorFilter();
+ if (data.getAppIcon() != null && !data.getResumption()) {
+ appIconView.setImageIcon(data.getAppIcon());
+ appIconView.setColorFilter(accentPrimary);
+ } else {
+ // Resume players use launcher icon
+ appIconView.setColorFilter(getGrayscaleFilter());
+ try {
+ Drawable icon = mContext.getPackageManager().getApplicationIcon(
+ data.getPackageName());
+ appIconView.setImageDrawable(icon);
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.w(TAG, "Cannot find icon for package " + data.getPackageName(), e);
+ appIconView.setImageResource(R.drawable.ic_music_note);
+ }
+ }
+
// Metadata text
mMediaViewHolder.getTitleText().setTextColor(textPrimary);
mMediaViewHolder.getArtistText().setTextColor(textSecondary);
@@ -660,26 +671,68 @@ public class MediaControlPanel {
// Media action buttons
MediaButton semanticActions = data.getSemanticActions();
+ PlayerSessionViewHolder sessionHolder = (PlayerSessionViewHolder) mMediaViewHolder;
+ ImageButton[] genericButtons = new ImageButton[]{
+ sessionHolder.getAction0(),
+ sessionHolder.getAction1(),
+ sessionHolder.getAction2(),
+ sessionHolder.getAction3(),
+ sessionHolder.getAction4()};
+
+ ImageButton[] semanticButtons = new ImageButton[]{
+ sessionHolder.getActionPlayPause(),
+ sessionHolder.getActionNext(),
+ sessionHolder.getActionPrev()};
+
if (semanticActions != null) {
- PlayerSessionViewHolder sessionHolder = (PlayerSessionViewHolder) mMediaViewHolder;
+ // Hide all the generic buttons
+ for (ImageButton b: genericButtons) {
+ setVisibleAndAlpha(collapsedSet, b.getId(), false);
+ setVisibleAndAlpha(expandedSet, b.getId(), false);
+ }
// Play/pause button has a background
sessionHolder.getActionPlayPause().setBackgroundTintList(accentColorList);
setSemanticButton(sessionHolder.getActionPlayPause(), semanticActions.getPlayOrPause(),
- ColorStateList.valueOf(textPrimaryInverse));
+ ColorStateList.valueOf(textPrimaryInverse), collapsedSet, expandedSet, true);
setSemanticButton(sessionHolder.getActionNext(), semanticActions.getNextOrCustom(),
- textColorList);
+ textColorList, collapsedSet, expandedSet, true);
setSemanticButton(sessionHolder.getActionPrev(), semanticActions.getPrevOrCustom(),
- textColorList);
- setSemanticButton(sessionHolder.getActionStart(), semanticActions.getStartCustom(),
- textColorList);
- setSemanticButton(sessionHolder.getActionEnd(), semanticActions.getEndCustom(),
- textColorList);
+ textColorList, collapsedSet, expandedSet, true);
+ setSemanticButton(sessionHolder.getAction0(), semanticActions.getCustom0(),
+ textColorList, collapsedSet, expandedSet, false);
+ setSemanticButton(sessionHolder.getAction1(), semanticActions.getCustom1(),
+ textColorList, collapsedSet, expandedSet, false);
} else {
- Log.w(TAG, "Using semantic player, but did not get buttons");
+ // Hide all the semantic buttons
+ for (int id : SEMANTIC_ACTION_IDS) {
+ setVisibleAndAlpha(collapsedSet, id, false);
+ setVisibleAndAlpha(expandedSet, id, false);
+ }
+
+ // Set all the generic buttons
+ List<Integer> actionsWhenCollapsed = data.getActionsToShowInCompact();
+ List<MediaAction> actions = data.getActions();
+ int i = 0;
+ for (; i < actions.size(); i++) {
+ boolean showInCompact = actionsWhenCollapsed.contains(i);
+ setSemanticButton(genericButtons[i], actions.get(i), textColorList, collapsedSet,
+ expandedSet, showInCompact);
+ }
+ for (; i < 5; i++) {
+ // Hide any unused buttons
+ setSemanticButton(genericButtons[i], null, textColorList, collapsedSet,
+ expandedSet, false);
+ }
}
+ // If disabled, set progress bar to INVISIBLE instead of GONE so layout weights still work
+ boolean seekbarEnabled = mSeekBarViewModel.getEnabled();
+ expandedSet.setVisibility(R.id.media_progress_bar,
+ seekbarEnabled ? ConstraintSet.VISIBLE : ConstraintSet.INVISIBLE);
+ expandedSet.setAlpha(R.id.media_progress_bar, seekbarEnabled ? 1.0f : 0.0f);
+
// Long press buttons
mMediaViewHolder.getLongPressText().setTextColor(textColorList);
mMediaViewHolder.getSettingsText().setTextColor(textColorList);
@@ -688,11 +741,11 @@ public class MediaControlPanel {
mMediaViewHolder.getCancelText().setBackgroundTintList(accentColorList);
mMediaViewHolder.getDismissText().setTextColor(textColorList);
mMediaViewHolder.getDismissText().setBackgroundTintList(accentColorList);
-
}
private void setSemanticButton(final ImageButton button, MediaAction mediaAction,
- ColorStateList fgColor) {
+ ColorStateList fgColor, ConstraintSet collapsedSet, ConstraintSet expandedSet,
+ boolean showInCompact) {
button.setImageTintList(fgColor);
if (mediaAction != null) {
button.setImageIcon(mediaAction.getIcon());
@@ -716,6 +769,9 @@ public class MediaControlPanel {
button.setContentDescription(null);
button.setEnabled(false);
}
+
+ setVisibleAndAlpha(collapsedSet, button.getId(), mediaAction != null && showInCompact);
+ setVisibleAndAlpha(expandedSet, button.getId(), mediaAction != null);
}
@Nullable
@@ -899,7 +955,7 @@ public class MediaControlPanel {
// Dismiss the card Smartspace data through Smartspace trampoline activity.
mContext.startActivity(dismissIntent);
} else {
- mContext.sendBroadcast(dismissIntent);
+ mBroadcastSender.sendBroadcast(dismissIntent);
}
});
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaData.kt b/packages/SystemUI/src/com/android/systemui/media/MediaData.kt
index 500e82efdb0a..4cf6291fe35b 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaData.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaData.kt
@@ -149,11 +149,11 @@ data class MediaButton(
/**
* First custom action space
*/
- var startCustom: MediaAction? = null,
+ var custom0: MediaAction? = null,
/**
- * Last custom action space
+ * Second custom action space
*/
- var endCustom: MediaAction? = null
+ var custom1: MediaAction? = null
)
/** State of a media action. */
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataFilter.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataFilter.kt
index ae5c1f2b19a9..de44a9c46963 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaDataFilter.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataFilter.kt
@@ -21,6 +21,7 @@ import android.os.SystemProperties
import android.util.Log
import com.android.internal.annotations.VisibleForTesting
import com.android.systemui.broadcast.BroadcastDispatcher
+import com.android.systemui.broadcast.BroadcastSender
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.settings.CurrentUserTracker
import com.android.systemui.statusbar.NotificationLockscreenUserManager
@@ -56,6 +57,7 @@ internal val SMARTSPACE_MAX_AGE = SystemProperties
class MediaDataFilter @Inject constructor(
private val context: Context,
private val broadcastDispatcher: BroadcastDispatcher,
+ private val broadcastSender: BroadcastSender,
private val lockscreenUserManager: NotificationLockscreenUserManager,
@Main private val executor: Executor,
private val systemClock: SystemClock
@@ -249,7 +251,7 @@ class MediaDataFilter @Inject constructor(
// Dismiss the card Smartspace data through Smartspace trampoline activity.
context.startActivity(dismissIntent)
} else {
- context.sendBroadcast(dismissIntent)
+ broadcastSender.sendBroadcast(dismissIntent)
}
smartspaceMediaData = EMPTY_SMARTSPACE_MEDIA_DATA.copy(
targetId = smartspaceMediaData.targetId, isValid = smartspaceMediaData.isValid)
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
index fab06c288ce1..56d8c6486631 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
@@ -610,7 +610,8 @@ class MediaDataManager(
var actionIcons: List<MediaAction> = emptyList()
var actionsToShowCollapsed: List<Int> = emptyList()
var semanticActions: MediaButton? = null
- if (mediaFlags.areMediaSessionActionsEnabled() && mediaController.playbackState != null) {
+ if (mediaFlags.areMediaSessionActionsEnabled(sbn.packageName, sbn.user) &&
+ mediaController.playbackState != null) {
semanticActions = createActionsFromState(sbn.packageName, mediaController)
} else {
val actions = createActionsFromNotification(sbn)
@@ -726,7 +727,7 @@ class MediaDataManager(
}
}
- // Finally, assign the remaining button slots: C A play/pause B D
+ // Finally, assign the remaining button slots: play/pause A B C D
// A = previous, else custom action (if not reserved)
// B = next, else custom action (if not reserved)
// C and D are always custom actions
@@ -752,8 +753,8 @@ class MediaDataManager(
null
}
- actions.startCustom = customActions[customIdx++]
- actions.endCustom = customActions[customIdx++]
+ actions.custom0 = customActions[customIdx++]
+ actions.custom1 = customActions[customIdx++]
}
return actions
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaFlags.kt b/packages/SystemUI/src/com/android/systemui/media/MediaFlags.kt
index dd35a9a81399..59237d936d72 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaFlags.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaFlags.kt
@@ -16,6 +16,8 @@
package com.android.systemui.media
+import android.app.StatusBarManager
+import android.os.UserHandle
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
@@ -26,16 +28,17 @@ class MediaFlags @Inject constructor(private val featureFlags: FeatureFlags) {
/**
* Check whether media control actions should be based on PlaybackState instead of notification
*/
- fun areMediaSessionActionsEnabled(): Boolean {
- return featureFlags.isEnabled(Flags.MEDIA_SESSION_ACTIONS)
+ fun areMediaSessionActionsEnabled(packageName: String, user: UserHandle): Boolean {
+ val enabled = StatusBarManager.useMediaSessionActionsForApp(packageName, user)
+ // Allow global override with flag
+ return enabled || featureFlags.isEnabled(Flags.MEDIA_SESSION_ACTIONS)
}
/**
* Check whether media controls should use the new session-based layout
*/
fun useMediaSessionLayout(): Boolean {
- return featureFlags.isEnabled(Flags.MEDIA_SESSION_ACTIONS) &&
- featureFlags.isEnabled(Flags.MEDIA_SESSION_LAYOUT)
+ return featureFlags.isEnabled(Flags.MEDIA_SESSION_LAYOUT)
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
index 18b6699c80e9..d472aeee1073 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
@@ -292,6 +292,18 @@ class MediaHierarchyManager @Inject constructor(
}
/**
+ * Returns the amount of translationY of the media container, during the current guided
+ * transformation, if running. If there is no guided transformation running, it will return 0.
+ */
+ fun getGuidedTransformationTranslationY(): Int {
+ if (!isCurrentlyInGuidedTransformation()) {
+ return -1
+ }
+ val startHost = getHost(previousLocation) ?: return 0
+ return targetBounds.top - startHost.currentBounds.top
+ }
+
+ /**
* Is the shade currently collapsing from the expanded qs? If we're on the lockscreen and in qs,
* we wouldn't want to transition in that case.
*/
@@ -800,7 +812,7 @@ class MediaHierarchyManager @Inject constructor(
@TransformationType
fun calculateTransformationType(): Int {
if (isTransitioningToFullShade) {
- if (inSplitShade) {
+ if (inSplitShade && areGuidedTransitionHostsVisible()) {
return TRANSFORMATION_TYPE_TRANSITION
}
return TRANSFORMATION_TYPE_FADE
@@ -817,6 +829,11 @@ class MediaHierarchyManager @Inject constructor(
return TRANSFORMATION_TYPE_TRANSITION
}
+ private fun areGuidedTransitionHostsVisible(): Boolean {
+ return getHost(previousLocation)?.visible == true &&
+ getHost(desiredLocation)?.visible == true
+ }
+
/**
* @return the current transformation progress if we're in a guided transformation and -1
* otherwise
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaHost.kt b/packages/SystemUI/src/com/android/systemui/media/MediaHost.kt
index 0a4b68b501f7..eb209f723cb5 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaHost.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaHost.kt
@@ -192,6 +192,14 @@ class MediaHost constructor(
}
}
+ override var squishFraction: Float = 1.0f
+ set(value) {
+ if (!value.equals(field)) {
+ field = value
+ changedListener?.invoke()
+ }
+ }
+
override var showsOnlyActiveMedia: Boolean = false
set(value) {
if (!value.equals(field)) {
@@ -242,6 +250,7 @@ class MediaHost constructor(
override fun copy(): MediaHostState {
val mediaHostState = MediaHostStateHolder()
mediaHostState.expansion = expansion
+ mediaHostState.squishFraction = squishFraction
mediaHostState.showsOnlyActiveMedia = showsOnlyActiveMedia
mediaHostState.measurementInput = measurementInput?.copy()
mediaHostState.visible = visible
@@ -260,6 +269,9 @@ class MediaHost constructor(
if (expansion != other.expansion) {
return false
}
+ if (squishFraction != other.squishFraction) {
+ return false
+ }
if (showsOnlyActiveMedia != other.showsOnlyActiveMedia) {
return false
}
@@ -278,6 +290,7 @@ class MediaHost constructor(
override fun hashCode(): Int {
var result = measurementInput?.hashCode() ?: 0
result = 31 * result + expansion.hashCode()
+ result = 31 * result + squishFraction.hashCode()
result = 31 * result + falsingProtectionNeeded.hashCode()
result = 31 * result + showsOnlyActiveMedia.hashCode()
result = 31 * result + if (visible) 1 else 2
@@ -318,6 +331,11 @@ interface MediaHostState {
var expansion: Float
/**
+ * Fraction of the height animation.
+ */
+ var squishFraction: Float
+
+ /**
* Is this host only showing active media or is it showing all of them including resumption?
*/
var showsOnlyActiveMedia: Boolean
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java
index 77873e829be3..38604091c409 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java
@@ -54,7 +54,7 @@ public class MediaProjectionPermissionActivity extends Activity
private int mUid;
private IMediaProjectionManager mService;
- private SystemUIDialog mDialog;
+ private AlertDialog mDialog;
@Override
public void onCreate(Bundle icicle) {
@@ -141,13 +141,18 @@ public class MediaProjectionPermissionActivity extends Activity
dialogTitle = getString(R.string.media_projection_dialog_title, appName);
}
- mDialog = new SystemUIDialog(this);
- mDialog.setTitle(dialogTitle);
- mDialog.setIcon(R.drawable.ic_media_projection_permission);
- mDialog.setMessage(dialogText);
- mDialog.setPositiveButton(R.string.media_projection_action_text, this);
- mDialog.setNeutralButton(android.R.string.cancel, this);
- mDialog.setOnCancelListener(this);
+ mDialog = new AlertDialog.Builder(this, R.style.Theme_SystemUI_Dialog)
+ .setTitle(dialogTitle)
+ .setIcon(R.drawable.ic_media_projection_permission)
+ .setMessage(dialogText)
+ .setPositiveButton(R.string.media_projection_action_text, this)
+ .setNeutralButton(android.R.string.cancel, this)
+ .setOnCancelListener(this)
+ .create();
+
+ SystemUIDialog.registerDismissListener(mDialog);
+ SystemUIDialog.applyFlags(mDialog);
+ SystemUIDialog.setDialogSize(mDialog);
mDialog.create();
mDialog.getButton(DialogInterface.BUTTON_POSITIVE).setFilterTouchesWhenObscured(true);
@@ -186,7 +191,7 @@ public class MediaProjectionPermissionActivity extends Activity
private Intent getMediaProjectionIntent(int uid, String packageName)
throws RemoteException {
IMediaProjection projection = mService.createProjection(uid, packageName,
- MediaProjectionManager.TYPE_SCREEN_CAPTURE, false /* permanentGrant */);
+ MediaProjectionManager.TYPE_SCREEN_CAPTURE, false /* permanentGrant */);
Intent intent = new Intent();
intent.putExtra(MediaProjectionManager.EXTRA_MEDIA_PROJECTION, projection.asBinder());
return intent;
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaViewController.kt b/packages/SystemUI/src/com/android/systemui/media/MediaViewController.kt
index 591aad1014bd..a60016b23a7c 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaViewController.kt
@@ -18,13 +18,11 @@ package com.android.systemui.media
import android.content.Context
import android.content.res.Configuration
+import androidx.annotation.VisibleForTesting
import androidx.constraintlayout.widget.ConstraintSet
import com.android.systemui.R
import com.android.systemui.statusbar.policy.ConfigurationController
-import com.android.systemui.util.animation.MeasurementOutput
-import com.android.systemui.util.animation.TransitionLayout
-import com.android.systemui.util.animation.TransitionLayoutController
-import com.android.systemui.util.animation.TransitionViewState
+import com.android.systemui.util.animation.*
import javax.inject.Inject
/**
@@ -270,7 +268,6 @@ class MediaViewController @Inject constructor(
TYPE.PLAYER_SESSION -> PlayerSessionViewHolder.gutsIds
TYPE.RECOMMENDATION -> RecommendationViewHolder.gutsIds
}
-
controlsIds.forEach { id ->
viewState.widgetStates.get(id)?.let { state ->
// Make sure to use the unmodified state if guts are not visible.
@@ -282,59 +279,79 @@ class MediaViewController @Inject constructor(
viewState.widgetStates.get(id)?.alpha = if (isGutsVisible) 1f else 0f
viewState.widgetStates.get(id)?.gone = !isGutsVisible
}
-
if (shouldHideGutsSettings) {
viewState.widgetStates.get(R.id.settings)?.gone = true
}
}
/**
+ * Apply squishFraction to a copy of viewState such that the cached version is untouched.
+ */
+ private fun squishViewState(viewState: TransitionViewState,
+ squishFraction: Float): TransitionViewState {
+ val squishedViewState = viewState.copy()
+ squishedViewState.height = (squishedViewState.height * squishFraction).toInt()
+ val albumArtViewState = viewState.widgetStates.get(R.id.album_art)
+ if (albumArtViewState != null) {
+ albumArtViewState.height = squishedViewState.height
+ }
+ return squishedViewState;
+ }
+
+ /**
* Obtain a new viewState for a given media state. This usually returns a cached state, but if
* it's not available, it will recreate one by measuring, which may be expensive.
*/
- private fun obtainViewState(state: MediaHostState?): TransitionViewState? {
+ @VisibleForTesting
+ public fun obtainViewState(state: MediaHostState?): TransitionViewState? {
if (state == null || state.measurementInput == null) {
return null
}
// Only a subset of the state is relevant to get a valid viewState. Let's get the cachekey
var cacheKey = getKey(state, isGutsVisible, tmpKey)
val viewState = viewStates[cacheKey]
+
if (viewState != null) {
// we already have cached this measurement, let's continue
+ if (state.squishFraction < 1f) {
+ return squishViewState(viewState, state.squishFraction);
+ }
return viewState
}
// Copy the key since this might call recursively into it and we're using tmpKey
cacheKey = cacheKey.copy()
val result: TransitionViewState?
- if (transitionLayout != null) {
- // Let's create a new measurement
- if (state.expansion == 0.0f || state.expansion == 1.0f) {
- result = transitionLayout!!.calculateViewState(
- state.measurementInput!!,
- constraintSetForExpansion(state.expansion),
- TransitionViewState())
-
- setGutsViewState(result)
- // We don't want to cache interpolated or null states as this could quickly fill up
- // our cache. We only cache the start and the end states since the interpolation
- // is cheap
- viewStates[cacheKey] = result
- } else {
- // This is an interpolated state
- val startState = state.copy().also { it.expansion = 0.0f }
-
- // Given that we have a measurement and a view, let's get (guaranteed) viewstates
- // from the start and end state and interpolate them
- val startViewState = obtainViewState(startState) as TransitionViewState
- val endState = state.copy().also { it.expansion = 1.0f }
- val endViewState = obtainViewState(endState) as TransitionViewState
- result = layoutController.getInterpolatedState(
- startViewState,
- endViewState,
- state.expansion)
- }
+ if (transitionLayout == null) {
+ return null
+ }
+ // Not cached. Let's create a new measurement
+ if (state.expansion == 0.0f || state.expansion == 1.0f) {
+ result = transitionLayout!!.calculateViewState(
+ state.measurementInput!!,
+ constraintSetForExpansion(state.expansion),
+ TransitionViewState())
+ // We don't want to cache interpolated or null states as this could quickly fill up
+ // our cache. We only cache the start and the end states since the interpolation
+ // is cheap
+ setGutsViewState(result)
+ viewStates[cacheKey] = result
} else {
- result = null
+ // This is an interpolated state
+ val startState = state.copy().also { it.expansion = 0.0f }
+
+ // Given that we have a measurement and a view, let's get (guaranteed) viewstates
+ // from the start and end state and interpolate them
+ val startViewState = obtainViewState(startState) as TransitionViewState
+ val endState = state.copy().also { it.expansion = 1.0f }
+
+ val endViewState = obtainViewState(endState) as TransitionViewState
+ result = layoutController.getInterpolatedState(
+ startViewState,
+ endViewState,
+ state.expansion)
+ }
+ if (state.squishFraction < 1f) {
+ return squishViewState(result, state.squishFraction);
}
return result
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaViewHolder.kt b/packages/SystemUI/src/com/android/systemui/media/MediaViewHolder.kt
index e57b247da055..5f606969153c 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaViewHolder.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaViewHolder.kt
@@ -60,12 +60,24 @@ abstract class MediaViewHolder constructor(itemView: View) {
val settings = itemView.requireViewById<View>(R.id.settings)
val settingsText = itemView.requireViewById<TextView>(R.id.settings_text)
+ // Action Buttons
+ val action0 = itemView.requireViewById<ImageButton>(R.id.action0)
+ val action1 = itemView.requireViewById<ImageButton>(R.id.action1)
+ val action2 = itemView.requireViewById<ImageButton>(R.id.action2)
+ val action3 = itemView.requireViewById<ImageButton>(R.id.action3)
+ val action4 = itemView.requireViewById<ImageButton>(R.id.action4)
+
init {
(player.background as IlluminationDrawable).let {
it.registerLightSource(seamless)
it.registerLightSource(cancel)
it.registerLightSource(dismiss)
it.registerLightSource(settings)
+ it.registerLightSource(action0)
+ it.registerLightSource(action1)
+ it.registerLightSource(action2)
+ it.registerLightSource(action3)
+ it.registerLightSource(action4)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/PlayerSessionViewHolder.kt b/packages/SystemUI/src/com/android/systemui/media/PlayerSessionViewHolder.kt
index 87d2cffea257..6928ebb8bb32 100644
--- a/packages/SystemUI/src/com/android/systemui/media/PlayerSessionViewHolder.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/PlayerSessionViewHolder.kt
@@ -31,16 +31,12 @@ class PlayerSessionViewHolder private constructor(itemView: View) : MediaViewHol
val actionPlayPause = itemView.requireViewById<ImageButton>(R.id.actionPlayPause)
val actionNext = itemView.requireViewById<ImageButton>(R.id.actionNext)
val actionPrev = itemView.requireViewById<ImageButton>(R.id.actionPrev)
- val actionStart = itemView.requireViewById<ImageButton>(R.id.actionStart)
- val actionEnd = itemView.requireViewById<ImageButton>(R.id.actionEnd)
init {
(player.background as IlluminationDrawable).let {
it.registerLightSource(actionPlayPause)
it.registerLightSource(actionNext)
it.registerLightSource(actionPrev)
- it.registerLightSource(actionStart)
- it.registerLightSource(actionEnd)
}
}
@@ -49,8 +45,11 @@ class PlayerSessionViewHolder private constructor(itemView: View) : MediaViewHol
R.id.actionPlayPause -> actionPlayPause
R.id.actionNext -> actionNext
R.id.actionPrev -> actionPrev
- R.id.actionStart -> actionStart
- R.id.actionEnd -> actionEnd
+ R.id.action0 -> action0
+ R.id.action1 -> action1
+ R.id.action2 -> action2
+ R.id.action3 -> action3
+ R.id.action4 -> action4
else -> {
throw IllegalArgumentException()
}
@@ -90,8 +89,11 @@ class PlayerSessionViewHolder private constructor(itemView: View) : MediaViewHol
R.id.actionPlayPause,
R.id.actionNext,
R.id.actionPrev,
- R.id.actionStart,
- R.id.actionEnd,
+ R.id.action0,
+ R.id.action1,
+ R.id.action2,
+ R.id.action3,
+ R.id.action4,
R.id.icon
)
val gutsIds = setOf(
diff --git a/packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt b/packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt
index 20b2d4a452f5..dd3fa89dea66 100644
--- a/packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt
@@ -33,23 +33,6 @@ class PlayerViewHolder private constructor(itemView: View) : MediaViewHolder(ite
override val elapsedTimeView = itemView.requireViewById<TextView>(R.id.media_elapsed_time)
override val totalTimeView = itemView.requireViewById<TextView>(R.id.media_total_time)
- // Action Buttons
- val action0 = itemView.requireViewById<ImageButton>(R.id.action0)
- val action1 = itemView.requireViewById<ImageButton>(R.id.action1)
- val action2 = itemView.requireViewById<ImageButton>(R.id.action2)
- val action3 = itemView.requireViewById<ImageButton>(R.id.action3)
- val action4 = itemView.requireViewById<ImageButton>(R.id.action4)
-
- init {
- (player.background as IlluminationDrawable).let {
- it.registerLightSource(action0)
- it.registerLightSource(action1)
- it.registerLightSource(action2)
- it.registerLightSource(action3)
- it.registerLightSource(action4)
- }
- }
-
override fun getAction(id: Int): ImageButton {
return when (id) {
R.id.action0 -> action0
diff --git a/packages/SystemUI/src/com/android/systemui/media/SeekBarObserver.kt b/packages/SystemUI/src/com/android/systemui/media/SeekBarObserver.kt
index cf997055c692..57701ab618c9 100644
--- a/packages/SystemUI/src/com/android/systemui/media/SeekBarObserver.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/SeekBarObserver.kt
@@ -50,25 +50,46 @@ class SeekBarObserver(
.getDimensionPixelSize(R.dimen.qs_media_disabled_seekbar_vertical_padding)
}
+ init {
+ val seekBarProgressWavelength = holder.seekBar.context.resources
+ .getDimensionPixelSize(R.dimen.qs_media_seekbar_progress_wavelength).toFloat()
+ val seekBarProgressAmplitude = holder.seekBar.context.resources
+ .getDimensionPixelSize(R.dimen.qs_media_seekbar_progress_amplitude).toFloat()
+ val seekBarProgressPhase = holder.seekBar.context.resources
+ .getDimensionPixelSize(R.dimen.qs_media_seekbar_progress_phase).toFloat()
+ val seekBarProgressStrokeWidth = holder.seekBar.context.resources
+ .getDimensionPixelSize(R.dimen.qs_media_seekbar_progress_stroke_width).toFloat()
+ val progressDrawable = holder.seekBar.progressDrawable as? SquigglyProgress
+ progressDrawable?.let {
+ it.waveLength = seekBarProgressWavelength
+ it.lineAmplitude = seekBarProgressAmplitude
+ it.phaseSpeed = seekBarProgressPhase
+ it.strokeWidth = seekBarProgressStrokeWidth
+ }
+ }
+
/** Updates seek bar views when the data model changes. */
@UiThread
override fun onChanged(data: SeekBarViewModel.Progress) {
+ val progressDrawable = holder.seekBar.progressDrawable as? SquigglyProgress
if (!data.enabled) {
if (holder.seekBar.maxHeight != seekBarDisabledHeight) {
holder.seekBar.maxHeight = seekBarDisabledHeight
setVerticalPadding(seekBarDisabledVerticalPadding)
}
- holder.seekBar.setEnabled(false)
- holder.seekBar.getThumb().setAlpha(0)
- holder.seekBar.setProgress(0)
- holder.elapsedTimeView?.setText("")
- holder.totalTimeView?.setText("")
+ holder.seekBar.isEnabled = false
+ progressDrawable?.animate = false
+ holder.seekBar.thumb.alpha = 0
+ holder.seekBar.progress = 0
+ holder.elapsedTimeView?.text = ""
+ holder.totalTimeView?.text = ""
holder.seekBar.contentDescription = ""
return
}
- holder.seekBar.getThumb().setAlpha(if (data.seekAvailable) 255 else 0)
- holder.seekBar.setEnabled(data.seekAvailable)
+ holder.seekBar.thumb.alpha = if (data.seekAvailable) 255 else 0
+ holder.seekBar.isEnabled = data.seekAvailable
+ progressDrawable?.animate = data.playing
if (holder.seekBar.maxHeight != seekBarEnabledMaxHeight) {
holder.seekBar.maxHeight = seekBarEnabledMaxHeight
diff --git a/packages/SystemUI/src/com/android/systemui/media/SeekBarViewModel.kt b/packages/SystemUI/src/com/android/systemui/media/SeekBarViewModel.kt
index 9cf9c4815b67..49cd16175f0a 100644
--- a/packages/SystemUI/src/com/android/systemui/media/SeekBarViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/SeekBarViewModel.kt
@@ -31,6 +31,7 @@ import androidx.core.view.GestureDetectorCompat
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.statusbar.NotificationMediaManager
import com.android.systemui.util.concurrency.RepeatableExecutor
import javax.inject.Inject
@@ -73,7 +74,7 @@ private fun PlaybackState.computePosition(duration: Long): Long {
class SeekBarViewModel @Inject constructor(
@Background private val bgExecutor: RepeatableExecutor
) {
- private var _data = Progress(false, false, null, 0)
+ private var _data = Progress(false, false, false, null, 0)
set(value) {
field = value
_progress.postValue(value)
@@ -131,6 +132,8 @@ class SeekBarViewModel @Inject constructor(
lateinit var logSmartspaceClick: () -> Unit
+ fun getEnabled() = _data.enabled
+
/**
* Event indicating that the user has started interacting with the seek bar.
*/
@@ -192,10 +195,12 @@ class SeekBarViewModel @Inject constructor(
val seekAvailable = ((playbackState?.actions ?: 0L) and PlaybackState.ACTION_SEEK_TO) != 0L
val position = playbackState?.position?.toInt()
val duration = mediaMetadata?.getLong(MediaMetadata.METADATA_KEY_DURATION)?.toInt() ?: 0
+ val playing = NotificationMediaManager
+ .isPlayingState(playbackState?.state ?: PlaybackState.STATE_NONE)
val enabled = if (playbackState == null ||
playbackState?.getState() == PlaybackState.STATE_NONE ||
(duration <= 0)) false else true
- _data = Progress(enabled, seekAvailable, position, duration)
+ _data = Progress(enabled, seekAvailable, playing, position, duration)
checkIfPollingNeeded()
}
@@ -412,6 +417,7 @@ class SeekBarViewModel @Inject constructor(
data class Progress(
val enabled: Boolean,
val seekAvailable: Boolean,
+ val playing: Boolean,
val elapsedTime: Int?,
val duration: Int
)
diff --git a/packages/SystemUI/src/com/android/systemui/media/SquigglyProgress.kt b/packages/SystemUI/src/com/android/systemui/media/SquigglyProgress.kt
new file mode 100644
index 000000000000..f1058e28863a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/SquigglyProgress.kt
@@ -0,0 +1,184 @@
+package com.android.systemui.media
+
+import android.animation.Animator
+import android.animation.AnimatorListenerAdapter
+import android.animation.ValueAnimator
+import android.content.res.ColorStateList
+import android.graphics.Canvas
+import android.graphics.Color
+import android.graphics.ColorFilter
+import android.graphics.Paint
+import android.graphics.Path
+import android.graphics.PixelFormat
+import android.graphics.drawable.Drawable
+import android.os.SystemClock
+import androidx.annotation.VisibleForTesting
+import com.android.systemui.animation.Interpolators
+import kotlin.math.abs
+import kotlin.math.cos
+
+private const val TAG = "Squiggly"
+
+private const val TWO_PI = (Math.PI * 2f).toFloat()
+@VisibleForTesting
+internal const val DISABLED_ALPHA = 77
+
+class SquigglyProgress : Drawable() {
+
+ private val wavePaint = Paint()
+ private val linePaint = Paint()
+ private val path = Path()
+ private var heightFraction = 0f
+ private var heightAnimator: ValueAnimator? = null
+ private var phaseOffset = 0f
+ private var lastFrameTime = -1L
+
+ // Horizontal length of the sine wave
+ var waveLength = 0f
+ // Height of each peak of the sine wave
+ var lineAmplitude = 0f
+ // Line speed in px per second
+ var phaseSpeed = 0f
+ // Progress stroke width, both for wave and solid line
+ var strokeWidth = 0f
+ set(value) {
+ if (field == value) {
+ return
+ }
+ field = value
+ wavePaint.strokeWidth = value
+ linePaint.strokeWidth = value
+ }
+
+ init {
+ wavePaint.strokeCap = Paint.Cap.ROUND
+ linePaint.strokeCap = Paint.Cap.ROUND
+ linePaint.style = Paint.Style.STROKE
+ wavePaint.style = Paint.Style.STROKE
+ linePaint.alpha = DISABLED_ALPHA
+ }
+
+ var animate: Boolean = false
+ set(value) {
+ if (field == value) {
+ return
+ }
+ field = value
+ if (field) {
+ lastFrameTime = SystemClock.uptimeMillis()
+ }
+ heightAnimator?.cancel()
+ heightAnimator = ValueAnimator.ofFloat(heightFraction, if (animate) 1f else 0f).apply {
+ if (animate) {
+ startDelay = 60
+ duration = 800
+ interpolator = Interpolators.EMPHASIZED_DECELERATE
+ } else {
+ duration = 550
+ interpolator = Interpolators.STANDARD_DECELERATE
+ }
+ addUpdateListener {
+ heightFraction = it.animatedValue as Float
+ invalidateSelf()
+ }
+ addListener(object : AnimatorListenerAdapter() {
+ override fun onAnimationEnd(animation: Animator?) {
+ heightAnimator = null
+ }
+ })
+ start()
+ }
+ }
+
+ override fun draw(canvas: Canvas) {
+ if (animate) {
+ invalidateSelf()
+ val now = SystemClock.uptimeMillis()
+ phaseOffset -= (now - lastFrameTime) / 1000f * phaseSpeed
+ phaseOffset %= waveLength
+ lastFrameTime = now
+ }
+
+ val totalProgressPx = (bounds.width() * (level / 10_000f))
+ canvas.save()
+ canvas.translate(bounds.left.toFloat(), bounds.centerY().toFloat())
+ // Clip drawing, so we stop at the thumb
+ canvas.clipRect(
+ 0f,
+ -lineAmplitude - strokeWidth,
+ totalProgressPx,
+ lineAmplitude + strokeWidth)
+
+ // The squiggly line
+ val start = phaseOffset
+ var currentX = start
+ var waveSign = 1f
+ path.rewind()
+ path.moveTo(start, lineAmplitude * heightFraction)
+ while (currentX < totalProgressPx) {
+ val nextX = currentX + waveLength / 2f
+ val nextWaveSign = waveSign * -1
+ path.cubicTo(
+ currentX + waveLength / 4f, lineAmplitude * waveSign * heightFraction,
+ nextX - waveLength / 4f, lineAmplitude * nextWaveSign * heightFraction,
+ nextX, lineAmplitude * nextWaveSign * heightFraction)
+ currentX = nextX
+ waveSign = nextWaveSign
+ }
+ wavePaint.style = Paint.Style.STROKE
+ canvas.drawPath(path, wavePaint)
+ canvas.restore()
+
+ // Draw round line cap at the beginning of the wave
+ val startAmp = cos(abs(phaseOffset) / waveLength * TWO_PI)
+ val p = Paint()
+ p.color = Color.WHITE
+ canvas.drawPoint(
+ bounds.left.toFloat(),
+ bounds.centerY() + startAmp * lineAmplitude * heightFraction,
+ wavePaint)
+
+ // Draw continuous line, to the right of the thumb
+ canvas.drawLine(
+ bounds.left.toFloat() + totalProgressPx,
+ bounds.centerY().toFloat(),
+ bounds.width().toFloat(),
+ bounds.centerY().toFloat(),
+ linePaint)
+ }
+
+ override fun getOpacity(): Int {
+ return PixelFormat.TRANSLUCENT
+ }
+
+ override fun setColorFilter(colorFilter: ColorFilter?) {
+ wavePaint.colorFilter = colorFilter
+ linePaint.colorFilter = colorFilter
+ }
+
+ override fun setAlpha(alpha: Int) {
+ wavePaint.alpha = alpha
+ linePaint.alpha = (DISABLED_ALPHA * (alpha / 255f)).toInt()
+ }
+
+ override fun getAlpha(): Int {
+ return wavePaint.alpha
+ }
+
+ override fun setTint(tintColor: Int) {
+ wavePaint.color = tintColor
+ linePaint.color = tintColor
+ }
+
+ override fun onLevelChange(level: Int): Boolean {
+ return animate
+ }
+
+ override fun setTintList(tint: ColorStateList?) {
+ if (tint == null) {
+ return
+ }
+ wavePaint.color = tint.defaultColor
+ linePaint.color = tint.defaultColor
+ }
+} \ 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 0b23ad50a726..a6464829623f 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
@@ -119,7 +119,9 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter {
mCheckBox.setVisibility(View.GONE);
mStatusIcon.setVisibility(View.GONE);
mContainerLayout.setOnClickListener(null);
- mTitleText.setTextColor(mController.getColorInactiveItem());
+ mTitleText.setTextColor(mController.getColorItemContent());
+ mSubTitleText.setTextColor(mController.getColorItemContent());
+ mTwoLineTitleText.setTextColor(mController.getColorItemContent());
mSeekBar.getProgressDrawable().setColorFilter(
new PorterDuffColorFilter(mController.getColorSeekbarProgress(),
PorterDuff.Mode.SRC_IN));
@@ -140,7 +142,7 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter {
&& !mController.hasAdjustVolumeUserRestriction()) {
mProgressBar.getIndeterminateDrawable().setColorFilter(
new PorterDuffColorFilter(
- mController.getColorInactiveItem(),
+ mController.getColorItemContent(),
PorterDuff.Mode.SRC_IN));
setSingleLineLayout(getItemTitle(device), true /* bFocused */,
false /* showSeekBar*/,
@@ -155,7 +157,7 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter {
mTitleIcon.setAlpha(DEVICE_CONNECTED_ALPHA);
mStatusIcon.setImageDrawable(
mContext.getDrawable(R.drawable.media_output_status_failed));
- mStatusIcon.setColorFilter(mController.getColorInactiveItem());
+ mStatusIcon.setColorFilter(mController.getColorItemContent());
setTwoLineLayout(device, false /* bFocused */,
false /* showSeekBar */, false /* showProgressBar */,
true /* showSubtitle */, true /* showStatus */);
@@ -163,7 +165,7 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter {
mContainerLayout.setOnClickListener(v -> onItemClick(v, device));
} else if (mController.getSelectedMediaDevice().size() > 1
&& isDeviceIncluded(mController.getSelectedMediaDevice(), device)) {
- mTitleText.setTextColor(mController.getColorActiveItem());
+ mTitleText.setTextColor(mController.getColorItemContent());
setSingleLineLayout(getItemTitle(device), true /* bFocused */,
true /* showSeekBar */,
false /* showProgressBar */, false /* showStatus */);
@@ -173,13 +175,13 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter {
mCheckBox.setOnCheckedChangeListener((buttonView, isChecked) -> {
onCheckBoxClicked(false, device);
});
- setCheckBoxColor(mCheckBox, mController.getColorActiveItem());
+ setCheckBoxColor(mCheckBox, mController.getColorItemContent());
initSeekbar(device);
} else if (!mController.hasAdjustVolumeUserRestriction() && currentlyConnected) {
mStatusIcon.setImageDrawable(
mContext.getDrawable(R.drawable.media_output_status_check));
- mStatusIcon.setColorFilter(mController.getColorActiveItem());
- mTitleText.setTextColor(mController.getColorActiveItem());
+ mStatusIcon.setColorFilter(mController.getColorItemContent());
+ mTitleText.setTextColor(mController.getColorItemContent());
setSingleLineLayout(getItemTitle(device), true /* bFocused */,
true /* showSeekBar */,
false /* showProgressBar */, true /* showStatus */);
@@ -192,7 +194,7 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter {
mCheckBox.setOnCheckedChangeListener((buttonView, isChecked) -> {
onCheckBoxClicked(true, device);
});
- setCheckBoxColor(mCheckBox, mController.getColorInactiveItem());
+ setCheckBoxColor(mCheckBox, mController.getColorItemContent());
setSingleLineLayout(getItemTitle(device), false /* bFocused */,
false /* showSeekBar */,
false /* showProgressBar */, false /* showStatus */);
@@ -214,7 +216,7 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter {
@Override
void onBind(int customizedItem, boolean topMargin, boolean bottomMargin) {
if (customizedItem == CUSTOMIZED_ITEM_PAIR_NEW) {
- mTitleText.setTextColor(mController.getColorInactiveItem());
+ mTitleText.setTextColor(mController.getColorItemContent());
mCheckBox.setVisibility(View.GONE);
setSingleLineLayout(mContext.getText(R.string.media_output_dialog_pairing_new),
false /* bFocused */);
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 c96aca37987b..df0c14b25c26 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
@@ -34,7 +34,6 @@ import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
-import android.widget.RelativeLayout;
import android.widget.SeekBar;
import android.widget.TextView;
@@ -129,7 +128,7 @@ public abstract class MediaOutputBaseAdapter extends
final ImageView mTitleIcon;
final ProgressBar mProgressBar;
final SeekBar mSeekBar;
- final RelativeLayout mTwoLineLayout;
+ final LinearLayout mTwoLineLayout;
final ImageView mStatusIcon;
final CheckBox mCheckBox;
private String mDeviceId;
@@ -171,14 +170,16 @@ public abstract class MediaOutputBaseAdapter extends
void setSingleLineLayout(CharSequence title, boolean bFocused, boolean showSeekBar,
boolean showProgressBar, boolean showStatus) {
mTwoLineLayout.setVisibility(View.GONE);
+ boolean isActive = showSeekBar || showProgressBar;
final Drawable backgroundDrawable =
- showSeekBar || showProgressBar
+ isActive
? mContext.getDrawable(R.drawable.media_output_item_background_active)
.mutate() : mContext.getDrawable(
R.drawable.media_output_item_background)
.mutate();
backgroundDrawable.setColorFilter(new PorterDuffColorFilter(
- mController.getColorItemBackground(),
+ isActive ? mController.getColorConnectedItemBackground()
+ : mController.getColorItemBackground(),
PorterDuff.Mode.SRC_IN));
mItemLayout.setBackground(backgroundDrawable);
mProgressBar.setVisibility(showProgressBar ? View.VISIBLE : View.GONE);
@@ -367,7 +368,7 @@ public abstract class MediaOutputBaseAdapter extends
.mutate();
drawable.setColorFilter(
new PorterDuffColorFilter(Utils.getColorStateListDefaultColor(mContext,
- R.color.media_dialog_active_item_main_content),
+ R.color.media_dialog_item_main_content),
PorterDuff.Mode.SRC_IN));
return drawable;
}
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 04a324b87382..dcb1c7c4637c 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
@@ -21,7 +21,6 @@ import static android.view.WindowInsets.Type.statusBars;
import android.app.WallpaperColors;
import android.content.Context;
-import android.content.Intent;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.Canvas;
@@ -55,6 +54,7 @@ import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.android.systemui.R;
+import com.android.systemui.broadcast.BroadcastSender;
import com.android.systemui.statusbar.phone.SystemUIDialog;
/**
@@ -71,6 +71,7 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements
final Context mContext;
final MediaOutputController mMediaOutputController;
+ final BroadcastSender mBroadcastSender;
@VisibleForTesting
View mDialogView;
@@ -98,11 +99,13 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements
}
};
- public MediaOutputBaseDialog(Context context, MediaOutputController mediaOutputController) {
+ public MediaOutputBaseDialog(Context context, BroadcastSender broadcastSender,
+ MediaOutputController mediaOutputController) {
super(context, R.style.Theme_SystemUI_Dialog_Media);
// Save the context that is wrapped with our theme.
mContext = getContext();
+ mBroadcastSender = broadcastSender;
mMediaOutputController = mediaOutputController;
mLayoutManager = new LinearLayoutManager(mContext);
mListMaxHeight = context.getResources().getDimensionPixelSize(
@@ -152,7 +155,7 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements
dismiss();
});
mAppButton.setOnClickListener(v -> {
- mContext.sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
+ mBroadcastSender.closeSystemDialogs();
if (mMediaOutputController.getAppLaunchIntent() != null) {
mContext.startActivity(mMediaOutputController.getAppLaunchIntent());
}
@@ -211,10 +214,9 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements
ColorFilter buttonColorFilter = new PorterDuffColorFilter(
mAdapter.getController().getColorButtonBackground(),
PorterDuff.Mode.SRC_IN);
- ColorFilter onlineButtonColorFilter = new PorterDuffColorFilter(
- mAdapter.getController().getColorInactiveItem(), PorterDuff.Mode.SRC_IN);
mDoneButton.getBackground().setColorFilter(buttonColorFilter);
- mStopButton.getBackground().setColorFilter(onlineButtonColorFilter);
+ mStopButton.getBackground().setColorFilter(buttonColorFilter);
+ mDoneButton.setTextColor(mAdapter.getController().getColorPositiveButtonText());
}
mHeaderIcon.setVisibility(View.VISIBLE);
mHeaderIcon.setImageIcon(icon);
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 f16ca7dd7361..ea7f7f2bb646 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
@@ -30,12 +30,16 @@ import android.graphics.PorterDuffColorFilter;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
+import android.media.INearbyMediaDevicesUpdateCallback;
import android.media.MediaMetadata;
import android.media.MediaRoute2Info;
+import android.media.NearbyDevice;
import android.media.RoutingSessionInfo;
import android.media.session.MediaController;
import android.media.session.MediaSessionManager;
import android.media.session.PlaybackState;
+import android.os.IBinder;
+import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
@@ -49,7 +53,6 @@ import androidx.core.graphics.drawable.IconCompat;
import androidx.mediarouter.media.MediaRouter;
import androidx.mediarouter.media.MediaRouterParams;
-import com.android.internal.logging.UiEventLogger;
import com.android.settingslib.RestrictedLockUtilsInternal;
import com.android.settingslib.Utils;
import com.android.settingslib.bluetooth.BluetoothUtils;
@@ -61,15 +64,18 @@ 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.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.ShadeController;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import javax.inject.Inject;
@@ -77,7 +83,8 @@ import javax.inject.Inject;
/**
* Controller for media output dialog
*/
-public class MediaOutputController implements LocalMediaManager.DeviceCallback {
+public class MediaOutputController implements LocalMediaManager.DeviceCallback,
+ INearbyMediaDevicesUpdateCallback {
private static final String TAG = "MediaOutputController";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
@@ -86,15 +93,14 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback {
private final String mPackageName;
private final Context mContext;
private final MediaSessionManager mMediaSessionManager;
- private final LocalBluetoothManager mLocalBluetoothManager;
- private final ShadeController mShadeController;
private final ActivityStarter mActivityStarter;
private final DialogLaunchAnimator mDialogLaunchAnimator;
private final List<MediaDevice> mGroupMediaDevices = new CopyOnWriteArrayList<>();
- private final boolean mAboveStatusbar;
private final CommonNotifCollection mNotifCollection;
@VisibleForTesting
final List<MediaDevice> mMediaDevices = new CopyOnWriteArrayList<>();
+ private final NearbyMediaDevicesManager mNearbyMediaDevicesManager;
+ private final Map<String, Integer> mNearbyDeviceInfoMap = new ConcurrentHashMap<>();
private MediaController mMediaController;
@VisibleForTesting
@@ -103,47 +109,51 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback {
LocalMediaManager mLocalMediaManager;
private MediaOutputMetricLogger mMetricLogger;
- private UiEventLogger mUiEventLogger;
- private int mColorActiveItem;
- private int mColorInactiveItem;
+ private int mColorItemContent;
private int mColorSeekbarProgress;
private int mColorButtonBackground;
private int mColorItemBackground;
+ private int mColorConnectedItemBackground;
+ private int mColorPositiveButtonText;
@Inject
public MediaOutputController(@NonNull Context context, String packageName,
- boolean aboveStatusbar, MediaSessionManager mediaSessionManager, LocalBluetoothManager
- lbm, ShadeController shadeController, ActivityStarter starter,
- CommonNotifCollection notifCollection, UiEventLogger uiEventLogger,
- DialogLaunchAnimator dialogLaunchAnimator) {
+ MediaSessionManager mediaSessionManager, LocalBluetoothManager
+ lbm, ActivityStarter starter,
+ CommonNotifCollection notifCollection,
+ DialogLaunchAnimator dialogLaunchAnimator,
+ Optional<NearbyMediaDevicesManager> nearbyMediaDevicesManagerOptional) {
mContext = context;
mPackageName = packageName;
mMediaSessionManager = mediaSessionManager;
- mLocalBluetoothManager = lbm;
- mShadeController = shadeController;
mActivityStarter = starter;
- mAboveStatusbar = aboveStatusbar;
mNotifCollection = notifCollection;
InfoMediaManager imm = new InfoMediaManager(mContext, packageName, null, lbm);
mLocalMediaManager = new LocalMediaManager(mContext, lbm, imm, packageName);
mMetricLogger = new MediaOutputMetricLogger(mContext, mPackageName);
- mUiEventLogger = uiEventLogger;
mDialogLaunchAnimator = dialogLaunchAnimator;
- mColorActiveItem = Utils.getColorStateListDefaultColor(mContext,
- R.color.media_dialog_active_item_main_content);
- mColorInactiveItem = Utils.getColorStateListDefaultColor(mContext,
- R.color.media_dialog_inactive_item_main_content);
+ mNearbyMediaDevicesManager = nearbyMediaDevicesManagerOptional.orElse(null);
+ mColorItemContent = Utils.getColorStateListDefaultColor(mContext,
+ R.color.media_dialog_item_main_content);
mColorSeekbarProgress = Utils.getColorStateListDefaultColor(mContext,
- android.R.color.system_accent1_200);
+ R.color.media_dialog_seekbar_progress);
mColorButtonBackground = Utils.getColorStateListDefaultColor(mContext,
- R.color.media_dialog_item_background);
+ R.color.media_dialog_button_background);
mColorItemBackground = Utils.getColorStateListDefaultColor(mContext,
- android.R.color.system_accent2_50);
+ R.color.media_dialog_item_background);
+ mColorConnectedItemBackground = Utils.getColorStateListDefaultColor(mContext,
+ R.color.media_dialog_connected_item_background);
+ mColorPositiveButtonText = Utils.getColorStateListDefaultColor(mContext,
+ R.color.media_dialog_solid_button_text);
}
void start(@NonNull Callback cb) {
mMediaDevices.clear();
+ mNearbyDeviceInfoMap.clear();
+ if (mNearbyMediaDevicesManager != null) {
+ mNearbyMediaDevicesManager.registerNearbyDevicesCallback(this);
+ }
if (!TextUtils.isEmpty(mPackageName)) {
for (MediaController controller : mMediaSessionManager.getActiveSessions(null)) {
if (TextUtils.equals(controller.getPackageName(), mPackageName)) {
@@ -187,6 +197,10 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback {
mLocalMediaManager.stopScan();
}
mMediaDevices.clear();
+ if (mNearbyMediaDevicesManager != null) {
+ mNearbyMediaDevicesManager.unregisterNearbyDevicesCallback(this);
+ }
+ mNearbyDeviceInfoMap.clear();
}
@Override
@@ -311,8 +325,7 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback {
}
void setColorFilter(Drawable drawable, boolean isActive) {
- drawable.setColorFilter(new PorterDuffColorFilter(isActive
- ? mColorActiveItem : mColorInactiveItem,
+ drawable.setColorFilter(new PorterDuffColorFilter(mColorItemContent,
PorterDuff.Mode.SRC_IN));
}
@@ -347,26 +360,32 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback {
ColorScheme mCurrentColorScheme = new ColorScheme(wallpaperColors,
isDarkTheme);
if (isDarkTheme) {
- mColorActiveItem = mCurrentColorScheme.getNeutral1().get(10);
- mColorInactiveItem = mCurrentColorScheme.getNeutral1().get(10);
- mColorSeekbarProgress = mCurrentColorScheme.getAccent1().get(2);
- mColorButtonBackground = mCurrentColorScheme.getAccent1().get(2);
- mColorItemBackground = mCurrentColorScheme.getAccent2().get(0);
+ mColorItemContent = mCurrentColorScheme.getAccent1().get(2); // A1-100
+ mColorSeekbarProgress = mCurrentColorScheme.getAccent2().get(7); // A2-600
+ mColorButtonBackground = mCurrentColorScheme.getAccent1().get(4); // A1-300
+ mColorItemBackground = mCurrentColorScheme.getNeutral2().get(9); // N2-800
+ mColorConnectedItemBackground = mCurrentColorScheme.getAccent2().get(9); // A2-800
+ mColorPositiveButtonText = mCurrentColorScheme.getAccent2().get(9); // A2-800
} else {
- mColorActiveItem = mCurrentColorScheme.getNeutral1().get(10);
- mColorInactiveItem = mCurrentColorScheme.getAccent1().get(7);
- mColorSeekbarProgress = mCurrentColorScheme.getAccent1().get(3);
- mColorButtonBackground = mCurrentColorScheme.getAccent1().get(3);
- mColorItemBackground = mCurrentColorScheme.getAccent2().get(0);
+ mColorItemContent = mCurrentColorScheme.getAccent1().get(9); // A1-800
+ mColorSeekbarProgress = mCurrentColorScheme.getAccent1().get(4); // A1-300
+ mColorButtonBackground = mCurrentColorScheme.getAccent1().get(7); // A1-600
+ mColorItemBackground = mCurrentColorScheme.getAccent2().get(1); // A2-50
+ mColorConnectedItemBackground = mCurrentColorScheme.getAccent1().get(2); // A1-100
+ mColorPositiveButtonText = mCurrentColorScheme.getNeutral1().get(1); // N1-50
}
}
- public int getColorActiveItem() {
- return mColorActiveItem;
+ public int getColorConnectedItemBackground() {
+ return mColorConnectedItemBackground;
+ }
+
+ public int getColorPositiveButtonText() {
+ return mColorPositiveButtonText;
}
- public int getColorInactiveItem() {
- return mColorInactiveItem;
+ public int getColorItemContent() {
+ return mColorItemContent;
}
public int getColorSeekbarProgress() {
@@ -417,6 +436,15 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback {
}
mMediaDevices.clear();
mMediaDevices.addAll(targetMediaDevices);
+ attachRangeInfo();
+ }
+
+ private void attachRangeInfo() {
+ for (MediaDevice mediaDevice : mMediaDevices) {
+ if (mNearbyDeviceInfoMap.containsKey(mediaDevice.getId())) {
+ mediaDevice.setRangeZone(mNearbyDeviceInfoMap.get(mediaDevice.getId()));
+ }
+ }
}
List<MediaDevice> getGroupMediaDevices() {
@@ -600,16 +628,6 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback {
mActivityStarter.startActivity(launchIntent, true, controller);
}
- void launchMediaOutputGroupDialog(View mediaOutputDialog) {
- // We show the output group dialog from the output dialog.
- MediaOutputController controller = new MediaOutputController(mContext, mPackageName,
- mAboveStatusbar, mMediaSessionManager, mLocalBluetoothManager, mShadeController,
- mActivityStarter, mNotifCollection, mUiEventLogger, mDialogLaunchAnimator);
- MediaOutputGroupDialog dialog = new MediaOutputGroupDialog(mContext, mAboveStatusbar,
- controller);
- mDialogLaunchAnimator.showFromView(dialog, mediaOutputDialog);
- }
-
boolean isActiveRemoteDevice(@NonNull MediaDevice device) {
final List<String> features = device.getFeatures();
return (features.contains(MediaRoute2Info.FEATURE_REMOTE_PLAYBACK)
@@ -629,6 +647,20 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback {
|| mLocalMediaManager.isMediaSessionAvailableForVolumeControl();
}
+ @Override
+ public void onDevicesUpdated(List<NearbyDevice> nearbyDevices) throws RemoteException {
+ mNearbyDeviceInfoMap.clear();
+ for (NearbyDevice nearbyDevice : nearbyDevices) {
+ mNearbyDeviceInfoMap.put(nearbyDevice.getMediaRoute2Id(), nearbyDevice.getRangeZone());
+ }
+ mNearbyMediaDevicesManager.unregisterNearbyDevicesCallback(this);
+ }
+
+ @Override
+ public IBinder asBinder() {
+ return null;
+ }
+
private final MediaController.Callback mCb = new MediaController.Callback() {
@Override
public void onMetadataChanged(MediaMetadata metadata) {
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 7696a1f63c01..7834ec0fa17f 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java
@@ -28,6 +28,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.UiEvent;
import com.android.internal.logging.UiEventLogger;
import com.android.systemui.R;
+import com.android.systemui.broadcast.BroadcastSender;
import com.android.systemui.dagger.SysUISingleton;
/**
@@ -37,9 +38,9 @@ import com.android.systemui.dagger.SysUISingleton;
public class MediaOutputDialog extends MediaOutputBaseDialog {
final UiEventLogger mUiEventLogger;
- MediaOutputDialog(Context context, boolean aboveStatusbar, MediaOutputController
- mediaOutputController, UiEventLogger uiEventLogger) {
- super(context, mediaOutputController);
+ MediaOutputDialog(Context context, boolean aboveStatusbar, BroadcastSender broadcastSender,
+ MediaOutputController mediaOutputController, UiEventLogger uiEventLogger) {
+ super(context, broadcastSender, mediaOutputController);
mUiEventLogger = uiEventLogger;
mAdapter = new MediaOutputAdapter(mMediaOutputController, this);
if (!aboveStatusbar) {
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogFactory.kt b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogFactory.kt
index 9e252ea1eddc..0d7d60ac5923 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogFactory.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogFactory.kt
@@ -22,9 +22,11 @@ import android.view.View
import com.android.internal.logging.UiEventLogger
import com.android.settingslib.bluetooth.LocalBluetoothManager
import com.android.systemui.animation.DialogLaunchAnimator
+import com.android.systemui.broadcast.BroadcastSender
+import com.android.systemui.media.nearby.NearbyMediaDevicesManager
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection
-import com.android.systemui.statusbar.phone.ShadeController
+import java.util.Optional
import javax.inject.Inject
/**
@@ -34,11 +36,12 @@ class MediaOutputDialogFactory @Inject constructor(
private val context: Context,
private val mediaSessionManager: MediaSessionManager,
private val lbm: LocalBluetoothManager?,
- private val shadeController: ShadeController,
private val starter: ActivityStarter,
+ private val broadcastSender: BroadcastSender,
private val notifCollection: CommonNotifCollection,
private val uiEventLogger: UiEventLogger,
- private val dialogLaunchAnimator: DialogLaunchAnimator
+ private val dialogLaunchAnimator: DialogLaunchAnimator,
+ private val nearbyMediaDevicesManagerOptional: Optional<NearbyMediaDevicesManager>
) {
companion object {
var mediaOutputDialog: MediaOutputDialog? = null
@@ -49,10 +52,11 @@ class MediaOutputDialogFactory @Inject constructor(
// Dismiss the previous dialog, if any.
mediaOutputDialog?.dismiss()
- val controller = MediaOutputController(context, packageName, aboveStatusBar,
- mediaSessionManager, lbm, shadeController, starter, notifCollection,
- uiEventLogger, dialogLaunchAnimator)
- val dialog = MediaOutputDialog(context, aboveStatusBar, controller, uiEventLogger)
+ val controller = MediaOutputController(context, packageName,
+ mediaSessionManager, lbm, starter, notifCollection,
+ dialogLaunchAnimator, nearbyMediaDevicesManagerOptional)
+ val dialog =
+ MediaOutputDialog(context, aboveStatusBar, broadcastSender, controller, uiEventLogger)
mediaOutputDialog = dialog
// Show the dialog.
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupDialog.java
index f1c66016a49a..bb3f969c86df 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupDialog.java
@@ -25,6 +25,7 @@ import android.view.WindowManager;
import androidx.core.graphics.drawable.IconCompat;
import com.android.systemui.R;
+import com.android.systemui.broadcast.BroadcastSender;
/**
* Dialog for media output group.
@@ -32,9 +33,9 @@ import com.android.systemui.R;
// TODO(b/203073091): Remove this class once group logic been implemented.
public class MediaOutputGroupDialog extends MediaOutputBaseDialog {
- MediaOutputGroupDialog(Context context, boolean aboveStatusbar, MediaOutputController
- mediaOutputController) {
- super(context, mediaOutputController);
+ MediaOutputGroupDialog(Context context, boolean aboveStatusbar, BroadcastSender broadcastSender,
+ MediaOutputController mediaOutputController) {
+ super(context, broadcastSender, mediaOutputController);
mMediaOutputController.resetGroupMediaDevices();
mAdapter = new MediaOutputGroupAdapter(mMediaOutputController);
if (!aboveStatusbar) {
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelper.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelper.kt
index 9dd8222ff6a1..e4b8874ff601 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelper.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelper.kt
@@ -16,6 +16,7 @@
package com.android.systemui.media.taptotransfer
+import android.annotation.SuppressLint
import android.app.StatusBarManager
import android.content.Context
import android.media.MediaRoute2Info
@@ -23,16 +24,12 @@ import android.util.Log
import androidx.annotation.VisibleForTesting
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main
-import com.android.systemui.media.taptotransfer.sender.AlmostCloseToEndCast
-import com.android.systemui.media.taptotransfer.sender.AlmostCloseToStartCast
-import com.android.systemui.media.taptotransfer.sender.TransferFailed
-import com.android.systemui.media.taptotransfer.sender.TransferToReceiverTriggered
-import com.android.systemui.media.taptotransfer.sender.TransferToThisDeviceSucceeded
-import com.android.systemui.media.taptotransfer.sender.TransferToThisDeviceTriggered
-import com.android.systemui.media.taptotransfer.sender.TransferToReceiverSucceeded
+import com.android.systemui.media.taptotransfer.receiver.ChipStateReceiver
+import com.android.systemui.media.taptotransfer.sender.ChipStateSender
import com.android.systemui.statusbar.commandline.Command
import com.android.systemui.statusbar.commandline.CommandRegistry
import java.io.PrintWriter
+import java.lang.IllegalArgumentException
import java.util.concurrent.Executor
import javax.inject.Inject
@@ -46,28 +43,6 @@ class MediaTttCommandLineHelper @Inject constructor(
private val context: Context,
@Main private val mainExecutor: Executor
) {
- /**
- * A map from a display state string typed in the command line to the display int it represents.
- */
- private val stateStringToStateInt: Map<String, Int> = mapOf(
- AlmostCloseToStartCast::class.simpleName!!
- to StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_START_CAST,
- AlmostCloseToEndCast::class.simpleName!!
- to StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_END_CAST,
- TransferToReceiverTriggered::class.simpleName!!
- to StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_TRIGGERED,
- TransferToThisDeviceTriggered::class.simpleName!!
- to StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_TRIGGERED,
- TransferToReceiverSucceeded::class.simpleName!!
- to StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_SUCCEEDED,
- TransferToThisDeviceSucceeded::class.simpleName!!
- to StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_SUCCEEDED,
- TransferFailed::class.simpleName!!
- to StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_FAILED,
- FAR_FROM_RECEIVER_STATE
- to StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_FAR_FROM_RECEIVER
- )
-
init {
commandRegistry.registerCommand(SENDER_COMMAND) { SenderCommand() }
commandRegistry.registerCommand(RECEIVER_COMMAND) { ReceiverCommand() }
@@ -76,21 +51,23 @@ class MediaTttCommandLineHelper @Inject constructor(
/** All commands for the sender device. */
inner class SenderCommand : Command {
override fun execute(pw: PrintWriter, args: List<String>) {
- val routeInfo = MediaRoute2Info.Builder("id", args[0])
- .addFeature("feature")
- .setPackageName(TEST_PACKAGE_NAME)
- .build()
-
val commandName = args[1]
@StatusBarManager.MediaTransferSenderState
- val displayState = stateStringToStateInt[commandName]
- if (displayState == null) {
+ val displayState: Int?
+ try {
+ displayState = ChipStateSender.getSenderStateIdFromName(commandName)
+ } catch (ex: IllegalArgumentException) {
pw.println("Invalid command name $commandName")
return
}
+ @SuppressLint("WrongConstant") // sysui allowed to call STATUS_BAR_SERVICE
val statusBarManager = context.getSystemService(Context.STATUS_BAR_SERVICE)
as StatusBarManager
+ val routeInfo = MediaRoute2Info.Builder("id", args[0])
+ .addFeature("feature")
+ .setPackageName(TEST_PACKAGE_NAME)
+ .build()
statusBarManager.updateMediaTapToTransferSenderDisplay(
displayState,
routeInfo,
@@ -136,35 +113,36 @@ class MediaTttCommandLineHelper @Inject constructor(
/** All commands for the receiver device. */
inner class ReceiverCommand : Command {
override fun execute(pw: PrintWriter, args: List<String>) {
+ val commandName = args[0]
+ @StatusBarManager.MediaTransferReceiverState
+ val displayState: Int?
+ try {
+ displayState = ChipStateReceiver.getReceiverStateIdFromName(commandName)
+ } catch (ex: IllegalArgumentException) {
+ pw.println("Invalid command name $commandName")
+ return
+ }
+
+ @SuppressLint("WrongConstant") // sysui is allowed to call STATUS_BAR_SERVICE
val statusBarManager = context.getSystemService(Context.STATUS_BAR_SERVICE)
as StatusBarManager
val routeInfo = MediaRoute2Info.Builder("id", "Test Name")
.addFeature("feature")
- .setPackageName(TEST_PACKAGE_NAME)
- .build()
-
- when(val commandName = args[0]) {
- CLOSE_TO_SENDER_STATE ->
- statusBarManager.updateMediaTapToTransferReceiverDisplay(
- StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_CLOSE_TO_SENDER,
- routeInfo,
- null,
- null
- )
- FAR_FROM_SENDER_STATE ->
- statusBarManager.updateMediaTapToTransferReceiverDisplay(
- StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_FAR_FROM_SENDER,
- routeInfo,
- null,
- null
- )
- else ->
- pw.println("Invalid command name $commandName")
+ if (args.size >= 2 && args[1] == "useAppIcon=true") {
+ routeInfo.setPackageName(TEST_PACKAGE_NAME)
}
+
+ statusBarManager.updateMediaTapToTransferReceiverDisplay(
+ displayState,
+ routeInfo.build(),
+ null,
+ null
+ )
}
override fun help(pw: PrintWriter) {
- pw.println("Usage: adb shell cmd statusbar $RECEIVER_COMMAND <chipState>")
+ pw.println("Usage: adb shell cmd statusbar $RECEIVER_COMMAND " +
+ "<chipState> useAppIcon=[true|false]")
}
}
}
@@ -173,11 +151,5 @@ class MediaTttCommandLineHelper @Inject constructor(
const val SENDER_COMMAND = "media-ttt-chip-sender"
@VisibleForTesting
const val RECEIVER_COMMAND = "media-ttt-chip-receiver"
-@VisibleForTesting
-const val FAR_FROM_RECEIVER_STATE = "FarFromReceiver"
-@VisibleForTesting
-const val CLOSE_TO_SENDER_STATE = "CloseToSender"
-@VisibleForTesting
-const val FAR_FROM_SENDER_STATE = "FarFromSender"
private const val CLI_TAG = "MediaTransferCli"
private const val TEST_PACKAGE_NAME = "com.android.systemui"
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/ChipInfoCommon.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/ChipInfoCommon.kt
new file mode 100644
index 000000000000..3cc99a8ef77e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/ChipInfoCommon.kt
@@ -0,0 +1,30 @@
+/*
+ * 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.systemui.media.taptotransfer.common
+
+/**
+ * A superclass chip state that will be subclassed by the sender chip and receiver chip.
+ */
+interface ChipInfoCommon {
+ /**
+ * Returns the amount of time the given chip state should display on the screen before it times
+ * out and disappears.
+ */
+ fun getTimeoutMs(): Long
+}
+
+const val DEFAULT_TIMEOUT_MILLIS = 3000L
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt
index 9c4b39d9cb77..54b0c1345601 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt
@@ -19,15 +19,21 @@ package com.android.systemui.media.taptotransfer.common
import android.annotation.LayoutRes
import android.annotation.SuppressLint
import android.content.Context
+import android.content.pm.PackageManager
import android.graphics.PixelFormat
+import android.graphics.drawable.Drawable
+import android.os.PowerManager
+import android.os.SystemClock
+import android.util.Log
import android.view.Gravity
import android.view.LayoutInflater
import android.view.MotionEvent
import android.view.View
import android.view.ViewGroup
import android.view.WindowManager
-import androidx.annotation.VisibleForTesting
+import android.widget.LinearLayout
import com.android.internal.widget.CachingIconView
+import com.android.settingslib.Utils
import com.android.systemui.R
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.statusbar.gesture.TapGestureDetector
@@ -40,14 +46,18 @@ import com.android.systemui.util.view.ViewUtil
*
* Subclasses need to override and implement [updateChipView], which is where they can control what
* gets displayed to the user.
+ *
+ * The generic type T is expected to contain all the information necessary for the subclasses to
+ * display the chip in a certain state, since they receive <T> in [updateChipView].
*/
-abstract class MediaTttChipControllerCommon<T : MediaTttChipState>(
+abstract class MediaTttChipControllerCommon<T : ChipInfoCommon>(
internal val context: Context,
internal val logger: MediaTttLogger,
private val windowManager: WindowManager,
private val viewUtil: ViewUtil,
@Main private val mainExecutor: DelayableExecutor,
private val tapGestureDetector: TapGestureDetector,
+ private val powerManager: PowerManager,
@LayoutRes private val chipLayoutRes: Int
) {
/** The window layout parameters we'll use when attaching the view to a window. */
@@ -64,10 +74,10 @@ abstract class MediaTttChipControllerCommon<T : MediaTttChipState>(
}
/** The chip view currently being displayed. Null if the chip is not being displayed. */
- var chipView: ViewGroup? = null
+ private var chipView: ViewGroup? = null
/** A [Runnable] that, when run, will cancel the pending timeout of the chip. */
- var cancelChipViewTimeout: Runnable? = null
+ private var cancelChipViewTimeout: Runnable? = null
/**
* Displays the chip with the current state.
@@ -75,7 +85,7 @@ abstract class MediaTttChipControllerCommon<T : MediaTttChipState>(
* This method handles inflating and attaching the view, then delegates to [updateChipView] to
* display the correct information in the chip.
*/
- fun displayChip(chipState: T) {
+ fun displayChip(chipInfo: T) {
val oldChipView = chipView
if (chipView == null) {
chipView = LayoutInflater
@@ -84,19 +94,25 @@ abstract class MediaTttChipControllerCommon<T : MediaTttChipState>(
}
val currentChipView = chipView!!
- updateChipView(chipState, currentChipView)
+ updateChipView(chipInfo, currentChipView)
// Add view if necessary
if (oldChipView == null) {
tapGestureDetector.addOnGestureDetectedCallback(TAG, this::onScreenTapped)
windowManager.addView(chipView, windowLayoutParams)
+ // Wake the screen so the user will see the chip
+ powerManager.wakeUp(
+ SystemClock.uptimeMillis(),
+ PowerManager.WAKE_REASON_APPLICATION,
+ "com.android.systemui:media_tap_to_transfer_activated"
+ )
}
// Cancel and re-set the chip timeout each time we get a new state.
cancelChipViewTimeout?.run()
cancelChipViewTimeout = mainExecutor.executeDelayed(
{ removeChip(MediaTttRemovalReason.REASON_TIMEOUT) },
- chipState.getTimeoutMs()
+ chipInfo.getTimeoutMs()
)
}
@@ -117,27 +133,72 @@ abstract class MediaTttChipControllerCommon<T : MediaTttChipState>(
}
/**
- * A method implemented by subclasses to update [currentChipView] based on [chipState].
+ * A method implemented by subclasses to update [currentChipView] based on [chipInfo].
+ */
+ abstract fun updateChipView(chipInfo: T, currentChipView: ViewGroup)
+
+ /**
+ * Returns the size that the icon should be, or null if no size override is needed.
*/
- abstract fun updateChipView(chipState: T, currentChipView: ViewGroup)
+ open fun getIconSize(isAppIcon: Boolean): Int? = null
/**
* An internal method to set the icon on the view.
*
* This is in the common superclass since both the sender and the receiver show an icon.
+ *
+ * @param appPackageName the package name of the app playing the media. Will be used to fetch
+ * the app icon and app name if overrides aren't provided.
*/
- internal fun setIcon(chipState: T, currentChipView: ViewGroup) {
+ internal fun setIcon(
+ currentChipView: ViewGroup,
+ appPackageName: String?,
+ appIconDrawableOverride: Drawable? = null,
+ appNameOverride: CharSequence? = null,
+ ) {
val appIconView = currentChipView.requireViewById<CachingIconView>(R.id.app_icon)
- appIconView.contentDescription = chipState.getAppName(context)
+ val iconInfo = getIconInfo(appPackageName)
- val appIcon = chipState.getAppIcon(context)
- val visibility = if (appIcon != null) {
- View.VISIBLE
- } else {
- View.GONE
+ getIconSize(iconInfo.isAppIcon)?.let { size ->
+ val lp = appIconView.layoutParams
+ lp.width = size
+ lp.height = size
+ appIconView.layoutParams = lp
}
- appIconView.setImageDrawable(appIcon)
- appIconView.visibility = visibility
+
+ appIconView.contentDescription = appNameOverride ?: iconInfo.iconName
+ appIconView.setImageDrawable(appIconDrawableOverride ?: iconInfo.icon)
+ }
+
+ /**
+ * Returns the information needed to display the icon.
+ *
+ * The information will either contain app name and icon of the app playing media, or a default
+ * name and icon if we can't find the app name/icon.
+ */
+ private fun getIconInfo(appPackageName: String?): IconInfo {
+ if (appPackageName != null) {
+ try {
+ return IconInfo(
+ iconName = context.packageManager.getApplicationInfo(
+ appPackageName, PackageManager.ApplicationInfoFlags.of(0)
+ ).loadLabel(context.packageManager).toString(),
+ icon = context.packageManager.getApplicationIcon(appPackageName),
+ isAppIcon = true
+ )
+ } catch (e: PackageManager.NameNotFoundException) {
+ Log.w(TAG, "Cannot find package $appPackageName", e)
+ }
+ }
+ return IconInfo(
+ iconName = context.getString(R.string.media_output_dialog_unknown_launch_app_name),
+ icon = context.resources.getDrawable(R.drawable.ic_cast).apply {
+ this.setTint(
+ Utils.getColorAttrDefaultColor(context, android.R.attr.textColorPrimary)
+ )
+ },
+ isAppIcon = false
+ )
}
private fun onScreenTapped(e: MotionEvent) {
@@ -160,3 +221,9 @@ object MediaTttRemovalReason {
const val REASON_SCREEN_TAP = "SCREEN_TAP"
}
+private data class IconInfo(
+ val iconName: String,
+ val icon: Drawable,
+ /** True if [icon] is the app's icon, and false if [icon] is some generic default icon. */
+ val isAppIcon: Boolean
+)
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipState.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipState.kt
deleted file mode 100644
index 6f6018170f98..000000000000
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipState.kt
+++ /dev/null
@@ -1,65 +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.systemui.media.taptotransfer.common
-
-import android.content.Context
-import android.content.pm.PackageManager
-import android.graphics.drawable.Drawable
-import android.util.Log
-
-/**
- * A superclass chip state that will be subclassed by the sender chip and receiver chip.
- *
- * @property appPackageName the package name of the app playing the media. Will be used to fetch the
- * app icon and app name.
- */
-open class MediaTttChipState(
- internal val appPackageName: String?,
-) {
- open fun getAppIcon(context: Context): Drawable? {
- appPackageName ?: return null
- return try {
- context.packageManager.getApplicationIcon(appPackageName)
- } catch (e: PackageManager.NameNotFoundException) {
- Log.w(TAG, "Cannot find icon for package $appPackageName", e)
- null
- }
- }
-
- /** Returns the name of the app playing the media or null if we can't find it. */
- open fun getAppName(context: Context): String? {
- appPackageName ?: return null
- return try {
- context.packageManager.getApplicationInfo(
- appPackageName, PackageManager.ApplicationInfoFlags.of(0)
- ).loadLabel(context.packageManager).toString()
- } catch (e: PackageManager.NameNotFoundException) {
- Log.w(TAG, "Cannot find name for package $appPackageName", e)
- null
- }
- }
-
- /**
- * Returns the amount of time this chip should display on the screen before it times out and
- * disappears. [MediaTttChipControllerCommon] will ensure that the timeout resets each time we
- * receive a new state.
- */
- open fun getTimeoutMs(): Long = DEFAULT_TIMEOUT_MILLIS
-}
-
-private const val DEFAULT_TIMEOUT_MILLIS = 3000L
-private val TAG = MediaTttChipState::class.simpleName!!
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/ChipStateReceiver.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/ChipStateReceiver.kt
index 6a4b62a8c1ae..a0e803f6bb8d 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/ChipStateReceiver.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/ChipStateReceiver.kt
@@ -16,35 +16,43 @@
package com.android.systemui.media.taptotransfer.receiver
-import android.content.Context
-import android.graphics.drawable.Drawable
-import com.android.systemui.media.taptotransfer.common.MediaTttChipState
+import android.app.StatusBarManager
+import com.android.internal.logging.UiEventLogger
/**
* A class that stores all the information necessary to display the media tap-to-transfer chip on
* the receiver device.
- *
- * @property appIconDrawable a drawable representing the icon of the app playing the media. If
- * present, this will be used in [this.getAppIcon] instead of [appPackageName].
- * @property appName a name for the app playing the media. If present, this will be used in
- * [this.getAppName] instead of [appPackageName].
*/
-class ChipStateReceiver(
- appPackageName: String?,
- private val appIconDrawable: Drawable?,
- private val appName: CharSequence?
-) : MediaTttChipState(appPackageName) {
- override fun getAppIcon(context: Context): Drawable? {
- if (appIconDrawable != null) {
- return appIconDrawable
- }
- return super.getAppIcon(context)
- }
+enum class ChipStateReceiver(
+ @StatusBarManager.MediaTransferSenderState val stateInt: Int,
+ val uiEvent: UiEventLogger.UiEventEnum,
+) {
+ CLOSE_TO_SENDER(
+ StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_CLOSE_TO_SENDER,
+ MediaTttReceiverUiEvents.MEDIA_TTT_RECEIVER_CLOSE_TO_SENDER,
+ ),
+ FAR_FROM_SENDER(
+ StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_FAR_FROM_SENDER,
+ MediaTttReceiverUiEvents.MEDIA_TTT_RECEIVER_FAR_FROM_SENDER,
+ );
+
+ companion object {
+ /**
+ * Returns the receiver state enum associated with the given [displayState] from
+ * [StatusBarManager].
+ */
+ fun getReceiverStateFromId(
+ @StatusBarManager.MediaTransferReceiverState displayState: Int
+ ) : ChipStateReceiver = values().first { it.stateInt == displayState }
+
- override fun getAppName(context: Context): String? {
- if (appName != null) {
- return appName.toString()
- }
- return super.getAppName(context)
+ /**
+ * Returns the state int from [StatusBarManager] associated with the given sender state
+ * name.
+ *
+ * @param name the name of one of the [ChipStateReceiver] enums.
+ */
+ @StatusBarManager.MediaTransferReceiverState
+ fun getReceiverStateIdFromName(name: String): Int = valueOf(name).stateInt
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt
index 1a96ddf69b28..072263fcf38c 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt
@@ -18,15 +18,19 @@ package com.android.systemui.media.taptotransfer.receiver
import android.app.StatusBarManager
import android.content.Context
+import android.graphics.drawable.Drawable
import android.graphics.drawable.Icon
import android.media.MediaRoute2Info
import android.os.Handler
+import android.os.PowerManager
import android.util.Log
import android.view.ViewGroup
import android.view.WindowManager
import com.android.systemui.R
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.media.taptotransfer.common.ChipInfoCommon
+import com.android.systemui.media.taptotransfer.common.DEFAULT_TIMEOUT_MILLIS
import com.android.systemui.media.taptotransfer.common.MediaTttChipControllerCommon
import com.android.systemui.media.taptotransfer.common.MediaTttLogger
import com.android.systemui.statusbar.CommandQueue
@@ -49,14 +53,17 @@ class MediaTttChipControllerReceiver @Inject constructor(
viewUtil: ViewUtil,
mainExecutor: DelayableExecutor,
tapGestureDetector: TapGestureDetector,
+ powerManager: PowerManager,
@Main private val mainHandler: Handler,
-) : MediaTttChipControllerCommon<ChipStateReceiver>(
+ private val uiEventLogger: MediaTttReceiverUiEventLogger,
+) : MediaTttChipControllerCommon<ChipReceiverInfo>(
context,
logger,
windowManager,
viewUtil,
mainExecutor,
tapGestureDetector,
+ powerManager,
R.layout.media_ttt_chip_receiver
) {
private val commandQueueCallbacks = object : CommandQueue.Callbacks {
@@ -82,45 +89,61 @@ class MediaTttChipControllerReceiver @Inject constructor(
appIcon: Icon?,
appName: CharSequence?
) {
- logger.logStateChange(stateIntToString(displayState), routeInfo.id)
- when(displayState) {
- StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_CLOSE_TO_SENDER -> {
- val packageName = routeInfo.packageName
- if (appIcon == null) {
- displayChip(ChipStateReceiver(packageName, null, appName))
- } else {
- appIcon.loadDrawableAsync(
- context,
- Icon.OnDrawableLoadedListener { drawable ->
- displayChip(
- ChipStateReceiver(packageName, drawable, appName)
- )},
- // Notify the listener on the main handler since the listener will update
- // the UI.
- mainHandler
- )
- }
- }
- StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_FAR_FROM_SENDER ->
- removeChip(removalReason = FAR_FROM_SENDER)
- else ->
- Log.e(RECEIVER_TAG, "Unhandled MediaTransferReceiverState $displayState")
+ val chipState: ChipStateReceiver? = ChipStateReceiver.getReceiverStateFromId(displayState)
+ val stateName = chipState?.name ?: "Invalid"
+ logger.logStateChange(stateName, routeInfo.id)
+
+ if (chipState == null) {
+ Log.e(RECEIVER_TAG, "Unhandled MediaTransferReceiverState $displayState")
+ return
+ }
+ uiEventLogger.logReceiverStateChange(chipState)
+
+ if (chipState == ChipStateReceiver.FAR_FROM_SENDER) {
+ removeChip(removalReason = ChipStateReceiver.FAR_FROM_SENDER::class.simpleName!!)
+ return
+ }
+ if (appIcon == null) {
+ displayChip(ChipReceiverInfo(routeInfo, appIconDrawableOverride = null, appName))
+ return
}
- }
- override fun updateChipView(chipState: ChipStateReceiver, currentChipView: ViewGroup) {
- setIcon(chipState, currentChipView)
+ appIcon.loadDrawableAsync(
+ context,
+ Icon.OnDrawableLoadedListener { drawable ->
+ displayChip(ChipReceiverInfo(routeInfo, drawable, appName))
+ },
+ // Notify the listener on the main handler since the listener will update
+ // the UI.
+ mainHandler
+ )
}
- private fun stateIntToString(@StatusBarManager.MediaTransferReceiverState state: Int): String {
- return when (state) {
- StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_CLOSE_TO_SENDER -> CLOSE_TO_SENDER
- StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_FAR_FROM_SENDER -> FAR_FROM_SENDER
- else -> "INVALID: $state"
- }
+ override fun updateChipView(chipInfo: ChipReceiverInfo, currentChipView: ViewGroup) {
+ setIcon(
+ currentChipView,
+ chipInfo.routeInfo.packageName,
+ chipInfo.appIconDrawableOverride,
+ chipInfo.appNameOverride
+ )
}
+
+ override fun getIconSize(isAppIcon: Boolean): Int? =
+ context.resources.getDimensionPixelSize(
+ if (isAppIcon) {
+ R.dimen.media_ttt_icon_size_receiver
+ } else {
+ R.dimen.media_ttt_generic_icon_size_receiver
+ }
+ )
+}
+
+data class ChipReceiverInfo(
+ val routeInfo: MediaRoute2Info,
+ val appIconDrawableOverride: Drawable?,
+ val appNameOverride: CharSequence?
+) : ChipInfoCommon {
+ override fun getTimeoutMs() = DEFAULT_TIMEOUT_MILLIS
}
private const val RECEIVER_TAG = "MediaTapToTransferRcvr"
-private const val CLOSE_TO_SENDER = "CLOSE_TO_SENDER"
-private const val FAR_FROM_SENDER = "FAR_FROM_SENDER"
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttReceiverUiEventLogger.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttReceiverUiEventLogger.kt
new file mode 100644
index 000000000000..39a276329a9b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttReceiverUiEventLogger.kt
@@ -0,0 +1,40 @@
+/*
+ * 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.taptotransfer.receiver
+
+import com.android.internal.logging.UiEvent
+import com.android.internal.logging.UiEventLogger
+import com.android.systemui.dagger.SysUISingleton
+import javax.inject.Inject
+
+/** A class for analytics logging for the media tap-to-transfer chip on the receiver device. */
+@SysUISingleton
+class MediaTttReceiverUiEventLogger @Inject constructor(private val logger: UiEventLogger) {
+ /** Logs that the receiver chip has changed states. */
+ fun logReceiverStateChange(chipState: ChipStateReceiver) {
+ logger.log(chipState.uiEvent)
+ }
+}
+
+enum class MediaTttReceiverUiEvents(val metricId: Int) : UiEventLogger.UiEventEnum {
+ @UiEvent(doc = "See android.app.StatusBarManager.MEDIA_TRANSFER_RECEIVER_* docs")
+ MEDIA_TTT_RECEIVER_CLOSE_TO_SENDER(982),
+ @UiEvent(doc = "See android.app.StatusBarManager.MEDIA_TRANSFER_RECEIVER_* docs")
+ MEDIA_TTT_RECEIVER_FAR_FROM_SENDER(983);
+
+ override fun getId() = metricId
+}
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/ChipStateSender.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/ChipStateSender.kt
index 22424a4e9c74..3c6805b4e881 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/ChipStateSender.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/ChipStateSender.kt
@@ -16,188 +16,225 @@
package com.android.systemui.media.taptotransfer.sender
+import android.app.StatusBarManager
import android.content.Context
+import android.media.MediaRoute2Info
import android.view.View
+import androidx.annotation.StringRes
+import com.android.internal.logging.UiEventLogger
import com.android.internal.statusbar.IUndoMediaTransferCallback
import com.android.systemui.R
-import com.android.systemui.media.taptotransfer.common.MediaTttChipState
+import com.android.systemui.media.taptotransfer.common.DEFAULT_TIMEOUT_MILLIS
/**
- * A class that stores all the information necessary to display the media tap-to-transfer chip on
- * the sender device.
+ * A class enumerating all the possible states of the media tap-to-transfer chip on the sender
+ * device.
*
- * This is a sealed class where each subclass represents a specific chip state. Each subclass can
- * contain additional information that is necessary for only that state.
+ * @property stateInt the integer from [StatusBarManager] corresponding with this state.
+ * @property stringResId the res ID of the string that should be displayed in the chip. Null if the
+ * state should not have the chip be displayed.
+ * @property isMidTransfer true if the state represents that a transfer is currently ongoing.
+ * @property isTransferFailure true if the state represents that the transfer has failed.
+ * @property timeout the amount of time this chip should display on the screen before it times out
+ * and disappears.
*/
-sealed class ChipStateSender(
- appPackageName: String?
-) : MediaTttChipState(appPackageName) {
- /** Returns a fully-formed string with the text that the chip should display. */
- abstract fun getChipTextString(context: Context): String
-
- /** Returns true if the loading icon should be displayed and false otherwise. */
- open fun showLoading(): Boolean = false
-
+enum class ChipStateSender(
+ @StatusBarManager.MediaTransferSenderState val stateInt: Int,
+ val uiEvent: UiEventLogger.UiEventEnum,
+ @StringRes val stringResId: Int?,
+ val isMidTransfer: Boolean = false,
+ val isTransferFailure: Boolean = false,
+ val timeout: Long = DEFAULT_TIMEOUT_MILLIS
+) {
/**
- * Returns a click listener for the undo button on the chip. Returns null if this chip state
- * doesn't have an undo button.
- *
- * @param controllerSender passed as a parameter in case we want to display a new chip state
- * when undo is clicked.
+ * A state representing that the two devices are close but not close enough to *start* a cast to
+ * the receiver device. The chip will instruct the user to move closer in order to initiate the
+ * transfer to the receiver.
*/
- open fun undoClickListener(
- controllerSender: MediaTttChipControllerSender
- ): View.OnClickListener? = null
-}
-
-/**
- * A state representing that the two devices are close but not close enough to *start* a cast to
- * the receiver device. The chip will instruct the user to move closer in order to initiate the
- * transfer to the receiver.
- *
- * @property otherDeviceName the name of the other device involved in the transfer.
- */
-class AlmostCloseToStartCast(
- appPackageName: String?,
- private val otherDeviceName: String,
-) : ChipStateSender(appPackageName) {
- override fun getChipTextString(context: Context): String {
- return context.getString(R.string.media_move_closer_to_start_cast, otherDeviceName)
- }
-}
-
-/**
- * A state representing that the two devices are close but not close enough to *end* a cast that's
- * currently occurring the receiver device. The chip will instruct the user to move closer in order
- * to initiate the transfer from the receiver and back onto this device (the original sender).
- *
- * @property otherDeviceName the name of the other device involved in the transfer.
- */
-class AlmostCloseToEndCast(
- appPackageName: String?,
- private val otherDeviceName: String,
-) : ChipStateSender(appPackageName) {
- override fun getChipTextString(context: Context): String {
- return context.getString(R.string.media_move_closer_to_end_cast, otherDeviceName)
- }
-}
-
-/**
- * A state representing that a transfer to the receiver device has been initiated (but not
- * completed).
- *
- * @property otherDeviceName the name of the other device involved in the transfer.
- */
-class TransferToReceiverTriggered(
- appPackageName: String?,
- private val otherDeviceName: String
-) : ChipStateSender(appPackageName) {
- override fun getChipTextString(context: Context): String {
- return context.getString(R.string.media_transfer_playing_different_device, otherDeviceName)
- }
-
- override fun showLoading() = true
- override fun getTimeoutMs() = TRANSFER_TRIGGERED_TIMEOUT_MILLIS
-}
+ ALMOST_CLOSE_TO_START_CAST(
+ StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_START_CAST,
+ MediaTttSenderUiEvents.MEDIA_TTT_SENDER_ALMOST_CLOSE_TO_START_CAST,
+ R.string.media_move_closer_to_start_cast,
+ ),
-/**
- * A state representing that a transfer from the receiver device and back to this device (the
- * sender) has been initiated (but not completed).
- */
-class TransferToThisDeviceTriggered(
- appPackageName: String?,
-) : ChipStateSender(appPackageName) {
- override fun getChipTextString(context: Context): String {
- return context.getString(R.string.media_transfer_playing_this_device)
- }
+ /**
+ * A state representing that the two devices are close but not close enough to *end* a cast
+ * that's currently occurring the receiver device. The chip will instruct the user to move
+ * closer in order to initiate the transfer from the receiver and back onto this device (the
+ * original sender).
+ */
+ ALMOST_CLOSE_TO_END_CAST(
+ StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_END_CAST,
+ MediaTttSenderUiEvents.MEDIA_TTT_SENDER_ALMOST_CLOSE_TO_END_CAST,
+ R.string.media_move_closer_to_end_cast,
+ ),
- override fun showLoading() = true
- override fun getTimeoutMs() = TRANSFER_TRIGGERED_TIMEOUT_MILLIS
-}
+ /**
+ * A state representing that a transfer to the receiver device has been initiated (but not
+ * completed).
+ */
+ TRANSFER_TO_RECEIVER_TRIGGERED(
+ StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_TRIGGERED,
+ MediaTttSenderUiEvents.MEDIA_TTT_SENDER_TRANSFER_TO_RECEIVER_TRIGGERED,
+ R.string.media_transfer_playing_different_device,
+ isMidTransfer = true,
+ timeout = TRANSFER_TRIGGERED_TIMEOUT_MILLIS
+ ),
-/**
- * A state representing that a transfer to the receiver device has been successfully completed.
- *
- * @property otherDeviceName the name of the other device involved in the transfer.
- * @property undoCallback if present, the callback that should be called when the user clicks the
- * undo button. The undo button will only be shown if this is non-null.
- */
-class TransferToReceiverSucceeded(
- appPackageName: String?,
- private val otherDeviceName: String,
- val undoCallback: IUndoMediaTransferCallback? = null
-) : ChipStateSender(appPackageName) {
- override fun getChipTextString(context: Context): String {
- return context.getString(R.string.media_transfer_playing_different_device, otherDeviceName)
- }
+ /**
+ * A state representing that a transfer from the receiver device and back to this device (the
+ * sender) has been initiated (but not completed).
+ */
+ TRANSFER_TO_THIS_DEVICE_TRIGGERED(
+ StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_TRIGGERED,
+ MediaTttSenderUiEvents.MEDIA_TTT_SENDER_TRANSFER_TO_THIS_DEVICE_TRIGGERED,
+ R.string.media_transfer_playing_this_device,
+ isMidTransfer = true,
+ timeout = TRANSFER_TRIGGERED_TIMEOUT_MILLIS
+ ),
- override fun undoClickListener(
- controllerSender: MediaTttChipControllerSender
- ): View.OnClickListener? {
- if (undoCallback == null) {
- return null
+ /**
+ * A state representing that a transfer to the receiver device has been successfully completed.
+ */
+ TRANSFER_TO_RECEIVER_SUCCEEDED(
+ StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_SUCCEEDED,
+ MediaTttSenderUiEvents.MEDIA_TTT_SENDER_TRANSFER_TO_RECEIVER_SUCCEEDED,
+ R.string.media_transfer_playing_different_device
+ ) {
+ override fun undoClickListener(
+ controllerSender: MediaTttChipControllerSender,
+ routeInfo: MediaRoute2Info,
+ undoCallback: IUndoMediaTransferCallback?,
+ uiEventLogger: MediaTttSenderUiEventLogger
+ ): View.OnClickListener? {
+ if (undoCallback == null) {
+ return null
+ }
+ return View.OnClickListener {
+ uiEventLogger.logUndoClicked(
+ MediaTttSenderUiEvents.MEDIA_TTT_SENDER_UNDO_TRANSFER_TO_RECEIVER_CLICKED
+ )
+ undoCallback.onUndoTriggered()
+ // The external service should eventually send us a TransferToThisDeviceTriggered
+ // state, but that may take too long to go through the binder and the user may be
+ // confused ast o why the UI hasn't changed yet. So, we immediately change the UI
+ // here.
+ controllerSender.displayChip(
+ ChipSenderInfo(
+ TRANSFER_TO_THIS_DEVICE_TRIGGERED, routeInfo, undoCallback
+ )
+ )
+ }
}
+ },
- return View.OnClickListener {
- this.undoCallback.onUndoTriggered()
- // The external service should eventually send us a TransferToThisDeviceTriggered state,
- // but that may take too long to go through the binder and the user may be confused as
- // to why the UI hasn't changed yet. So, we immediately change the UI here.
- controllerSender.displayChip(
- TransferToThisDeviceTriggered(this.appPackageName)
- )
+ /**
+ * A state representing that a transfer back to this device has been successfully completed.
+ */
+ TRANSFER_TO_THIS_DEVICE_SUCCEEDED(
+ StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_SUCCEEDED,
+ MediaTttSenderUiEvents.MEDIA_TTT_SENDER_TRANSFER_TO_THIS_DEVICE_SUCCEEDED,
+ R.string.media_transfer_playing_this_device
+ ) {
+ override fun undoClickListener(
+ controllerSender: MediaTttChipControllerSender,
+ routeInfo: MediaRoute2Info,
+ undoCallback: IUndoMediaTransferCallback?,
+ uiEventLogger: MediaTttSenderUiEventLogger
+ ): View.OnClickListener? {
+ if (undoCallback == null) {
+ return null
+ }
+ return View.OnClickListener {
+ uiEventLogger.logUndoClicked(
+ MediaTttSenderUiEvents.MEDIA_TTT_SENDER_UNDO_TRANSFER_TO_THIS_DEVICE_CLICKED
+ )
+ undoCallback.onUndoTriggered()
+ // The external service should eventually send us a TransferToReceiverTriggered
+ // state, but that may take too long to go through the binder and the user may be
+ // confused as to why the UI hasn't changed yet. So, we immediately change the UI
+ // here.
+ controllerSender.displayChip(
+ ChipSenderInfo(
+ TRANSFER_TO_RECEIVER_TRIGGERED, routeInfo, undoCallback
+ )
+ )
+ }
}
- }
-}
-
-/**
- * A state representing that a transfer back to this device has been successfully completed.
- *
- * @property otherDeviceName the name of the other device involved in the transfer.
- * @property undoCallback if present, the callback that should be called when the user clicks the
- * undo button. The undo button will only be shown if this is non-null.
- */
-class TransferToThisDeviceSucceeded(
- appPackageName: String?,
- private val otherDeviceName: String,
- val undoCallback: IUndoMediaTransferCallback? = null
-) : ChipStateSender(appPackageName) {
- override fun getChipTextString(context: Context): String {
- return context.getString(R.string.media_transfer_playing_this_device)
- }
+ },
+
+ /** A state representing that a transfer to the receiver device has failed. */
+ TRANSFER_TO_RECEIVER_FAILED(
+ StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_FAILED,
+ MediaTttSenderUiEvents.MEDIA_TTT_SENDER_TRANSFER_TO_RECEIVER_FAILED,
+ R.string.media_transfer_failed,
+ isTransferFailure = true
+ ),
+
+ /** A state representing that a transfer back to this device has failed. */
+ TRANSFER_TO_THIS_DEVICE_FAILED(
+ StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_FAILED,
+ MediaTttSenderUiEvents.MEDIA_TTT_SENDER_TRANSFER_TO_THIS_DEVICE_FAILED,
+ R.string.media_transfer_failed,
+ isTransferFailure = true
+ ),
+
+ /** A state representing that this device is far away from any receiver device. */
+ FAR_FROM_RECEIVER(
+ StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_FAR_FROM_RECEIVER,
+ MediaTttSenderUiEvents.MEDIA_TTT_SENDER_FAR_FROM_RECEIVER,
+ stringResId = null
+ );
- override fun undoClickListener(
- controllerSender: MediaTttChipControllerSender
- ): View.OnClickListener? {
- if (undoCallback == null) {
+ /**
+ * Returns a fully-formed string with the text that the chip should display.
+ *
+ * @param otherDeviceName the name of the other device involved in the transfer.
+ */
+ fun getChipTextString(context: Context, otherDeviceName: String): String? {
+ if (stringResId == null) {
return null
}
-
- return View.OnClickListener {
- this.undoCallback.onUndoTriggered()
- // The external service should eventually send us a TransferToReceiverTriggered state,
- // but that may take too long to go through the binder and the user may be confused as
- // to why the UI hasn't changed yet. So, we immediately change the UI here.
- controllerSender.displayChip(
- TransferToReceiverTriggered(
- this.appPackageName,
- this.otherDeviceName
- )
- )
- }
+ return context.getString(stringResId, otherDeviceName)
}
-}
-/** A state representing that a transfer has failed. */
-class TransferFailed(
- appPackageName: String?,
-) : ChipStateSender(appPackageName) {
- override fun getChipTextString(context: Context): String {
- return context.getString(R.string.media_transfer_failed)
+ /**
+ * Returns a click listener for the undo button on the chip. Returns null if this chip state
+ * doesn't have an undo button.
+ *
+ * @param controllerSender passed as a parameter in case we want to display a new chip state
+ * when undo is clicked.
+ * @param undoCallback if present, the callback that should be called when the user clicks the
+ * undo button. The undo button will only be shown if this is non-null.
+ */
+ open fun undoClickListener(
+ controllerSender: MediaTttChipControllerSender,
+ routeInfo: MediaRoute2Info,
+ undoCallback: IUndoMediaTransferCallback?,
+ uiEventLogger: MediaTttSenderUiEventLogger
+ ): View.OnClickListener? = null
+
+ companion object {
+ /**
+ * Returns the sender state enum associated with the given [displayState] from
+ * [StatusBarManager].
+ */
+ fun getSenderStateFromId(
+ @StatusBarManager.MediaTransferSenderState displayState: Int,
+ ): ChipStateSender = values().first { it.stateInt == displayState }
+
+ /**
+ * Returns the state int from [StatusBarManager] associated with the given sender state
+ * name.
+ *
+ * @param name the name of one of the [ChipStateSender] enums.
+ */
+ @StatusBarManager.MediaTransferSenderState
+ fun getSenderStateIdFromName(name: String): Int = valueOf(name).stateInt
}
}
// Give the Transfer*Triggered states a longer timeout since those states represent an active
// process and we should keep the user informed about it as long as possible (but don't allow it to
// continue indefinitely).
-private const val TRANSFER_TRIGGERED_TIMEOUT_MILLIS = 15000L \ No newline at end of file
+private const val TRANSFER_TRIGGERED_TIMEOUT_MILLIS = 15000L
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSender.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSender.kt
index da2aac4d5ad7..9f5ec7e1a330 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSender.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSender.kt
@@ -19,6 +19,7 @@ package com.android.systemui.media.taptotransfer.sender
import android.app.StatusBarManager
import android.content.Context
import android.media.MediaRoute2Info
+import android.os.PowerManager
import android.util.Log
import android.view.View
import android.view.ViewGroup
@@ -28,6 +29,7 @@ import com.android.internal.statusbar.IUndoMediaTransferCallback
import com.android.systemui.R
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.media.taptotransfer.common.ChipInfoCommon
import com.android.systemui.media.taptotransfer.common.MediaTttChipControllerCommon
import com.android.systemui.media.taptotransfer.common.MediaTttLogger
import com.android.systemui.media.taptotransfer.common.MediaTttRemovalReason
@@ -50,13 +52,16 @@ class MediaTttChipControllerSender @Inject constructor(
viewUtil: ViewUtil,
@Main mainExecutor: DelayableExecutor,
tapGestureDetector: TapGestureDetector,
-) : MediaTttChipControllerCommon<ChipStateSender>(
+ powerManager: PowerManager,
+ private val uiEventLogger: MediaTttSenderUiEventLogger
+) : MediaTttChipControllerCommon<ChipSenderInfo>(
context,
logger,
windowManager,
viewUtil,
mainExecutor,
tapGestureDetector,
+ powerManager,
R.layout.media_ttt_chip
) {
private var currentlyDisplayedChipState: ChipStateSender? = null
@@ -82,104 +87,83 @@ class MediaTttChipControllerSender @Inject constructor(
routeInfo: MediaRoute2Info,
undoCallback: IUndoMediaTransferCallback?
) {
- logger.logStateChange(stateIntToString(displayState), routeInfo.id)
- val appPackageName = routeInfo.packageName
- val otherDeviceName = routeInfo.name.toString()
- val chipState = when(displayState) {
- StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_START_CAST ->
- AlmostCloseToStartCast(appPackageName, otherDeviceName)
- StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_END_CAST ->
- AlmostCloseToEndCast(appPackageName, otherDeviceName)
- StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_TRIGGERED ->
- TransferToReceiverTriggered(appPackageName, otherDeviceName)
- StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_TRIGGERED ->
- TransferToThisDeviceTriggered(appPackageName)
- StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_SUCCEEDED ->
- TransferToReceiverSucceeded(appPackageName, otherDeviceName, undoCallback)
- StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_SUCCEEDED ->
- TransferToThisDeviceSucceeded(appPackageName, otherDeviceName, undoCallback)
- StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_FAILED,
- StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_FAILED ->
- TransferFailed(appPackageName)
- StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_FAR_FROM_RECEIVER -> {
- removeChip(removalReason = FAR_FROM_RECEIVER)
- null
- }
- else -> {
- Log.e(SENDER_TAG, "Unhandled MediaTransferSenderState $displayState")
- null
- }
+ val chipState: ChipStateSender? = ChipStateSender.getSenderStateFromId(displayState)
+ val stateName = chipState?.name ?: "Invalid"
+ logger.logStateChange(stateName, routeInfo.id)
+
+ if (chipState == null) {
+ Log.e(SENDER_TAG, "Unhandled MediaTransferSenderState $displayState")
+ return
}
+ uiEventLogger.logSenderStateChange(chipState)
- chipState?.let {
- displayChip(it)
+ if (chipState == ChipStateSender.FAR_FROM_RECEIVER) {
+ removeChip(removalReason = ChipStateSender.FAR_FROM_RECEIVER::class.simpleName!!)
+ } else {
+ displayChip(ChipSenderInfo(chipState, routeInfo, undoCallback))
}
}
/** Displays the chip view for the given state. */
- override fun updateChipView(chipState: ChipStateSender, currentChipView: ViewGroup) {
+ override fun updateChipView(
+ chipInfo: ChipSenderInfo,
+ currentChipView: ViewGroup) {
+ val chipState = chipInfo.state
currentlyDisplayedChipState = chipState
// App icon
- setIcon(chipState, currentChipView)
+ setIcon(currentChipView, chipInfo.routeInfo.packageName)
// Text
+ val otherDeviceName = chipInfo.routeInfo.name.toString()
currentChipView.requireViewById<TextView>(R.id.text).apply {
- text = chipState.getChipTextString(context)
+ text = chipState.getChipTextString(context, otherDeviceName)
}
// Loading
currentChipView.requireViewById<View>(R.id.loading).visibility =
- if (chipState.showLoading()) { View.VISIBLE } else { View.GONE }
+ chipState.isMidTransfer.visibleIfTrue()
+
// Undo
val undoView = currentChipView.requireViewById<View>(R.id.undo)
- val undoClickListener = chipState.undoClickListener(this)
+ val undoClickListener = chipState.undoClickListener(
+ this, chipInfo.routeInfo, chipInfo.undoCallback, uiEventLogger
+ )
undoView.setOnClickListener(undoClickListener)
- undoView.visibility = if (undoClickListener != null) { View.VISIBLE } else { View.GONE }
+ undoView.visibility = (undoClickListener != null).visibleIfTrue()
// Failure
- val showFailure = chipState is TransferFailed
currentChipView.requireViewById<View>(R.id.failure_icon).visibility =
- if (showFailure) { View.VISIBLE } else { View.GONE }
+ chipState.isTransferFailure.visibleIfTrue()
}
override fun removeChip(removalReason: String) {
// Don't remove the chip if we're mid-transfer since the user should still be able to
// see the status of the transfer. (But do remove it if it's finally timed out.)
- if ((currentlyDisplayedChipState is TransferToReceiverTriggered ||
- currentlyDisplayedChipState is TransferToThisDeviceTriggered)
- && removalReason != MediaTttRemovalReason.REASON_TIMEOUT) {
+ if (currentlyDisplayedChipState?.isMidTransfer == true
+ && removalReason != MediaTttRemovalReason.REASON_TIMEOUT) {
return
}
super.removeChip(removalReason)
currentlyDisplayedChipState = null
}
- private fun stateIntToString(@StatusBarManager.MediaTransferSenderState state: Int): String {
- return when(state) {
- StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_START_CAST ->
- "ALMOST_CLOSE_TO_START_CAST"
- StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_END_CAST ->
- "ALMOST_CLOSE_TO_END_CAST"
- StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_TRIGGERED ->
- "TRANSFER_TO_RECEIVER_TRIGGERED"
- StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_TRIGGERED ->
- "TRANSFER_TO_THIS_DEVICE_TRIGGERED"
- StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_SUCCEEDED ->
- "TRANSFER_TO_RECEIVER_SUCCEEDED"
- StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_SUCCEEDED ->
- "TRANSFER_TO_THIS_DEVICE_SUCCEEDED"
- StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_FAILED ->
- "TRANSFER_TO_RECEIVER_FAILED"
- StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_FAILED ->
- "TRANSFER_TO_THIS_DEVICE_FAILED"
- StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_FAR_FROM_RECEIVER ->
- FAR_FROM_RECEIVER
- else -> "INVALID: $state"
+ private fun Boolean.visibleIfTrue(): Int {
+ return if (this) {
+ View.VISIBLE
+ } else {
+ View.GONE
}
}
}
+data class ChipSenderInfo(
+ val state: ChipStateSender,
+ val routeInfo: MediaRoute2Info,
+ val undoCallback: IUndoMediaTransferCallback? = null
+) : ChipInfoCommon {
+ override fun getTimeoutMs() = state.timeout
+}
+
const val SENDER_TAG = "MediaTapToTransferSender"
-private const val FAR_FROM_RECEIVER = "FAR_FROM_RECEIVER"
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderUiEventLogger.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderUiEventLogger.kt
new file mode 100644
index 000000000000..af3c1b60bacf
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderUiEventLogger.kt
@@ -0,0 +1,82 @@
+/*
+ * 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.taptotransfer.sender
+
+import android.util.Log
+import com.android.internal.logging.UiEvent
+import com.android.internal.logging.UiEventLogger
+import com.android.systemui.dagger.SysUISingleton
+import javax.inject.Inject
+
+/** A class for analytics logging for the media tap-to-transfer chip on the sender device. */
+@SysUISingleton
+class MediaTttSenderUiEventLogger @Inject constructor(private val logger: UiEventLogger) {
+ /** Logs that the sender chip has changed states. */
+ fun logSenderStateChange(chipState: ChipStateSender) {
+ logger.log(chipState.uiEvent)
+ }
+
+ /**
+ * Logs that the undo button was clicked.
+ *
+ * @param undoUiEvent the uiEvent specific to which undo button was clicked.
+ */
+ fun logUndoClicked(undoUiEvent: UiEventLogger.UiEventEnum) {
+ val isUndoEvent =
+ undoUiEvent == MediaTttSenderUiEvents.MEDIA_TTT_SENDER_UNDO_TRANSFER_TO_RECEIVER_CLICKED
+ || undoUiEvent ==
+ MediaTttSenderUiEvents.MEDIA_TTT_SENDER_UNDO_TRANSFER_TO_THIS_DEVICE_CLICKED
+ if (!isUndoEvent) {
+ Log.w(
+ MediaTttSenderUiEventLogger::class.simpleName!!,
+ "Must pass an undo-specific UiEvent."
+ )
+ return
+ }
+ logger.log(undoUiEvent)
+ }
+}
+
+enum class MediaTttSenderUiEvents(val metricId: Int) : UiEventLogger.UiEventEnum {
+ @UiEvent(doc = "The undo button on the media ttt chip on the sender device was clicked " +
+ "to undo the transfer to the receiver device")
+ MEDIA_TTT_SENDER_UNDO_TRANSFER_TO_RECEIVER_CLICKED(971),
+ @UiEvent(doc = "The undo button on the media ttt chip on the sender device was clicked " +
+ "to undo the transfer back to this device")
+ MEDIA_TTT_SENDER_UNDO_TRANSFER_TO_THIS_DEVICE_CLICKED(972),
+
+ @UiEvent(doc = "See android.app.StatusBarManager.MEDIA_TRANSFER_SENDER_* docs")
+ MEDIA_TTT_SENDER_ALMOST_CLOSE_TO_START_CAST(973),
+ @UiEvent(doc = "See android.app.StatusBarManager.MEDIA_TRANSFER_SENDER_* docs")
+ MEDIA_TTT_SENDER_ALMOST_CLOSE_TO_END_CAST(974),
+ @UiEvent(doc = "See android.app.StatusBarManager.MEDIA_TRANSFER_SENDER_* docs")
+ MEDIA_TTT_SENDER_TRANSFER_TO_RECEIVER_TRIGGERED(975),
+ @UiEvent(doc = "See android.app.StatusBarManager.MEDIA_TRANSFER_SENDER_* docs")
+ MEDIA_TTT_SENDER_TRANSFER_TO_THIS_DEVICE_TRIGGERED(976),
+ @UiEvent(doc = "See android.app.StatusBarManager.MEDIA_TRANSFER_SENDER_* docs")
+ MEDIA_TTT_SENDER_TRANSFER_TO_RECEIVER_SUCCEEDED(977),
+ @UiEvent(doc = "See android.app.StatusBarManager.MEDIA_TRANSFER_SENDER_* docs")
+ MEDIA_TTT_SENDER_TRANSFER_TO_THIS_DEVICE_SUCCEEDED(978),
+ @UiEvent(doc = "See android.app.StatusBarManager.MEDIA_TRANSFER_SENDER_* docs")
+ MEDIA_TTT_SENDER_TRANSFER_TO_RECEIVER_FAILED(979),
+ @UiEvent(doc = "See android.app.StatusBarManager.MEDIA_TRANSFER_SENDER_* docs")
+ MEDIA_TTT_SENDER_TRANSFER_TO_THIS_DEVICE_FAILED(980),
+ @UiEvent(doc = "See android.app.StatusBarManager.MEDIA_TRANSFER_SENDER_* docs")
+ MEDIA_TTT_SENDER_FAR_FROM_RECEIVER(981);
+
+ override fun getId() = metricId
+}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
index ec6094dd9973..d8d86779ea0a 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
@@ -47,6 +47,7 @@ import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_IME_SHOWING;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_IME_SWITCHER_SHOWING;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NAV_BAR_HIDDEN;
+import static com.android.systemui.shared.system.QuickStepContract.isGesturalMode;
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT;
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT_TRANSPARENT;
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_OPAQUE;
@@ -61,7 +62,6 @@ import android.app.ActivityTaskManager;
import android.app.IActivityTaskManager;
import android.app.StatusBarManager;
import android.content.BroadcastReceiver;
-import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
@@ -107,13 +107,15 @@ import com.android.internal.logging.UiEventLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.util.LatencyTracker;
import com.android.internal.view.AppearanceRegion;
+import com.android.systemui.Gefingerpoken;
import com.android.systemui.R;
-import com.android.systemui.accessibility.AccessibilityButtonModeObserver;
import com.android.systemui.assist.AssistManager;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.model.SysUiState;
+import com.android.systemui.navigationbar.NavigationModeController.ModeChangedListener;
import com.android.systemui.navigationbar.buttons.ButtonDispatcher;
+import com.android.systemui.navigationbar.buttons.DeadZone;
import com.android.systemui.navigationbar.buttons.KeyButtonView;
import com.android.systemui.navigationbar.buttons.RotationContextButton;
import com.android.systemui.navigationbar.gestural.QuickswitchOrientedNavHandle;
@@ -125,6 +127,7 @@ import com.android.systemui.shared.rotation.RotationButton;
import com.android.systemui.shared.rotation.RotationButtonController;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.QuickStepContract;
+import com.android.systemui.shared.system.SysUiStatsLog;
import com.android.systemui.statusbar.AutoHideUiElement;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.CommandQueue.Callbacks;
@@ -146,15 +149,15 @@ import java.util.Locale;
import java.util.Optional;
import java.util.function.Consumer;
-import javax.inject.Inject;
-
import dagger.Lazy;
+import dagger.assisted.Assisted;
+import dagger.assisted.AssistedFactory;
+import dagger.assisted.AssistedInject;
/**
* Contains logic for a navigation bar view.
*/
-public class NavigationBar implements View.OnAttachStateChangeListener,
- Callbacks, NavigationModeController.ModeChangedListener {
+public class NavigationBar implements View.OnAttachStateChangeListener, Callbacks {
public static final String TAG = "NavigationBar";
private static final boolean DEBUG = false;
@@ -181,7 +184,6 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
private final NotificationRemoteInputManager mNotificationRemoteInputManager;
private final OverviewProxyService mOverviewProxyService;
private final NavigationModeController mNavigationModeController;
- private final AccessibilityButtonModeObserver mAccessibilityButtonModeObserver;
private final BroadcastDispatcher mBroadcastDispatcher;
private final CommandQueue mCommandQueue;
private final Optional<Pip> mPipOptional;
@@ -200,8 +202,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
private @WindowVisibleState int mNavigationBarWindowState = WINDOW_STATE_SHOWING;
private int mNavigationIconHints = 0;
- private @TransitionMode int mNavigationBarMode;
- private ContentResolver mContentResolver;
+ private @TransitionMode int mTransitionMode;
private boolean mLongPressHomeEnabled;
private int mDisabledFlags1;
@@ -255,7 +256,8 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
private int mCurrentRotation;
private ViewTreeObserver.OnGlobalLayoutListener mOrientationHandleGlobalLayoutListener;
private boolean mShowOrientedHandleForImmersiveMode;
-
+ private DeadZone mDeadZone;
+ private boolean mImeVisible;
@com.android.internal.annotations.VisibleForTesting
public enum NavBarActionEvent implements UiEventLogger.UiEventEnum {
@@ -471,15 +473,16 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
}
};
- private NavigationBar(Context context,
- WindowManager windowManager,
+ @AssistedInject
+ NavigationBar(
+ @Assisted Context context,
+ @Assisted WindowManager windowManager,
Lazy<AssistManager> assistManagerLazy,
AccessibilityManager accessibilityManager,
DeviceProvisionedController deviceProvisionedController,
MetricsLogger metricsLogger,
OverviewProxyService overviewProxyService,
NavigationModeController navigationModeController,
- AccessibilityButtonModeObserver accessibilityButtonModeObserver,
StatusBarStateController statusBarStateController,
SysUiState sysUiFlagsContainer,
BroadcastDispatcher broadcastDispatcher,
@@ -514,7 +517,6 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
mNotificationRemoteInputManager = notificationRemoteInputManager;
mOverviewProxyService = overviewProxyService;
mNavigationModeController = navigationModeController;
- mAccessibilityButtonModeObserver = accessibilityButtonModeObserver;
mBroadcastDispatcher = broadcastDispatcher;
mCommandQueue = commandQueue;
mPipOptional = pipOptional;
@@ -532,7 +534,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
mTelecomManagerOptional = telecomManagerOptional;
mInputMethodManager = inputMethodManager;
- mNavBarMode = mNavigationModeController.addListener(this);
+ mNavBarMode = mNavigationModeController.addListener(mModeChangedListener);
}
public NavigationBarView getView() {
@@ -546,6 +548,11 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
R.layout.navigation_bar, mFrame);
barView.addOnAttachStateChangeListener(this);
mNavigationBarView = barView.findViewById(R.id.navigation_bar_view);
+ mDeadZone = new DeadZone(mNavigationBarView);
+ mNavigationBarView.setTouchHandler(mTouchHandler);
+ mNavigationBarView.setNavBarMode(mNavBarMode);
+
+ mNavigationBarView.updateRotationButton();
mNavigationBarView.setVisibility(initialVisibility ? View.VISIBLE : View.INVISIBLE);
@@ -558,7 +565,6 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
mCommandQueue.addCallback(this);
mLongPressHomeEnabled = mNavBarHelper.getLongPressHomeEnabled();
- mContentResolver = mContext.getContentResolver();
mNavBarHelper.init();
mAllowForceNavBarHandleOpaque = mContext.getResources().getBoolean(
R.bool.allow_force_nav_bar_handle_opaque);
@@ -597,7 +603,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
setAutoHideController(/* autoHideController */ null);
mCommandQueue.removeCallback(this);
mWindowManager.removeViewImmediate(mNavigationBarView.getRootView());
- mNavigationModeController.removeListener(this);
+ mNavigationModeController.removeListener(mModeChangedListener);
mNavBarHelper.removeNavTaskStateUpdater(mNavbarTaskbarStateUpdater);
mNavBarHelper.destroy();
@@ -612,15 +618,16 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
final Display display = v.getDisplay();
mNavigationBarView.setComponents(mRecentsOptional);
mNavigationBarView.setComponents(mCentralSurfacesOptionalLazy.get().get().getPanelController());
- mNavigationBarView.setDisabledFlags(mDisabledFlags1);
+ mNavigationBarView.setDisabledFlags(mDisabledFlags1, mSysUiFlagsContainer);
mNavigationBarView.setOnVerticalChangedListener(this::onVerticalChanged);
mNavigationBarView.setOnTouchListener(this::onNavigationTouch);
if (mSavedState != null) {
mNavigationBarView.getLightTransitionsController().restoreState(mSavedState);
}
- mNavigationBarView.setNavigationIconHints(mNavigationIconHints);
+ setNavigationIconHints(mNavigationIconHints);
mNavigationBarView.setWindowVisible(isNavBarWindowVisible());
mNavigationBarView.setBehavior(mBehavior);
+ mNavigationBarView.setNavBarMode(mNavBarMode);
mNavBarHelper.registerNavTaskStateUpdater(mNavbarTaskbarStateUpdater);
@@ -865,8 +872,8 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
pw.println(" mLongPressHomeEnabled=" + mLongPressHomeEnabled);
pw.println(" mNavigationBarWindowState="
+ windowStateToString(mNavigationBarWindowState));
- pw.println(" mNavigationBarMode="
- + BarTransitions.modeToString(mNavigationBarMode));
+ pw.println(" mTransitionMode="
+ + BarTransitions.modeToString(mTransitionMode));
pw.println(" mTransientShown=" + mTransientShown);
pw.println(" mTransientShownFromGestureOnSystemBar="
+ mTransientShownFromGestureOnSystemBar);
@@ -888,11 +895,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
imeShown, showImeSwitcher);
if (hints == mNavigationIconHints) return;
- mNavigationIconHints = hints;
- if (!isTablet(mContext)) {
- // All IME functions handled by launcher via Sysui flags for large screen
- mNavigationBarView.setNavigationIconHints(hints);
- }
+ setNavigationIconHints(hints);
checkBarModes();
updateSystemUiStateFlags();
}
@@ -952,15 +955,15 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
/** Restores the appearance and the transient saved state to {@link NavigationBar}. */
public void restoreAppearanceAndTransientState() {
- final int barMode = barMode(mTransientShown, mAppearance);
- mNavigationBarMode = barMode;
+ final int transitionMode = transitionMode(mTransientShown, mAppearance);
+ mTransitionMode = transitionMode;
checkNavBarModes();
if (mAutoHideController != null) {
mAutoHideController.touchAutoHide();
}
if (mLightBarController != null) {
mLightBarController.onNavigationBarAppearanceChanged(mAppearance,
- true /* nbModeChanged */, barMode, false /* navbarColorManagedByIme */);
+ true /* nbModeChanged */, transitionMode, false /* navbarColorManagedByIme */);
}
}
@@ -974,11 +977,11 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
boolean nbModeChanged = false;
if (mAppearance != appearance) {
mAppearance = appearance;
- nbModeChanged = updateBarMode(barMode(mTransientShown, appearance));
+ nbModeChanged = updateTransitionMode(transitionMode(mTransientShown, appearance));
}
if (mLightBarController != null) {
mLightBarController.onNavigationBarAppearanceChanged(appearance, nbModeChanged,
- mNavigationBarMode, navbarColorManagedByIme);
+ mTransitionMode, navbarColorManagedByIme);
}
if (mBehavior != behavior) {
mBehavior = behavior;
@@ -1025,16 +1028,16 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
private void handleTransientChanged() {
mNavigationBarView.onTransientStateChanged(mTransientShown,
mTransientShownFromGestureOnSystemBar);
- final int barMode = barMode(mTransientShown, mAppearance);
- if (updateBarMode(barMode) && mLightBarController != null) {
- mLightBarController.onNavigationBarModeChanged(barMode);
+ final int transitionMode = transitionMode(mTransientShown, mAppearance);
+ if (updateTransitionMode(transitionMode) && mLightBarController != null) {
+ mLightBarController.onNavigationBarModeChanged(transitionMode);
}
}
// Returns true if the bar mode is changed.
- private boolean updateBarMode(int barMode) {
- if (mNavigationBarMode != barMode) {
- mNavigationBarMode = barMode;
+ private boolean updateTransitionMode(int barMode) {
+ if (mTransitionMode != barMode) {
+ mTransitionMode = barMode;
checkNavBarModes();
if (mAutoHideController != null) {
mAutoHideController.touchAutoHide();
@@ -1044,7 +1047,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
return false;
}
- private static @TransitionMode int barMode(boolean isTransient, int appearance) {
+ private static @TransitionMode int transitionMode(boolean isTransient, int appearance) {
final int lightsOutOpaque = APPEARANCE_LOW_PROFILE_BARS | APPEARANCE_OPAQUE_NAVIGATION_BARS;
if (isTransient) {
return MODE_SEMI_TRANSPARENT;
@@ -1073,7 +1076,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
| StatusBarManager.DISABLE_SEARCH);
if (masked != mDisabledFlags1) {
mDisabledFlags1 = masked;
- mNavigationBarView.setDisabledFlags(state1);
+ mNavigationBarView.setDisabledFlags(state1, mSysUiFlagsContainer);
updateScreenPinningGestures();
}
@@ -1455,24 +1458,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
mCentralSurfacesOptionalLazy.get().map(CentralSurfaces::isDeviceInteractive)
.orElse(false)
&& mNavigationBarWindowState != WINDOW_STATE_HIDDEN;
- mNavigationBarView.getBarTransitions().transitionTo(mNavigationBarMode, anim);
- }
-
- @Override
- public void onNavigationModeChanged(int mode) {
- mNavBarMode = mode;
-
- if (!QuickStepContract.isGesturalMode(mode)) {
- // Reset the override alpha
- if (getBarTransitions() != null) {
- getBarTransitions().setBackgroundOverrideAlpha(1f);
- }
- }
- updateScreenPinningGestures();
-
- if (!canShowSecondaryHandle()) {
- resetSecondaryHandle();
- }
+ mNavigationBarView.getBarTransitions().transitionTo(mTransitionMode, anim);
}
public void disableAnimationsDuringHide(long delay) {
@@ -1613,114 +1599,102 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
return mNavigationIconHints;
}
+ private void setNavigationIconHints(int hints) {
+ if (hints == mNavigationIconHints) return;
+ if (!isTablet(mContext)) {
+ // All IME functions handled by launcher via Sysui flags for large screen
+ final boolean newBackAlt = (hints & StatusBarManager.NAVIGATION_HINT_BACK_ALT) != 0;
+ final boolean oldBackAlt =
+ (mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_BACK_ALT) != 0;
+ if (newBackAlt != oldBackAlt) {
+ mNavigationBarView.onImeVisibilityChanged(newBackAlt);
+ mImeVisible = newBackAlt;
+ }
+
+ mNavigationBarView.setNavigationIconHints(hints);
+ }
+ if (DEBUG) {
+ android.widget.Toast.makeText(mContext,
+ "Navigation icon hints = " + hints,
+ 500).show();
+ }
+ mNavigationIconHints = hints;
+ }
+
+ private final ModeChangedListener mModeChangedListener = new ModeChangedListener() {
+ @Override
+ public void onNavigationModeChanged(int mode) {
+ mNavBarMode = mode;
+
+ if (!QuickStepContract.isGesturalMode(mode)) {
+ // Reset the override alpha
+ if (getBarTransitions() != null) {
+ getBarTransitions().setBackgroundOverrideAlpha(1f);
+ }
+ }
+ updateScreenPinningGestures();
+
+ if (!canShowSecondaryHandle()) {
+ resetSecondaryHandle();
+ }
+ if (mNavigationBarView != null) {
+ mNavigationBarView.setNavBarMode(mode);
+ }
+ }
+ };
+
+ private final Gefingerpoken mTouchHandler = new Gefingerpoken() {
+ private boolean mDeadZoneConsuming;
+
+ @Override
+ public boolean onInterceptTouchEvent(MotionEvent ev) {
+ if (isGesturalMode(mNavBarMode) && mImeVisible
+ && ev.getAction() == MotionEvent.ACTION_DOWN) {
+ SysUiStatsLog.write(SysUiStatsLog.IME_TOUCH_REPORTED,
+ (int) ev.getX(), (int) ev.getY());
+ }
+ return shouldDeadZoneConsumeTouchEvents(ev);
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent ev) {
+ shouldDeadZoneConsumeTouchEvents(ev);
+ return false;
+ }
+
+ private boolean shouldDeadZoneConsumeTouchEvents(MotionEvent event) {
+ int action = event.getActionMasked();
+ if (action == MotionEvent.ACTION_DOWN) {
+ mDeadZoneConsuming = false;
+ }
+ if (mDeadZone.onTouchEvent(event) || mDeadZoneConsuming) {
+ switch (action) {
+ case MotionEvent.ACTION_DOWN:
+ // Allow gestures starting in the deadzone to be slippery
+ mNavigationBarView.setSlippery(true);
+ mDeadZoneConsuming = true;
+ break;
+ case MotionEvent.ACTION_CANCEL:
+ case MotionEvent.ACTION_UP:
+ // When a gesture started in the deadzone is finished, restore
+ // slippery state
+ mNavigationBarView.updateSlippery();
+ mDeadZoneConsuming = false;
+ break;
+ }
+ return true;
+ }
+ return false;
+ }
+ };
+
+
/**
* Injectable factory for construction a {@link NavigationBar}.
*/
- public static class Factory {
- private final Lazy<AssistManager> mAssistManagerLazy;
- private final AccessibilityManager mAccessibilityManager;
- private final DeviceProvisionedController mDeviceProvisionedController;
- private final MetricsLogger mMetricsLogger;
- private final OverviewProxyService mOverviewProxyService;
- private final NavigationModeController mNavigationModeController;
- private final AccessibilityButtonModeObserver mAccessibilityButtonModeObserver;
- private final StatusBarStateController mStatusBarStateController;
- private final SysUiState mSysUiFlagsContainer;
- private final BroadcastDispatcher mBroadcastDispatcher;
- private final CommandQueue mCommandQueue;
- private final Optional<Pip> mPipOptional;
- private final Optional<Recents> mRecentsOptional;
- private final Lazy<Optional<CentralSurfaces>> mCentralSurfacesOptionalLazy;
- private final ShadeController mShadeController;
- private final NotificationRemoteInputManager mNotificationRemoteInputManager;
- private final NotificationShadeDepthController mNotificationShadeDepthController;
- private final Handler mMainHandler;
- private final NavigationBarOverlayController mNavbarOverlayController;
- private final UiEventLogger mUiEventLogger;
- private final NavBarHelper mNavBarHelper;
- private final LightBarController mMainLightBarController;
- private final LightBarController.Factory mLightBarControllerFactory;
- private final AutoHideController mMainAutoHideController;
- private final AutoHideController.Factory mAutoHideControllerFactory;
- private final Optional<TelecomManager> mTelecomManagerOptional;
- private final InputMethodManager mInputMethodManager;
- private final Optional<BackAnimation> mBackAnimation;
-
- @Inject
- public Factory(
- Lazy<AssistManager> assistManagerLazy,
- AccessibilityManager accessibilityManager,
- DeviceProvisionedController deviceProvisionedController,
- MetricsLogger metricsLogger,
- OverviewProxyService overviewProxyService,
- NavigationModeController navigationModeController,
- AccessibilityButtonModeObserver accessibilityButtonModeObserver,
- StatusBarStateController statusBarStateController,
- SysUiState sysUiFlagsContainer,
- BroadcastDispatcher broadcastDispatcher,
- CommandQueue commandQueue,
- Optional<Pip> pipOptional,
- Optional<Recents> recentsOptional,
- Lazy<Optional<CentralSurfaces>> centralSurfacesOptionalLazy,
- ShadeController shadeController,
- NotificationRemoteInputManager notificationRemoteInputManager,
- NotificationShadeDepthController notificationShadeDepthController,
- @Main Handler mainHandler,
- NavigationBarOverlayController navbarOverlayController,
- UiEventLogger uiEventLogger,
- NavBarHelper navBarHelper,
- LightBarController mainLightBarController,
- LightBarController.Factory lightBarControllerFactory,
- AutoHideController mainAutoHideController,
- AutoHideController.Factory autoHideControllerFactory,
- Optional<TelecomManager> telecomManagerOptional,
- InputMethodManager inputMethodManager,
- Optional<BackAnimation> backAnimation) {
- mAssistManagerLazy = assistManagerLazy;
- mAccessibilityManager = accessibilityManager;
- mDeviceProvisionedController = deviceProvisionedController;
- mMetricsLogger = metricsLogger;
- mOverviewProxyService = overviewProxyService;
- mNavigationModeController = navigationModeController;
- mAccessibilityButtonModeObserver = accessibilityButtonModeObserver;
- mStatusBarStateController = statusBarStateController;
- mSysUiFlagsContainer = sysUiFlagsContainer;
- mBroadcastDispatcher = broadcastDispatcher;
- mCommandQueue = commandQueue;
- mPipOptional = pipOptional;
- mRecentsOptional = recentsOptional;
- mCentralSurfacesOptionalLazy = centralSurfacesOptionalLazy;
- mShadeController = shadeController;
- mNotificationRemoteInputManager = notificationRemoteInputManager;
- mNotificationShadeDepthController = notificationShadeDepthController;
- mMainHandler = mainHandler;
- mNavbarOverlayController = navbarOverlayController;
- mUiEventLogger = uiEventLogger;
- mNavBarHelper = navBarHelper;
- mMainLightBarController = mainLightBarController;
- mLightBarControllerFactory = lightBarControllerFactory;
- mMainAutoHideController = mainAutoHideController;
- mAutoHideControllerFactory = autoHideControllerFactory;
- mTelecomManagerOptional = telecomManagerOptional;
- mInputMethodManager = inputMethodManager;
- mBackAnimation = backAnimation;
- }
-
+ @AssistedFactory
+ public interface Factory {
/** Construct a {@link NavigationBar} */
- public NavigationBar create(Context context) {
- final WindowManager wm = context.getSystemService(WindowManager.class);
- return new NavigationBar(context, wm, mAssistManagerLazy,
- mAccessibilityManager, mDeviceProvisionedController, mMetricsLogger,
- mOverviewProxyService, mNavigationModeController,
- mAccessibilityButtonModeObserver, mStatusBarStateController,
- mSysUiFlagsContainer, mBroadcastDispatcher, mCommandQueue, mPipOptional,
- mRecentsOptional, mCentralSurfacesOptionalLazy,
- mShadeController, mNotificationRemoteInputManager,
- mNotificationShadeDepthController, mMainHandler,
- mNavbarOverlayController, mUiEventLogger, mNavBarHelper,
- mMainLightBarController, mLightBarControllerFactory,
- mMainAutoHideController, mAutoHideControllerFactory, mTelecomManagerOptional,
- mInputMethodManager, mBackAnimation);
- }
+ NavigationBar create(Context context, WindowManager windowManager);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
index a049736a53d5..b640e1d24385 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
@@ -39,6 +39,7 @@ import android.util.SparseArray;
import android.view.Display;
import android.view.IWindowManager;
import android.view.View;
+import android.view.WindowManager;
import android.view.WindowManagerGlobal;
import androidx.annotation.NonNull;
@@ -323,7 +324,8 @@ public class NavigationBarController implements
final Context context = isOnDefaultDisplay
? mContext
: mContext.createDisplayContext(display);
- NavigationBar navBar = mNavigationBarFactory.create(context);
+ NavigationBar navBar = mNavigationBarFactory.create(
+ context, context.getSystemService(WindowManager.class));
mNavigationBars.put(displayId, navBar);
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
index 017bbdffdc4f..f5abe28914c3 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
@@ -65,6 +65,7 @@ import android.widget.FrameLayout;
import com.android.internal.annotations.VisibleForTesting;
import com.android.settingslib.Utils;
import com.android.systemui.Dependency;
+import com.android.systemui.Gefingerpoken;
import com.android.systemui.R;
import com.android.systemui.animation.Interpolators;
import com.android.systemui.model.SysUiState;
@@ -84,13 +85,12 @@ import com.android.systemui.shared.rotation.RotationButton.RotationButtonUpdates
import com.android.systemui.shared.rotation.RotationButtonController;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.QuickStepContract;
-import com.android.systemui.shared.system.SysUiStatsLog;
import com.android.systemui.shared.system.WindowManagerWrapper;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.phone.AutoHideController;
+import com.android.systemui.statusbar.phone.CentralSurfaces;
import com.android.systemui.statusbar.phone.LightBarTransitionsController;
import com.android.systemui.statusbar.phone.NotificationPanelViewController;
-import com.android.systemui.statusbar.phone.CentralSurfaces;
import com.android.wm.shell.back.BackAnimation;
import com.android.wm.shell.pip.Pip;
@@ -101,15 +101,14 @@ import java.util.Optional;
import java.util.concurrent.Executor;
import java.util.function.Consumer;
-public class NavigationBarView extends FrameLayout implements
- NavigationModeController.ModeChangedListener {
+/** */
+public class NavigationBarView extends FrameLayout {
final static boolean DEBUG = false;
final static String TAG = "NavBarView";
final static boolean ALTERNATE_CAR_MODE_UI = false;
private final RegionSamplingHelper mRegionSamplingHelper;
private final int mNavColorSampleMargin;
- private final SysUiState mSysUiFlagContainer;
// The current view is one of mHorizontal or mVertical depending on the current configuration
View mCurrentView = null;
@@ -197,6 +196,7 @@ public class NavigationBarView extends FrameLayout implements
* <p>Cache the value here for better performance.</p>
*/
private final boolean mImeCanRenderGesturalNavButtons = canImeRenderGesturalNavButtons();
+ private Gefingerpoken mTouchHandler;
private class NavTransitionListener implements TransitionListener {
private boolean mBackTransitioning;
@@ -333,10 +333,8 @@ public class NavigationBarView extends FrameLayout implements
mDarkIconColor = Utils.getColorAttrDefaultColor(darkContext, R.attr.singleToneColor);
mIsVertical = false;
mLongClickableAccessibilityButton = false;
- mNavBarMode = Dependency.get(NavigationModeController.class).addListener(this);
mImeDrawsImeNavBar = Dependency.get(NavigationModeController.class).getImeDrawsImeNavBar();
- mSysUiFlagContainer = Dependency.get(SysUiState.class);
// Set up the context group of buttons
mContextualButtonGroup = new ContextualButtonGroup(R.id.menu_container);
final ContextualButton imeSwitcherButton = new ContextualButton(R.id.ime_switcher,
@@ -365,8 +363,6 @@ public class NavigationBarView extends FrameLayout implements
R.drawable.ic_sysbar_rotate_button_cw_start_90,
() -> getDisplay().getRotation());
- updateRotationButton();
-
mOverviewProxyService = Dependency.get(OverviewProxyService.class);
mConfiguration = new Configuration();
@@ -448,19 +444,18 @@ public class NavigationBarView extends FrameLayout implements
notifyVerticalChangedListener(mIsVertical);
}
+ public void setTouchHandler(Gefingerpoken touchHandler) {
+ mTouchHandler = touchHandler;
+ }
+
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
- if (isGesturalMode(mNavBarMode) && mImeVisible
- && event.getAction() == MotionEvent.ACTION_DOWN) {
- SysUiStatsLog.write(SysUiStatsLog.IME_TOUCH_REPORTED,
- (int) event.getX(), (int) event.getY());
- }
- return shouldDeadZoneConsumeTouchEvents(event) || super.onInterceptTouchEvent(event);
+ return mTouchHandler.onInterceptTouchEvent(event) || super.onInterceptTouchEvent(event);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
- shouldDeadZoneConsumeTouchEvents(event);
+ mTouchHandler.onTouchEvent(event);
return super.onTouchEvent(event);
}
@@ -497,30 +492,6 @@ public class NavigationBarView extends FrameLayout implements
}
}
- private boolean shouldDeadZoneConsumeTouchEvents(MotionEvent event) {
- int action = event.getActionMasked();
- if (action == MotionEvent.ACTION_DOWN) {
- mDeadZoneConsuming = false;
- }
- if (mDeadZone.onTouchEvent(event) || mDeadZoneConsuming) {
- switch (action) {
- case MotionEvent.ACTION_DOWN:
- // Allow gestures starting in the deadzone to be slippery
- setSlippery(true);
- mDeadZoneConsuming = true;
- break;
- case MotionEvent.ACTION_CANCEL:
- case MotionEvent.ACTION_UP:
- // When a gesture started in the deadzone is finished, restore slippery state
- updateSlippery();
- mDeadZoneConsuming = false;
- break;
- }
- return true;
- }
- return false;
- }
-
public void abortCurrentGesture() {
getHomeButton().abortCurrentGesture();
}
@@ -589,7 +560,7 @@ public class NavigationBarView extends FrameLayout implements
return (mDisabledFlags & View.STATUS_BAR_DISABLE_RECENT) == 0;
}
- public boolean isQuickStepSwipeUpEnabled() {
+ private boolean isQuickStepSwipeUpEnabled() {
return mOverviewProxyService.shouldShowSwipeUpUI() && isOverviewEnabled();
}
@@ -618,7 +589,7 @@ public class NavigationBarView extends FrameLayout implements
/**
* Updates the rotation button based on the current navigation mode.
*/
- private void updateRotationButton() {
+ void updateRotationButton() {
if (isGesturalMode(mNavBarMode)) {
mContextualButtonGroup.removeButton(R.id.rotate_suggestion);
mButtonDispatchers.remove(R.id.rotate_suggestion);
@@ -722,25 +693,13 @@ public class NavigationBarView extends FrameLayout implements
super.setLayoutDirection(layoutDirection);
}
- public void setNavigationIconHints(int hints) {
+ void setNavigationIconHints(int hints) {
if (hints == mNavigationIconHints) return;
- final boolean newBackAlt = (hints & StatusBarManager.NAVIGATION_HINT_BACK_ALT) != 0;
- final boolean oldBackAlt =
- (mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_BACK_ALT) != 0;
- if (newBackAlt != oldBackAlt) {
- onImeVisibilityChanged(newBackAlt);
- }
-
- if (DEBUG) {
- android.widget.Toast.makeText(getContext(),
- "Navigation icon hints = " + hints,
- 500).show();
- }
mNavigationIconHints = hints;
updateNavButtonIcons();
}
- private void onImeVisibilityChanged(boolean visible) {
+ void onImeVisibilityChanged(boolean visible) {
if (!visible) {
mTransitionListener.onBackAltCleared();
}
@@ -751,7 +710,7 @@ public class NavigationBarView extends FrameLayout implements
}
}
- public void setDisabledFlags(int disabledFlags) {
+ void setDisabledFlags(int disabledFlags, SysUiState sysUiState) {
if (mDisabledFlags == disabledFlags) return;
final boolean overviewEnabledBefore = isOverviewEnabled();
@@ -764,7 +723,7 @@ public class NavigationBarView extends FrameLayout implements
updateNavButtonIcons();
updateSlippery();
- updateDisabledSystemUiStateFlags();
+ updateDisabledSystemUiStateFlags(sysUiState);
}
public void updateNavButtonIcons() {
@@ -907,10 +866,11 @@ public class NavigationBarView extends FrameLayout implements
updateSlippery();
}
- public void updateDisabledSystemUiStateFlags() {
+ /** */
+ public void updateDisabledSystemUiStateFlags(SysUiState sysUiState) {
int displayId = mContext.getDisplayId();
- mSysUiFlagContainer.setFlag(SYSUI_STATE_SCREEN_PINNING,
+ sysUiState.setFlag(SYSUI_STATE_SCREEN_PINNING,
ActivityManagerWrapper.getInstance().isScreenPinningActive())
.setFlag(SYSUI_STATE_OVERVIEW_DISABLED,
(mDisabledFlags & View.STATUS_BAR_DISABLE_RECENT) != 0)
@@ -952,12 +912,12 @@ public class NavigationBarView extends FrameLayout implements
* slippery is enabled, touch events will leave the nav bar window and enter into the fullscreen
* app/home window, if not nav bar will receive a cancelled touch event once gesture leaves bar.
*/
- public void updateSlippery() {
+ void updateSlippery() {
setSlippery(!isQuickStepSwipeUpEnabled() ||
(mPanelView != null && mPanelView.isFullyExpanded() && !mPanelView.isCollapsing()));
}
- private void setSlippery(boolean slippery) {
+ void setSlippery(boolean slippery) {
setWindowFlag(WindowManager.LayoutParams.FLAG_SLIPPERY, slippery);
}
@@ -979,8 +939,7 @@ public class NavigationBarView extends FrameLayout implements
wm.updateViewLayout(navbarView, lp);
}
- @Override
- public void onNavigationModeChanged(int mode) {
+ void setNavBarMode(int mode) {
mNavBarMode = mode;
mImeDrawsImeNavBar = Dependency.get(NavigationModeController.class).getImeDrawsImeNavBar();
mBarTransitions.onNavigationModeChanged(mNavBarMode);
@@ -1323,7 +1282,6 @@ public class NavigationBarView extends FrameLayout implements
mEdgeBackGestureHandler.onNavBarAttached();
requestApplyInsets();
reorient();
- onNavigationModeChanged(mNavBarMode);
if (mRotationButtonController != null) {
mRotationButtonController.registerListeners();
}
@@ -1338,7 +1296,6 @@ public class NavigationBarView extends FrameLayout implements
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
- Dependency.get(NavigationModeController.class).removeListener(this);
for (int i = 0; i < mButtonDispatchers.size(); ++i) {
mButtonDispatchers.valueAt(i).onDestroy();
}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
index 4dacf5dfd78c..001a4628916f 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
@@ -57,6 +57,7 @@ import android.view.WindowMetrics;
import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
import com.android.internal.policy.GestureNavigationSettingsObserver;
+import com.android.internal.util.LatencyTracker;
import com.android.systemui.R;
import com.android.systemui.SystemUIFactory;
import com.android.systemui.broadcast.BroadcastDispatcher;
@@ -198,6 +199,7 @@ public class EdgeBackGestureHandler extends CurrentUserTracker
private final Rect mNavBarOverlayExcludedBounds = new Rect();
private final Region mExcludeRegion = new Region();
private final Region mUnrestrictedExcludeRegion = new Region();
+ private final LatencyTracker mLatencyTracker;
// The left side edge width where touch down is allowed
private int mEdgeWidthLeft;
@@ -302,7 +304,7 @@ public class EdgeBackGestureHandler extends CurrentUserTracker
BroadcastDispatcher broadcastDispatcher, ProtoTracer protoTracer,
NavigationModeController navigationModeController, ViewConfiguration viewConfiguration,
WindowManager windowManager, IWindowManager windowManagerService,
- FalsingManager falsingManager) {
+ FalsingManager falsingManager, LatencyTracker latencyTracker) {
super(broadcastDispatcher);
mContext = context;
mDisplayId = context.getDisplayId();
@@ -316,6 +318,7 @@ public class EdgeBackGestureHandler extends CurrentUserTracker
mWindowManager = windowManager;
mWindowManagerService = windowManagerService;
mFalsingManager = falsingManager;
+ mLatencyTracker = latencyTracker;
ComponentName recentsComponentName = ComponentName.unflattenFromString(
context.getString(com.android.internal.R.string.config_recentsComponentName));
if (recentsComponentName != null) {
@@ -505,7 +508,8 @@ public class EdgeBackGestureHandler extends CurrentUserTracker
Choreographer.getInstance(), this::onInputEvent);
// Add a nav bar panel window
- setEdgeBackPlugin(new NavigationBarEdgePanel(mContext, mBackAnimation));
+ setEdgeBackPlugin(
+ new NavigationBarEdgePanel(mContext, mBackAnimation, mLatencyTracker));
mPluginManager.addPluginListener(
this, NavigationEdgeBackPlugin.class, /*allowMultiple=*/ false);
}
@@ -520,7 +524,7 @@ public class EdgeBackGestureHandler extends CurrentUserTracker
@Override
public void onPluginDisconnected(NavigationEdgeBackPlugin plugin) {
- setEdgeBackPlugin(new NavigationBarEdgePanel(mContext, mBackAnimation));
+ setEdgeBackPlugin(new NavigationBarEdgePanel(mContext, mBackAnimation, mLatencyTracker));
}
private void setEdgeBackPlugin(NavigationEdgeBackPlugin edgeBackPlugin) {
@@ -968,6 +972,7 @@ public class EdgeBackGestureHandler extends CurrentUserTracker
private final WindowManager mWindowManager;
private final IWindowManager mWindowManagerService;
private final FalsingManager mFalsingManager;
+ private final LatencyTracker mLatencyTracker;
@Inject
public Factory(OverviewProxyService overviewProxyService,
@@ -975,7 +980,8 @@ public class EdgeBackGestureHandler extends CurrentUserTracker
BroadcastDispatcher broadcastDispatcher, ProtoTracer protoTracer,
NavigationModeController navigationModeController,
ViewConfiguration viewConfiguration, WindowManager windowManager,
- IWindowManager windowManagerService, FalsingManager falsingManager) {
+ IWindowManager windowManagerService, FalsingManager falsingManager,
+ LatencyTracker latencyTracker) {
mOverviewProxyService = overviewProxyService;
mSysUiState = sysUiState;
mPluginManager = pluginManager;
@@ -987,6 +993,7 @@ public class EdgeBackGestureHandler extends CurrentUserTracker
mWindowManager = windowManager;
mWindowManagerService = windowManagerService;
mFalsingManager = falsingManager;
+ mLatencyTracker = latencyTracker;
}
/** Construct a {@link EdgeBackGestureHandler}. */
@@ -994,7 +1001,7 @@ public class EdgeBackGestureHandler extends CurrentUserTracker
return new EdgeBackGestureHandler(context, mOverviewProxyService, mSysUiState,
mPluginManager, mExecutor, mBroadcastDispatcher, mProtoTracer,
mNavigationModeController, mViewConfiguration, mWindowManager,
- mWindowManagerService, mFalsingManager);
+ mWindowManagerService, mFalsingManager, mLatencyTracker);
}
}
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 a6919e826d4f..a1258df7a12c 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationBarEdgePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationBarEdgePanel.java
@@ -51,6 +51,7 @@ import androidx.dynamicanimation.animation.FloatPropertyCompat;
import androidx.dynamicanimation.animation.SpringAnimation;
import androidx.dynamicanimation.animation.SpringForce;
+import com.android.internal.util.LatencyTracker;
import com.android.settingslib.Utils;
import com.android.systemui.Dependency;
import com.android.systemui.R;
@@ -176,6 +177,7 @@ public class NavigationBarEdgePanel extends View implements NavigationEdgeBackPl
private final ValueAnimator mArrowDisappearAnimation;
private final SpringForce mRegularTranslationSpring;
private final SpringForce mTriggerBackSpring;
+ private final LatencyTracker mLatencyTracker;
private VelocityTracker mVelocityTracker;
private boolean mIsDark = false;
@@ -225,6 +227,7 @@ public class NavigationBarEdgePanel extends View implements NavigationEdgeBackPl
private float mDisappearAmount;
private long mVibrationTime;
private int mScreenSize;
+ private boolean mTrackingBackArrowLatency = false;
private final Handler mHandler = new Handler();
private final Runnable mFailsafeRunnable = this::onFailsafe;
@@ -283,7 +286,7 @@ public class NavigationBarEdgePanel extends View implements NavigationEdgeBackPl
private BackAnimation mBackAnimation;
public NavigationBarEdgePanel(Context context,
- BackAnimation backAnimation) {
+ BackAnimation backAnimation, LatencyTracker latencyTracker) {
super(context);
mWindowManager = context.getSystemService(WindowManager.class);
@@ -383,6 +386,7 @@ public class NavigationBarEdgePanel extends View implements NavigationEdgeBackPl
}, backgroundExecutor);
mRegionSamplingHelper.setWindowVisible(true);
mShowProtection = !isPrimaryDisplay;
+ mLatencyTracker = latencyTracker;
}
public void setBackAnimation(BackAnimation backAnimation) {
@@ -492,6 +496,8 @@ public class NavigationBarEdgePanel extends View implements NavigationEdgeBackPl
updatePosition(event.getY());
mRegionSamplingHelper.start(mSamplingRect);
mWindowManager.updateViewLayout(this, mLayoutParams);
+ mLatencyTracker.onActionStart(LatencyTracker.ACTION_SHOW_BACK_ARROW);
+ mTrackingBackArrowLatency = true;
break;
case MotionEvent.ACTION_MOVE:
handleMoveEvent(event);
@@ -547,6 +553,10 @@ public class NavigationBarEdgePanel extends View implements NavigationEdgeBackPl
canvas.drawPath(arrowPath, mPaint);
canvas.restore();
+ if (mTrackingBackArrowLatency) {
+ mLatencyTracker.onActionEnd(LatencyTracker.ACTION_SHOW_BACK_ARROW);
+ mTrackingBackArrowLatency = false;
+ }
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
index 039c33315741..2ac34b22be5b 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
@@ -60,6 +60,7 @@ import com.android.settingslib.fuelgauge.BatterySaverUtils;
import com.android.settingslib.utils.PowerUtil;
import com.android.systemui.R;
import com.android.systemui.SystemUIApplication;
+import com.android.systemui.broadcast.BroadcastSender;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.statusbar.phone.SystemUIDialog;
@@ -97,7 +98,7 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI {
"SHOWING_AUTO_SAVER_SUGGESTION",
};
- private static final String ACTION_SHOW_BATTERY_SETTINGS = "PNW.batterySettings";
+ private static final String ACTION_SHOW_BATTERY_SAVER_SETTINGS = "PNW.batterySaverSettings";
private static final String ACTION_START_SAVER = "PNW.startSaver";
private static final String ACTION_DISMISSED_WARNING = "PNW.dismissedWarning";
private static final String ACTION_CLICKED_TEMP_WARNING = "PNW.clickedTempWarning";
@@ -120,8 +121,6 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI {
private static final String ACTION_ENABLE_SEVERE_BATTERY_DIALOG = "PNW.enableSevereDialog";
- private static final String SETTINGS_ACTION_OPEN_BATTERY_SAVER_SETTING =
- "android.settings.BATTERY_SAVER_SETTINGS";
public static final String BATTERY_SAVER_SCHEDULE_SCREEN_INTENT_ACTION =
"com.android.settings.BATTERY_SAVER_SCHEDULE_SETTINGS";
@@ -140,6 +139,9 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI {
private final Handler mHandler = new Handler(Looper.getMainLooper());
private final Receiver mReceiver = new Receiver();
private final Intent mOpenBatterySettings = settings(Intent.ACTION_POWER_USAGE_SUMMARY);
+ private final Intent mOpenBatterySaverSettings =
+ settings(Settings.ACTION_BATTERY_SAVER_SETTINGS);
+ private final boolean mUseSevereDialog;
private int mBatteryLevel;
private int mBucket;
@@ -159,17 +161,21 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI {
@VisibleForTesting SystemUIDialog mUsbHighTempDialog;
private BatteryStateSnapshot mCurrentBatterySnapshot;
private ActivityStarter mActivityStarter;
+ private final BroadcastSender mBroadcastSender;
/**
*/
@Inject
- public PowerNotificationWarnings(Context context, ActivityStarter activityStarter) {
+ public PowerNotificationWarnings(Context context, ActivityStarter activityStarter,
+ BroadcastSender broadcastSender) {
mContext = context;
mNoMan = mContext.getSystemService(NotificationManager.class);
mPowerMan = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
mKeyguard = mContext.getSystemService(KeyguardManager.class);
mReceiver.init();
mActivityStarter = activityStarter;
+ mBroadcastSender = broadcastSender;
+ mUseSevereDialog = mContext.getResources().getBoolean(R.bool.config_severe_battery_dialog);
}
@Override
@@ -256,7 +262,7 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI {
protected void showWarningNotification() {
if (showSevereLowBatteryDialog()) {
- mContext.sendBroadcast(new Intent(ACTION_ENABLE_SEVERE_BATTERY_DIALOG)
+ mBroadcastSender.sendBroadcast(new Intent(ACTION_ENABLE_SEVERE_BATTERY_DIALOG)
.setPackage(mContext.getPackageName())
.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
| Intent.FLAG_RECEIVER_FOREGROUND));
@@ -283,11 +289,11 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI {
.setContentText(contentText)
.setContentTitle(title)
.setOnlyAlertOnce(true)
- .setDeleteIntent(pendingBroadcast(ACTION_DISMISSED_WARNING))
+ .setOngoing(true)
.setStyle(new Notification.BigTextStyle().bigText(contentText))
.setVisibility(Notification.VISIBILITY_PUBLIC);
if (hasBatterySettings()) {
- nb.setContentIntent(pendingBroadcast(ACTION_SHOW_BATTERY_SETTINGS));
+ nb.setContentIntent(pendingBroadcast(ACTION_SHOW_BATTERY_SAVER_SETTINGS));
}
// Make the notification red if the percentage goes below a certain amount or the time
// remaining estimate is disabled
@@ -298,6 +304,8 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI {
}
if (!mPowerMan.isPowerSaveMode()) {
+ nb.addAction(0, mContext.getString(R.string.battery_saver_dismiss_action),
+ pendingBroadcast(ACTION_DISMISSED_WARNING));
nb.addAction(0,
mContext.getString(R.string.battery_saver_start_action),
pendingBroadcast(ACTION_START_SAVER));
@@ -312,9 +320,7 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI {
private boolean showSevereLowBatteryDialog() {
final boolean isSevereState = !mCurrentBatterySnapshot.isHybrid() || mBucket < -1;
- final boolean useSevereDialog = mContext.getResources().getBoolean(
- R.bool.config_severe_battery_dialog);
- return isSevereState && useSevereDialog;
+ return isSevereState && mUseSevereDialog;
}
private void showAutoSaverSuggestionNotification() {
@@ -714,9 +720,9 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI {
mSaverConfirmation.dismiss();
}
// Also close the notification shade, if it's open.
- mContext.sendBroadcast(
+ mBroadcastSender.sendBroadcast(
new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)
- .setFlags(Intent.FLAG_RECEIVER_FOREGROUND));
+ .setFlags(Intent.FLAG_RECEIVER_FOREGROUND));
final Uri uri = Uri.parse(getURL());
Context context = widget.getContext();
@@ -748,7 +754,7 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI {
public void init() {
IntentFilter filter = new IntentFilter();
- filter.addAction(ACTION_SHOW_BATTERY_SETTINGS);
+ filter.addAction(ACTION_SHOW_BATTERY_SAVER_SETTINGS);
filter.addAction(ACTION_START_SAVER);
filter.addAction(ACTION_DISMISSED_WARNING);
filter.addAction(ACTION_CLICKED_TEMP_WARNING);
@@ -768,9 +774,9 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI {
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
Slog.i(TAG, "Received " + action);
- if (action.equals(ACTION_SHOW_BATTERY_SETTINGS)) {
+ if (action.equals(ACTION_SHOW_BATTERY_SAVER_SETTINGS)) {
dismissLowBatteryNotification();
- mContext.startActivityAsUser(mOpenBatterySettings, UserHandle.CURRENT);
+ mContext.startActivityAsUser(mOpenBatterySaverSettings, UserHandle.CURRENT);
} else if (action.equals(ACTION_START_SAVER)) {
setSaverMode(true, true);
dismissLowBatteryNotification();
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
index 56528c9974ac..61b434d6a28f 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
@@ -51,7 +51,6 @@ import com.android.systemui.statusbar.phone.CentralSurfaces;
import java.io.FileDescriptor;
import java.io.PrintWriter;
-import java.time.Duration;
import java.util.Arrays;
import java.util.Optional;
import java.util.concurrent.Future;
@@ -70,7 +69,6 @@ public class PowerUI extends CoreStartable implements CommandQueue.Callbacks {
private static final int MAX_RECENT_TEMPS = 125; // TEMPERATURE_LOGGING_INTERVAL plus a buffer
static final long THREE_HOURS_IN_MILLIS = DateUtils.HOUR_IN_MILLIS * 3;
private static final int CHARGE_CYCLE_PERCENT_RESET = 30;
- private static final long SIX_HOURS_MILLIS = Duration.ofHours(6).toMillis();
public static final int NO_ESTIMATE_AVAILABLE = -1;
private static final String BOOT_COUNT_KEY = "boot_count";
private static final String PREFS = "powerui_prefs";
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt b/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt
index 9cd97ff8e343..2a6ca1acb38e 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt
+++ b/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt
@@ -22,13 +22,14 @@ import android.widget.ImageView
import android.widget.LinearLayout
import com.android.settingslib.Utils
import com.android.systemui.R
+import com.android.systemui.statusbar.events.BackgroundAnimatableView
class OngoingPrivacyChip @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttrs: Int = 0,
defStyleRes: Int = 0
-) : FrameLayout(context, attrs, defStyleAttrs, defStyleRes) {
+) : FrameLayout(context, attrs, defStyleAttrs, defStyleRes), BackgroundAnimatableView {
private var iconMargin = 0
private var iconSize = 0
@@ -50,6 +51,16 @@ class OngoingPrivacyChip @JvmOverloads constructor(
updateResources()
}
+ /**
+ * When animating as a chip in the status bar, we want to animate the width for the container
+ * of the privacy items. We have to subtract our own top and left offset because the bounds
+ * come to us as absolute on-screen bounds, and `iconsContainer` is laid out relative to the
+ * frame layout's bounds.
+ */
+ override fun setBoundsForAnimation(l: Int, t: Int, r: Int, b: Int) {
+ iconsContainer.setLeftTopRightBottom(l - left, t - top, r - left, b - top)
+ }
+
// Should only be called if the builder icons or app changed
private fun updateView(builder: PrivacyChipBuilder) {
fun setIcons(chipBuilder: PrivacyChipBuilder, iconsContainer: ViewGroup) {
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogController.kt b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogController.kt
index 61071235db0b..8147877a8a29 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogController.kt
+++ b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogController.kt
@@ -150,24 +150,27 @@ class PrivacyDialogController(
packageName: String,
userId: Int,
permGroupName: CharSequence,
- attributionTag: CharSequence?
+ attributionTag: CharSequence?,
+ isAttributionSupported: Boolean
): Intent
{
lateinit var intent: Intent
- if (attributionTag != null) {
+ if (attributionTag != null && isAttributionSupported) {
intent = Intent(Intent.ACTION_MANAGE_PERMISSION_USAGE)
intent.setPackage(packageName)
intent.putExtra(Intent.EXTRA_PERMISSION_GROUP_NAME, permGroupName.toString())
intent.putExtra(Intent.EXTRA_ATTRIBUTION_TAGS, arrayOf(attributionTag.toString()))
intent.putExtra(Intent.EXTRA_SHOWING_ATTRIBUTION, true)
val resolveInfo = packageManager.resolveActivity(
- intent, PackageManager.ResolveInfoFlags.of(0))
- ?: return getDefaultManageAppPermissionsIntent(packageName, userId)
- intent.component = ComponentName(packageName, resolveInfo.activityInfo.name)
- return intent
- } else {
- return getDefaultManageAppPermissionsIntent(packageName, userId)
+ intent, PackageManager.ResolveInfoFlags.of(0))
+ if (resolveInfo != null && resolveInfo.activityInfo != null &&
+ resolveInfo.activityInfo.permission ==
+ android.Manifest.permission.START_VIEW_PERMISSION_USAGE) {
+ intent.component = ComponentName(packageName, resolveInfo.activityInfo.name)
+ return intent
+ }
}
+ return getDefaultManageAppPermissionsIntent(packageName, userId)
}
fun getDefaultManageAppPermissionsIntent(packageName: String, userId: Int): Intent {
@@ -226,9 +229,15 @@ class PrivacyDialogController(
userInfo?.isManagedProfile ?: false,
it.isPhoneCall,
it.permissionGroupName,
- getManagePermissionIntent(it.packageName, userId,
- it.permissionGroupName,
- it.attributionTag)
+ getManagePermissionIntent(
+ it.packageName,
+ userId,
+ it.permissionGroupName,
+ it.attributionTag,
+ // attributionLabel is set only when subattribution policies
+ // are supported and satisfied
+ it.attributionLabel != null
+ )
)
}
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/qrcodescanner/controller/QRCodeScannerController.java b/packages/SystemUI/src/com/android/systemui/qrcodescanner/controller/QRCodeScannerController.java
index e26c768a5e80..8000bdccfa68 100644
--- a/packages/SystemUI/src/com/android/systemui/qrcodescanner/controller/QRCodeScannerController.java
+++ b/packages/SystemUI/src/com/android/systemui/qrcodescanner/controller/QRCodeScannerController.java
@@ -160,14 +160,15 @@ public class QRCodeScannerController implements
* Returns true if lock screen entry point for QR Code Scanner is to be enabled.
*/
public boolean isEnabledForLockScreenButton() {
- return mQRCodeScannerEnabled && mIntent != null && mConfigEnableLockScreenButton;
+ return mQRCodeScannerEnabled && mIntent != null && mConfigEnableLockScreenButton
+ && isActivityCallable(mIntent);
}
/**
* Returns true if quick settings entry point for QR Code Scanner is to be enabled.
*/
public boolean isEnabledForQuickSettings() {
- return mIntent != null;
+ return mIntent != null && isActivityCallable(mIntent);
}
/**
@@ -278,7 +279,7 @@ public class QRCodeScannerController implements
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
}
- if (isActivityCallable(intent)) {
+ if (isActivityAvailable(intent)) {
mQRCodeScannerActivity = qrCodeScannerActivity;
mComponentName = componentName;
mIntent = intent;
@@ -293,7 +294,7 @@ public class QRCodeScannerController implements
}
}
- private boolean isActivityCallable(Intent intent) {
+ private boolean isActivityAvailable(Intent intent) {
// Our intent should always be explicit and should have a component set
if (intent.getComponent() == null) return false;
@@ -307,6 +308,17 @@ public class QRCodeScannerController implements
flags).isEmpty();
}
+ private boolean isActivityCallable(Intent intent) {
+ // Our intent should always be explicit and should have a component set
+ if (intent.getComponent() == null) return false;
+
+ int flags = PackageManager.MATCH_DIRECT_BOOT_AWARE
+ | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
+ | PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS;
+ return !mContext.getPackageManager().queryIntentActivities(intent,
+ flags).isEmpty();
+ }
+
private void unregisterUserChangeObservers() {
mUserTracker.removeCallback(mUserChangedListener);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/FgsManagerController.kt b/packages/SystemUI/src/com/android/systemui/qs/FgsManagerController.kt
index 5d9361d201c1..e0d158cd7db6 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/FgsManagerController.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/FgsManagerController.kt
@@ -18,7 +18,10 @@ package com.android.systemui.qs
import android.app.IActivityManager
import android.app.IForegroundServiceObserver
+import android.content.BroadcastReceiver
import android.content.Context
+import android.content.Intent
+import android.content.IntentFilter
import android.content.pm.PackageManager
import android.graphics.drawable.Drawable
import android.os.IBinder
@@ -42,6 +45,7 @@ import com.android.internal.config.sysui.SystemUiDeviceConfigFlags.TASK_MANAGER_
import com.android.systemui.Dumpable
import com.android.systemui.R
import com.android.systemui.animation.DialogLaunchAnimator
+import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
@@ -67,6 +71,7 @@ class FgsManagerController @Inject constructor(
private val packageManager: PackageManager,
private val deviceConfigProxy: DeviceConfigProxy,
private val dialogLaunchAnimator: DialogLaunchAnimator,
+ private val broadcastDispatcher: BroadcastDispatcher,
private val dumpManager: DumpManager
) : IForegroundServiceObserver.Stub(), Dumpable {
@@ -125,6 +130,18 @@ class FgsManagerController @Inject constructor(
dumpManager.registerDumpable(this)
+ broadcastDispatcher.registerReceiver(
+ object : BroadcastReceiver() {
+ override fun onReceive(context: Context, intent: Intent) {
+ if (intent.action == Intent.ACTION_SHOW_FOREGROUND_SERVICE_MANAGER) {
+ showDialog(null)
+ }
+ }
+ },
+ IntentFilter(Intent.ACTION_SHOW_FOREGROUND_SERVICE_MANAGER),
+ executor = mainExecutor,
+ flags = Context.RECEIVER_NOT_EXPORTED)
+
initialized = true
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
index d1b569f7f438..4640205c82f5 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
@@ -241,7 +241,13 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha
private void addNonFirstPageAnimators(int page) {
Pair<HeightExpansionAnimator, TouchAnimator> pair = createSecondaryPageAnimators(page);
- mNonFirstPageQSAnimators.put(page, pair);
+ if (pair != null) {
+ // pair is null in one of two cases:
+ // * mPagedTileLayout is null, meaning we are still setting up.
+ // * the page has no tiles
+ // In either case, don't add the animators to the map.
+ mNonFirstPageQSAnimators.put(page, pair);
+ }
}
@Override
@@ -518,6 +524,13 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha
SideLabelTileLayout qqsLayout = (SideLabelTileLayout) mQuickQsPanel.getTileLayout();
View view = mQs.getView();
List<String> specs = mPagedLayout.getSpecsForPage(page);
+ if (specs.isEmpty()) {
+ // specs should not be empty in a valid secondary page, as we scrolled to it.
+ // We may crash later on because there's a null animator.
+ specs = mQsPanelController.getHost().mTileSpecs;
+ Log.e(TAG, "Trying to create animators for empty page " + page + ". Tiles: " + specs);
+ // return null;
+ }
int row = -1;
int lastTileTop = -1;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index 3ef72202a591..fe8c309ad2f3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -573,6 +573,7 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
if (mQSAnimator != null) {
mQSAnimator.setPosition(expansion);
}
+ mQqsMediaHost.setSquishFraction(mSquishinessFraction);
updateMediaPositions();
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java
index 00142799c541..865f09337fa3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java
@@ -199,9 +199,7 @@ public class QSPanelController extends QSPanelControllerBase<QSPanel> {
/** */
public void setListening(boolean listening, boolean expanded) {
- // TODO(218268829): checking for split shade is workaround but when proper fix lands
- // "|| mShouldUseSplitNotificationShade" should be removed
- setListening(listening && (expanded || mShouldUseSplitNotificationShade));
+ setListening(listening && expanded);
if (mView.isListening()) {
refreshAllTiles();
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
index 3824e1b83461..ea9bc6946ffe 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
@@ -325,12 +325,12 @@ class QSSecurityFooter implements OnClickListener, DialogInterface.OnClickListen
private String getManagedDeviceMonitoringText(CharSequence organizationName) {
if (organizationName == null) {
- return mDpm.getString(
+ return mDpm.getResources().getString(
QS_MSG_MANAGEMENT_MONITORING,
() -> mContext.getString(
R.string.quick_settings_disclosure_management_monitoring));
}
- return mDpm.getString(
+ return mDpm.getResources().getString(
QS_MSG_NAMED_MANAGEMENT_MONITORING,
() -> mContext.getString(
R.string.quick_settings_disclosure_named_management_monitoring,
@@ -342,12 +342,12 @@ class QSSecurityFooter implements OnClickListener, DialogInterface.OnClickListen
String vpnName, String vpnNameWorkProfile, CharSequence organizationName) {
if (vpnName != null && vpnNameWorkProfile != null) {
if (organizationName == null) {
- return mDpm.getString(
+ return mDpm.getResources().getString(
QS_MSG_MANAGEMENT_MULTIPLE_VPNS,
() -> mContext.getString(
R.string.quick_settings_disclosure_management_vpns));
}
- return mDpm.getString(
+ return mDpm.getResources().getString(
QS_MSG_NAMED_MANAGEMENT_MULTIPLE_VPNS,
() -> mContext.getString(
R.string.quick_settings_disclosure_named_management_vpns,
@@ -356,14 +356,14 @@ class QSSecurityFooter implements OnClickListener, DialogInterface.OnClickListen
}
String name = vpnName != null ? vpnName : vpnNameWorkProfile;
if (organizationName == null) {
- return mDpm.getString(
+ return mDpm.getResources().getString(
QS_MSG_MANAGEMENT_NAMED_VPN,
() -> mContext.getString(
R.string.quick_settings_disclosure_management_named_vpn,
name),
name);
}
- return mDpm.getString(
+ return mDpm.getResources().getString(
QS_MSG_NAMED_MANAGEMENT_NAMED_VPN,
() -> mContext.getString(
R.string.quick_settings_disclosure_named_management_named_vpn,
@@ -375,7 +375,7 @@ class QSSecurityFooter implements OnClickListener, DialogInterface.OnClickListen
private String getMangedDeviceGeneralText(CharSequence organizationName) {
if (organizationName == null) {
- return mDpm.getString(
+ return mDpm.getResources().getString(
QS_MSG_MANAGEMENT,
() -> mContext.getString(
R.string.quick_settings_disclosure_management));
@@ -385,7 +385,7 @@ class QSSecurityFooter implements OnClickListener, DialogInterface.OnClickListen
R.string.quick_settings_financed_disclosure_named_management,
organizationName);
} else {
- return mDpm.getString(
+ return mDpm.getResources().getString(
QS_MSG_NAMED_MANAGEMENT,
() -> mContext.getString(
R.string.quick_settings_disclosure_named_management,
@@ -419,12 +419,12 @@ class QSSecurityFooter implements OnClickListener, DialogInterface.OnClickListen
CharSequence workProfileOrganizationName, boolean isWorkProfileOn) {
if (hasCACertsInWorkProfile && isWorkProfileOn) {
if (workProfileOrganizationName == null) {
- return mDpm.getString(
+ return mDpm.getResources().getString(
QS_MSG_WORK_PROFILE_MONITORING,
() -> mContext.getString(
R.string.quick_settings_disclosure_managed_profile_monitoring));
}
- return mDpm.getString(
+ return mDpm.getResources().getString(
QS_MSG_NAMED_WORK_PROFILE_MONITORING,
() -> mContext.getString(
R.string.quick_settings_disclosure_named_managed_profile_monitoring,
@@ -443,7 +443,7 @@ class QSSecurityFooter implements OnClickListener, DialogInterface.OnClickListen
return mContext.getString(R.string.quick_settings_disclosure_vpns);
}
if (vpnNameWorkProfile != null && isWorkProfileOn) {
- return mDpm.getString(
+ return mDpm.getResources().getString(
QS_MSG_WORK_PROFILE_NAMED_VPN,
() -> mContext.getString(
R.string.quick_settings_disclosure_managed_profile_named_vpn,
@@ -452,7 +452,7 @@ class QSSecurityFooter implements OnClickListener, DialogInterface.OnClickListen
}
if (vpnName != null) {
if (hasWorkProfile) {
- return mDpm.getString(
+ return mDpm.getResources().getString(
QS_MSG_PERSONAL_PROFILE_NAMED_VPN,
() -> mContext.getString(
R.string.quick_settings_disclosure_personal_profile_named_vpn,
@@ -466,7 +466,7 @@ class QSSecurityFooter implements OnClickListener, DialogInterface.OnClickListen
}
private String getManagedProfileNetworkActivityText() {
- return mDpm.getString(
+ return mDpm.getResources().getString(
QS_MSG_WORK_PROFILE_NETWORK,
() -> mContext.getString(
R.string.quick_settings_disclosure_managed_profile_network_activity));
@@ -634,7 +634,7 @@ class QSSecurityFooter implements OnClickListener, DialogInterface.OnClickListen
@VisibleForTesting
String getSettingsButton() {
- return mDpm.getString(
+ return mDpm.getResources().getString(
QS_DIALOG_VIEW_POLICIES,
() -> mContext.getString(R.string.monitoring_button_view_policies));
}
@@ -662,7 +662,7 @@ class QSSecurityFooter implements OnClickListener, DialogInterface.OnClickListen
return mContext.getString(R.string.monitoring_financed_description_named_management,
organizationName, organizationName);
} else {
- return mDpm.getString(
+ return mDpm.getResources().getString(
QS_DIALOG_NAMED_MANAGEMENT,
() -> mContext.getString(
R.string.monitoring_description_named_management,
@@ -670,7 +670,7 @@ class QSSecurityFooter implements OnClickListener, DialogInterface.OnClickListen
organizationName);
}
}
- return mDpm.getString(
+ return mDpm.getResources().getString(
QS_DIALOG_MANAGEMENT,
() -> mContext.getString(R.string.monitoring_description_management));
}
@@ -680,13 +680,13 @@ class QSSecurityFooter implements OnClickListener, DialogInterface.OnClickListen
boolean hasCACertsInWorkProfile) {
if (!(hasCACerts || hasCACertsInWorkProfile)) return null;
if (isDeviceManaged) {
- return mDpm.getString(
+ return mDpm.getResources().getString(
QS_DIALOG_MANAGEMENT_CA_CERT,
() -> mContext.getString(
R.string.monitoring_description_management_ca_certificate));
}
if (hasCACertsInWorkProfile) {
- return mDpm.getString(
+ return mDpm.getResources().getString(
QS_DIALOG_WORK_PROFILE_CA_CERT,
() -> mContext.getString(
R.string.monitoring_description_managed_profile_ca_certificate));
@@ -699,12 +699,12 @@ class QSSecurityFooter implements OnClickListener, DialogInterface.OnClickListen
boolean isNetworkLoggingEnabled) {
if (!isNetworkLoggingEnabled) return null;
if (isDeviceManaged) {
- return mDpm.getString(
+ return mDpm.getResources().getString(
QS_DIALOG_MANAGEMENT_NETWORK,
() -> mContext.getString(
R.string.monitoring_description_management_network_logging));
} else {
- return mDpm.getString(
+ return mDpm.getResources().getString(
QS_DIALOG_WORK_PROFILE_NETWORK,
() -> mContext.getString(
R.string.monitoring_description_managed_profile_network_logging));
@@ -718,7 +718,7 @@ class QSSecurityFooter implements OnClickListener, DialogInterface.OnClickListen
final SpannableStringBuilder message = new SpannableStringBuilder();
if (isDeviceManaged) {
if (vpnName != null && vpnNameWorkProfile != null) {
- String namedVpns = mDpm.getString(
+ String namedVpns = mDpm.getResources().getString(
QS_DIALOG_MANAGEMENT_TWO_NAMED_VPN,
() -> mContext.getString(
R.string.monitoring_description_two_named_vpns,
@@ -727,7 +727,7 @@ class QSSecurityFooter implements OnClickListener, DialogInterface.OnClickListen
message.append(namedVpns);
} else {
String name = vpnName != null ? vpnName : vpnNameWorkProfile;
- String namedVp = mDpm.getString(
+ String namedVp = mDpm.getResources().getString(
QS_DIALOG_MANAGEMENT_NAMED_VPN,
() -> mContext.getString(R.string.monitoring_description_named_vpn, name),
name);
@@ -735,7 +735,7 @@ class QSSecurityFooter implements OnClickListener, DialogInterface.OnClickListen
}
} else {
if (vpnName != null && vpnNameWorkProfile != null) {
- String namedVpns = mDpm.getString(
+ String namedVpns = mDpm.getResources().getString(
QS_DIALOG_MANAGEMENT_TWO_NAMED_VPN,
() -> mContext.getString(
R.string.monitoring_description_two_named_vpns,
@@ -743,7 +743,7 @@ class QSSecurityFooter implements OnClickListener, DialogInterface.OnClickListen
vpnName, vpnNameWorkProfile);
message.append(namedVpns);
} else if (vpnNameWorkProfile != null) {
- String namedVpn = mDpm.getString(
+ String namedVpn = mDpm.getResources().getString(
QS_DIALOG_WORK_PROFILE_NAMED_VPN,
() -> mContext.getString(
R.string.monitoring_description_managed_profile_named_vpn,
@@ -751,7 +751,7 @@ class QSSecurityFooter implements OnClickListener, DialogInterface.OnClickListen
vpnNameWorkProfile);
message.append(namedVpn);
} else if (hasWorkProfile) {
- String namedVpn = mDpm.getString(
+ String namedVpn = mDpm.getResources().getString(
QS_DIALOG_PERSONAL_PROFILE_NAMED_VPN,
() -> mContext.getString(
R.string.monitoring_description_personal_profile_named_vpn,
@@ -775,7 +775,7 @@ class QSSecurityFooter implements OnClickListener, DialogInterface.OnClickListen
return mContext.getString(R.string.monitoring_title_financed_device,
deviceOwnerOrganization);
} else {
- return mDpm.getString(
+ return mDpm.getResources().getString(
QS_DIALOG_MANAGEMENT_TITLE,
() -> mContext.getString(R.string.monitoring_title_device_owned));
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
index 8c08873b9ab6..f2dd7700e65e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
@@ -102,7 +102,7 @@ public class QuickStatusBarHeader extends FrameLayout {
private int mTopViewMeasureHeight;
@NonNull
- private List<String> mRssiIgnoredSlots;
+ private List<String> mRssiIgnoredSlots = List.of();
private boolean mIsSingleCarrier;
private boolean mHasCenterCutout;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
index 32515a258b46..4cacbbacec2f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
@@ -15,26 +15,22 @@
*/
package com.android.systemui.qs.external;
-import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.graphics.drawable.Icon;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
-import android.os.Looper;
import android.os.RemoteException;
import android.os.UserHandle;
import android.service.quicksettings.IQSService;
import android.service.quicksettings.Tile;
-import android.service.quicksettings.TileService;
import android.util.ArrayMap;
import android.util.Log;
+import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.internal.statusbar.StatusBarIcon;
@@ -42,6 +38,7 @@ import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.qs.QSTileHost;
import com.android.systemui.settings.UserTracker;
+import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -51,6 +48,7 @@ import java.util.Comparator;
import java.util.Objects;
import javax.inject.Inject;
+import javax.inject.Provider;
/**
* Runs the day-to-day operations of which tiles should be bound and when.
@@ -64,11 +62,12 @@ public class TileServices extends IQSService.Stub {
private final ArrayMap<ComponentName, CustomTile> mTiles = new ArrayMap<>();
private final ArrayMap<IBinder, CustomTile> mTokenMap = new ArrayMap<>();
private final Context mContext;
- private final Handler mHandler;
private final Handler mMainHandler;
+ private final Provider<Handler> mHandlerProvider;
private final QSTileHost mHost;
private final KeyguardStateController mKeyguardStateController;
private final BroadcastDispatcher mBroadcastDispatcher;
+ private final CommandQueue mCommandQueue;
private final UserTracker mUserTracker;
private int mMaxBound = DEFAULT_MAX_BOUND;
@@ -76,23 +75,20 @@ public class TileServices extends IQSService.Stub {
@Inject
public TileServices(
QSTileHost host,
- @Main Looper looper,
+ @Main Provider<Handler> handlerProvider,
BroadcastDispatcher broadcastDispatcher,
UserTracker userTracker,
- KeyguardStateController keyguardStateController) {
+ KeyguardStateController keyguardStateController,
+ CommandQueue commandQueue) {
mHost = host;
mKeyguardStateController = keyguardStateController;
mContext = mHost.getContext();
mBroadcastDispatcher = broadcastDispatcher;
- mHandler = new Handler(looper);
- mMainHandler = new Handler(Looper.getMainLooper());
+ mHandlerProvider = handlerProvider;
+ mMainHandler = mHandlerProvider.get();
mUserTracker = userTracker;
- mBroadcastDispatcher.registerReceiver(
- mRequestListeningReceiver,
- new IntentFilter(TileService.ACTION_REQUEST_LISTENING),
- null, // Use the default Executor
- UserHandle.ALL
- );
+ mCommandQueue = commandQueue;
+ mCommandQueue.addCallback(mRequestListeningCallback);
}
public Context getContext() {
@@ -118,7 +114,7 @@ public class TileServices extends IQSService.Stub {
protected TileServiceManager onCreateTileService(ComponentName component,
BroadcastDispatcher broadcastDispatcher) {
- return new TileServiceManager(this, mHandler, component,
+ return new TileServiceManager(this, mHandlerProvider.get(), component,
broadcastDispatcher, mUserTracker);
}
@@ -354,21 +350,14 @@ public class TileServices extends IQSService.Stub {
public void destroy() {
synchronized (mServices) {
mServices.values().forEach(service -> service.handleDestroy());
- mBroadcastDispatcher.unregisterReceiver(mRequestListeningReceiver);
}
+ mCommandQueue.removeCallback(mRequestListeningCallback);
}
- private final BroadcastReceiver mRequestListeningReceiver = new BroadcastReceiver() {
+ private final CommandQueue.Callbacks mRequestListeningCallback = new CommandQueue.Callbacks() {
@Override
- public void onReceive(Context context, Intent intent) {
- if (TileService.ACTION_REQUEST_LISTENING.equals(intent.getAction())) {
- try {
- ComponentName c = intent.getParcelableExtra(Intent.EXTRA_COMPONENT_NAME);
- requestListening(c);
- } catch (ClassCastException ex) {
- Log.e(TAG, "Bad component name", ex);
- }
- }
+ public void requestTileServiceListeningState(@NonNull ComponentName componentName) {
+ mMainHandler.post(() -> requestListening(componentName));
}
};
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/QRCodeScannerTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/QRCodeScannerTile.java
index b65802506cbf..b41502213555 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/QRCodeScannerTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/QRCodeScannerTile.java
@@ -117,7 +117,6 @@ public class QRCodeScannerTile extends QSTileImpl<QSTile.State> {
state.icon = ResourceIcon.get(R.drawable.ic_qr_code_scanner);
state.state = mQRCodeScannerController.isEnabledForQuickSettings() ? Tile.STATE_ACTIVE
: Tile.STATE_UNAVAILABLE;
- state.secondaryLabel = mContext.getString(R.string.qr_code_scanner_description);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java
index 4279b62d54ab..7130294deccb 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java
@@ -104,7 +104,7 @@ public class WorkModeTile extends QSTileImpl<BooleanState> implements
@Override
public CharSequence getTileLabel() {
DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class);
- return dpm.getString(QS_WORK_PROFILE_LABEL,
+ return dpm.getResources().getString(QS_WORK_PROFILE_LABEL,
() -> mContext.getString(R.string.quick_settings_work_mode_label));
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetAdapter.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetAdapter.java
index e1d20706c625..2cc3986c6e82 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetAdapter.java
@@ -21,6 +21,7 @@ import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.text.Html;
import android.text.TextUtils;
+import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -47,9 +48,6 @@ import java.util.concurrent.atomic.AtomicReference;
public class InternetAdapter extends RecyclerView.Adapter<InternetAdapter.InternetViewHolder> {
private static final String TAG = "InternetAdapter";
- private static final String ACTION_WIFI_DIALOG = "com.android.settings.WIFI_DIALOG";
- private static final String EXTRA_CHOSEN_WIFI_ENTRY_KEY = "key_chosen_wifientry_key";
- private static final String EXTRA_CONNECT_FOR_CALLER = "connect_for_caller";
private final InternetDialogController mInternetDialogController;
@Nullable
@@ -161,23 +159,47 @@ public class InternetAdapter extends RecyclerView.Adapter<InternetAdapter.Intern
final int security = wifiEntry.getSecurity();
updateEndIcon(connectedState, security);
+ mWifiListLayout.setEnabled(shouldEnabled(wifiEntry));
if (connectedState != WifiEntry.CONNECTED_STATE_DISCONNECTED) {
mWifiListLayout.setOnClickListener(
- v -> mInternetDialogController.launchWifiNetworkDetailsSetting(
+ v -> mInternetDialogController.launchWifiDetailsSetting(
wifiEntry.getKey(), v));
return;
}
- mWifiListLayout.setOnClickListener(v -> {
- if (wifiEntry.shouldEditBeforeConnect()) {
- final Intent intent = new Intent(ACTION_WIFI_DIALOG);
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
- intent.putExtra(EXTRA_CHOSEN_WIFI_ENTRY_KEY, wifiEntry.getKey());
- intent.putExtra(EXTRA_CONNECT_FOR_CALLER, false);
- mContext.startActivity(intent);
- }
+ mWifiListLayout.setOnClickListener(v -> onWifiClick(wifiEntry, v));
+ }
+
+ boolean shouldEnabled(@NonNull WifiEntry wifiEntry) {
+ if (wifiEntry.canConnect()) {
+ return true;
+ }
+ // If Wi-Fi is connected or saved network, leave it enabled to disconnect or configure.
+ if (wifiEntry.canDisconnect() || wifiEntry.isSaved()) {
+ return true;
+ }
+ return false;
+ }
+
+ void onWifiClick(@NonNull WifiEntry wifiEntry, @NonNull View view) {
+ if (wifiEntry.shouldEditBeforeConnect()) {
+ final Intent intent = WifiUtils.getWifiDialogIntent(wifiEntry.getKey(),
+ true /* connectForCaller */);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
+ mContext.startActivity(intent);
+ return;
+ }
+
+ if (wifiEntry.canConnect()) {
mInternetDialogController.connect(wifiEntry);
- });
+ return;
+ }
+
+ if (wifiEntry.isSaved()) {
+ Log.w(TAG, "The saved Wi-Fi network does not allow to connect. SSID:"
+ + wifiEntry.getSsid());
+ mInternetDialogController.launchWifiDetailsSetting(wifiEntry.getKey(), view);
+ }
}
void setWifiNetworkLayout(CharSequence title, CharSequence summary) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java
index d1c784457c9f..8921e95fcee9 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java
@@ -531,8 +531,7 @@ public class InternetDialog extends SystemUIDialog implements
if (mConnectedWifiEntry == null) {
return;
}
- mInternetDialogController.launchWifiNetworkDetailsSetting(mConnectedWifiEntry.getKey(),
- view);
+ mInternetDialogController.launchWifiDetailsSetting(mConnectedWifiEntry.getKey(), view);
}
void onClickSeeMoreButton(View view) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java
index b3bc3be852fb..d97ce7757d8c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java
@@ -112,7 +112,6 @@ public class InternetDialogController implements AccessPointController.AccessPoi
"android.settings.NETWORK_PROVIDER_SETTINGS";
private static final String ACTION_WIFI_SCANNING_SETTINGS =
"android.settings.WIFI_SCANNING_SETTINGS";
- private static final String EXTRA_CHOSEN_WIFI_ENTRY_KEY = "key_chosen_wifientry_key";
public static final Drawable EMPTY_DRAWABLE = new ColorDrawable(Color.TRANSPARENT);
public static final int NO_CELL_DATA_TYPE_ICON = 0;
private static final int SUBTITLE_TEXT_WIFI_IS_OFF = R.string.wifi_is_off;
@@ -636,7 +635,7 @@ public class InternetDialogController implements AccessPointController.AccessPoi
startActivity(getSettingsIntent(), view);
}
- void launchWifiNetworkDetailsSetting(String key, View view) {
+ void launchWifiDetailsSetting(String key, View view) {
Intent intent = getWifiDetailsSettingsIntent(key);
if (intent != null) {
startActivity(intent, view);
@@ -853,8 +852,8 @@ public class InternetDialogController implements AccessPointController.AccessPoi
}
if (status == WifiEntry.ConnectCallback.CONNECT_STATUS_FAILURE_NO_CONFIG) {
- final Intent intent = new Intent("com.android.settings.WIFI_DIALOG")
- .putExtra(EXTRA_CHOSEN_WIFI_ENTRY_KEY, mWifiEntry.getKey());
+ final Intent intent = WifiUtils.getWifiDialogIntent(mWifiEntry.getKey(),
+ true /* connectForCaller */);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mActivityStarter.startActivity(intent, false /* dismissShade */);
} else if (status == CONNECT_STATUS_FAILURE_UNKNOWN) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index a3dea1c68b14..53a27ff4e08b 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -101,8 +101,8 @@ import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.NotificationShadeWindowController;
-import com.android.systemui.statusbar.phone.NotificationPanelViewController;
import com.android.systemui.statusbar.phone.CentralSurfaces;
+import com.android.systemui.statusbar.phone.NotificationPanelViewController;
import com.android.systemui.statusbar.phone.StatusBarWindowCallback;
import com.android.systemui.statusbar.policy.CallbackController;
import com.android.wm.shell.back.BackAnimation;
@@ -675,7 +675,7 @@ public class OverviewProxyService extends CurrentUserTracker implements
navBarFragment.updateSystemUiStateFlags();
}
if (navBarView != null) {
- navBarView.updateDisabledSystemUiStateFlags();
+ navBarView.updateDisabledSystemUiStateFlags(mSysUiState);
}
if (panelController != null) {
panelController.updateSystemUiStateFlags();
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/DraggableConstraintLayout.java b/packages/SystemUI/src/com/android/systemui/screenshot/DraggableConstraintLayout.java
new file mode 100644
index 000000000000..0b987677eac9
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/DraggableConstraintLayout.java
@@ -0,0 +1,354 @@
+/*
+ * 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.systemui.screenshot;
+
+import static com.android.systemui.screenshot.LogConfig.DEBUG_ANIM;
+import static com.android.systemui.screenshot.LogConfig.DEBUG_DISMISS;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.graphics.Rect;
+import android.graphics.Region;
+import android.util.AttributeSet;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.util.MathUtils;
+import android.view.GestureDetector;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewTreeObserver;
+
+import androidx.constraintlayout.widget.ConstraintLayout;
+
+import com.android.systemui.R;
+
+/**
+ * ConstraintLayout that is draggable when touched in a specific region
+ */
+public class DraggableConstraintLayout extends ConstraintLayout
+ implements ViewTreeObserver.OnComputeInternalInsetsListener {
+
+ private final SwipeDismissHandler mSwipeDismissHandler;
+ private final GestureDetector mSwipeDetector;
+ private View mActionsContainer;
+ private SwipeDismissCallbacks mCallbacks;
+
+ /**
+ * Stores the callbacks when the view is interacted with or dismissed.
+ */
+ public interface SwipeDismissCallbacks {
+ /**
+ * Run when the view is interacted with (touched)
+ */
+ default void onInteraction() {
+
+ }
+
+ /**
+ * Run when the view is dismissed (the distance threshold is met), pre-dismissal animation
+ */
+ default void onSwipeDismissInitiated(Animator animator) {
+
+ }
+
+ /**
+ * Run when the view is dismissed (the distance threshold is met), post-dismissal animation
+ */
+ default void onDismissComplete() {
+
+ }
+ }
+
+ public DraggableConstraintLayout(Context context) {
+ this(context, null);
+ }
+
+ public DraggableConstraintLayout(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public DraggableConstraintLayout(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+
+ mSwipeDismissHandler = new SwipeDismissHandler(mContext, this);
+ setOnTouchListener(mSwipeDismissHandler);
+
+ mSwipeDetector = new GestureDetector(mContext,
+ new GestureDetector.SimpleOnGestureListener() {
+ final Rect mActionsRect = new Rect();
+
+ @Override
+ public boolean onScroll(
+ MotionEvent ev1, MotionEvent ev2, float distanceX, float distanceY) {
+ mActionsContainer.getBoundsOnScreen(mActionsRect);
+ // return true if we aren't in the actions bar, or if we are but it isn't
+ // scrollable in the direction of movement
+ return !mActionsRect.contains((int) ev2.getRawX(), (int) ev2.getRawY())
+ || !mActionsContainer.canScrollHorizontally((int) distanceX);
+ }
+ });
+ mSwipeDetector.setIsLongpressEnabled(false);
+ }
+
+ public void setCallbacks(SwipeDismissCallbacks callbacks) {
+ mCallbacks = callbacks;
+ }
+
+ @Override // View
+ protected void onFinishInflate() {
+ mActionsContainer = findViewById(R.id.actions_container_background);
+ }
+
+ @Override
+ public boolean onInterceptTouchEvent(MotionEvent ev) {
+ if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) {
+ mSwipeDismissHandler.onTouch(this, ev);
+ }
+ return mSwipeDetector.onTouchEvent(ev);
+ }
+
+ public int getVisibleRight() {
+ return mActionsContainer.getRight();
+ }
+
+ /**
+ * Cancel current dismissal animation, if any
+ */
+ public void cancelDismissal() {
+ mSwipeDismissHandler.cancel();
+ }
+
+ /**
+ * Return whether the view is currently dismissing
+ */
+ public boolean isDismissing() {
+ return mSwipeDismissHandler.isDismissing();
+ }
+
+ /**
+ * Dismiss the view, with animation controlled by SwipeDismissHandler
+ */
+ public void dismiss() {
+ mSwipeDismissHandler.dismiss();
+ }
+
+
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ getViewTreeObserver().addOnComputeInternalInsetsListener(this);
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ getViewTreeObserver().removeOnComputeInternalInsetsListener(this);
+ }
+
+ @Override
+ public void onComputeInternalInsets(ViewTreeObserver.InternalInsetsInfo inoutInfo) {
+ // Only child views are touchable.
+ Region r = new Region();
+ Rect rect = new Rect();
+ for (int i = 0; i < getChildCount(); i++) {
+ getChildAt(i).getGlobalVisibleRect(rect);
+ r.op(rect, Region.Op.UNION);
+ }
+ inoutInfo.setTouchableInsets(ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
+ inoutInfo.touchableRegion.set(r);
+ }
+
+ /**
+ * Allows a view to be swipe-dismissed, or returned to its location if distance threshold is not
+ * met
+ */
+ private class SwipeDismissHandler implements OnTouchListener {
+ private static final String TAG = "SwipeDismissHandler";
+
+ // distance needed to register a dismissal
+ private static final float DISMISS_DISTANCE_THRESHOLD_DP = 20;
+
+ private final DraggableConstraintLayout mView;
+ private final GestureDetector mGestureDetector;
+ private final DisplayMetrics mDisplayMetrics;
+ private ValueAnimator mDismissAnimation;
+
+ private float mStartX;
+ // Keeps track of the most recent direction (between the last two move events).
+ // -1 for left; +1 for right.
+ private int mDirectionX;
+ private float mPreviousX;
+
+ SwipeDismissHandler(Context context, DraggableConstraintLayout view) {
+ mView = view;
+ GestureDetector.OnGestureListener gestureListener = new SwipeDismissGestureListener();
+ mGestureDetector = new GestureDetector(context, gestureListener);
+ mDisplayMetrics = new DisplayMetrics();
+ context.getDisplay().getRealMetrics(mDisplayMetrics);
+ mCallbacks = new SwipeDismissCallbacks() {
+ }; // default to unimplemented callbacks
+ }
+
+ @Override
+ public boolean onTouch(View view, MotionEvent event) {
+ boolean gestureResult = mGestureDetector.onTouchEvent(event);
+ mCallbacks.onInteraction();
+ if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
+ mStartX = event.getRawX();
+ mPreviousX = mStartX;
+ return true;
+ } else if (event.getActionMasked() == MotionEvent.ACTION_UP) {
+ if (mDismissAnimation != null && mDismissAnimation.isRunning()) {
+ return true;
+ }
+ if (isPastDismissThreshold()) {
+ dismiss();
+ } else {
+ // if we've moved, but not past the threshold, start the return animation
+ if (DEBUG_DISMISS) {
+ Log.d(TAG, "swipe gesture abandoned");
+ }
+ createSwipeReturnAnimation().start();
+ }
+ return true;
+ }
+ return gestureResult;
+ }
+
+ class SwipeDismissGestureListener extends GestureDetector.SimpleOnGestureListener {
+ @Override
+ public boolean onScroll(
+ MotionEvent ev1, MotionEvent ev2, float distanceX, float distanceY) {
+ mView.setTranslationX(ev2.getRawX() - mStartX);
+ mDirectionX = (ev2.getRawX() < mPreviousX) ? -1 : 1;
+ mPreviousX = ev2.getRawX();
+ return true;
+ }
+
+ @Override
+ public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
+ float velocityY) {
+ if (mView.getTranslationX() * velocityX > 0
+ && (mDismissAnimation == null || !mDismissAnimation.isRunning())) {
+ ValueAnimator dismissAnimator =
+ createSwipeDismissAnimation(velocityX / (float) 1000);
+ mCallbacks.onSwipeDismissInitiated(dismissAnimator);
+ dismiss(dismissAnimator);
+ return true;
+ }
+ return false;
+ }
+ }
+
+ private boolean isPastDismissThreshold() {
+ float translationX = mView.getTranslationX();
+ // Determines whether the absolute translation from the start is in the same direction
+ // as the current movement. For example, if the user moves most of the way to the right,
+ // but then starts dragging back left, we do not dismiss even though the absolute
+ // distance is greater than the threshold.
+ if (translationX * mDirectionX > 0) {
+ return Math.abs(translationX) >= FloatingWindowUtil.dpToPx(mDisplayMetrics,
+ DISMISS_DISTANCE_THRESHOLD_DP);
+ }
+ return false;
+ }
+
+ boolean isDismissing() {
+ return (mDismissAnimation != null && mDismissAnimation.isRunning());
+ }
+
+ void cancel() {
+ if (isDismissing()) {
+ if (DEBUG_ANIM) {
+ Log.d(TAG, "cancelling dismiss animation");
+ }
+ mDismissAnimation.cancel();
+ }
+ }
+
+ void dismiss() {
+ ValueAnimator anim = createSwipeDismissAnimation(3);
+ mCallbacks.onSwipeDismissInitiated(anim);
+ dismiss(anim);
+ }
+
+ private void dismiss(ValueAnimator animator) {
+ mDismissAnimation = animator;
+ mDismissAnimation.addListener(new AnimatorListenerAdapter() {
+ private boolean mCancelled;
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ super.onAnimationCancel(animation);
+ mCancelled = true;
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ super.onAnimationEnd(animation);
+ if (!mCancelled) {
+ mCallbacks.onDismissComplete();
+ }
+ }
+ });
+ mDismissAnimation.start();
+ }
+
+ private ValueAnimator createSwipeDismissAnimation(float velocity) {
+ // velocity is measured in pixels per millisecond
+ velocity = Math.min(3, Math.max(1, velocity));
+ ValueAnimator anim = ValueAnimator.ofFloat(0, 1);
+ float startX = mView.getTranslationX();
+ // make sure the UI gets all the way off the screen in the direction of movement
+ // (the actions container background is guaranteed to be both the leftmost and
+ // rightmost UI element in LTR and RTL)
+ float finalX;
+ int layoutDir =
+ mView.getContext().getResources().getConfiguration().getLayoutDirection();
+ if (startX > 0 || (startX == 0 && layoutDir == LAYOUT_DIRECTION_RTL)) {
+ finalX = mDisplayMetrics.widthPixels;
+ } else {
+ finalX = -1 * mActionsContainer.getRight();
+ }
+ float distance = Math.abs(finalX - startX);
+
+ anim.addUpdateListener(animation -> {
+ float translation = MathUtils.lerp(startX, finalX, animation.getAnimatedFraction());
+ mView.setTranslationX(translation);
+ mView.setAlpha(1 - animation.getAnimatedFraction());
+ });
+ anim.setDuration((long) (distance / Math.abs(velocity)));
+ return anim;
+ }
+
+ private ValueAnimator createSwipeReturnAnimation() {
+ ValueAnimator anim = ValueAnimator.ofFloat(0, 1);
+ float startX = mView.getTranslationX();
+ float finalX = 0;
+
+ anim.addUpdateListener(animation -> {
+ float translation = MathUtils.lerp(
+ startX, finalX, animation.getAnimatedFraction());
+ mView.setTranslationX(translation);
+ });
+
+ return anim;
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
index 50765f227554..009d4b9b48e6 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
@@ -88,10 +88,12 @@ import com.android.internal.logging.UiEventLogger;
import com.android.internal.policy.PhoneWindow;
import com.android.settingslib.applications.InterestingConfigChanges;
import com.android.systemui.R;
+import com.android.systemui.broadcast.BroadcastSender;
import com.android.systemui.clipboardoverlay.ClipboardOverlayController;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.screenshot.ScreenshotController.SavedImageData.ActionTransition;
import com.android.systemui.screenshot.TakeScreenshotService.RequestCallback;
+import com.android.systemui.util.Assert;
import com.google.common.util.concurrent.ListenableFuture;
@@ -247,6 +249,7 @@ public class ScreenshotController {
private final ImageExporter mImageExporter;
private final Executor mMainExecutor;
private final ExecutorService mBgExecutor;
+ private final BroadcastSender mBroadcastSender;
private final WindowManager mWindowManager;
private final WindowManager.LayoutParams mWindowLayoutParams;
@@ -271,7 +274,6 @@ public class ScreenshotController {
private String mPackageName = "";
private BroadcastReceiver mCopyBroadcastReceiver;
-
/** Tracks config changes that require re-creating UI */
private final InterestingConfigChanges mConfigChanges = new InterestingConfigChanges(
ActivityInfo.CONFIG_ORIENTATION
@@ -293,7 +295,8 @@ public class ScreenshotController {
ScrollCaptureController scrollCaptureController,
LongScreenshotData longScreenshotHolder,
ActivityManager activityManager,
- TimeoutHandler timeoutHandler) {
+ TimeoutHandler timeoutHandler,
+ BroadcastSender broadcastSender) {
mScreenshotSmartActions = screenshotSmartActions;
mNotificationsController = screenshotNotificationsController;
mScrollCaptureClient = scrollCaptureClient;
@@ -304,6 +307,7 @@ public class ScreenshotController {
mLongScreenshotHolder = longScreenshotHolder;
mIsLowRamDevice = activityManager.isLowRamDevice();
mBgExecutor = Executors.newSingleThreadExecutor();
+ mBroadcastSender = broadcastSender;
mScreenshotHandler = timeoutHandler;
mScreenshotHandler.setDefaultTimeoutMillis(SCREENSHOT_CORNER_DEFAULT_TIMEOUT_MILLIS);
@@ -355,8 +359,10 @@ public class ScreenshotController {
ClipboardOverlayController.SELF_PERMISSION, null, Context.RECEIVER_NOT_EXPORTED);
}
+ @MainThread
void takeScreenshotFullscreen(ComponentName topComponent, Consumer<Uri> finisher,
RequestCallback requestCallback) {
+ Assert.isMainThread();
mCurrentRequestCallback = requestCallback;
DisplayMetrics displayMetrics = new DisplayMetrics();
getDefaultDisplay().getRealMetrics(displayMetrics);
@@ -365,11 +371,12 @@ public class ScreenshotController {
new Rect(0, 0, displayMetrics.widthPixels, displayMetrics.heightPixels));
}
+ @MainThread
void handleImageAsScreenshot(Bitmap screenshot, Rect screenshotScreenBounds,
Insets visibleInsets, int taskId, int userId, ComponentName topComponent,
Consumer<Uri> finisher, RequestCallback requestCallback) {
// TODO: use task Id, userId, topComponent for smart handler
-
+ Assert.isMainThread();
if (screenshot == null) {
Log.e(TAG, "Got null bitmap from screenshot message");
mNotificationsController.notifyScreenshotError(
@@ -392,8 +399,10 @@ public class ScreenshotController {
/**
* Displays a screenshot selector
*/
+ @MainThread
void takeScreenshotPartial(ComponentName topComponent,
final Consumer<Uri> finisher, RequestCallback requestCallback) {
+ Assert.isMainThread();
mScreenshotView.reset();
mCurrentRequestCallback = requestCallback;
@@ -517,7 +526,7 @@ public class ScreenshotController {
saveScreenshot(screenshot, finisher, screenRect, Insets.NONE, topComponent, true);
- mContext.sendBroadcast(new Intent(ClipboardOverlayController.SCREENSHOT_ACTION),
+ mBroadcastSender.sendBroadcast(new Intent(ClipboardOverlayController.SCREENSHOT_ACTION),
ClipboardOverlayController.SELF_PERMISSION);
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
index 1241e1de0ca4..6af6e36a75f7 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
@@ -141,7 +141,7 @@ public class ScreenshotView extends FrameLayout implements
private ScreenshotSelectorView mScreenshotSelectorView;
private ImageView mScrollingScrim;
- private View mScreenshotStatic;
+ private DraggableConstraintLayout mScreenshotStatic;
private ImageView mScreenshotPreview;
private View mScreenshotPreviewBorder;
private ImageView mScrollablePreview;
@@ -159,7 +159,6 @@ public class ScreenshotView extends FrameLayout implements
private UiEventLogger mUiEventLogger;
private ScreenshotViewCallback mCallbacks;
private boolean mPendingSharedTransition;
- private SwipeDismissHandler mSwipeDismissHandler;
private InputMonitorCompat mInputMonitor;
private InputChannelCompat.InputEventReceiver mInputEventReceiver;
private boolean mShowScrollablePreview;
@@ -332,19 +331,6 @@ public class ScreenshotView extends FrameLayout implements
}
}
- @Override // ViewGroup
- public boolean onInterceptTouchEvent(MotionEvent ev) {
- // scrolling scrim should not be swipeable; return early if we're on the scrim
- if (!getSwipeRegion().contains((int) ev.getRawX(), (int) ev.getRawY())) {
- return false;
- }
- // always pass through the down event so the swipe handler knows the initial state
- if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) {
- mSwipeDismissHandler.onTouch(this, ev);
- }
- return mSwipeDetector.onTouchEvent(ev);
- }
-
@Override // View
protected void onFinishInflate() {
mScrollingScrim = requireNonNull(findViewById(R.id.screenshot_scrolling_scrim));
@@ -356,8 +342,8 @@ public class ScreenshotView extends FrameLayout implements
mScreenshotPreview.setClipToOutline(true);
mActionsContainerBackground = requireNonNull(findViewById(
- R.id.screenshot_actions_container_background));
- mActionsContainer = requireNonNull(findViewById(R.id.screenshot_actions_container));
+ R.id.actions_container_background));
+ mActionsContainer = requireNonNull(findViewById(R.id.actions_container));
mActionsView = requireNonNull(findViewById(R.id.screenshot_actions));
mBackgroundProtection = requireNonNull(
findViewById(R.id.screenshot_actions_background));
@@ -395,27 +381,34 @@ public class ScreenshotView extends FrameLayout implements
setFocusableInTouchMode(true);
requestFocus();
- mSwipeDismissHandler = new SwipeDismissHandler(mContext, mScreenshotStatic,
- new SwipeDismissHandler.SwipeDismissCallbacks() {
- @Override
- public void onInteraction() {
- mCallbacks.onUserInteraction();
- }
-
- @Override
- public void onSwipeDismissInitiated(Animator animator) {
- if (DEBUG_DISMISS) {
- Log.d(ScreenshotView.TAG, "dismiss triggered via swipe gesture");
- }
- mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_SWIPE_DISMISSED, 0,
- mPackageName);
- }
+ mScreenshotStatic.setCallbacks(new DraggableConstraintLayout.SwipeDismissCallbacks() {
+ @Override
+ public void onInteraction() {
+ mCallbacks.onUserInteraction();
+ }
+ @Override
+ public void onSwipeDismissInitiated(Animator animator) {
+ if (DEBUG_DISMISS) {
+ Log.d(ScreenshotView.TAG, "dismiss triggered via swipe gesture");
+ }
+ mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_SWIPE_DISMISSED, 0,
+ mPackageName);
+ animator.addListener(new AnimatorListenerAdapter() {
@Override
- public void onDismissComplete() {
- mCallbacks.onDismiss();
+ public void onAnimationStart(Animator animation) {
+ super.onAnimationStart(animation);
+ mBackgroundProtection.animate()
+ .alpha(0).setDuration(animation.getDuration()).start();
}
});
+ }
+
+ @Override
+ public void onDismissComplete() {
+ mCallbacks.onDismiss();
+ }
+ });
}
View getScreenshotPreview() {
@@ -640,8 +633,6 @@ public class ScreenshotView extends FrameLayout implements
requestLayout();
createScreenshotActionsShadeAnimation().start();
-
- setOnTouchListener(mSwipeDismissHandler);
}
});
@@ -950,7 +941,7 @@ public class ScreenshotView extends FrameLayout implements
}
boolean isDismissing() {
- return mSwipeDismissHandler.isDismissing();
+ return mScreenshotStatic.isDismissing();
}
boolean isPendingSharedTransition() {
@@ -958,15 +949,14 @@ public class ScreenshotView extends FrameLayout implements
}
void animateDismissal() {
- mSwipeDismissHandler.dismiss();
+ mScreenshotStatic.dismiss();
}
void reset() {
if (DEBUG_UI) {
Log.d(TAG, "reset screenshot view");
}
-
- mSwipeDismissHandler.cancel();
+ mScreenshotStatic.cancelDismissal();
if (DEBUG_WINDOW) {
Log.d(TAG, "removing OnComputeInternalInsetsListener");
}
@@ -999,6 +989,7 @@ public class ScreenshotView extends FrameLayout implements
mSmartChips.clear();
mQuickShareChip = null;
setAlpha(1);
+ mScreenshotStatic.setAlpha(1);
mScreenshotSelectorView.stop();
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/SwipeDismissHandler.java b/packages/SystemUI/src/com/android/systemui/screenshot/SwipeDismissHandler.java
deleted file mode 100644
index 24b1249c3f98..000000000000
--- a/packages/SystemUI/src/com/android/systemui/screenshot/SwipeDismissHandler.java
+++ /dev/null
@@ -1,237 +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.systemui.screenshot;
-
-import static com.android.systemui.screenshot.LogConfig.DEBUG_ANIM;
-import static com.android.systemui.screenshot.LogConfig.DEBUG_DISMISS;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ValueAnimator;
-import android.content.Context;
-import android.util.DisplayMetrics;
-import android.util.Log;
-import android.util.MathUtils;
-import android.view.GestureDetector;
-import android.view.MotionEvent;
-import android.view.View;
-
-/**
- * Allows a view to be swipe-dismissed, or returned to its location if distance threshold is not met
- */
-public class SwipeDismissHandler implements View.OnTouchListener {
- private static final String TAG = "SwipeDismissHandler";
-
- // distance needed to register a dismissal
- private static final float DISMISS_DISTANCE_THRESHOLD_DP = 20;
-
- /**
- * Stores the callbacks when the view is interacted with or dismissed.
- */
- public interface SwipeDismissCallbacks {
- /**
- * Run when the view is interacted with (touched)
- */
- void onInteraction();
-
- /**
- * Run when the view is dismissed (the distance threshold is met), pre-dismissal animation
- */
- void onSwipeDismissInitiated(Animator animator);
-
- /**
- * Run when the view is dismissed (the distance threshold is met), post-dismissal animation
- */
- void onDismissComplete();
- }
-
- private final View mView;
- private final SwipeDismissCallbacks mCallbacks;
- private final GestureDetector mGestureDetector;
- private DisplayMetrics mDisplayMetrics;
- private ValueAnimator mDismissAnimation;
-
-
- private float mStartX;
- // Keeps track of the most recent direction (between the last two move events).
- // -1 for left; +1 for right.
- private int mDirectionX;
- private float mPreviousX;
-
- public SwipeDismissHandler(Context context, View view, SwipeDismissCallbacks callbacks) {
- mView = view;
- mCallbacks = callbacks;
- GestureDetector.OnGestureListener gestureListener = new SwipeDismissGestureListener();
- mGestureDetector = new GestureDetector(context, gestureListener);
- mDisplayMetrics = new DisplayMetrics();
- context.getDisplay().getRealMetrics(mDisplayMetrics);
- }
-
- @Override
- public boolean onTouch(View view, MotionEvent event) {
- boolean gestureResult = mGestureDetector.onTouchEvent(event);
- mCallbacks.onInteraction();
- if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
- mStartX = event.getRawX();
- mPreviousX = mStartX;
- return true;
- } else if (event.getActionMasked() == MotionEvent.ACTION_UP) {
- if (mDismissAnimation != null && mDismissAnimation.isRunning()) {
- return true;
- }
- if (isPastDismissThreshold()) {
- ValueAnimator dismissAnimator = createSwipeDismissAnimation(1);
- mCallbacks.onSwipeDismissInitiated(dismissAnimator);
- dismiss(dismissAnimator);
- } else {
- // if we've moved, but not past the threshold, start the return animation
- if (DEBUG_DISMISS) {
- Log.d(TAG, "swipe gesture abandoned");
- }
- createSwipeReturnAnimation().start();
- }
- return true;
- }
- return gestureResult;
- }
-
- class SwipeDismissGestureListener extends GestureDetector.SimpleOnGestureListener {
- @Override
- public boolean onScroll(
- MotionEvent ev1, MotionEvent ev2, float distanceX, float distanceY) {
- mView.setTranslationX(ev2.getRawX() - mStartX);
- mDirectionX = (ev2.getRawX() < mPreviousX) ? -1 : 1;
- mPreviousX = ev2.getRawX();
- return true;
- }
-
- @Override
- public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
- float velocityY) {
- if (mView.getTranslationX() * velocityX > 0
- && (mDismissAnimation == null || !mDismissAnimation.isRunning())) {
- ValueAnimator dismissAnimator =
- createSwipeDismissAnimation(velocityX / (float) 1000);
- mCallbacks.onSwipeDismissInitiated(dismissAnimator);
- dismiss(dismissAnimator);
- return true;
- }
- return false;
- }
- }
-
- private boolean isPastDismissThreshold() {
- float translationX = mView.getTranslationX();
- // Determines whether the absolute translation from the start is in the same direction
- // as the current movement. For example, if the user moves most of the way to the right,
- // but then starts dragging back left, we do not dismiss even though the absolute
- // distance is greater than the threshold.
- if (translationX * mDirectionX > 0) {
- return Math.abs(translationX) >= FloatingWindowUtil.dpToPx(mDisplayMetrics,
- DISMISS_DISTANCE_THRESHOLD_DP);
- }
- return false;
- }
-
- /**
- * Return whether the view is currently being dismissed
- */
- public boolean isDismissing() {
- return (mDismissAnimation != null && mDismissAnimation.isRunning());
- }
-
- /**
- * Cancel the currently-running dismissal animation, if any.
- */
- public void cancel() {
- if (isDismissing()) {
- if (DEBUG_ANIM) {
- Log.d(TAG, "cancelling dismiss animation");
- }
- mDismissAnimation.cancel();
- }
- }
-
- /**
- * Start dismissal animation (will run onDismiss callback when animation complete)
- */
- public void dismiss() {
- dismiss(createSwipeDismissAnimation(1));
- }
-
- private void dismiss(ValueAnimator animator) {
- mDismissAnimation = animator;
- mDismissAnimation.addListener(new AnimatorListenerAdapter() {
- private boolean mCancelled;
-
- @Override
- public void onAnimationCancel(Animator animation) {
- super.onAnimationCancel(animation);
- mCancelled = true;
- }
-
- @Override
- public void onAnimationEnd(Animator animation) {
- super.onAnimationEnd(animation);
- if (!mCancelled) {
- mCallbacks.onDismissComplete();
- }
- }
- });
- mDismissAnimation.start();
- }
-
- private ValueAnimator createSwipeDismissAnimation(float velocity) {
- // velocity is measured in pixels per millisecond
- velocity = Math.min(3, Math.max(1, velocity));
- ValueAnimator anim = ValueAnimator.ofFloat(0, 1);
- float startX = mView.getTranslationX();
- // make sure the UI gets all the way off the screen in the direction of movement
- // (the actions container background is guaranteed to be both the leftmost and
- // rightmost UI element in LTR and RTL)
- float finalX;
- int layoutDir = mView.getContext().getResources().getConfiguration().getLayoutDirection();
- if (startX > 0 || (startX == 0 && layoutDir == View.LAYOUT_DIRECTION_RTL)) {
- finalX = mDisplayMetrics.widthPixels;
- } else {
- finalX = -1 * mView.getRight();
- }
- float distance = Math.abs(finalX - startX);
-
- anim.addUpdateListener(animation -> {
- float translation = MathUtils.lerp(startX, finalX, animation.getAnimatedFraction());
- mView.setTranslationX(translation);
- mView.setAlpha(1 - animation.getAnimatedFraction());
- });
- anim.setDuration((long) (distance / Math.abs(velocity)));
- return anim;
- }
-
- private ValueAnimator createSwipeReturnAnimation() {
- ValueAnimator anim = ValueAnimator.ofFloat(0, 1);
- float startX = mView.getTranslationX();
- float finalX = 0;
-
- anim.addUpdateListener(animation -> {
- float translation = MathUtils.lerp(
- startX, finalX, animation.getAnimatedFraction());
- mView.setTranslationX(translation);
- });
-
- return anim;
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
index 98e6bd141b65..924351df3117 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
@@ -51,7 +51,6 @@ import androidx.annotation.NonNull;
import com.android.internal.logging.UiEventLogger;
import com.android.internal.util.ScreenshotHelper;
import com.android.systemui.R;
-import com.android.systemui.shared.recents.utilities.BitmapUtil;
import java.util.function.Consumer;
@@ -208,7 +207,7 @@ public class TakeScreenshotService extends Service {
if (DEBUG_SERVICE) {
Log.d(TAG, "handleMessage: TAKE_SCREENSHOT_PROVIDED_IMAGE");
}
- Bitmap screenshot = BitmapUtil.bundleToHardwareBitmap(
+ Bitmap screenshot = ScreenshotHelper.HardwareBitmapBundler.bundleToHardwareBitmap(
screenshotRequest.getBitmapBundle());
Rect screenBounds = screenshotRequest.getBoundsInScreen();
Insets insets = screenshotRequest.getInsets();
diff --git a/packages/SystemUI/src/com/android/systemui/smartspace/SmartspacePrecondition.kt b/packages/SystemUI/src/com/android/systemui/smartspace/SmartspacePrecondition.kt
new file mode 100644
index 000000000000..aa2bcecbd224
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/smartspace/SmartspacePrecondition.kt
@@ -0,0 +1,45 @@
+/*
+ * 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.smartspace
+
+/**
+ * A {@link SmartspacePrecondition} captures the conditions that must be met for Smartspace to be
+ * used in a particular setting.
+ */
+interface SmartspacePrecondition {
+ /**
+ * A callback for receiving updates when conditions have changed.
+ */
+ interface Listener {
+ fun onCriteriaChanged()
+ }
+
+ /**
+ * Adds a listener to receive future updates. {@link Listener#onCriteriaChanged} will be called
+ * immediately upon adding.
+ */
+ fun addListener(listener: Listener)
+
+ /**
+ * Removes a listener from receiving future updates.
+ */
+ fun removeListener(listener: Listener)
+
+ /**
+ * Returns whether all conditions have been met.
+ */
+ fun conditionsMet(): Boolean
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/smartspace/SmartspaceTargetFilter.kt b/packages/SystemUI/src/com/android/systemui/smartspace/SmartspaceTargetFilter.kt
new file mode 100644
index 000000000000..7228550e4e41
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/smartspace/SmartspaceTargetFilter.kt
@@ -0,0 +1,49 @@
+/*
+ * 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.smartspace
+
+import android.app.smartspace.SmartspaceTarget
+
+/**
+ * {@link SmartspaceTargetFilter} defines a way to locally filter targets from inclusion. This
+ * should be used for filtering that isn't available further upstream.
+ */
+interface SmartspaceTargetFilter {
+ /**
+ * An interface implemented by clients to receive updates when the filtering criteria changes.
+ * When this happens, the client should refresh their target set.
+ */
+ interface Listener {
+ fun onCriteriaChanged()
+ }
+
+ /**
+ * Adds a listener to receive future updates. {@link Listener#onCriteriaChanged} will be
+ * invoked immediately after.
+ */
+ fun addListener(listener: Listener)
+
+ /**
+ * Removes listener from receiving future updates.
+ */
+ fun removeListener(listener: Listener)
+
+ /**
+ * Returns {@code true} if the {@link SmartspaceTarget} should be included in the current
+ * target set, {@code false} otherwise.
+ */
+ fun filterSmartspaceTarget(t: SmartspaceTarget): Boolean
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/smartspace/dagger/SmartspaceModule.kt b/packages/SystemUI/src/com/android/systemui/smartspace/dagger/SmartspaceModule.kt
new file mode 100644
index 000000000000..1b74ac36ebf0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/smartspace/dagger/SmartspaceModule.kt
@@ -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.systemui.smartspace.dagger
+
+import com.android.systemui.plugins.BcSmartspaceDataPlugin
+import com.android.systemui.smartspace.SmartspacePrecondition
+import com.android.systemui.smartspace.SmartspaceTargetFilter
+import com.android.systemui.smartspace.filters.LockscreenTargetFilter
+import com.android.systemui.smartspace.preconditions.LockscreenPrecondition
+import dagger.Binds
+import dagger.BindsOptionalOf
+import dagger.Module
+import javax.inject.Named
+
+@Module(subcomponents = [SmartspaceViewComponent::class])
+abstract class SmartspaceModule {
+ @Module
+ companion object {
+ /**
+ * The BcSmartspaceDataProvider for dreams.
+ */
+ const val DREAM_SMARTSPACE_DATA_PLUGIN = "dreams_smartspace_data_plugin"
+
+ /**
+ * The lockscreen smartspace target filter.
+ */
+ const val LOCKSCREEN_SMARTSPACE_TARGET_FILTER = "lockscreen_smartspace_target_filter"
+
+ /**
+ * The dream smartspace target filter.
+ */
+ const val DREAM_SMARTSPACE_TARGET_FILTER = "dream_smartspace_target_filter"
+
+ /**
+ * The precondition for dream smartspace
+ */
+ const val DREAM_SMARTSPACE_PRECONDITION = "dream_smartspace_precondition"
+ }
+
+ @BindsOptionalOf
+ @Named(DREAM_SMARTSPACE_TARGET_FILTER)
+ abstract fun optionalDreamSmartspaceTargetFilter(): SmartspaceTargetFilter?
+
+ @BindsOptionalOf
+ @Named(DREAM_SMARTSPACE_DATA_PLUGIN)
+ abstract fun optionalDreamsBcSmartspaceDataPlugin(): BcSmartspaceDataPlugin?
+
+ @Binds
+ @Named(LOCKSCREEN_SMARTSPACE_TARGET_FILTER)
+ abstract fun provideLockscreenSmartspaceTargetFilter(
+ filter: LockscreenTargetFilter?
+ ): SmartspaceTargetFilter?
+
+ @Binds
+ @Named(DREAM_SMARTSPACE_PRECONDITION)
+ abstract fun bindSmartspacePrecondition(
+ lockscreenPrecondition: LockscreenPrecondition?
+ ): SmartspacePrecondition?
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/smartspace/dagger/SmartspaceViewComponent.kt b/packages/SystemUI/src/com/android/systemui/smartspace/dagger/SmartspaceViewComponent.kt
new file mode 100644
index 000000000000..d3ae198e8e35
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/smartspace/dagger/SmartspaceViewComponent.kt
@@ -0,0 +1,84 @@
+/*
+ * 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.smartspace.dagger
+
+import android.app.PendingIntent
+import android.content.Intent
+import android.view.View
+import android.view.ViewGroup
+import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.plugins.BcSmartspaceDataPlugin
+import com.android.systemui.plugins.FalsingManager
+import com.android.systemui.smartspace.dagger.SmartspaceViewComponent.SmartspaceViewModule.PLUGIN
+import dagger.BindsInstance
+import dagger.Module
+import dagger.Provides
+import dagger.Subcomponent
+import javax.inject.Named
+
+@Subcomponent(modules = [SmartspaceViewComponent.SmartspaceViewModule::class])
+interface SmartspaceViewComponent {
+ @Subcomponent.Factory
+ interface Factory {
+ fun create(
+ @BindsInstance parent: ViewGroup,
+ @BindsInstance @Named(PLUGIN) plugin: BcSmartspaceDataPlugin,
+ @BindsInstance onAttachListener: View.OnAttachStateChangeListener
+ ): SmartspaceViewComponent
+ }
+
+ fun getView(): BcSmartspaceDataPlugin.SmartspaceView
+
+ @Module
+ object SmartspaceViewModule {
+ const val PLUGIN = "plugin"
+
+ @Provides
+ fun providesSmartspaceView(
+ activityStarter: ActivityStarter,
+ falsingManager: FalsingManager,
+ parent: ViewGroup,
+ @Named(PLUGIN) plugin: BcSmartspaceDataPlugin,
+ onAttachListener: View.OnAttachStateChangeListener
+ ):
+ BcSmartspaceDataPlugin.SmartspaceView {
+ val ssView = plugin.getView(parent)
+ ssView.registerDataProvider(plugin)
+
+ ssView.setIntentStarter(object : BcSmartspaceDataPlugin.IntentStarter {
+ override fun startIntent(view: View, intent: Intent, showOnLockscreen: Boolean) {
+ activityStarter.startActivity(
+ intent,
+ true, /* dismissShade */
+ null, /* launch animator */
+ showOnLockscreen
+ )
+ }
+
+ override fun startPendingIntent(pi: PendingIntent, showOnLockscreen: Boolean) {
+ if (showOnLockscreen) {
+ pi.send()
+ } else {
+ activityStarter.startPendingIntentDismissingKeyguard(pi)
+ }
+ }
+ })
+ (ssView as View).addOnAttachStateChangeListener(onAttachListener)
+ ssView.setFalsingManager(falsingManager)
+ return ssView
+ }
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/smartspace/filters/LockscreenTargetFilter.kt b/packages/SystemUI/src/com/android/systemui/smartspace/filters/LockscreenTargetFilter.kt
new file mode 100644
index 000000000000..6ad490169c17
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/smartspace/filters/LockscreenTargetFilter.kt
@@ -0,0 +1,152 @@
+/*
+ * 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.smartspace.filters
+
+import android.app.smartspace.SmartspaceTarget
+import android.content.ContentResolver
+import android.content.Context
+import android.database.ContentObserver
+import android.net.Uri
+import android.os.Handler
+import android.os.UserHandle
+import android.provider.Settings
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.settings.UserTracker
+import com.android.systemui.smartspace.SmartspaceTargetFilter
+import com.android.systemui.util.concurrency.Execution
+import com.android.systemui.util.settings.SecureSettings
+import java.util.concurrent.Executor
+import javax.inject.Inject
+
+/**
+ * {@link SmartspaceTargetFilter} for smartspace targets that show above the lockscreen.
+ */
+class LockscreenTargetFilter @Inject constructor(
+ private val secureSettings: SecureSettings,
+ private val userTracker: UserTracker,
+ private val execution: Execution,
+ @Main private val handler: Handler,
+ private val contentResolver: ContentResolver,
+ @Main private val uiExecutor: Executor
+) : SmartspaceTargetFilter {
+ private var listeners: MutableSet<SmartspaceTargetFilter.Listener> = mutableSetOf()
+ private var showSensitiveContentForCurrentUser = false
+ set(value) {
+ val existing = field
+ field = value
+ if (existing != field) {
+ listeners.forEach { it.onCriteriaChanged() }
+ }
+ }
+ private var showSensitiveContentForManagedUser = false
+ set(value) {
+ val existing = field
+ field = value
+ if (existing != field) {
+ listeners.forEach { it.onCriteriaChanged() }
+ }
+ }
+
+ private val settingsObserver = object : ContentObserver(handler) {
+ override fun onChange(selfChange: Boolean, uri: Uri?) {
+ execution.assertIsMainThread()
+ updateUserContentSettings()
+ }
+ }
+
+ private var managedUserHandle: UserHandle? = null
+
+ override fun addListener(listener: SmartspaceTargetFilter.Listener) {
+ listeners.add(listener)
+
+ if (listeners.size != 1) {
+ return
+ }
+
+ userTracker.addCallback(userTrackerCallback, uiExecutor)
+
+ contentResolver.registerContentObserver(
+ secureSettings.getUriFor(Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS),
+ true,
+ settingsObserver,
+ UserHandle.USER_ALL
+ )
+
+ updateUserContentSettings()
+ }
+
+ override fun removeListener(listener: SmartspaceTargetFilter.Listener) {
+ listeners.remove(listener)
+
+ if (listeners.isNotEmpty()) {
+ return
+ }
+
+ userTracker.removeCallback(userTrackerCallback)
+ contentResolver.unregisterContentObserver(settingsObserver)
+ }
+
+ override fun filterSmartspaceTarget(t: SmartspaceTarget): Boolean {
+ return when (t.userHandle) {
+ userTracker.userHandle -> {
+ !t.isSensitive || showSensitiveContentForCurrentUser
+ }
+ managedUserHandle -> {
+ // Really, this should be "if this managed profile is associated with the current
+ // active user", but we don't have a good way to check that, so instead we cheat:
+ // Only the primary user can have an associated managed profile, so only show
+ // content for the managed profile if the primary user is active
+ userTracker.userHandle.identifier == UserHandle.USER_SYSTEM &&
+ (!t.isSensitive || showSensitiveContentForManagedUser)
+ }
+ else -> {
+ false
+ }
+ }
+ }
+
+ private val userTrackerCallback = object : UserTracker.Callback {
+ override fun onUserChanged(newUser: Int, userContext: Context) {
+ execution.assertIsMainThread()
+ updateUserContentSettings()
+ }
+ }
+
+ private fun getWorkProfileUser(): UserHandle? {
+ for (userInfo in userTracker.userProfiles) {
+ if (userInfo.isManagedProfile) {
+ return userInfo.userHandle
+ }
+ }
+ return null
+ }
+
+ private fun updateUserContentSettings() {
+ val setting = Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS
+
+ showSensitiveContentForCurrentUser =
+ secureSettings.getIntForUser(setting, 0, userTracker.userId) == 1
+
+ managedUserHandle = getWorkProfileUser()
+ val managedId = managedUserHandle?.identifier
+ if (managedId != null) {
+ showSensitiveContentForManagedUser =
+ secureSettings.getIntForUser(setting, 0, managedId) == 1
+ }
+
+ listeners.forEach { it.onCriteriaChanged() }
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/smartspace/preconditions/LockscreenPrecondition.kt b/packages/SystemUI/src/com/android/systemui/smartspace/preconditions/LockscreenPrecondition.kt
new file mode 100644
index 000000000000..1302ec9dbc55
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/smartspace/preconditions/LockscreenPrecondition.kt
@@ -0,0 +1,95 @@
+/*
+ * 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.smartspace.preconditions
+
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
+import com.android.systemui.smartspace.SmartspacePrecondition
+import com.android.systemui.statusbar.policy.DeviceProvisionedController
+import com.android.systemui.util.concurrency.Execution
+import javax.inject.Inject
+
+/**
+ * {@link LockscreenPrecondition} covers the conditions that must be met before Smartspace can be
+ * used over lockscreen. These conditions include the device being provisioned with a setup user
+ * and the Smartspace feature flag enabled.
+ */
+class LockscreenPrecondition @Inject constructor(
+ private val featureFlags: FeatureFlags,
+ private val deviceProvisionedController: DeviceProvisionedController,
+ private val execution: Execution
+) : SmartspacePrecondition {
+ private var listeners = mutableSetOf<SmartspacePrecondition.Listener>()
+
+ private val deviceProvisionedListener =
+ object : DeviceProvisionedController.DeviceProvisionedListener {
+ override fun onDeviceProvisionedChanged() {
+ updateDeviceReadiness()
+ }
+
+ override fun onUserSetupChanged() {
+ updateDeviceReadiness()
+ }
+ }
+
+ init {
+ deviceProvisionedController.addCallback(deviceProvisionedListener)
+ }
+
+ var deviceReady: Boolean = false
+ private set
+
+ init {
+ updateDeviceReadiness()
+ }
+
+ private fun updateDeviceReadiness() {
+ if (deviceReady) {
+ return
+ }
+
+ deviceReady = deviceProvisionedController.isDeviceProvisioned &&
+ deviceProvisionedController.isCurrentUserSetup
+
+ if (!deviceReady) {
+ return
+ }
+
+ deviceProvisionedController.removeCallback(deviceProvisionedListener)
+ synchronized(listeners) {
+ listeners.forEach { it.onCriteriaChanged() }
+ }
+ }
+
+ override fun addListener(listener: SmartspacePrecondition.Listener) {
+ synchronized(listeners) {
+ listeners += listener
+ }
+ // Always trigger a targeted callback upon addition of listener.
+ listener.onCriteriaChanged()
+ }
+
+ override fun removeListener(listener: SmartspacePrecondition.Listener) {
+ synchronized(listeners) {
+ listeners -= listener
+ }
+ }
+
+ override fun conditionsMet(): Boolean {
+ execution.assertIsMainThread()
+ return featureFlags.isEnabled(Flags.SMARTSPACE) && deviceReady
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 5932a64c1c71..d9a98b165795 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -163,6 +163,7 @@ public class CommandQueue extends IStatusBar.Stub implements
private static final int MSG_MEDIA_TRANSFER_RECEIVER_STATE = 65 << MSG_SHIFT;
private static final int MSG_REGISTER_NEARBY_MEDIA_DEVICE_PROVIDER = 66 << MSG_SHIFT;
private static final int MSG_UNREGISTER_NEARBY_MEDIA_DEVICE_PROVIDER = 67 << MSG_SHIFT;
+ private static final int MSG_TILE_SERVICE_REQUEST_LISTENING_STATE = 68 << MSG_SHIFT;
public static final int FLAG_EXCLUDE_NONE = 0;
public static final int FLAG_EXCLUDE_SEARCH_PANEL = 1 << 0;
@@ -433,6 +434,11 @@ public class CommandQueue extends IStatusBar.Stub implements
default void setNavigationBarLumaSamplingEnabled(int displayId, boolean enable) {}
/**
+ * @see IStatusBar#requestTileServiceListeningState
+ */
+ default void requestTileServiceListeningState(@NonNull ComponentName componentName) {}
+
+ /**
* @see IStatusBar#requestAddTile
*/
default void requestAddTile(
@@ -1190,6 +1196,12 @@ public class CommandQueue extends IStatusBar.Stub implements
}
@Override
+ public void requestTileServiceListeningState(@NonNull ComponentName componentName) {
+ mHandler.obtainMessage(MSG_TILE_SERVICE_REQUEST_LISTENING_STATE, componentName)
+ .sendToTarget();
+ }
+
+ @Override
public void requestAddTile(
@NonNull ComponentName componentName,
@NonNull CharSequence appName,
@@ -1686,6 +1698,12 @@ public class CommandQueue extends IStatusBar.Stub implements
mCallbacks.get(i).unregisterNearbyMediaDevicesProvider(provider);
}
break;
+ case MSG_TILE_SERVICE_REQUEST_LISTENING_STATE:
+ ComponentName component = (ComponentName) msg.obj;
+ for (int i = 0; i < mCallbacks.size(); i++) {
+ mCallbacks.get(i).requestTileServiceListeningState(component);
+ }
+ break;
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index ccec0c2d58cc..d51aaad46432 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -293,6 +293,14 @@ public class KeyguardIndicationController {
}
}
+ /**
+ * Cleanup
+ */
+ public void destroy() {
+ mHandler.removeCallbacksAndMessages(null);
+ mBroadcastDispatcher.unregisterReceiver(mBroadcastReceiver);
+ }
+
private void handleAlignStateChanged(int alignState) {
String alignmentIndication = "";
if (alignState == DockManager.ALIGN_STATE_POOR) {
@@ -374,7 +382,7 @@ public class KeyguardIndicationController {
private CharSequence getDisclosureText(@Nullable CharSequence organizationName) {
final Resources packageResources = mContext.getResources();
if (organizationName == null) {
- return mDevicePolicyManager.getString(
+ return mDevicePolicyManager.getResources().getString(
KEYGUARD_MANAGEMENT_DISCLOSURE,
() -> packageResources.getString(R.string.do_disclosure_generic));
} else if (mDevicePolicyManager.isDeviceManaged()
@@ -384,7 +392,7 @@ public class KeyguardIndicationController {
return packageResources.getString(R.string.do_financed_disclosure_with_name,
organizationName);
} else {
- return mDevicePolicyManager.getString(
+ return mDevicePolicyManager.getResources().getString(
KEYGUARD_MANAGEMENT_DISCLOSURE,
() -> packageResources.getString(
R.string.do_disclosure_with_name, organizationName),
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
index 17f42b1a3a43..4732a8c09500 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
@@ -34,11 +34,11 @@ import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
import com.android.systemui.statusbar.notification.row.ExpandableView
import com.android.systemui.statusbar.notification.stack.AmbientState
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
+import com.android.systemui.statusbar.phone.CentralSurfaces
import com.android.systemui.statusbar.phone.KeyguardBypassController
import com.android.systemui.statusbar.phone.LSShadeTransitionLogger
import com.android.systemui.statusbar.phone.NotificationPanelViewController
import com.android.systemui.statusbar.phone.ScrimController
-import com.android.systemui.statusbar.phone.CentralSurfaces
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.util.Utils
import java.io.FileDescriptor
@@ -99,15 +99,67 @@ class LockscreenShadeTransitionController @Inject constructor(
internal var pulseHeightAnimator: ValueAnimator? = null
/**
- * Distance that the full shade transition takes in order for scrim to fully transition to
- * the shade (in alpha)
+ * Distance that the full shade transition takes in order to complete.
+ */
+ private var fullTransitionDistance = 0
+
+ /**
+ * Distance that the full transition takes in order for us to fully transition to the shade by
+ * tapping on a button, such as "expand".
+ */
+ private var fullTransitionDistanceByTap = 0
+
+ /**
+ * Distance that the full shade transition takes in order for scrim to fully transition to the
+ * shade (in alpha)
*/
private var scrimTransitionDistance = 0
/**
- * Distance that the full transition takes in order for us to fully transition to the shade
+ * Distance that it takes in order for the notifications scrim fade in to start.
*/
- private var fullTransitionDistance = 0
+ private var notificationsScrimTransitionDelay = 0
+
+ /**
+ * Distance that it takes for the notifications scrim to fully fade if after it started.
+ */
+ private var notificationsScrimTransitionDistance = 0
+
+ /**
+ * Distance that the full shade transition takes in order for the notification shelf to fully
+ * expand.
+ */
+ private var notificationShelfTransitionDistance = 0
+
+ /**
+ * Distance that the full shade transition takes in order for the Quick Settings to fully fade
+ * and expand.
+ */
+ private var qsTransitionDistance = 0
+
+ /**
+ * Distance that the full shade transition takes in order for the keyguard content on
+ * NotificationPanelViewController to fully fade (e.g. Clock & Smartspace).
+ */
+ private var npvcKeyguardContentAlphaTransitionDistance = 0
+
+ /**
+ * Distance that the full shade transition takes in order for depth of the wallpaper to fully
+ * change.
+ */
+ private var depthControllerTransitionDistance = 0
+
+ /**
+ * Distance that the full shade transition takes in order for the UDFPS Keyguard View to fully
+ * fade.
+ */
+ private var udfpsTransitionDistance = 0
+
+ /**
+ * Used for StatusBar to know that a transition is in progress. At the moment it only checks
+ * whether the progress is > 0, therefore this value is not very important.
+ */
+ private var statusBarTransitionDistance = 0
/**
* Flag to make sure that the dragDownAmount is applied to the listeners even when in the
@@ -130,7 +182,7 @@ class LockscreenShadeTransitionController @Inject constructor(
* The distance until we're showing the notifications when pulsing
*/
val distanceUntilShowingPulsingNotifications
- get() = scrimTransitionDistance
+ get() = fullTransitionDistance
/**
* The udfpsKeyguardViewController if it exists.
@@ -177,10 +229,28 @@ class LockscreenShadeTransitionController @Inject constructor(
}
private fun updateResources() {
+ fullTransitionDistance = context.resources.getDimensionPixelSize(
+ R.dimen.lockscreen_shade_full_transition_distance)
+ fullTransitionDistanceByTap = context.resources.getDimensionPixelSize(
+ R.dimen.lockscreen_shade_transition_by_tap_distance)
scrimTransitionDistance = context.resources.getDimensionPixelSize(
R.dimen.lockscreen_shade_scrim_transition_distance)
- fullTransitionDistance = context.resources.getDimensionPixelSize(
+ notificationsScrimTransitionDelay = context.resources.getDimensionPixelSize(
+ R.dimen.lockscreen_shade_notifications_scrim_transition_delay)
+ notificationsScrimTransitionDistance = context.resources.getDimensionPixelSize(
+ R.dimen.lockscreen_shade_notifications_scrim_transition_distance)
+ notificationShelfTransitionDistance = context.resources.getDimensionPixelSize(
+ R.dimen.lockscreen_shade_notif_shelf_transition_distance)
+ qsTransitionDistance = context.resources.getDimensionPixelSize(
R.dimen.lockscreen_shade_qs_transition_distance)
+ npvcKeyguardContentAlphaTransitionDistance = context.resources.getDimensionPixelSize(
+ R.dimen.lockscreen_shade_npvc_keyguard_content_alpha_transition_distance)
+ depthControllerTransitionDistance = context.resources.getDimensionPixelSize(
+ R.dimen.lockscreen_shade_depth_controller_transition_distance)
+ udfpsTransitionDistance = context.resources.getDimensionPixelSize(
+ R.dimen.lockscreen_shade_udfps_keyguard_transition_distance)
+ statusBarTransitionDistance = context.resources.getDimensionPixelSize(
+ R.dimen.lockscreen_shade_status_bar_transition_distance)
useSplitShade = Utils.shouldUseSplitNotificationShade(context.resources)
}
@@ -248,6 +318,7 @@ class LockscreenShadeTransitionController @Inject constructor(
// override that
forceApplyAmount = true
// Reset the behavior. At this point the animation is already started
+ logger.logDragDownAmountReset()
dragDownAmount = 0f
forceApplyAmount = false
}
@@ -337,13 +408,20 @@ class LockscreenShadeTransitionController @Inject constructor(
if (field != value || forceApplyAmount) {
field = value
if (!nsslController.isInLockedDownShade() || field == 0f || forceApplyAmount) {
- qSDragProgress = MathUtils.saturate(dragDownAmount / scrimTransitionDistance)
- nsslController.setTransitionToFullShadeAmount(field, qSDragProgress)
+ val notificationShelfProgress =
+ MathUtils.saturate(dragDownAmount / notificationShelfTransitionDistance)
+ nsslController.setTransitionToFullShadeAmount(field, notificationShelfProgress)
+
+ qSDragProgress = MathUtils.saturate(dragDownAmount / qsTransitionDistance)
qS.setTransitionToFullShadeAmount(field, qSDragProgress)
+
notificationPanelController.setTransitionToFullShadeAmount(field,
false /* animate */, 0 /* delay */)
+
mediaHierarchyManager.setTransitionToFullShadeAmount(field)
+ transitionToShadeAmountScrim(field)
transitionToShadeAmountCommon(field)
+ transitionToShadeAmountKeyguard(field)
}
}
}
@@ -354,14 +432,42 @@ class LockscreenShadeTransitionController @Inject constructor(
var qSDragProgress = 0f
private set
- private fun transitionToShadeAmountCommon(dragDownAmount: Float) {
+ private fun transitionToShadeAmountScrim(dragDownAmount: Float) {
val scrimProgress = MathUtils.saturate(dragDownAmount / scrimTransitionDistance)
- scrimController.setTransitionToFullShadeProgress(scrimProgress)
+ val notificationsScrimDragAmount = dragDownAmount - notificationsScrimTransitionDelay
+ val notificationsScrimProgress = MathUtils.saturate(
+ notificationsScrimDragAmount / notificationsScrimTransitionDistance)
+ scrimController.setTransitionToFullShadeProgress(scrimProgress, notificationsScrimProgress)
+ }
+
+ private fun transitionToShadeAmountCommon(dragDownAmount: Float) {
+ if (depthControllerTransitionDistance > 0) {
+ val depthProgress =
+ MathUtils.saturate(dragDownAmount / depthControllerTransitionDistance)
+ depthController.transitionToFullShadeProgress = depthProgress
+ }
+
+ val udfpsProgress = MathUtils.saturate(dragDownAmount / udfpsTransitionDistance)
+ udfpsKeyguardViewController?.setTransitionToFullShadeProgress(udfpsProgress)
+
+ val statusBarProgress = MathUtils.saturate(dragDownAmount / statusBarTransitionDistance)
+ centralSurfaces.setTransitionToFullShadeProgress(statusBarProgress)
+ }
+
+ private fun transitionToShadeAmountKeyguard(dragDownAmount: Float) {
// Fade out all content only visible on the lockscreen
- notificationPanelController.setKeyguardOnlyContentAlpha(1.0f - scrimProgress)
- depthController.transitionToFullShadeProgress = scrimProgress
- udfpsKeyguardViewController?.setTransitionToFullShadeProgress(scrimProgress)
- centralSurfaces.setTransitionToFullShadeProgress(scrimProgress)
+ val keyguardAlphaProgress =
+ MathUtils.saturate(dragDownAmount / npvcKeyguardContentAlphaTransitionDistance)
+ val keyguardAlpha = 1f - keyguardAlphaProgress
+ val keyguardTranslationY = if (useSplitShade) {
+ // On split-shade, the translationY of the keyguard should stay in sync with the
+ // translation of media.
+ mediaHierarchyManager.getGuidedTransformationTranslationY()
+ } else {
+ 0
+ }
+ notificationPanelController
+ .setKeyguardTransitionProgress(keyguardAlpha, keyguardTranslationY)
}
private fun setDragDownAmountAnimated(
@@ -404,9 +510,10 @@ class LockscreenShadeTransitionController @Inject constructor(
// be a couple of frames later. if we're setting it to 0, it will use the
// default inset and therefore flicker
dragDownAmount = 1f
- setDragDownAmountAnimated(fullTransitionDistance.toFloat(), delay = delay) {
+ setDragDownAmountAnimated(fullTransitionDistanceByTap.toFloat(), delay = delay) {
// End listener:
// Reset
+ logger.logDragDownAmountReset()
dragDownAmount = 0f
forceApplyAmount = false
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
index 94a6d3e99842..66c1d87fb812 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
@@ -507,12 +507,11 @@ public class NotificationRemoteInputManager implements Dumpable {
Math.max(cx + cy, cx + (h - cy)),
Math.max((w - cx) + cy, (w - cx) + (h - cy)));
- riv.setRevealParameters(cx, cy, r);
- riv.setPendingIntent(pendingIntent);
+ riv.getController().setRevealParams(new RemoteInputView.RevealParams(cx, cy, r));
riv.getController().setPendingIntent(pendingIntent);
- riv.setRemoteInput(inputs, input, editedSuggestionInfo);
riv.getController().setRemoteInput(input);
riv.getController().setRemoteInputs(inputs);
+ riv.getController().setEditedSuggestionInfo(editedSuggestionInfo);
riv.focusAnimated();
if (userMessageContent != null) {
riv.setEditTextContent(userMessageContent);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
index 267ee6d2d177..a0388de5150c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
@@ -259,6 +259,7 @@ class NotificationShadeDepthController @Inject constructor(
addListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator?) {
keyguardAnimator = null
+ wakeAndUnlockBlurRadius = 0f
scheduleUpdate()
}
})
@@ -439,7 +440,7 @@ class NotificationShadeDepthController @Inject constructor(
it.println("StatusBarWindowBlurController:")
it.increaseIndent()
it.println("shadeExpansion: $shadeExpansion")
- it.println("shouldApplyShaeBlur: ${shouldApplyShadeBlur()}")
+ it.println("shouldApplyShadeBlur: ${shouldApplyShadeBlur()}")
it.println("shadeAnimation: ${shadeAnimation.radius}")
it.println("brightnessMirrorRadius: ${brightnessMirrorSpring.radius}")
it.println("wakeAndUnlockBlur: $wakeAndUnlockBlurRadius")
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index 3dd717d2f377..eaa66bbc15ac 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -226,10 +226,7 @@ public class NotificationShelf extends ActivatableNotificationView implements
? MathUtils.lerp(shortestWidth, getWidth(), fractionToShade)
: getWidth();
ActivatableNotificationView anv = (ActivatableNotificationView) this;
- NotificationBackgroundView bg = anv.getBackgroundNormal();
- if (bg != null) {
- anv.getBackgroundNormal().setActualWidth((int) actualWidth);
- }
+ anv.setBackgroundWidth((int) actualWidth);
if (mShelfIcons != null) {
mShelfIcons.setActualLayoutWidth((int) actualWidth);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt b/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
index 3fe108f2c951..f0e01a33fc99 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
@@ -192,7 +192,10 @@ constructor(
override fun onTouchEvent(event: MotionEvent): Boolean {
val finishExpanding = (event.action == MotionEvent.ACTION_CANCEL ||
event.action == MotionEvent.ACTION_UP) && isExpanding
- if (!canHandleMotionEvent() && !finishExpanding) {
+
+ val isDraggingNotificationOrCanBypass = mStartingChild?.showingPulsing() == true ||
+ bypassController.canBypass()
+ if ((!canHandleMotionEvent() || !isDraggingNotificationOrCanBypass) && !finishExpanding) {
// We allow cancellations/finishing to still go through here to clean up the state
return false
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java
index 465ab93132f9..3013ad0070a0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java
@@ -188,7 +188,7 @@ public class StatusBarMobileView extends FrameLayout implements DarkReceiver,
setContentDescription(state.contentDescription);
int newVisibility = state.visible && !mForceHidden ? View.VISIBLE : View.GONE;
- if (newVisibility != mMobileGroup.getVisibility()) {
+ if (newVisibility != mMobileGroup.getVisibility() && STATE_ICON == mVisibleState) {
mMobileGroup.setVisibility(newVisibility);
needsLayout = true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/events/StatusEvent.kt b/packages/SystemUI/src/com/android/systemui/statusbar/events/StatusEvent.kt
index d4d84c138b20..4e1404d0637b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/events/StatusEvent.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/events/StatusEvent.kt
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.events
+import android.annotation.SuppressLint
import android.content.Context
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
@@ -27,13 +28,15 @@ import com.android.systemui.R
import com.android.systemui.privacy.OngoingPrivacyChip
import com.android.systemui.privacy.PrivacyItem
+typealias ViewCreator = (context: Context) -> BackgroundAnimatableView
+
interface StatusEvent {
val priority: Int
// Whether or not to force the status bar open and show a dot
val forceVisible: Boolean
// Whether or not to show an animation for this event
val showAnimation: Boolean
- val viewCreator: (context: Context) -> View
+ val viewCreator: ViewCreator
var contentDescription: String?
// Update this event with values from another event.
@@ -47,14 +50,37 @@ interface StatusEvent {
}
}
+class BGView(
+ context: Context
+) : View(context), BackgroundAnimatableView {
+ override val view: View
+ get() = this
+
+ override fun setBoundsForAnimation(l: Int, t: Int, r: Int, b: Int) {
+ setLeftTopRightBottom(l, t, r, b)
+ }
+}
+
+@SuppressLint("AppCompatCustomView")
+class BGImageView(
+ context: Context
+) : ImageView(context), BackgroundAnimatableView {
+ override val view: View
+ get() = this
+
+ override fun setBoundsForAnimation(l: Int, t: Int, r: Int, b: Int) {
+ setLeftTopRightBottom(l, t, r, b)
+ }
+}
+
class BatteryEvent : StatusEvent {
override val priority = 50
override val forceVisible = false
override val showAnimation = true
override var contentDescription: String? = ""
- override val viewCreator: (context: Context) -> View = { context ->
- val iv = ImageView(context)
+ override val viewCreator: (context: Context) -> BGImageView = { context ->
+ val iv = BGImageView(context)
iv.setImageDrawable(ThemedBatteryDrawable(context, Color.WHITE))
iv.setBackgroundDrawable(ColorDrawable(Color.GREEN))
iv
@@ -72,7 +98,7 @@ class PrivacyEvent(override val showAnimation: Boolean = true) : StatusEvent {
var privacyItems: List<PrivacyItem> = listOf()
private var privacyChip: OngoingPrivacyChip? = null
- override val viewCreator: (context: Context) -> View = { context ->
+ override val viewCreator: ViewCreator = { context ->
val v = LayoutInflater.from(context)
.inflate(R.layout.ongoing_privacy_chip, null) as OngoingPrivacyChip
v.privacyList = privacyItems
@@ -82,7 +108,7 @@ class PrivacyEvent(override val showAnimation: Boolean = true) : StatusEvent {
}
override fun toString(): String {
- return javaClass.simpleName
+ return "${javaClass.simpleName}(forceVisible=$forceVisible, privacyItems=$privacyItems)"
}
override fun shouldUpdateFromEvent(other: StatusEvent?): Boolean {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventChipAnimationController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventChipAnimationController.kt
index d5a0467c9b9e..b74140da99d2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventChipAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventChipAnimationController.kt
@@ -16,18 +16,24 @@
package com.android.systemui.statusbar.events
+import android.animation.Animator
+import android.animation.AnimatorListenerAdapter
+import android.animation.AnimatorSet
import android.animation.ValueAnimator
import android.content.Context
+import android.graphics.Rect
import android.view.Gravity
import android.view.LayoutInflater
import android.view.View
+import android.view.View.MeasureSpec.AT_MOST
import android.view.ViewGroup.LayoutParams.MATCH_PARENT
import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
import android.widget.FrameLayout
import com.android.systemui.R
-import com.android.systemui.statusbar.phone.StatusBarLocationPublisher
+import com.android.systemui.statusbar.phone.StatusBarContentInsetsProvider
import com.android.systemui.statusbar.window.StatusBarWindowController
import javax.inject.Inject
+import kotlin.math.roundToInt
/**
* Controls the view for system event animations.
@@ -35,105 +41,262 @@ import javax.inject.Inject
class SystemEventChipAnimationController @Inject constructor(
private val context: Context,
private val statusBarWindowController: StatusBarWindowController,
- private val locationPublisher: StatusBarLocationPublisher
-) : SystemStatusChipAnimationCallback {
- var showPersistentDot = false
- set(value) {
- field = value
- statusBarWindowController.setForceStatusBarVisible(value)
- maybeUpdateShowDot()
- }
+ private val contentInsetsProvider: StatusBarContentInsetsProvider
+) : SystemStatusAnimationCallback {
private lateinit var animationWindowView: FrameLayout
- private lateinit var animationDotView: View
- private var currentAnimatedView: View? = null
+
+ private var currentAnimatedView: BackgroundAnimatableView? = null
+
+ // Left for LTR, Right for RTL
+ private var animationDirection = LEFT
+ private var chipRight = 0
+ private var chipLeft = 0
+ private var chipWidth = 0
+ private var chipMinWidth = context.resources.getDimensionPixelSize(
+ R.dimen.ongoing_appops_chip_min_animation_width)
+ private var dotSize = context.resources.getDimensionPixelSize(
+ R.dimen.ongoing_appops_dot_diameter)
+ // Use during animation so that multiple animators can update the drawing rect
+ private var animRect = Rect()
// TODO: move to dagger
private var initialized = false
- override fun onChipAnimationStart(
- viewCreator: (context: Context) -> View,
- @SystemAnimationState state: Int
- ) {
- if (!initialized) init()
-
- if (state == ANIMATING_IN) {
- currentAnimatedView = viewCreator(context)
- animationWindowView.addView(currentAnimatedView, layoutParamsDefault())
-
- // We are animating IN; chip comes in from View.END
- currentAnimatedView?.apply {
- val translation = width.toFloat()
- translationX = if (isLayoutRtl) -translation else translation
- alpha = 0f
- visibility = View.VISIBLE
- setPadding(locationPublisher.marginLeft, 0, locationPublisher.marginRight, 0)
+ /**
+ * Give the chip controller a chance to inflate and configure the chip view before we start
+ * animating
+ */
+ fun prepareChipAnimation(viewCreator: ViewCreator) {
+ if (!initialized) {
+ init()
+ }
+ animationDirection = if (animationWindowView.isLayoutRtl) RIGHT else LEFT
+
+ // Initialize the animated view
+ val insets = contentInsetsProvider.getStatusBarContentInsetsForCurrentRotation()
+ currentAnimatedView = viewCreator(context).also {
+ animationWindowView.addView(
+ it.view,
+ layoutParamsDefault(
+ if (animationWindowView.isLayoutRtl) insets.first
+ else insets.second))
+ it.view.alpha = 0f
+ // For some reason, the window view's measured width is always 0 here, so use the
+ // parent (status bar)
+ it.view.measure(
+ View.MeasureSpec.makeMeasureSpec(
+ (animationWindowView.parent as View).width, AT_MOST),
+ View.MeasureSpec.makeMeasureSpec(animationWindowView.height, AT_MOST))
+ chipWidth = it.chipWidth
+ }
+
+ // decide which direction we're animating from, and then set some screen coordinates
+ val contentRect = contentInsetsProvider.getStatusBarContentAreaForCurrentRotation()
+ when (animationDirection) {
+ LEFT -> {
+ chipRight = contentRect.right
+ chipLeft = contentRect.right - chipWidth
}
- } else {
- // We are animating away
- currentAnimatedView?.apply {
- translationX = 0f
- alpha = 1f
+ else /* RIGHT */ -> {
+ chipLeft = contentRect.left
+ chipRight = contentRect.left + chipWidth
}
}
}
- override fun onChipAnimationEnd(@SystemAnimationState state: Int) {
- if (state == ANIMATING_IN) {
- // Finished animating in
- currentAnimatedView?.apply {
- translationX = 0f
- alpha = 1f
+ override fun onSystemEventAnimationBegin(): Animator {
+ initializeAnimRect()
+
+ val alphaIn = ValueAnimator.ofFloat(0f, 1f).apply {
+ startDelay = 117
+ duration = 83
+ interpolator = null
+ addUpdateListener { currentAnimatedView?.view?.alpha = animatedValue as Float }
+ }
+ val moveIn = ValueAnimator.ofInt(chipMinWidth, chipWidth).apply {
+ startDelay = 117
+ duration = 383
+ interpolator = STATUS_BAR_X_MOVE_IN
+ addUpdateListener {
+ updateAnimatedViewBoundsWidth(animatedValue as Int)
}
+ }
+ val animSet = AnimatorSet()
+ animSet.playTogether(alphaIn, moveIn)
+ return animSet
+ }
+
+ override fun onSystemEventAnimationFinish(hasPersistentDot: Boolean): Animator {
+ initializeAnimRect()
+ val finish = if (hasPersistentDot) {
+ createMoveOutAnimationForDot()
} else {
- // Finished animating away
- currentAnimatedView?.apply {
- visibility = View.INVISIBLE
- }
- animationWindowView.removeView(currentAnimatedView)
+ createMoveOutAnimationDefault()
}
+
+ finish.addListener(object : AnimatorListenerAdapter() {
+ override fun onAnimationEnd(animation: Animator?) {
+ animationWindowView.removeView(currentAnimatedView!!.view)
+ }
+ })
+
+ return finish
}
- override fun onChipAnimationUpdate(
- animator: ValueAnimator,
- @SystemAnimationState state: Int
- ) {
- // Alpha is parameterized 0,1, and translation from (width, 0)
- currentAnimatedView?.apply {
- val amt = animator.animatedValue as Float
+ private fun createMoveOutAnimationForDot(): Animator {
+ val width1 = ValueAnimator.ofInt(chipWidth, chipMinWidth).apply {
+ duration = 150
+ interpolator = STATUS_CHIP_WIDTH_TO_DOT_KEYFRAME_1
+ addUpdateListener {
+ updateAnimatedViewBoundsWidth(it.animatedValue as Int)
+ }
+ }
- alpha = amt
+ val width2 = ValueAnimator.ofInt(chipMinWidth, dotSize).apply {
+ startDelay = 150
+ duration = 333
+ interpolator = STATUS_CHIP_WIDTH_TO_DOT_KEYFRAME_2
+ addUpdateListener {
+ updateAnimatedViewBoundsWidth(it.animatedValue as Int)
+ }
+ }
- val w = width
- val translation = (1 - amt) * w
- translationX = if (isLayoutRtl) -translation else translation
+ val keyFrame1Height = dotSize * 2
+ val v = currentAnimatedView!!.view
+ val chipVerticalCenter = v.top + v.measuredHeight / 2
+ val height1 = ValueAnimator.ofInt(
+ currentAnimatedView!!.view.measuredHeight, keyFrame1Height).apply {
+ startDelay = 133
+ duration = 100
+ interpolator = STATUS_CHIP_HEIGHT_TO_DOT_KEYFRAME_1
+ addUpdateListener {
+ updateAnimatedViewBoundsHeight(it.animatedValue as Int, chipVerticalCenter)
+ }
}
+
+ val height2 = ValueAnimator.ofInt(keyFrame1Height, dotSize).apply {
+ startDelay = 233
+ duration = 250
+ interpolator = STATUS_CHIP_HEIGHT_TO_DOT_KEYFRAME_2
+ addUpdateListener {
+ updateAnimatedViewBoundsHeight(it.animatedValue as Int, chipVerticalCenter)
+ }
+ }
+
+ // Move the chip view to overlap exactly with the privacy dot. The chip displays by default
+ // exactly adjacent to the dot, so we can just move over by the diameter of the dot itself
+ val moveOut = ValueAnimator.ofInt(0, dotSize).apply {
+ startDelay = 50
+ duration = 183
+ interpolator = STATUS_CHIP_MOVE_TO_DOT
+ addUpdateListener {
+ // If RTL, we can just invert the move
+ val amt = if (animationDirection == LEFT) {
+ animatedValue as Int
+ } else {
+ -(animatedValue as Int)
+ }
+ updateAnimatedBoundsX(amt)
+ }
+ }
+
+ val animSet = AnimatorSet()
+ animSet.playTogether(width1, width2, height1, height2, moveOut)
+ return animSet
}
- private fun maybeUpdateShowDot() {
- if (!initialized) return
- if (!showPersistentDot && currentAnimatedView == null) {
- animationDotView.visibility = View.INVISIBLE
+ private fun createMoveOutAnimationDefault(): Animator {
+ val moveOut = ValueAnimator.ofInt(chipWidth, chipMinWidth).apply {
+ duration = 383
+ addUpdateListener {
+ currentAnimatedView?.apply {
+ updateAnimatedViewBoundsWidth(it.animatedValue as Int)
+ }
+ }
}
+ return moveOut
}
private fun init() {
initialized = true
animationWindowView = LayoutInflater.from(context)
.inflate(R.layout.system_event_animation_window, null) as FrameLayout
- animationDotView = animationWindowView.findViewById(R.id.dot_view)
val lp = FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT)
lp.gravity = Gravity.END or Gravity.CENTER_VERTICAL
statusBarWindowController.addViewToWindow(animationWindowView, lp)
+ animationWindowView.clipToPadding = false
+ animationWindowView.clipChildren = false
}
- private fun start() = if (animationWindowView.isLayoutRtl) right() else left()
- private fun right() = locationPublisher.marginRight
- private fun left() = locationPublisher.marginLeft
+ private fun layoutParamsDefault(marginEnd: Int): FrameLayout.LayoutParams =
+ FrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT).also {
+ it.gravity = Gravity.END or Gravity.CENTER_VERTICAL
+ it.marginEnd = marginEnd
+ }
+
+ private fun initializeAnimRect() = animRect.set(
+ chipLeft,
+ currentAnimatedView!!.view.top,
+ chipRight,
+ currentAnimatedView!!.view.bottom)
+
+ /**
+ * To be called during an animation, sets the width and updates the current animated chip view
+ */
+ private fun updateAnimatedViewBoundsWidth(width: Int) {
+ when (animationDirection) {
+ LEFT -> {
+ animRect.set((chipRight - width), animRect.top, chipRight, animRect.bottom)
+ } else /* RIGHT */ -> {
+ animRect.set(chipLeft, animRect.top, (chipLeft + width), animRect.bottom)
+ }
+ }
- private fun layoutParamsDefault(): FrameLayout.LayoutParams =
- FrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT).also {
- it.gravity = Gravity.END or Gravity.CENTER_VERTICAL
- it.marginStart = start()
+ updateCurrentAnimatedView()
+ }
+
+ /**
+ * To be called during an animation, updates the animation rect and sends the update to the chip
+ */
+ private fun updateAnimatedViewBoundsHeight(height: Int, verticalCenter: Int) {
+ animRect.set(
+ animRect.left,
+ verticalCenter - (height.toFloat() / 2).roundToInt(),
+ animRect.right,
+ verticalCenter + (height.toFloat() / 2).roundToInt())
+
+ updateCurrentAnimatedView()
+ }
+
+ /**
+ * To be called during an animation, updates the animation rect offset and updates the chip
+ */
+ private fun updateAnimatedBoundsX(translation: Int) {
+ currentAnimatedView?.view?.translationX = translation.toFloat()
+ }
+
+ /**
+ * To be called during an animation. Sets the chip rect to animRect
+ */
+ private fun updateCurrentAnimatedView() {
+ currentAnimatedView?.setBoundsForAnimation(
+ animRect.left, animRect.top, animRect.right, animRect.bottom
+ )
}
}
+
+/**
+ * Chips should provide a view that can be animated with something better than a fade-in
+ */
+interface BackgroundAnimatableView {
+ val view: View // Since this can't extend View, add a view prop
+ get() = this as View
+ val chipWidth: Int
+ get() = view.measuredWidth
+ fun setBoundsForAnimation(l: Int, t: Int, r: Int, b: Int)
+}
+
+// Animation directions
+private const val LEFT = 1
+private const val RIGHT = 2
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventCoordinator.kt
index 04f7492e8562..fde5d39db7e3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventCoordinator.kt
@@ -70,11 +70,11 @@ class SystemEventCoordinator @Inject constructor(
fun notifyPrivacyItemsChanged(showAnimation: Boolean = true) {
val event = PrivacyEvent(showAnimation)
event.privacyItems = privacyStateListener.currentPrivacyItems
- event.contentDescription = {
+ event.contentDescription = run {
val items = PrivacyChipBuilder(context, event.privacyItems).joinTypes()
context.getString(
R.string.ongoing_privacy_chip_content_multiple_apps, items)
- }()
+ }
scheduler.onStatusEvent(event)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationScheduler.kt b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationScheduler.kt
index 5a273294e87c..36233e4e3eab 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationScheduler.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationScheduler.kt
@@ -19,13 +19,11 @@ package com.android.systemui.statusbar.events
import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.animation.AnimatorSet
-import android.animation.ValueAnimator
import android.annotation.IntDef
-import android.content.Context
import android.os.Process
import android.provider.DeviceConfig
import android.util.Log
-import android.view.View
+import android.view.animation.PathInterpolator
import com.android.systemui.Dumpable
import com.android.systemui.dagger.SysUISingleton
@@ -38,6 +36,7 @@ import com.android.systemui.util.concurrency.DelayableExecutor
import com.android.systemui.util.time.SystemClock
import java.io.FileDescriptor
import java.io.PrintWriter
+import java.lang.IllegalStateException
import javax.inject.Inject
@@ -45,7 +44,7 @@ import javax.inject.Inject
* Dead-simple scheduler for system status events. Obeys the following principles (all values TBD):
* - Avoiding log spam by only allowing 12 events per minute (1event/5s)
* - Waits 100ms to schedule any event for debouncing/prioritization
- * - Simple prioritization: Privacy > Battery > connectivity (encoded in StatusEvent)
+ * - Simple prioritization: Privacy > Battery > connectivity (encoded in [StatusEvent])
* - Only schedules a single event, and throws away lowest priority events
*
* There are 4 basic stages of animation at play here:
@@ -111,12 +110,15 @@ class SystemStatusAnimationScheduler @Inject constructor(
scheduleEvent(event)
} else if (scheduledEvent?.shouldUpdateFromEvent(event) == true) {
if (DEBUG) {
- Log.d(TAG, "updating current event from: $event")
+ Log.d(TAG, "updating current event from: $event. animationState=$animationState")
}
scheduledEvent?.updateFromEvent(event)
if (event.forceVisible) {
hasPersistentDot = true
- notifyTransitionToPersistentDot()
+ // If we missed the chance to show the persistent dot, do it now
+ if (animationState == IDLE) {
+ notifyTransitionToPersistentDot()
+ }
}
} else {
if (DEBUG) {
@@ -162,60 +164,90 @@ class SystemStatusAnimationScheduler @Inject constructor(
return
}
- // Schedule the animation to start after a debounce period
- cancelExecutionRunnable = executor.executeDelayed({
- cancelExecutionRunnable = null
- animationState = ANIMATING_IN
- statusBarWindowController.setForceStatusBarVisible(true)
-
- val entranceAnimator = ValueAnimator.ofFloat(1f, 0f)
- entranceAnimator.duration = ENTRANCE_ANIM_LENGTH
- entranceAnimator.addListener(systemAnimatorAdapter)
- entranceAnimator.addUpdateListener(systemUpdateListener)
-
- val chipAnimator = ValueAnimator.ofFloat(0f, 1f)
- chipAnimator.duration = CHIP_ANIM_LENGTH
- chipAnimator.addListener(
- ChipAnimatorAdapter(RUNNING_CHIP_ANIM, scheduledEvent!!.viewCreator))
- chipAnimator.addUpdateListener(chipUpdateListener)
-
- val aSet2 = AnimatorSet()
- aSet2.playSequentially(entranceAnimator, chipAnimator)
- aSet2.start()
-
- executor.executeDelayed({
- animationState = ANIMATING_OUT
-
- val systemAnimator = ValueAnimator.ofFloat(0f, 1f)
- systemAnimator.duration = ENTRANCE_ANIM_LENGTH
- systemAnimator.addListener(systemAnimatorAdapter)
- systemAnimator.addUpdateListener(systemUpdateListener)
-
- val chipAnimator = ValueAnimator.ofFloat(1f, 0f)
- chipAnimator.duration = CHIP_ANIM_LENGTH
- val endState = if (hasPersistentDot) {
- SHOWING_PERSISTENT_DOT
- } else {
- IDLE
+ chipAnimationController.prepareChipAnimation(scheduledEvent!!.viewCreator)
+ animationState = ANIMATION_QUEUED
+ executor.executeDelayed({
+ runChipAnimation()
+ }, DEBOUNCE_DELAY)
+ }
+
+ /**
+ * 1. Define a total budget for the chip animation (1500ms)
+ * 2. Send out callbacks to listeners so that they can generate animations locally
+ * 3. Update the scheduler state so that clients know where we are
+ * 4. Maybe: provide scaffolding such as: dot location, margins, etc
+ * 5. Maybe: define a maximum animation length and enforce it. Probably only doable if we
+ * collect all of the animators and run them together.
+ */
+ private fun runChipAnimation() {
+ statusBarWindowController.setForceStatusBarVisible(true)
+ animationState = ANIMATING_IN
+
+ val animSet = collectStartAnimations()
+ if (animSet.totalDuration > 500) {
+ throw IllegalStateException("System animation total length exceeds budget. " +
+ "Expected: 500, actual: ${animSet.totalDuration}")
+ }
+ animSet.addListener(object : AnimatorListenerAdapter() {
+ override fun onAnimationEnd(animation: Animator?) {
+ animationState = RUNNING_CHIP_ANIM
+ }
+ })
+ animSet.start()
+
+ executor.executeDelayed({
+ val animSet2 = collectFinishAnimations()
+ animationState = ANIMATING_OUT
+ animSet2.addListener(object : AnimatorListenerAdapter() {
+ override fun onAnimationEnd(animation: Animator?) {
+ animationState = if (hasPersistentDot) {
+ SHOWING_PERSISTENT_DOT
+ } else {
+ IDLE
+ }
+
+ statusBarWindowController.setForceStatusBarVisible(false)
}
- chipAnimator.addListener(
- ChipAnimatorAdapter(endState, scheduledEvent!!.viewCreator))
- chipAnimator.addUpdateListener(chipUpdateListener)
+ })
+ animSet2.start()
+ scheduledEvent = null
+ }, DISPLAY_LENGTH)
+ }
- val aSet2 = AnimatorSet()
+ private fun collectStartAnimations(): AnimatorSet {
+ val animators = mutableListOf<Animator>()
+ listeners.forEach { listener ->
+ listener.onSystemEventAnimationBegin()?.let { anim ->
+ animators.add(anim)
+ }
+ }
+ animators.add(chipAnimationController.onSystemEventAnimationBegin())
+ val animSet = AnimatorSet().also {
+ it.playTogether(animators)
+ }
- aSet2.play(chipAnimator).before(systemAnimator)
- if (hasPersistentDot) {
- val dotAnim = notifyTransitionToPersistentDot()
- if (dotAnim != null) aSet2.playTogether(systemAnimator, dotAnim)
- }
+ return animSet
+ }
- aSet2.start()
+ private fun collectFinishAnimations(): AnimatorSet {
+ val animators = mutableListOf<Animator>()
+ listeners.forEach { listener ->
+ listener.onSystemEventAnimationFinish(hasPersistentDot)?.let { anim ->
+ animators.add(anim)
+ }
+ }
+ animators.add(chipAnimationController.onSystemEventAnimationFinish(hasPersistentDot))
+ if (hasPersistentDot) {
+ val dotAnim = notifyTransitionToPersistentDot()
+ if (dotAnim != null) {
+ animators.add(dotAnim)
+ }
+ }
+ val animSet = AnimatorSet().also {
+ it.playTogether(animators)
+ }
- statusBarWindowController.setForceStatusBarVisible(false)
- scheduledEvent = null
- }, DISPLAY_LENGTH)
- }, DELAY)
+ return animSet
}
private fun notifyTransitionToPersistentDot(): Animator? {
@@ -249,18 +281,6 @@ class SystemStatusAnimationScheduler @Inject constructor(
return null
}
- private fun notifySystemStart() {
- listeners.forEach { it.onSystemChromeAnimationStart() }
- }
-
- private fun notifySystemFinish() {
- listeners.forEach { it.onSystemChromeAnimationEnd() }
- }
-
- private fun notifySystemAnimationUpdate(anim: ValueAnimator) {
- listeners.forEach { it.onSystemChromeAnimationUpdate(anim) }
- }
-
override fun addCallback(listener: SystemStatusAnimationCallback) {
Assert.isMainThread()
@@ -279,24 +299,6 @@ class SystemStatusAnimationScheduler @Inject constructor(
}
}
- private val systemUpdateListener = ValueAnimator.AnimatorUpdateListener {
- anim -> notifySystemAnimationUpdate(anim)
- }
-
- private val systemAnimatorAdapter = object : AnimatorListenerAdapter() {
- override fun onAnimationEnd(p0: Animator?) {
- notifySystemFinish()
- }
-
- override fun onAnimationStart(p0: Animator?) {
- notifySystemStart()
- }
- }
-
- private val chipUpdateListener = ValueAnimator.AnimatorUpdateListener {
- anim -> chipAnimationController.onChipAnimationUpdate(anim, animationState)
- }
-
override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>) {
pw.println("Scheduled event: $scheduledEvent")
pw.println("Has persistent privacy dot: $hasPersistentDot")
@@ -310,24 +312,6 @@ class SystemStatusAnimationScheduler @Inject constructor(
}
}
}
-
- inner class ChipAnimatorAdapter(
- @SystemAnimationState val endState: Int,
- val viewCreator: (context: Context) -> View
- ) : AnimatorListenerAdapter() {
- override fun onAnimationEnd(p0: Animator?) {
- chipAnimationController.onChipAnimationEnd(animationState)
- animationState = if (endState == SHOWING_PERSISTENT_DOT && !hasPersistentDot) {
- IDLE
- } else {
- endState
- }
- }
-
- override fun onAnimationStart(p0: Animator?) {
- chipAnimationController.onChipAnimationStart(viewCreator, animationState)
- }
- }
}
/**
@@ -336,16 +320,14 @@ class SystemStatusAnimationScheduler @Inject constructor(
* create space for the chip animation to display. This means hiding the system elements in the
* status bar and keyguard.
*
- * TODO: the chip animation really only has one client, we can probably remove it from this
- * interface
- *
* The value animators themselves are simple animators from 0.0 to 1.0. Listeners can apply any
* interpolation they choose but realistically these are most likely to be simple alpha transitions
*/
interface SystemStatusAnimationCallback {
- @JvmDefault fun onSystemChromeAnimationUpdate(animator: ValueAnimator) {}
- @JvmDefault fun onSystemChromeAnimationStart() {}
- @JvmDefault fun onSystemChromeAnimationEnd() {}
+ /** Implement this method to return an [Animator] or [AnimatorSet] that presents the chip */
+ fun onSystemEventAnimationBegin(): Animator? { return null }
+ /** Implement this method to return an [Animator] or [AnimatorSet] that hides the chip */
+ fun onSystemEventAnimationFinish(hasPersistentDot: Boolean): Animator? { return null }
// Best method name, change my mind
@JvmDefault
@@ -355,50 +337,61 @@ interface SystemStatusAnimationCallback {
@JvmDefault fun onHidePersistentDot(): Animator? { return null }
}
-interface SystemStatusChipAnimationCallback {
- fun onChipAnimationUpdate(animator: ValueAnimator, @SystemAnimationState state: Int) {}
-
- fun onChipAnimationStart(
- viewCreator: (context: Context) -> View,
- @SystemAnimationState state: Int
- ) {}
-
- fun onChipAnimationEnd(@SystemAnimationState state: Int) {}
-}
-
/**
+ * Animation state IntDef
*/
@Retention(AnnotationRetention.SOURCE)
@IntDef(
value = [
- IDLE, ANIMATING_IN, RUNNING_CHIP_ANIM, ANIMATING_OUT
+ IDLE,
+ ANIMATION_QUEUED,
+ ANIMATING_IN,
+ RUNNING_CHIP_ANIM,
+ ANIMATING_OUT,
+ SHOWING_PERSISTENT_DOT
]
)
annotation class SystemAnimationState
/** No animation is in progress */
const val IDLE = 0
+/** An animation is queued, and awaiting the debounce period */
+const val ANIMATION_QUEUED = 1
/** System is animating out, and chip is animating in */
-const val ANIMATING_IN = 1
+const val ANIMATING_IN = 2
/** Chip has animated in and is awaiting exit animation, and optionally playing its own animation */
-const val RUNNING_CHIP_ANIM = 2
+const val RUNNING_CHIP_ANIM = 3
/** Chip is animating away and system is animating back */
-const val ANIMATING_OUT = 3
+const val ANIMATING_OUT = 4
/** Chip has animated away, and the persistent dot is showing */
-const val SHOWING_PERSISTENT_DOT = 4
+const val SHOWING_PERSISTENT_DOT = 5
+
+/** Commonly-needed interpolators can go here */
+@JvmField val STATUS_BAR_X_MOVE_OUT = PathInterpolator(0.33f, 0f, 0f, 1f)
+@JvmField val STATUS_BAR_X_MOVE_IN = PathInterpolator(0f, 0f, 0f, 1f)
+/**
+ * Status chip animation to dot have multiple stages of motion, the _1 and _2 interpolators should
+ * be used in succession
+ */
+val STATUS_CHIP_WIDTH_TO_DOT_KEYFRAME_1 = PathInterpolator(0.44f, 0f, 0.25f, 1f)
+val STATUS_CHIP_WIDTH_TO_DOT_KEYFRAME_2 = PathInterpolator(0.3f, 0f, 0.26f, 1f)
+val STATUS_CHIP_HEIGHT_TO_DOT_KEYFRAME_1 = PathInterpolator(0.4f, 0f, 0.17f, 1f)
+val STATUS_CHIP_HEIGHT_TO_DOT_KEYFRAME_2 = PathInterpolator(0.3f, 0f, 0f, 1f)
+val STATUS_CHIP_MOVE_TO_DOT = PathInterpolator(0f, 0f, 0.05f, 1f)
private const val TAG = "SystemStatusAnimationScheduler"
-private const val DELAY = 0L
+private const val DEBOUNCE_DELAY = 100L
/**
- * The total time spent animation should be 1500ms. The entrance animation is how much time
- * we give to the system to animate system elements out of the way. Total chip animation length
- * will be equivalent to 2*chip_anim_length + display_length
+ * The total time spent on the chip animation is 1500ms, broken up into 3 sections:
+ * - 500ms to animate the chip in (including animating system icons away)
+ * - 500ms holding the chip on screen
+ * - 500ms to animate the chip away (and system icons back)
+ *
+ * So DISPLAY_LENGTH should be the sum of the first 2 phases, while the final 500ms accounts for
+ * the actual animation
*/
-private const val ENTRANCE_ANIM_LENGTH = 250L
-private const val CHIP_ANIM_LENGTH = 250L
-// 1s + entrance time + chip anim_length
-private const val DISPLAY_LENGTH = 1500L
+private const val DISPLAY_LENGTH = 1000L
private const val MIN_UPTIME: Long = 5 * 1000
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java
index 5b7d90bfca44..df412ed93f55 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java
@@ -16,11 +16,9 @@
package com.android.systemui.statusbar.notification;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
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;
-import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -182,25 +180,6 @@ public class InstantAppNotifier extends CoreStartable
}
/**
- * Posts an instant app notification if the top activity of the primary container in the
- * splitted screen is an instant app and the corresponding instant app notification is not
- * posted yet. If the notification already exists, this method removes it from {@code
- * notifs} in the arguments.
- */
- private void checkAndPostForPrimaryScreen(
- @NonNull ArraySet<Pair<String, Integer>> notifs,
- @NonNull NotificationManager noMan,
- @NonNull IPackageManager pm) {
- try {
- final RootTaskInfo info = ActivityTaskManager.getService().getRootTaskInfo(
- WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_UNDEFINED);
- checkAndPostForStack(info, notifs, noMan, pm);
- } catch (RemoteException e) {
- e.rethrowFromSystemServer();
- }
- }
-
- /**
* Posts an instant app notification if the top activity of the given stack is an instant app
* and the corresponding instant app notification is not posted yet. If the notification already
* exists, this method removes it from {@code notifs} in the arguments.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt
index 2c1296f34a42..02aa1f2fd585 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt
@@ -22,15 +22,18 @@ class NotificationLaunchAnimatorControllerProvider @Inject constructor(
private val headsUpManager: HeadsUpManagerPhone,
private val jankMonitor: InteractionJankMonitor
) {
+ @JvmOverloads
fun getAnimatorController(
- notification: ExpandableNotificationRow
+ notification: ExpandableNotificationRow,
+ onFinishAnimationCallback: Runnable? = null
): NotificationLaunchAnimatorController {
return NotificationLaunchAnimatorController(
notificationShadeWindowViewController,
notificationListContainer,
headsUpManager,
notification,
- jankMonitor
+ jankMonitor,
+ onFinishAnimationCallback
)
}
}
@@ -45,7 +48,8 @@ class NotificationLaunchAnimatorController(
private val notificationListContainer: NotificationListContainer,
private val headsUpManager: HeadsUpManagerPhone,
private val notification: ExpandableNotificationRow,
- private val jankMonitor: InteractionJankMonitor
+ private val jankMonitor: InteractionJankMonitor,
+ private val onFinishAnimationCallback: Runnable?
) : ActivityLaunchAnimator.Controller {
companion object {
@@ -119,6 +123,7 @@ class NotificationLaunchAnimatorController(
if (!willAnimate) {
removeHun(animate = true)
+ onFinishAnimationCallback?.run()
}
}
@@ -137,6 +142,7 @@ class NotificationLaunchAnimatorController(
notificationShadeWindowViewController.setExpandAnimationRunning(false)
notificationEntry.isExpandAnimationRunning = false
removeHun(animate = true)
+ onFinishAnimationCallback?.run()
}
override fun onLaunchAnimationStart(isExpandingFullyAbove: Boolean) {
@@ -156,6 +162,7 @@ class NotificationLaunchAnimatorController(
notificationListContainer.setExpandingNotification(null)
applyParams(null)
removeHun(animate = false)
+ onFinishAnimationCallback?.run()
}
private fun applyParams(params: ExpandAnimationParameters?) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java
index 369ef343a4e2..2baa0797b41f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java
@@ -230,7 +230,13 @@ public class ShadeListBuilder implements Dumpable {
mPipelineState.requireState(STATE_IDLE);
mNotifSections.clear();
+ NotifSectioner lastSection = null;
for (NotifSectioner sectioner : sectioners) {
+ if (lastSection != null && lastSection.getBucket() > sectioner.getBucket()) {
+ throw new IllegalArgumentException("setSectioners with non contiguous sections "
+ + lastSection.getName() + " - " + lastSection.getBucket() + " & "
+ + sectioner.getName() + " - " + sectioner.getBucket());
+ }
final NotifSection section = new NotifSection(sectioner, mNotifSections.size());
final NotifComparator sectionComparator = section.getComparator();
mNotifSections.add(section);
@@ -238,6 +244,7 @@ public class ShadeListBuilder implements Dumpable {
if (sectionComparator != null) {
sectionComparator.setInvalidationListener(this::onNotifComparatorInvalidated);
}
+ lastSection = sectioner;
}
mNotifSections.add(new NotifSection(DEFAULT_SECTIONER, mNotifSections.size()));
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ActivityLaunchAnimCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ActivityLaunchAnimCoordinator.kt
new file mode 100644
index 000000000000..b54163d29e80
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ActivityLaunchAnimCoordinator.kt
@@ -0,0 +1,95 @@
+/*
+ * 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.statusbar.notification.collection.coordinator
+
+import com.android.systemui.statusbar.notification.collection.NotifPipeline
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope
+import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender
+import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender.OnEndLifetimeExtensionCallback
+import com.android.systemui.statusbar.phone.NotifActivityLaunchEvents
+import dagger.Binds
+import dagger.Module
+import javax.inject.Inject
+
+/** Extends the lifetime of notifications while their activity launch animation is playing. */
+interface ActivityLaunchAnimCoordinator : Coordinator
+
+/** Provides an [ActivityLaunchAnimCoordinator] to [CoordinatorScope]. */
+@Module(includes = [PrivateActivityStarterCoordinatorModule::class])
+object ActivityLaunchAnimCoordinatorModule
+
+@Module
+private interface PrivateActivityStarterCoordinatorModule {
+ @Binds
+ fun bindCoordinator(impl: ActivityLaunchAnimCoordinatorImpl): ActivityLaunchAnimCoordinator
+}
+
+/**
+ * Listens for [NotifActivityLaunchEvents], and then extends the lifetimes of any notifs while their
+ * launch animation is playing.
+ */
+@CoordinatorScope
+private class ActivityLaunchAnimCoordinatorImpl @Inject constructor(
+ private val activityLaunchEvents: NotifActivityLaunchEvents
+) : ActivityLaunchAnimCoordinator {
+ // Tracks notification launches, and whether or not their lifetimes are extended.
+ private val notifsLaunchingActivities = mutableMapOf<String, Boolean>()
+
+ private var onEndLifetimeExtensionCallback: OnEndLifetimeExtensionCallback? = null
+
+ override fun attach(pipeline: NotifPipeline) {
+ activityLaunchEvents.registerListener(activityStartEventListener)
+ pipeline.addNotificationLifetimeExtender(extender)
+ }
+
+ private val activityStartEventListener = object : NotifActivityLaunchEvents.Listener {
+ override fun onStartLaunchNotifActivity(entry: NotificationEntry) {
+ notifsLaunchingActivities[entry.key] = false
+ }
+
+ override fun onFinishLaunchNotifActivity(entry: NotificationEntry) {
+ if (notifsLaunchingActivities.remove(entry.key) == true) {
+ // If we were extending the lifetime of this notification, stop.
+ onEndLifetimeExtensionCallback?.onEndLifetimeExtension(extender, entry)
+ }
+ }
+ }
+
+ private val extender = object : NotifLifetimeExtender {
+ override fun getName(): String = "ActivityStarterCoordinator"
+
+ override fun setCallback(callback: OnEndLifetimeExtensionCallback) {
+ onEndLifetimeExtensionCallback = callback
+ }
+
+ override fun maybeExtendLifetime(entry: NotificationEntry, reason: Int): Boolean {
+ if (entry.key in notifsLaunchingActivities) {
+ // Track that we're now extending this notif
+ notifsLaunchingActivities[entry.key] = true
+ return true
+ }
+ return false
+ }
+
+ override fun cancelLifetimeExtension(entry: NotificationEntry) {
+ if (entry.key in notifsLaunchingActivities) {
+ notifsLaunchingActivities[entry.key] = false
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/CommunalCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/CommunalCoordinator.java
deleted file mode 100644
index 5396b8638225..000000000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/CommunalCoordinator.java
+++ /dev/null
@@ -1,82 +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.systemui.statusbar.notification.collection.coordinator;
-
-import androidx.annotation.NonNull;
-
-import com.android.systemui.communal.CommunalStateController;
-import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.statusbar.NotificationLockscreenUserManager;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
-import com.android.systemui.statusbar.notification.collection.NotifPipeline;
-import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope;
-import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
-
-import java.util.concurrent.Executor;
-
-import javax.inject.Inject;
-
-/**
- * {@link CommunalCoordinator} prevents notifications from showing on the keyguard when the communal
- * view is present.
- */
-@CoordinatorScope
-public class CommunalCoordinator implements Coordinator {
- final Executor mExecutor;
- final CommunalStateController mCommunalStateController;
- final NotificationEntryManager mNotificationEntryManager;
- final NotificationLockscreenUserManager mNotificationLockscreenUserManager;
-
- @Inject
- public CommunalCoordinator(@Main Executor executor,
- NotificationEntryManager notificationEntryManager,
- NotificationLockscreenUserManager notificationLockscreenUserManager,
- CommunalStateController communalStateController) {
- mExecutor = executor;
- mNotificationEntryManager = notificationEntryManager;
- mNotificationLockscreenUserManager = notificationLockscreenUserManager;
- mCommunalStateController = communalStateController;
- }
-
- final NotifFilter mFilter = new NotifFilter("CommunalCoordinator") {
- @Override
- public boolean shouldFilterOut(@NonNull NotificationEntry entry, long now) {
- return mCommunalStateController.getCommunalViewShowing();
- }
- };
-
- final CommunalStateController.Callback mStateCallback = new CommunalStateController.Callback() {
- @Override
- public void onCommunalViewShowingChanged() {
- mExecutor.execute(() -> {
- mFilter.invalidateList();
- mNotificationEntryManager.updateNotifications("Communal mode state changed");
- });
- }
- };
-
- @Override
- public void attach(@NonNull NotifPipeline pipeline) {
- pipeline.addPreGroupFilter(mFilter);
- mCommunalStateController.addCallback(mStateCallback);
- if (!pipeline.isNewPipelineEnabled()) {
- mNotificationLockscreenUserManager.addKeyguardNotificationSuppressor(
- entry -> mCommunalStateController.getCommunalViewShowing());
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.kt
index 41b070635d4f..da0169bd6dc4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.kt
@@ -72,9 +72,10 @@ class HeadsUpCoordinator @Inject constructor(
private var mEndLifetimeExtension: OnEndLifetimeExtensionCallback? = null
private lateinit var mNotifPipeline: NotifPipeline
private var mNow: Long = -1
+ private val mPostedEntries = LinkedHashMap<String, PostedEntry>()
- // notifs we've extended the lifetime for
- private val mNotifsExtendingLifetime = ArraySet<NotificationEntry>()
+ // notifs we've extended the lifetime for with cancellation callbacks
+ private val mNotifsExtendingLifetime = ArrayMap<NotificationEntry, Runnable?>()
override fun attach(pipeline: NotifPipeline) {
mNotifPipeline = pipeline
@@ -101,10 +102,12 @@ class HeadsUpCoordinator @Inject constructor(
return
}
// Process all non-group adds/updates
- mPostedEntries.values.toList().forEach { posted ->
- if (!posted.entry.sbn.isGroup) {
- handlePostedEntry(posted, "non-group")
- mPostedEntries.remove(posted.key)
+ mHeadsUpManager.modifyHuns { hunMutator ->
+ mPostedEntries.values.toList().forEach { posted ->
+ if (!posted.entry.sbn.isGroup) {
+ handlePostedEntry(posted, hunMutator, "non-group")
+ mPostedEntries.remove(posted.key)
+ }
}
}
}
@@ -114,10 +117,10 @@ class HeadsUpCoordinator @Inject constructor(
* we know that stability and [NotifPromoter]s have been applied, so we can use the location of
* notifications in this list to determine what kind of group alert behavior should happen.
*/
- fun onBeforeFinalizeFilter(list: List<ListEntry>) {
+ fun onBeforeFinalizeFilter(list: List<ListEntry>) = mHeadsUpManager.modifyHuns { hunMutator ->
// Nothing to do if there are no other adds/updates
if (mPostedEntries.isEmpty()) {
- return
+ return@modifyHuns
}
// Calculate a bunch of information about the logical group and the locations of group
// entries in the nearly-finalized shade list. These may be used in the per-group loop.
@@ -138,13 +141,17 @@ class HeadsUpCoordinator @Inject constructor(
// If there is no logical summary, then there is no alert to transfer
if (logicalSummary == null) {
- postedEntries.forEach { handlePostedEntry(it, "logical-summary-missing") }
+ postedEntries.forEach {
+ handlePostedEntry(it, hunMutator, scenario = "logical-summary-missing")
+ }
return@forEach
}
// If summary isn't wanted to be heads up, then there is no alert to transfer
if (!isGoingToShowHunStrict(logicalSummary)) {
- postedEntries.forEach { handlePostedEntry(it, "logical-summary-not-alerting") }
+ postedEntries.forEach {
+ handlePostedEntry(it, hunMutator, scenario = "logical-summary-not-alerting")
+ }
return@forEach
}
@@ -177,7 +184,9 @@ class HeadsUpCoordinator @Inject constructor(
// If there is no child to receive the parent alert, then just handle the posted entries
// and return.
if (childToReceiveParentAlert == null) {
- postedEntries.forEach { handlePostedEntry(it, "no-transfer-target") }
+ postedEntries.forEach {
+ handlePostedEntry(it, hunMutator, scenario = "no-transfer-target")
+ }
return@forEach
}
@@ -189,51 +198,66 @@ class HeadsUpCoordinator @Inject constructor(
if (!isSummaryAttached) {
val summaryUpdateForRemoval = summaryUpdate?.also {
it.shouldHeadsUpEver = false
- } ?: PostedEntry(logicalSummary,
- wasAdded = false,
- wasUpdated = false,
- shouldHeadsUpEver = false,
- shouldHeadsUpAgain = false,
- isAlerting = mHeadsUpManager.isAlerting(logicalSummary.key),
- isBinding = isEntryBinding(logicalSummary),
+ } ?: PostedEntry(
+ logicalSummary,
+ wasAdded = false,
+ wasUpdated = false,
+ shouldHeadsUpEver = false,
+ shouldHeadsUpAgain = false,
+ isAlerting = mHeadsUpManager.isAlerting(logicalSummary.key),
+ isBinding = isEntryBinding(logicalSummary),
)
// If we transfer the alert and the summary isn't even attached, that means we
// should ensure the summary is no longer alerting, so we remove it here.
- handlePostedEntry(summaryUpdateForRemoval, "detached-summary-remove-alert")
- } else if (summaryUpdate!=null) {
- mLogger.logPostedEntryWillNotEvaluate(summaryUpdate, "attached-summary-transferred")
+ handlePostedEntry(
+ summaryUpdateForRemoval,
+ hunMutator,
+ scenario = "detached-summary-remove-alert")
+ } else if (summaryUpdate != null) {
+ mLogger.logPostedEntryWillNotEvaluate(
+ summaryUpdate,
+ reason = "attached-summary-transferred")
}
// Handle all posted entries -- if the child receiving the parent's alert is in the
// list, then set its flags to ensure it alerts.
var didAlertChildToReceiveParentAlert = false
postedEntries.asSequence()
- .filter { it.key != logicalSummary.key }
- .forEach { postedEntry ->
- if (childToReceiveParentAlert.key == postedEntry.key) {
- // Update the child's posted update so that it
- postedEntry.shouldHeadsUpEver = true
- postedEntry.shouldHeadsUpAgain = true
- handlePostedEntry(postedEntry, "child-alert-transfer-target-$targetType")
- didAlertChildToReceiveParentAlert = true
- } else {
- handlePostedEntry(postedEntry, "child-alert-non-target")
+ .filter { it.key != logicalSummary.key }
+ .forEach { postedEntry ->
+ if (childToReceiveParentAlert.key == postedEntry.key) {
+ // Update the child's posted update so that it
+ postedEntry.shouldHeadsUpEver = true
+ postedEntry.shouldHeadsUpAgain = true
+ handlePostedEntry(
+ postedEntry,
+ hunMutator,
+ scenario = "child-alert-transfer-target-$targetType")
+ didAlertChildToReceiveParentAlert = true
+ } else {
+ handlePostedEntry(
+ postedEntry,
+ hunMutator,
+ scenario = "child-alert-non-target")
+ }
}
- }
// If the child receiving the alert was not updated on this tick (which can happen in a
// standard alert transfer scenario), then construct an update so that we can apply it.
if (!didAlertChildToReceiveParentAlert) {
val posted = PostedEntry(
- childToReceiveParentAlert,
- wasAdded = false,
- wasUpdated = false,
- shouldHeadsUpEver = true,
- shouldHeadsUpAgain = true,
- isAlerting = mHeadsUpManager.isAlerting(childToReceiveParentAlert.key),
- isBinding = isEntryBinding(childToReceiveParentAlert),
+ childToReceiveParentAlert,
+ wasAdded = false,
+ wasUpdated = false,
+ shouldHeadsUpEver = true,
+ shouldHeadsUpAgain = true,
+ isAlerting = mHeadsUpManager.isAlerting(childToReceiveParentAlert.key),
+ isBinding = isEntryBinding(childToReceiveParentAlert),
)
- handlePostedEntry(posted, "non-posted-child-alert-transfer-target-$targetType")
+ handlePostedEntry(
+ posted,
+ hunMutator,
+ scenario = "non-posted-child-alert-transfer-target-$targetType")
}
}
// After this method runs, all posted entries should have been handled (or skipped).
@@ -292,9 +316,7 @@ class HeadsUpCoordinator @Inject constructor(
}
}
- private val mPostedEntries = LinkedHashMap<String, PostedEntry>()
-
- fun handlePostedEntry(posted: PostedEntry, scenario: String) {
+ private fun handlePostedEntry(posted: PostedEntry, hunMutator: HunMutator, scenario: String) {
mLogger.logPostedEntryWillEvaluate(posted, scenario)
if (posted.wasAdded) {
if (posted.shouldHeadsUpEver) {
@@ -308,12 +330,12 @@ class HeadsUpCoordinator @Inject constructor(
// If alerting, we need to post an update. Otherwise we're still binding,
// and we can just let that finish.
if (posted.isAlerting) {
- mHeadsUpManager.updateNotification(posted.key, posted.shouldHeadsUpAgain)
+ hunMutator.updateNotification(posted.key, posted.shouldHeadsUpAgain)
}
} else {
if (posted.isAlerting) {
// We don't want this to be interrupting anymore, let's remove it
- mHeadsUpManager.removeNotification(posted.key, false /*removeImmediately*/)
+ hunMutator.removeNotification(posted.key, false /*removeImmediately*/)
} else {
// Don't let the bind finish
cancelHeadsUpBind(posted.entry)
@@ -366,7 +388,7 @@ class HeadsUpCoordinator @Inject constructor(
val shouldHeadsUpAgain = shouldHunAgain(entry)
val isAlerting = mHeadsUpManager.isAlerting(entry.key)
val isBinding = isEntryBinding(entry)
- mPostedEntries.compute(entry.key) { _, value ->
+ val posted = mPostedEntries.compute(entry.key) { _, value ->
value?.also { update ->
update.wasUpdated = true
update.shouldHeadsUpEver = update.shouldHeadsUpEver || shouldHeadsUpEver
@@ -383,6 +405,18 @@ class HeadsUpCoordinator @Inject constructor(
isBinding = isBinding,
)
}
+ // Handle cancelling alerts here, rather than in the OnBeforeFinalizeFilter, so that
+ // work can be done before the ShadeListBuilder is run. This prevents re-entrant
+ // behavior between this Coordinator, HeadsUpManager, and VisualStabilityManager.
+ if (posted?.shouldHeadsUpEver == false) {
+ if (posted.isAlerting) {
+ // We don't want this to be interrupting anymore, let's remove it
+ mHeadsUpManager.removeNotification(posted.key, false /*removeImmediately*/)
+ } else if (posted.isBinding) {
+ // Don't let the bind finish
+ cancelHeadsUpBind(posted.entry)
+ }
+ }
}
/**
@@ -427,23 +461,20 @@ class HeadsUpCoordinator @Inject constructor(
}
if (isSticky(entry)) {
val removeAfterMillis = mHeadsUpManager.getEarliestRemovalTime(entry.key)
- mExecutor.executeDelayed({
- val canStillRemove = mHeadsUpManager.canRemoveImmediately(entry.key)
- if (mNotifsExtendingLifetime.contains(entry) && canStillRemove) {
- mHeadsUpManager.removeNotification(entry.key, /* releaseImmediately */ true)
- }
+ mNotifsExtendingLifetime[entry] = mExecutor.executeDelayed({
+ mHeadsUpManager.removeNotification(entry.key, /* releaseImmediately */ true)
}, removeAfterMillis)
} else {
mExecutor.execute {
mHeadsUpManager.removeNotification(entry.key, /* releaseImmediately */ false)
}
+ mNotifsExtendingLifetime[entry] = null
}
- mNotifsExtendingLifetime.add(entry)
return true
}
override fun cancelLifetimeExtension(entry: NotificationEntry) {
- mNotifsExtendingLifetime.remove(entry)
+ mNotifsExtendingLifetime.remove(entry)?.run()
}
}
@@ -510,7 +541,8 @@ class HeadsUpCoordinator @Inject constructor(
mPostedEntries[entry.key]?.calculateShouldBeHeadsUpStrict ?: isAttemptingToShowHun(entry)
private fun endNotifLifetimeExtensionIfExtended(entry: NotificationEntry) {
- if (mNotifsExtendingLifetime.remove(entry)) {
+ if (mNotifsExtendingLifetime.contains(entry)) {
+ mNotifsExtendingLifetime.remove(entry)?.run()
mEndLifetimeExtension?.onEndLifetimeExtension(mLifetimeExtender, entry)
}
}
@@ -543,3 +575,43 @@ private enum class GroupLocation { Detached, Isolated, Summary, Child }
private fun Map<String, GroupLocation>.getLocation(key: String): GroupLocation =
getOrDefault(key, GroupLocation.Detached)
+
+/**
+ * Invokes the given block with a [HunMutator] that defers all HUN removals. This ensures that the
+ * HeadsUpManager is notified of additions before removals, which prevents a glitch where the
+ * HeadsUpManager temporarily believes that nothing is alerting, causing bad re-entrant behavior.
+ */
+private fun <R> HeadsUpManager.modifyHuns(block: (HunMutator) -> R): R {
+ val mutator = HunMutatorImpl(this)
+ return block(mutator).also { mutator.commitModifications() }
+}
+
+/** Mutates the HeadsUp state of notifications. */
+private interface HunMutator {
+ fun updateNotification(key: String, alert: Boolean)
+ fun removeNotification(key: String, releaseImmediately: Boolean)
+}
+
+/**
+ * [HunMutator] implementation that defers removing notifications from the HeadsUpManager until
+ * after additions/updates.
+ */
+private class HunMutatorImpl(private val headsUpManager: HeadsUpManager) : HunMutator {
+ private val deferred = mutableListOf<Pair<String, Boolean>>()
+
+ override fun updateNotification(key: String, alert: Boolean) {
+ headsUpManager.updateNotification(key, alert)
+ }
+
+ override fun removeNotification(key: String, releaseImmediately: Boolean) {
+ val args = Pair(key, releaseImmediately)
+ deferred.add(args)
+ }
+
+ fun commitModifications() {
+ deferred.forEach { (key, releaseImmediately) ->
+ headsUpManager.removeNotification(key, releaseImmediately)
+ }
+ deferred.clear()
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java
index 22300d8c180d..aac5b8d6b2eb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java
@@ -16,36 +16,16 @@
package com.android.systemui.statusbar.notification.collection.coordinator;
-import static android.app.Notification.VISIBILITY_SECRET;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.database.ContentObserver;
-import android.net.Uri;
-import android.os.Handler;
-import android.os.UserHandle;
-import android.provider.Settings;
-import android.service.notification.StatusBarNotification;
-
-import androidx.annotation.MainThread;
-
import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.keyguard.KeyguardUpdateMonitorCallback;
-import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.notification.SectionHeaderVisibilityProvider;
-import com.android.systemui.statusbar.notification.collection.GroupEntry;
-import com.android.systemui.statusbar.notification.collection.ListEntry;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
-import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.systemui.statusbar.notification.interruption.KeyguardNotificationVisibilityProvider;
import javax.inject.Inject;
@@ -56,171 +36,48 @@ import javax.inject.Inject;
@CoordinatorScope
public class KeyguardCoordinator implements Coordinator {
private static final String TAG = "KeyguardCoordinator";
-
- private final Context mContext;
- private final Handler mMainHandler;
- private final KeyguardStateController mKeyguardStateController;
- private final NotificationLockscreenUserManager mLockscreenUserManager;
- private final BroadcastDispatcher mBroadcastDispatcher;
private final StatusBarStateController mStatusBarStateController;
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
private final HighPriorityProvider mHighPriorityProvider;
private final SectionHeaderVisibilityProvider mSectionHeaderVisibilityProvider;
-
- private boolean mHideSilentNotificationsOnLockscreen;
+ private final KeyguardNotificationVisibilityProvider mKeyguardNotificationVisibilityProvider;
@Inject
public KeyguardCoordinator(
- Context context,
- @MainThread Handler mainThreadHandler,
- KeyguardStateController keyguardStateController,
- NotificationLockscreenUserManager lockscreenUserManager,
- BroadcastDispatcher broadcastDispatcher,
StatusBarStateController statusBarStateController,
KeyguardUpdateMonitor keyguardUpdateMonitor,
HighPriorityProvider highPriorityProvider,
- SectionHeaderVisibilityProvider sectionHeaderVisibilityProvider) {
- mContext = context;
- mMainHandler = mainThreadHandler;
- mKeyguardStateController = keyguardStateController;
- mLockscreenUserManager = lockscreenUserManager;
- mBroadcastDispatcher = broadcastDispatcher;
+ SectionHeaderVisibilityProvider sectionHeaderVisibilityProvider,
+ KeyguardNotificationVisibilityProvider keyguardNotificationVisibilityProvider) {
mStatusBarStateController = statusBarStateController;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mHighPriorityProvider = highPriorityProvider;
mSectionHeaderVisibilityProvider = sectionHeaderVisibilityProvider;
+ mKeyguardNotificationVisibilityProvider = keyguardNotificationVisibilityProvider;
}
@Override
public void attach(NotifPipeline pipeline) {
- readShowSilentNotificationSetting();
setupInvalidateNotifListCallbacks();
// Filter at the "finalize" stage so that views remain bound by PreparationCoordinator
pipeline.addFinalizeFilter(mNotifFilter);
-
+ mKeyguardNotificationVisibilityProvider
+ .addOnStateChangedListener(this::invalidateListFromFilter);
updateSectionHeadersVisibility();
}
private final NotifFilter mNotifFilter = new NotifFilter(TAG) {
@Override
public boolean shouldFilterOut(NotificationEntry entry, long now) {
- final StatusBarNotification sbn = entry.getSbn();
-
- // FILTER OUT the notification when the keyguard is showing and...
- if (mKeyguardStateController.isShowing()) {
- // ... user settings or the device policy manager doesn't allow lockscreen
- // notifications;
- if (!mLockscreenUserManager.shouldShowLockscreenNotifications()) {
- return true;
- }
-
- final int currUserId = mLockscreenUserManager.getCurrentUserId();
- final int notifUserId = (sbn.getUser().getIdentifier() == UserHandle.USER_ALL)
- ? currUserId : sbn.getUser().getIdentifier();
-
- // ... user is in lockdown
- if (mKeyguardUpdateMonitor.isUserInLockdown(currUserId)
- || mKeyguardUpdateMonitor.isUserInLockdown(notifUserId)) {
- return true;
- }
-
- // ... device is in public mode and the user's settings doesn't allow
- // notifications to show in public mode
- if (mLockscreenUserManager.isLockscreenPublicMode(currUserId)
- || mLockscreenUserManager.isLockscreenPublicMode(notifUserId)) {
- if (entry.getRanking().getLockscreenVisibilityOverride() == VISIBILITY_SECRET) {
- return true;
- }
-
- if (!mLockscreenUserManager.userAllowsNotificationsInPublic(currUserId)
- || !mLockscreenUserManager.userAllowsNotificationsInPublic(
- notifUserId)) {
- return true;
- }
- }
-
- // ... neither this notification nor its group have high enough priority
- // to be shown on the lockscreen
- if (entry.getParent() != null) {
- final GroupEntry parent = entry.getParent();
- if (priorityExceedsLockscreenShowingThreshold(parent)) {
- return false;
- }
- }
- return !priorityExceedsLockscreenShowingThreshold(entry);
- }
- return false;
+ return mKeyguardNotificationVisibilityProvider.shouldHideNotification(entry);
}
};
- private boolean priorityExceedsLockscreenShowingThreshold(ListEntry entry) {
- if (entry == null) {
- return false;
- }
- if (mHideSilentNotificationsOnLockscreen) {
- return mHighPriorityProvider.isHighPriority(entry);
- } else {
- return entry.getRepresentativeEntry() != null
- && !entry.getRepresentativeEntry().getRanking().isAmbient();
- }
- }
-
// TODO(b/206118999): merge this class with SensitiveContentCoordinator which also depends on
// these same updates
private void setupInvalidateNotifListCallbacks() {
- // register onKeyguardShowing callback
- mKeyguardStateController.addCallback(mKeyguardCallback);
- mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateCallback);
-
- // register lockscreen settings changed callbacks:
- final ContentObserver settingsObserver = new ContentObserver(mMainHandler) {
- @Override
- public void onChange(boolean selfChange, Uri uri) {
- if (uri.equals(Settings.Secure.getUriFor(
- Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS))) {
- readShowSilentNotificationSetting();
- }
-
- if (mKeyguardStateController.isShowing()) {
- invalidateListFromFilter("Settings " + uri + " changed");
- }
- }
- };
-
- mContext.getContentResolver().registerContentObserver(
- Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS),
- false,
- settingsObserver,
- UserHandle.USER_ALL);
- mContext.getContentResolver().registerContentObserver(
- Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS),
- true,
- settingsObserver,
- UserHandle.USER_ALL);
-
- mContext.getContentResolver().registerContentObserver(
- Settings.Global.getUriFor(Settings.Global.ZEN_MODE),
- false,
- settingsObserver);
-
- mContext.getContentResolver().registerContentObserver(
- Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS),
- false,
- settingsObserver,
- UserHandle.USER_ALL);
-
- // register (maybe) public mode changed callbacks:
- mStatusBarStateController.addCallback(mStatusBarStateListener);
- mBroadcastDispatcher.registerReceiver(new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (mKeyguardStateController.isShowing()) {
- // maybe public mode changed
- invalidateListFromFilter(intent.getAction());
- }
- }}, new IntentFilter(Intent.ACTION_USER_SWITCHED));
}
private void invalidateListFromFilter(String reason) {
@@ -228,49 +85,10 @@ public class KeyguardCoordinator implements Coordinator {
mNotifFilter.invalidateList();
}
- private void readShowSilentNotificationSetting() {
- mHideSilentNotificationsOnLockscreen =
- Settings.Secure.getInt(
- mContext.getContentResolver(),
- Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS,
- 1) == 0;
- }
-
private void updateSectionHeadersVisibility() {
boolean onKeyguard = mStatusBarStateController.getState() == StatusBarState.KEYGUARD;
boolean neverShowSections = mSectionHeaderVisibilityProvider.getNeverShowSectionHeaders();
boolean showSections = !onKeyguard && !neverShowSections;
mSectionHeaderVisibilityProvider.setSectionHeadersVisible(showSections);
}
-
- private final KeyguardStateController.Callback mKeyguardCallback =
- new KeyguardStateController.Callback() {
- @Override
- public void onUnlockedChanged() {
- invalidateListFromFilter("onUnlockedChanged");
- }
-
- @Override
- public void onKeyguardShowingChanged() {
- invalidateListFromFilter("onKeyguardShowingChanged");
- }
- };
-
- private final StatusBarStateController.StateListener mStatusBarStateListener =
- new StatusBarStateController.StateListener() {
- @Override
- public void onStateChanged(int newState) {
- // maybe public mode changed
- invalidateListFromFilter("onStatusBarStateChanged");
- }
- };
-
- private final KeyguardUpdateMonitorCallback mKeyguardUpdateCallback =
- new KeyguardUpdateMonitorCallback() {
- @Override
- public void onStrongAuthStateChanged(int userId) {
- // maybe lockdown mode changed
- invalidateListFromFilter("onStrongAuthStateChanged");
- }
- };
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt
index 757fb5a2fe9a..985914acb2a2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt
@@ -45,7 +45,6 @@ class NotifCoordinatorsImpl @Inject constructor(
bubbleCoordinator: BubbleCoordinator,
headsUpCoordinator: HeadsUpCoordinator,
gutsCoordinator: GutsCoordinator,
- communalCoordinator: CommunalCoordinator,
conversationCoordinator: ConversationCoordinator,
debugModeCoordinator: DebugModeCoordinator,
groupCountCoordinator: GroupCountCoordinator,
@@ -58,7 +57,8 @@ class NotifCoordinatorsImpl @Inject constructor(
smartspaceDedupingCoordinator: SmartspaceDedupingCoordinator,
viewConfigCoordinator: ViewConfigCoordinator,
visualStabilityCoordinator: VisualStabilityCoordinator,
- sensitiveContentCoordinator: SensitiveContentCoordinator
+ sensitiveContentCoordinator: SensitiveContentCoordinator,
+ activityLaunchAnimCoordinator: ActivityLaunchAnimCoordinator
) : NotifCoordinators {
private val mCoordinators: MutableList<Coordinator> = ArrayList()
@@ -86,7 +86,6 @@ class NotifCoordinatorsImpl @Inject constructor(
mCoordinators.add(appOpsCoordinator)
mCoordinators.add(deviceProvisionedCoordinator)
mCoordinators.add(bubbleCoordinator)
- mCoordinators.add(communalCoordinator)
mCoordinators.add(debugModeCoordinator)
mCoordinators.add(conversationCoordinator)
mCoordinators.add(groupCountCoordinator)
@@ -97,6 +96,7 @@ class NotifCoordinatorsImpl @Inject constructor(
mCoordinators.add(viewConfigCoordinator)
mCoordinators.add(visualStabilityCoordinator)
mCoordinators.add(sensitiveContentCoordinator)
+ mCoordinators.add(activityLaunchAnimCoordinator)
if (notifPipelineFlags.isSmartspaceDedupingEnabled()) {
mCoordinators.add(smartspaceDedupingCoordinator)
}
@@ -144,4 +144,4 @@ class NotifCoordinatorsImpl @Inject constructor(
companion object {
private const val TAG = "NotifCoordinators"
}
-} \ No newline at end of file
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinator.kt
index 72d091883ce6..3f8a39f62dfb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinator.kt
@@ -34,11 +34,11 @@ import dagger.Binds
import dagger.Module
import javax.inject.Inject
-@Module(includes = [PrivateModule::class])
+@Module(includes = [PrivateSensitiveContentCoordinatorModule::class])
interface SensitiveContentCoordinatorModule
@Module
-private interface PrivateModule {
+private interface PrivateSensitiveContentCoordinatorModule {
@Binds
fun bindCoordinator(impl: SensitiveContentCoordinatorImpl): SensitiveContentCoordinator
}
@@ -121,4 +121,4 @@ private fun extractAllRepresentativeEntries(listEntry: ListEntry): Sequence<Noti
if (listEntry is GroupEntry) {
yieldAll(extractAllRepresentativeEntries(listEntry.children))
}
- } \ No newline at end of file
+ }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinator.java
index 3aa3549a7c27..acc493d4b992 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinator.java
@@ -32,7 +32,7 @@ import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifStabilityManager;
import com.android.systemui.statusbar.notification.collection.provider.VisualStabilityProvider;
-import com.android.systemui.statusbar.notification.collection.render.NotifPanelEventSource;
+import com.android.systemui.statusbar.phone.NotifPanelEvents;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.util.concurrency.DelayableExecutor;
@@ -53,10 +53,10 @@ import javax.inject.Inject;
// TODO(b/204468557): Move to @CoordinatorScope
@SysUISingleton
public class VisualStabilityCoordinator implements Coordinator, Dumpable,
- NotifPanelEventSource.Callbacks {
+ NotifPanelEvents.Listener {
private final DelayableExecutor mDelayableExecutor;
private final HeadsUpManager mHeadsUpManager;
- private final NotifPanelEventSource mNotifPanelEventSource;
+ private final NotifPanelEvents mNotifPanelEvents;
private final StatusBarStateController mStatusBarStateController;
private final VisualStabilityProvider mVisualStabilityProvider;
private final WakefulnessLifecycle mWakefulnessLifecycle;
@@ -87,7 +87,7 @@ public class VisualStabilityCoordinator implements Coordinator, Dumpable,
DelayableExecutor delayableExecutor,
DumpManager dumpManager,
HeadsUpManager headsUpManager,
- NotifPanelEventSource notifPanelEventSource,
+ NotifPanelEvents notifPanelEvents,
StatusBarStateController statusBarStateController,
VisualStabilityProvider visualStabilityProvider,
WakefulnessLifecycle wakefulnessLifecycle) {
@@ -96,7 +96,7 @@ public class VisualStabilityCoordinator implements Coordinator, Dumpable,
mWakefulnessLifecycle = wakefulnessLifecycle;
mStatusBarStateController = statusBarStateController;
mDelayableExecutor = delayableExecutor;
- mNotifPanelEventSource = notifPanelEventSource;
+ mNotifPanelEvents = notifPanelEvents;
dumpManager.registerDumpable(this);
}
@@ -109,7 +109,7 @@ public class VisualStabilityCoordinator implements Coordinator, Dumpable,
mStatusBarStateController.addCallback(mStatusBarStateControllerListener);
mPulsing = mStatusBarStateController.isPulsing();
- mNotifPanelEventSource.registerCallbacks(this);
+ mNotifPanelEvents.registerListener(this);
pipeline.setVisualStabilityManager(mNotifStabilityManager);
}
@@ -254,10 +254,14 @@ public class VisualStabilityCoordinator implements Coordinator, Dumpable,
@Override
public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
+ pw.println("pipelineRunAllowed: " + mPipelineRunAllowed);
+ pw.println(" notifPanelCollapsing: " + mNotifPanelCollapsing);
+ pw.println(" launchingNotifActivity: " + mNotifPanelLaunchingActivity);
pw.println("reorderingAllowed: " + mReorderingAllowed);
pw.println(" screenOn: " + mScreenOn);
pw.println(" panelExpanded: " + mPanelExpanded);
pw.println(" pulsing: " + mPulsing);
+ pw.println("isSuppressingPipelineRun: " + mIsSuppressingPipelineRun);
pw.println("isSuppressingGroupChange: " + mIsSuppressingGroupChange);
pw.println("isSuppressingEntryReorder: " + mIsSuppressingEntryReorder);
pw.println("entriesWithSuppressedSectionChange: "
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/dagger/CoordinatorsModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/dagger/CoordinatorsModule.kt
index a26d50d2a059..274affd9da43 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/dagger/CoordinatorsModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/dagger/CoordinatorsModule.kt
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.notification.collection.coordinator.dagger
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.statusbar.notification.collection.coordinator.ActivityLaunchAnimCoordinatorModule
import com.android.systemui.statusbar.notification.collection.coordinator.NotifCoordinators
import com.android.systemui.statusbar.notification.collection.coordinator.NotifCoordinatorsImpl
import com.android.systemui.statusbar.notification.collection.coordinator.SensitiveContentCoordinatorModule
@@ -47,7 +48,10 @@ interface CoordinatorsSubcomponent {
}
}
-@Module(includes = [SensitiveContentCoordinatorModule::class])
+@Module(includes = [
+ ActivityLaunchAnimCoordinatorModule::class,
+ SensitiveContentCoordinatorModule::class,
+])
private abstract class InternalCoordinatorsModule {
@Binds
@Internal
@@ -62,4 +66,4 @@ private annotation class Internal
@Scope
@MustBeDocumented
@Retention(AnnotationRetention.RUNTIME)
-annotation class CoordinatorScope \ No newline at end of file
+annotation class CoordinatorScope
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/NotificationGroupManagerLegacy.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/NotificationGroupManagerLegacy.java
index cd2affead92a..7c4e4499dca6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/NotificationGroupManagerLegacy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/NotificationGroupManagerLegacy.java
@@ -73,7 +73,7 @@ public class NotificationGroupManagerLegacy implements
GroupExpansionManager,
Dumpable {
- private static final String TAG = "NotifGroupManager";
+ private static final String TAG = "LegacyNotifGroupManager";
private static final boolean DEBUG = Compile.IS_DEBUG && Log.isLoggable(TAG, Log.DEBUG);
private static final boolean SPEW = Compile.IS_DEBUG && Log.isLoggable(TAG, Log.VERBOSE);
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilder.kt
index c35b77cfb4e0..6db544c77f87 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilder.kt
@@ -57,6 +57,7 @@ class NodeSpecBuilder(
var currentSection: NotifSection? = null
val prevSections = mutableSetOf<NotifSection?>()
+ var lastSection: NotifSection? = null
val showHeaders = sectionHeaderVisibilityProvider.sectionHeadersVisible
val sectionOrder = mutableListOf<NotifSection?>()
val sectionHeaders = mutableMapOf<NotifSection?, NodeController?>()
@@ -65,6 +66,14 @@ class NodeSpecBuilder(
for (entry in notifList) {
val section = entry.section!!
+ lastSection?.let {
+ if (it.bucket > section.bucket) {
+ throw IllegalStateException("buildNodeSpec with non contiguous section " +
+ "buckets ${it.sectioner.name} - ${it.bucket} & " +
+ "${it.sectioner.name} - ${it.bucket}")
+ }
+ }
+ lastSection = section
if (prevSections.contains(section)) {
throw java.lang.RuntimeException("Section ${section.label} has been duplicated")
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifPanelEventSource.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifPanelEventSource.kt
deleted file mode 100644
index 470737e3b772..000000000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifPanelEventSource.kt
+++ /dev/null
@@ -1,128 +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.systemui.statusbar.notification.collection.render
-
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.statusbar.phone.NotificationPanelViewController
-import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent
-import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent.CentralSurfacesScope
-import com.android.systemui.util.ListenerSet
-import dagger.Binds
-import dagger.Module
-import dagger.Provides
-import dagger.multibindings.IntoSet
-
-/** Provides certain notification panel events. */
-interface NotifPanelEventSource {
-
- /** Registers callbacks to be invoked when notification panel events occur. */
- fun registerCallbacks(callbacks: Callbacks)
-
- /** Unregisters callbacks previously registered via [.registerCallbacks] */
- fun unregisterCallbacks(callbacks: Callbacks)
-
- /** Callbacks for certain notification panel events. */
- interface Callbacks {
-
- /** Invoked when the notification panel starts or stops collapsing. */
- fun onPanelCollapsingChanged(isCollapsing: Boolean)
-
- /**
- * Invoked when the notification panel starts or stops launching an [android.app.Activity].
- */
- fun onLaunchingActivityChanged(isLaunchingActivity: Boolean)
- }
-}
-
-@Module
-abstract class NotifPanelEventSourceModule {
-
- @Binds
- @SysUISingleton
- abstract fun bindEventSource(manager: NotifPanelEventSourceManager): NotifPanelEventSource
-
- @Module
- companion object {
- @JvmStatic
- @Provides
- fun provideManager(): NotifPanelEventSourceManager = NotifPanelEventSourceManagerImpl()
- }
-}
-
-@Module
-object StatusBarNotifPanelEventSourceModule {
- @JvmStatic
- @Provides
- @IntoSet
- @CentralSurfacesScope
- fun bindStartable(
- manager: NotifPanelEventSourceManager,
- notifPanelController: NotificationPanelViewController
- ): CentralSurfacesComponent.Startable =
- EventSourceStatusBarStartableImpl(manager, notifPanelController)
-}
-
-/**
- * Management layer that bridges [SysUiSingleton] and [CentralSurfacesScope]. Necessary because code
- * that wants to listen to [NotifPanelEventSource] lives in [SysUiSingleton], but the events
- * themselves come from [NotificationPanelViewController] in [CentralSurfacesScope].
- */
-interface NotifPanelEventSourceManager : NotifPanelEventSource {
- var eventSource: NotifPanelEventSource?
-}
-
-private class NotifPanelEventSourceManagerImpl
- : NotifPanelEventSourceManager, NotifPanelEventSource.Callbacks {
-
- private val callbackSet = ListenerSet<NotifPanelEventSource.Callbacks>()
-
- override var eventSource: NotifPanelEventSource? = null
- set(value) {
- field?.unregisterCallbacks(this)
- value?.registerCallbacks(this)
- field = value
- }
-
- override fun registerCallbacks(callbacks: NotifPanelEventSource.Callbacks) {
- callbackSet.addIfAbsent(callbacks)
- }
-
- override fun unregisterCallbacks(callbacks: NotifPanelEventSource.Callbacks) {
- callbackSet.remove(callbacks)
- }
-
- override fun onPanelCollapsingChanged(isCollapsing: Boolean) {
- callbackSet.forEach { it.onPanelCollapsingChanged(isCollapsing) }
- }
-
- override fun onLaunchingActivityChanged(isLaunchingActivity: Boolean) {
- callbackSet.forEach { it.onLaunchingActivityChanged(isLaunchingActivity) }
- }
-}
-
-private class EventSourceStatusBarStartableImpl(
- private val manager: NotifPanelEventSourceManager,
- private val notifPanelController: NotificationPanelViewController
-) : CentralSurfacesComponent.Startable {
-
- override fun start() {
- manager.eventSource = notifPanelController
- }
-
- override fun stop() {
- manager.eventSource = null
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDiffer.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDiffer.kt
index 386e2d31380c..032e6784ae08 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDiffer.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDiffer.kt
@@ -18,7 +18,6 @@ package com.android.systemui.statusbar.notification.collection.render
import android.annotation.MainThread
import android.view.View
-import com.android.systemui.util.kotlin.transform
import com.android.systemui.util.traceSection
/**
@@ -41,7 +40,6 @@ class ShadeViewDiffer(
) {
private val rootNode = ShadeNode(rootController)
private val nodes = mutableMapOf(rootController to rootNode)
- private val views = mutableMapOf<View, ShadeNode>()
/**
* Adds and removes views from the root (and its children) until their structure matches the
@@ -66,26 +64,25 @@ class ShadeViewDiffer(
*
* For debugging purposes.
*/
- fun getViewLabel(view: View): String = views[view]?.label ?: view.toString()
-
- private fun detachChildren(
- parentNode: ShadeNode,
- specMap: Map<NodeController, NodeSpec>
- ) {
- val parentSpec = specMap[parentNode.controller]
-
- for (i in parentNode.getChildCount() - 1 downTo 0) {
- val childView = parentNode.getChildAt(i)
- views[childView]?.let { childNode ->
- val childSpec = specMap[childNode.controller]
-
- maybeDetachChild(parentNode, parentSpec, childNode, childSpec)
-
- if (childNode.controller.getChildCount() > 0) {
- detachChildren(childNode, specMap)
+ fun getViewLabel(view: View): String =
+ nodes.values.firstOrNull { node -> node.view === view }?.label ?: view.toString()
+
+ private fun detachChildren(parentNode: ShadeNode, specMap: Map<NodeController, NodeSpec>) {
+ val views = nodes.values.asSequence().map { node -> node.view to node }.toMap()
+ fun detachRecursively(parentNode: ShadeNode, specMap: Map<NodeController, NodeSpec>) {
+ val parentSpec = specMap[parentNode.controller]
+ for (i in parentNode.getChildCount() - 1 downTo 0) {
+ val childView = parentNode.getChildAt(i)
+ views[childView]?.let { childNode ->
+ val childSpec = specMap[childNode.controller]
+ maybeDetachChild(parentNode, parentSpec, childNode, childSpec)
+ if (childNode.controller.getChildCount() > 0) {
+ detachRecursively(childNode, specMap)
+ }
}
}
}
+ detachRecursively(parentNode, specMap)
}
private fun maybeDetachChild(
@@ -94,14 +91,13 @@ class ShadeViewDiffer(
childNode: ShadeNode,
childSpec: NodeSpec?
) {
- val newParentNode = transform(childSpec?.parent) { getNode(it) }
+ val newParentNode = childSpec?.parent?.let { getNode(it) }
if (newParentNode != parentNode) {
val childCompletelyRemoved = newParentNode == null
if (childCompletelyRemoved) {
nodes.remove(childNode.controller)
- views.remove(childNode.controller.view)
}
logger.logDetachingChild(
@@ -115,10 +111,7 @@ class ShadeViewDiffer(
}
}
- private fun attachChildren(
- parentNode: ShadeNode,
- specMap: Map<NodeController, NodeSpec>
- ) {
+ private fun attachChildren(parentNode: ShadeNode, specMap: Map<NodeController, NodeSpec>) {
val parentSpec = checkNotNull(specMap[parentNode.controller])
for ((index, childSpec) in parentSpec.children.withIndex()) {
@@ -160,7 +153,6 @@ class ShadeViewDiffer(
if (node == null) {
node = ShadeNode(spec.controller)
nodes[node.controller] = node
- views[node.view] = node
}
return node
}
@@ -194,10 +186,9 @@ class ShadeViewDiffer(
private class DuplicateNodeException(message: String) : RuntimeException(message)
-private class ShadeNode(
- val controller: NodeController
-) {
- val view = controller.view
+private class ShadeNode(val controller: NodeController) {
+ val view: View
+ get() = controller.view
var parent: ShadeNode? = null
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
index 51bbf1c80478..34c8044ef0d3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
@@ -68,12 +68,12 @@ import com.android.systemui.statusbar.notification.collection.render.GroupExpans
import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;
import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManagerImpl;
import com.android.systemui.statusbar.notification.collection.render.NotifGutsViewManager;
-import com.android.systemui.statusbar.notification.collection.render.NotifPanelEventSourceModule;
import com.android.systemui.statusbar.notification.collection.render.NotifShadeEventSource;
import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider;
import com.android.systemui.statusbar.notification.init.NotificationsController;
import com.android.systemui.statusbar.notification.init.NotificationsControllerImpl;
import com.android.systemui.statusbar.notification.init.NotificationsControllerStub;
+import com.android.systemui.statusbar.notification.interruption.KeyguardNotificationVisibilityProviderModule;
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderImpl;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
@@ -84,9 +84,11 @@ import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.notification.row.OnUserInteractionCallback;
import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager;
import com.android.systemui.statusbar.notification.stack.StackScrollAlgorithm;
+import com.android.systemui.statusbar.phone.CentralSurfaces;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
+import com.android.systemui.statusbar.phone.NotifActivityLaunchEventsModule;
+import com.android.systemui.statusbar.phone.NotifPanelEventsModule;
import com.android.systemui.statusbar.phone.ShadeController;
-import com.android.systemui.statusbar.phone.CentralSurfaces;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.util.leak.LeakDetector;
import com.android.systemui.wmshell.BubblesManager;
@@ -106,8 +108,10 @@ import dagger.Provides;
*/
@Module(includes = {
CoordinatorsModule.class,
+ KeyguardNotificationVisibilityProviderModule.class,
+ NotifActivityLaunchEventsModule.class,
+ NotifPanelEventsModule.class,
NotifPipelineChoreographerModule.class,
- NotifPanelEventSourceModule.class,
NotificationSectionHeadersModule.class,
})
public interface NotificationsModule {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/KeyguardNotificationVisibilityProvider.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/KeyguardNotificationVisibilityProvider.kt
new file mode 100644
index 000000000000..ff0e47f3cfec
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/KeyguardNotificationVisibilityProvider.kt
@@ -0,0 +1,213 @@
+package com.android.systemui.statusbar.notification.interruption
+
+import android.app.Notification
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.Intent
+import android.content.IntentFilter
+import android.database.ContentObserver
+import android.net.Uri
+import android.os.Handler
+import android.os.UserHandle
+import android.provider.Settings
+import com.android.keyguard.KeyguardUpdateMonitor
+import com.android.keyguard.KeyguardUpdateMonitorCallback
+import com.android.systemui.CoreStartable
+import com.android.systemui.broadcast.BroadcastDispatcher
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.statusbar.NotificationLockscreenUserManager
+import com.android.systemui.statusbar.notification.collection.ListEntry
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider
+import com.android.systemui.statusbar.policy.KeyguardStateController
+import com.android.systemui.util.ListenerSet
+import com.android.systemui.util.settings.GlobalSettings
+import com.android.systemui.util.settings.SecureSettings
+import dagger.Binds
+import dagger.Module
+import dagger.multibindings.ClassKey
+import dagger.multibindings.IntoMap
+import java.util.function.Consumer
+import javax.inject.Inject
+
+/** Determines if notifications should be visible based on the state of the keyguard. */
+interface KeyguardNotificationVisibilityProvider {
+ /**
+ * Determines if the given notification should be hidden based on the current keyguard state.
+ * If a [Consumer] registered via [addOnStateChangedListener] is invoked, the results of this
+ * method may no longer be valid and should be re-queried.
+ */
+ fun shouldHideNotification(entry: NotificationEntry): Boolean
+
+ /** Registers a listener to be notified when the internal keyguard state has been updated. */
+ fun addOnStateChangedListener(listener: Consumer<String>)
+
+ /** Unregisters a listener previously registered with [addOnStateChangedListener]. */
+ fun removeOnStateChangedListener(listener: Consumer<String>)
+}
+
+/** Provides a [KeyguardNotificationVisibilityProvider] in [SysUISingleton] scope. */
+@Module(includes = [KeyguardNotificationVisibilityProviderImplModule::class])
+object KeyguardNotificationVisibilityProviderModule
+
+@Module
+private interface KeyguardNotificationVisibilityProviderImplModule {
+ @Binds
+ fun bindImpl(impl: KeyguardNotificationVisibilityProviderImpl):
+ KeyguardNotificationVisibilityProvider
+
+ @Binds
+ @IntoMap
+ @ClassKey(KeyguardNotificationVisibilityProvider::class)
+ fun bindStartable(impl: KeyguardNotificationVisibilityProviderImpl): CoreStartable
+}
+
+@SysUISingleton
+private class KeyguardNotificationVisibilityProviderImpl @Inject constructor(
+ context: Context,
+ @Main private val handler: Handler,
+ private val keyguardStateController: KeyguardStateController,
+ private val lockscreenUserManager: NotificationLockscreenUserManager,
+ private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
+ private val highPriorityProvider: HighPriorityProvider,
+ private val statusBarStateController: StatusBarStateController,
+ private val broadcastDispatcher: BroadcastDispatcher,
+ private val secureSettings: SecureSettings,
+ private val globalSettings: GlobalSettings
+) : CoreStartable(context), KeyguardNotificationVisibilityProvider {
+ private val onStateChangedListeners = ListenerSet<Consumer<String>>()
+ private var hideSilentNotificationsOnLockscreen: Boolean = false
+
+ override fun start() {
+ readShowSilentNotificationSetting()
+ keyguardStateController.addCallback(object : KeyguardStateController.Callback {
+ override fun onUnlockedChanged() {
+ notifyStateChanged("onUnlockedChanged")
+ }
+
+ override fun onKeyguardShowingChanged() {
+ notifyStateChanged("onKeyguardShowingChanged")
+ }
+ })
+ keyguardUpdateMonitor.registerCallback(object : KeyguardUpdateMonitorCallback() {
+ override fun onStrongAuthStateChanged(userId: Int) {
+ notifyStateChanged("onStrongAuthStateChanged")
+ }
+ })
+
+ // register lockscreen settings changed callbacks:
+ val settingsObserver: ContentObserver = object : ContentObserver(handler) {
+ override fun onChange(selfChange: Boolean, uri: Uri?) {
+ if (keyguardStateController.isShowing) {
+ notifyStateChanged("Settings $uri changed")
+ }
+ }
+ }
+
+ secureSettings.registerContentObserverForUser(
+ Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS,
+ settingsObserver,
+ UserHandle.USER_ALL)
+
+ secureSettings.registerContentObserverForUser(
+ Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS,
+ true,
+ settingsObserver,
+ UserHandle.USER_ALL)
+
+ globalSettings.registerContentObserver(Settings.Global.ZEN_MODE, settingsObserver)
+
+ secureSettings.registerContentObserverForUser(
+ Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS,
+ settingsObserver,
+ UserHandle.USER_ALL)
+
+ // register (maybe) public mode changed callbacks:
+ statusBarStateController.addCallback(object : StatusBarStateController.StateListener {
+ override fun onStateChanged(state: Int) {
+ notifyStateChanged("onStatusBarStateChanged")
+ }
+ })
+ broadcastDispatcher.registerReceiver(object : BroadcastReceiver() {
+ override fun onReceive(context: Context, intent: Intent) {
+ if (keyguardStateController.isShowing) {
+ // maybe public mode changed
+ notifyStateChanged(intent.action!!)
+ }
+ }
+ }, IntentFilter(Intent.ACTION_USER_SWITCHED))
+ }
+
+ override fun addOnStateChangedListener(listener: Consumer<String>) {
+ onStateChangedListeners.addIfAbsent(listener)
+ }
+
+ override fun removeOnStateChangedListener(listener: Consumer<String>) {
+ onStateChangedListeners.remove(listener)
+ }
+
+ private fun notifyStateChanged(reason: String) {
+ onStateChangedListeners.forEach { it.accept(reason) }
+ }
+
+ override fun shouldHideNotification(entry: NotificationEntry): Boolean {
+ val sbn = entry.sbn
+ // FILTER OUT the notification when the keyguard is showing and...
+ if (keyguardStateController.isShowing) {
+ // ... user settings or the device policy manager doesn't allow lockscreen
+ // notifications;
+ if (!lockscreenUserManager.shouldShowLockscreenNotifications()) {
+ return true
+ }
+ val currUserId: Int = lockscreenUserManager.currentUserId
+ val notifUserId =
+ if (sbn.user.identifier == UserHandle.USER_ALL) currUserId
+ else sbn.user.identifier
+
+ // ... user is in lockdown
+ if (keyguardUpdateMonitor.isUserInLockdown(currUserId) ||
+ keyguardUpdateMonitor.isUserInLockdown(notifUserId)) {
+ return true
+ }
+
+ // ... device is in public mode and the user's settings doesn't allow
+ // notifications to show in public mode
+ if (lockscreenUserManager.isLockscreenPublicMode(currUserId) ||
+ lockscreenUserManager.isLockscreenPublicMode(notifUserId)) {
+ if (entry.ranking.lockscreenVisibilityOverride == Notification.VISIBILITY_SECRET) {
+ return true
+ }
+ if (!lockscreenUserManager.userAllowsNotificationsInPublic(currUserId) ||
+ !lockscreenUserManager.userAllowsNotificationsInPublic(
+ notifUserId)) {
+ return true
+ }
+ }
+
+ // ... neither this notification nor its group have high enough priority
+ // to be shown on the lockscreen
+ if (entry.parent != null) {
+ val parent = entry.parent
+ if (priorityExceedsLockscreenShowingThreshold(parent)) {
+ return false
+ }
+ }
+ return !priorityExceedsLockscreenShowingThreshold(entry)
+ }
+ return false
+ }
+
+ private fun priorityExceedsLockscreenShowingThreshold(entry: ListEntry?): Boolean =
+ when {
+ entry == null -> false
+ hideSilentNotificationsOnLockscreen -> highPriorityProvider.isHighPriority(entry)
+ else -> entry.representativeEntry?.ranking?.isAmbient == false
+ }
+
+ private fun readShowSilentNotificationSetting() {
+ hideSilentNotificationsOnLockscreen =
+ secureSettings.getBool(Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, true)
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptLogger.kt
index c991376c9e36..6c99e3adb73e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptLogger.kt
@@ -211,6 +211,14 @@ class NotificationInterruptLogger @Inject constructor(
"Pulsing: $str1"
})
}
+
+ fun keyguardHideNotification(key: String) {
+ hunBuffer.log(TAG, DEBUG, {
+ str1 = key
+ }, {
+ "Keyguard Hide Notification: $str1"
+ })
+ }
}
private const val TAG = "InterruptionStateProvider"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java
index 7ed2699b1068..e210f193b0a1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java
@@ -36,6 +36,7 @@ import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.notification.NotifPipelineFlags;
import com.android.systemui.statusbar.notification.NotificationFilter;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.policy.BatteryController;
@@ -66,6 +67,8 @@ public class NotificationInterruptStateProviderImpl implements NotificationInter
private final ContentObserver mHeadsUpObserver;
private final HeadsUpManager mHeadsUpManager;
private final NotificationInterruptLogger mLogger;
+ private final NotifPipelineFlags mFlags;
+ private final KeyguardNotificationVisibilityProvider mKeyguardNotificationVisibilityProvider;
@VisibleForTesting
protected boolean mUseHeadsUp = false;
@@ -81,7 +84,9 @@ public class NotificationInterruptStateProviderImpl implements NotificationInter
StatusBarStateController statusBarStateController,
HeadsUpManager headsUpManager,
NotificationInterruptLogger logger,
- @Main Handler mainHandler) {
+ @Main Handler mainHandler,
+ NotifPipelineFlags flags,
+ KeyguardNotificationVisibilityProvider keyguardNotificationVisibilityProvider) {
mContentResolver = contentResolver;
mPowerManager = powerManager;
mDreamManager = dreamManager;
@@ -91,6 +96,8 @@ public class NotificationInterruptStateProviderImpl implements NotificationInter
mStatusBarStateController = statusBarStateController;
mHeadsUpManager = headsUpManager;
mLogger = logger;
+ mFlags = flags;
+ mKeyguardNotificationVisibilityProvider = keyguardNotificationVisibilityProvider;
mHeadsUpObserver = new ContentObserver(mainHandler) {
@Override
public void onChange(boolean selfChange) {
@@ -282,7 +289,7 @@ public class NotificationInterruptStateProviderImpl implements NotificationInter
private boolean canAlertCommon(NotificationEntry entry) {
StatusBarNotification sbn = entry.getSbn();
- if (mNotificationFilter.shouldFilterOut(entry)) {
+ if (!mFlags.isNewPipelineEnabled() && mNotificationFilter.shouldFilterOut(entry)) {
mLogger.logNoAlertingFilteredOut(sbn);
return false;
}
@@ -305,6 +312,11 @@ public class NotificationInterruptStateProviderImpl implements NotificationInter
return false;
}
+ if (mKeyguardNotificationVisibilityProvider.shouldHideNotification(entry)) {
+ mLogger.keyguardHideNotification(entry.getKey());
+ return false;
+ }
+
return true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
index fca2aa167e37..577d536262b2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
@@ -163,10 +163,13 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
}
/**
- * @return The background of this view.
+ * @param width The actual width to apply to the background view.
*/
- public NotificationBackgroundView getBackgroundNormal() {
- return mBackgroundNormal;
+ public void setBackgroundWidth(int width) {
+ if (mBackgroundNormal == null) {
+ return;
+ }
+ mBackgroundNormal.setActualWidth(width);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index c237e1deeae3..e479509247d3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -79,7 +79,6 @@ import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.util.ContrastColorUtil;
import com.android.internal.widget.CachingIconView;
import com.android.internal.widget.CallLayout;
-import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.animation.Interpolators;
import com.android.systemui.classifier.FalsingCollector;
@@ -90,6 +89,7 @@ import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.MenuItem
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.NotificationMediaManager;
import com.android.systemui.statusbar.RemoteInputController;
+import com.android.systemui.statusbar.SmartReplyController;
import com.android.systemui.statusbar.StatusBarIconView;
import com.android.systemui.statusbar.notification.AboveShelfChangedListener;
import com.android.systemui.statusbar.notification.ExpandAnimationParameters;
@@ -111,10 +111,11 @@ import com.android.systemui.statusbar.notification.stack.ExpandableViewState;
import com.android.systemui.statusbar.notification.stack.NotificationChildrenContainer;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.notification.stack.SwipeableView;
-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.policy.HeadsUpManager;
import com.android.systemui.statusbar.policy.InflatedSmartReplyState;
+import com.android.systemui.statusbar.policy.SmartReplyConstants;
import com.android.systemui.statusbar.policy.dagger.RemoteInputViewSubcomponent;
import com.android.systemui.util.Compile;
import com.android.systemui.util.DumpUtilsKt;
@@ -169,6 +170,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
private RowContentBindStage mRowContentBindStage;
private PeopleNotificationIdentifier mPeopleNotificationIdentifier;
private Optional<BubblesManager> mBubblesManagerOptional;
+ private MetricsLogger mMetricsLogger;
private int mIconTransformContentShift;
private int mMaxHeadsUpHeightBeforeN;
private int mMaxHeadsUpHeightBeforeP;
@@ -304,8 +306,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
final boolean wasExpanded = mGroupExpansionManager.isGroupExpanded(mEntry);
boolean nowExpanded = mGroupExpansionManager.toggleGroupExpansion(mEntry);
mOnExpandClickListener.onExpandClicked(mEntry, v, nowExpanded);
- MetricsLogger.action(mContext, MetricsEvent.ACTION_NOTIFICATION_GROUP_EXPANDER,
- nowExpanded);
+ mMetricsLogger.action(MetricsEvent.ACTION_NOTIFICATION_GROUP_EXPANDER, nowExpanded);
onExpansionChanged(true /* userAction */, wasExpanded);
} else if (mEnableNonGroupedNotificationExpand) {
if (v.isAccessibilityFocused()) {
@@ -327,8 +328,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
}
notifyHeightChanged(true);
mOnExpandClickListener.onExpandClicked(mEntry, v, nowExpanded);
- MetricsLogger.action(mContext, MetricsEvent.ACTION_NOTIFICATION_EXPANDER,
- nowExpanded);
+ mMetricsLogger.action(MetricsEvent.ACTION_NOTIFICATION_EXPANDER, nowExpanded);
}
}
};
@@ -1271,7 +1271,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
addView(mMenuRow.getMenuView(), menuIndex);
}
for (NotificationContentView l : mLayouts) {
- l.initView();
+ l.reinflate();
l.reInflateViews();
}
mEntry.getSbn().clearPackageContext();
@@ -1464,7 +1464,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
* @param fromAccessibility whether this dismiss is coming from an accessibility action
*/
public void performDismiss(boolean fromAccessibility) {
- Dependency.get(MetricsLogger.class).count(NotificationCounters.NOTIFICATION_DISMISSED, 1);
+ mMetricsLogger.count(NotificationCounters.NOTIFICATION_DISMISSED, 1);
dismiss(fromAccessibility);
if (mEntry.isDismissable()) {
if (mOnUserInteractionCallback != null) {
@@ -1600,7 +1600,10 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
PeopleNotificationIdentifier peopleNotificationIdentifier,
OnUserInteractionCallback onUserInteractionCallback,
Optional<BubblesManager> bubblesManagerOptional,
- NotificationGutsManager gutsManager) {
+ NotificationGutsManager gutsManager,
+ MetricsLogger metricsLogger,
+ SmartReplyConstants smartReplyConstants,
+ SmartReplyController smartReplyController) {
mEntry = entry;
mAppName = appName;
if (mMenuRow == null) {
@@ -1623,15 +1626,18 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
mFalsingManager = falsingManager;
mFalsingCollector = falsingCollector;
mStatusBarStateController = statusBarStateController;
-
mPeopleNotificationIdentifier = peopleNotificationIdentifier;
for (NotificationContentView l : mLayouts) {
- l.setPeopleNotificationIdentifier(mPeopleNotificationIdentifier);
- l.setRemoteInputViewSubcomponentFactory(rivSubcomponentFactory);
+ l.initialize(
+ mPeopleNotificationIdentifier,
+ rivSubcomponentFactory,
+ smartReplyConstants,
+ smartReplyController);
}
mOnUserInteractionCallback = onUserInteractionCallback;
mBubblesManagerOptional = bubblesManagerOptional;
mNotificationGutsManager = gutsManager;
+ mMetricsLogger = metricsLogger;
cacheIsSystemNotification();
}
@@ -3127,7 +3133,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
if (mGroupMembershipManager.isGroupSummary(mEntry)) {
event = MetricsEvent.ACTION_NOTIFICATION_GROUP_GESTURE_EXPANDER;
}
- MetricsLogger.action(mContext, event, userExpanded);
+ mMetricsLogger.action(event, userExpanded);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
index c4beb5bf4d7b..599039d46556 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
@@ -27,6 +27,7 @@ import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import com.android.internal.logging.MetricsLogger;
import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
@@ -35,6 +36,7 @@ import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.shared.plugins.PluginManager;
import com.android.systemui.statusbar.NotificationMediaManager;
+import com.android.systemui.statusbar.SmartReplyController;
import com.android.systemui.statusbar.notification.FeedbackIcon;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager;
@@ -49,6 +51,7 @@ import com.android.systemui.statusbar.notification.row.dagger.NotificationRowSco
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.policy.HeadsUpManager;
+import com.android.systemui.statusbar.policy.SmartReplyConstants;
import com.android.systemui.statusbar.policy.dagger.RemoteInputViewSubcomponent;
import com.android.systemui.util.time.SystemClock;
import com.android.systemui.wmshell.BubblesManager;
@@ -82,6 +85,7 @@ public class ExpandableNotificationRowController implements NotifViewController
private final HeadsUpManager mHeadsUpManager;
private final ExpandableNotificationRow.OnExpandClickListener mOnExpandClickListener;
private final StatusBarStateController mStatusBarStateController;
+ private final MetricsLogger mMetricsLogger;
private final ExpandableNotificationRow.ExpansionLogger mExpansionLogger =
this::logNotificationExpansion;
@@ -94,16 +98,21 @@ public class ExpandableNotificationRowController implements NotifViewController
private final boolean mAllowLongPress;
private final PeopleNotificationIdentifier mPeopleNotificationIdentifier;
private final Optional<BubblesManager> mBubblesManagerOptional;
+ private final SmartReplyConstants mSmartReplyConstants;
+ private final SmartReplyController mSmartReplyController;
private final ExpandableNotificationRowDragController mDragController;
@Inject
public ExpandableNotificationRowController(
ExpandableNotificationRow view,
- NotificationListContainer listContainer,
- RemoteInputViewSubcomponent.Factory rivSubcomponentFactory,
ActivatableNotificationViewController activatableNotificationViewController,
+ RemoteInputViewSubcomponent.Factory rivSubcomponentFactory,
+ MetricsLogger metricsLogger,
+ NotificationListContainer listContainer,
NotificationMediaManager mediaManager,
+ SmartReplyConstants smartReplyConstants,
+ SmartReplyController smartReplyController,
PluginManager pluginManager,
SystemClock clock,
@AppName String appName,
@@ -152,6 +161,9 @@ public class ExpandableNotificationRowController implements NotifViewController
mPeopleNotificationIdentifier = peopleNotificationIdentifier;
mBubblesManagerOptional = bubblesManagerOptional;
mDragController = dragController;
+ mMetricsLogger = metricsLogger;
+ mSmartReplyConstants = smartReplyConstants;
+ mSmartReplyController = smartReplyController;
}
/**
@@ -179,7 +191,10 @@ public class ExpandableNotificationRowController implements NotifViewController
mPeopleNotificationIdentifier,
mOnUserInteractionCallback,
mBubblesManagerOptional,
- mNotificationGutsManager
+ mNotificationGutsManager,
+ mMetricsLogger,
+ mSmartReplyConstants,
+ mSmartReplyController
);
mView.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
if (mAllowLongPress) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
index 9cb5dc5d4aa4..b9c7113206df 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
@@ -39,7 +39,6 @@ import android.widget.ImageView;
import android.widget.LinearLayout;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.statusbar.RemoteInputController;
@@ -94,7 +93,6 @@ public class NotificationContentView extends FrameLayout implements Notification
private final Rect mClipBounds = new Rect();
private int mMinContractedHeight;
- private int mNotificationContentMarginEnd;
private View mContractedChild;
private View mExpandedChild;
private View mHeadsUpChild;
@@ -116,7 +114,7 @@ public class NotificationContentView extends FrameLayout implements Notification
private NotificationViewWrapper mContractedWrapper;
private NotificationViewWrapper mExpandedWrapper;
private NotificationViewWrapper mHeadsUpWrapper;
- private HybridGroupManager mHybridGroupManager;
+ private final HybridGroupManager mHybridGroupManager;
private int mClipTopAmount;
private int mContentHeight;
private int mVisibleType = VISIBLE_TYPE_NONE;
@@ -128,7 +126,6 @@ public class NotificationContentView extends FrameLayout implements Notification
private int mHeadsUpHeight;
private int mNotificationMaxHeight;
private NotificationEntry mNotificationEntry;
- private GroupMembershipManager mGroupMembershipManager;
private RemoteInputController mRemoteInputController;
private Runnable mExpandedVisibleListener;
private PeopleNotificationIdentifier mPeopleIdentifier;
@@ -184,7 +181,6 @@ public class NotificationContentView extends FrameLayout implements Notification
private boolean mFocusOnVisibilityChange;
private boolean mHeadsUpAnimatingAway;
private int mClipBottomAmount;
- private boolean mIsLowPriority;
private boolean mIsContentExpandable;
private boolean mRemoteInputVisible;
private int mUnrestrictedContentHeight;
@@ -192,16 +188,23 @@ public class NotificationContentView extends FrameLayout implements Notification
public NotificationContentView(Context context, AttributeSet attrs) {
super(context, attrs);
mHybridGroupManager = new HybridGroupManager(getContext());
- mSmartReplyConstants = Dependency.get(SmartReplyConstants.class);
- mSmartReplyController = Dependency.get(SmartReplyController.class);
- initView();
+ reinflate();
}
- public void initView() {
+ public void initialize(
+ PeopleNotificationIdentifier peopleNotificationIdentifier,
+ RemoteInputViewSubcomponent.Factory rivSubcomponentFactory,
+ SmartReplyConstants smartReplyConstants,
+ SmartReplyController smartReplyController) {
+ mPeopleIdentifier = peopleNotificationIdentifier;
+ mRemoteInputSubcomponentFactory = rivSubcomponentFactory;
+ mSmartReplyConstants = smartReplyConstants;
+ mSmartReplyController = smartReplyController;
+ }
+
+ public void reinflate() {
mMinContractedHeight = getResources().getDimensionPixelSize(
R.dimen.min_notification_layout_height);
- mNotificationContentMarginEnd = getResources().getDimensionPixelSize(
- com.android.internal.R.dimen.notification_content_margin_end);
}
public void setHeights(int smallHeight, int headsUpMaxHeight, int maxHeight) {
@@ -413,7 +416,10 @@ public class NotificationContentView extends FrameLayout implements Notification
if (mExpandedRemoteInput != null) {
mExpandedRemoteInput.onNotificationUpdateOrReset();
if (mExpandedRemoteInput.isActive()) {
- mPreviousExpandedRemoteInputIntent = mExpandedRemoteInput.getPendingIntent();
+ if (mExpandedRemoteInputController != null) {
+ mPreviousExpandedRemoteInputIntent =
+ mExpandedRemoteInputController.getPendingIntent();
+ }
mCachedExpandedRemoteInput = mExpandedRemoteInput;
mCachedExpandedRemoteInputViewController = mExpandedRemoteInputController;
mExpandedRemoteInput.dispatchStartTemporaryDetach();
@@ -460,7 +466,10 @@ public class NotificationContentView extends FrameLayout implements Notification
if (mHeadsUpRemoteInput != null) {
mHeadsUpRemoteInput.onNotificationUpdateOrReset();
if (mHeadsUpRemoteInput.isActive()) {
- mPreviousHeadsUpRemoteInputIntent = mHeadsUpRemoteInput.getPendingIntent();
+ if (mHeadsUpRemoteInputController != null) {
+ mPreviousHeadsUpRemoteInputIntent =
+ mHeadsUpRemoteInputController.getPendingIntent();
+ }
mCachedHeadsUpRemoteInput = mHeadsUpRemoteInput;
mCachedHeadsUpRemoteInputViewController = mHeadsUpRemoteInputController;
mHeadsUpRemoteInput.dispatchStartTemporaryDetach();
@@ -961,14 +970,16 @@ public class NotificationContentView extends FrameLayout implements Notification
private void transferRemoteInputFocus(int visibleType) {
if (visibleType == VISIBLE_TYPE_HEADSUP
- && mHeadsUpRemoteInput != null
- && (mExpandedRemoteInput != null && mExpandedRemoteInput.isActive())) {
- mHeadsUpRemoteInput.stealFocusFrom(mExpandedRemoteInput);
+ && mHeadsUpRemoteInputController != null
+ && mExpandedRemoteInputController != null
+ && mExpandedRemoteInputController.isActive()) {
+ mHeadsUpRemoteInputController.stealFocusFrom(mExpandedRemoteInputController);
}
if (visibleType == VISIBLE_TYPE_EXPANDED
- && mExpandedRemoteInput != null
- && (mHeadsUpRemoteInput != null && mHeadsUpRemoteInput.isActive())) {
- mExpandedRemoteInput.stealFocusFrom(mHeadsUpRemoteInput);
+ && mExpandedRemoteInputController != null
+ && mHeadsUpRemoteInputController != null
+ && mHeadsUpRemoteInputController.isActive()) {
+ mExpandedRemoteInputController.stealFocusFrom(mHeadsUpRemoteInputController);
}
}
@@ -1313,7 +1324,6 @@ public class NotificationContentView extends FrameLayout implements Notification
// If we find a matching action in the new notification, focus, otherwise close.
Notification.Action[] actions = entry.getSbn().getNotification().actions;
if (existingPendingIntent != null) {
- result.mView.setPendingIntent(existingPendingIntent);
result.mController.setPendingIntent(existingPendingIntent);
}
if (result.mController.updatePendingIntentFromActions(actions)) {
@@ -1599,7 +1609,6 @@ public class NotificationContentView extends FrameLayout implements Notification
}
public void setGroupMembershipManager(GroupMembershipManager groupMembershipManager) {
- mGroupMembershipManager = groupMembershipManager;
}
public void setRemoteInputController(RemoteInputController r) {
@@ -1687,10 +1696,6 @@ public class NotificationContentView extends FrameLayout implements Notification
mContainingNotification = containingNotification;
}
- public void setPeopleNotificationIdentifier(PeopleNotificationIdentifier peopleIdentifier) {
- mPeopleIdentifier = peopleIdentifier;
- }
-
public void requestSelectLayout(boolean needsAnimation) {
selectLayout(needsAnimation, false);
}
@@ -1858,7 +1863,6 @@ public class NotificationContentView extends FrameLayout implements Notification
}
public void setIsLowPriority(boolean isLowPriority) {
- mIsLowPriority = isLowPriority;
}
public boolean isDimmable() {
@@ -2083,10 +2087,6 @@ public class NotificationContentView extends FrameLayout implements Notification
return false;
}
- public void setRemoteInputViewSubcomponentFactory(RemoteInputViewSubcomponent.Factory factory) {
- mRemoteInputSubcomponentFactory = factory;
- }
-
private static class RemoteInputViewData {
@Nullable RemoteInputView mView;
@Nullable RemoteInputViewController mController;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
index f40a3c7186e6..3b22f2a86bfc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
@@ -102,6 +102,16 @@ public class AmbientState {
/** Whether we are swiping up. */
private boolean mIsSwipingUp;
+ /** Whether we are flinging the shade open or closed. */
+ private boolean mIsFlinging;
+
+ /**
+ * Whether we need to do a fling down after swiping up on lockscreen.
+ * True right after we swipe up on lockscreen and have not finished the fling down that follows.
+ * False when we stop flinging or leave lockscreen.
+ */
+ private boolean mNeedFlingAfterLockscreenSwipeUp = false;
+
/**
* @return Height of the notifications panel without top padding when expansion completes.
*/
@@ -142,6 +152,10 @@ public class AmbientState {
* @param isSwipingUp Whether we are swiping up.
*/
public void setSwipingUp(boolean isSwipingUp) {
+ if (!isSwipingUp && mIsSwipingUp) {
+ // Just stopped swiping up.
+ mNeedFlingAfterLockscreenSwipeUp = true;
+ }
mIsSwipingUp = isSwipingUp;
}
@@ -153,6 +167,17 @@ public class AmbientState {
}
/**
+ * @param isFlinging Whether we are flinging the shade open or closed.
+ */
+ public void setIsFlinging(boolean isFlinging) {
+ if (isOnKeyguard() && !isFlinging && mIsFlinging) {
+ // Just stopped flinging.
+ mNeedFlingAfterLockscreenSwipeUp = false;
+ }
+ mIsFlinging = isFlinging;
+ }
+
+ /**
* @return Fraction of shade expansion.
*/
public float getExpansionFraction() {
@@ -459,6 +484,9 @@ public class AmbientState {
}
public void setStatusBarState(int statusBarState) {
+ if (mStatusBarState != StatusBarState.KEYGUARD) {
+ mNeedFlingAfterLockscreenSwipeUp = false;
+ }
mStatusBarState = statusBarState;
}
@@ -522,6 +550,13 @@ public class AmbientState {
}
/**
+ * @return Whether we need to do a fling down after swiping up on lockscreen.
+ */
+ public boolean isFlingingAfterSwipeUpOnLockscreen() {
+ return mIsFlinging && mNeedFlingAfterLockscreenSwipeUp;
+ }
+
+ /**
* @return whether a view is dozing and not pulsing right now
*/
public boolean isDozingAndNotPulsing(ExpandableView view) {
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 efe559a64cc4..c89f4d797819 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
@@ -202,9 +202,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
private float mQsExpansionFraction;
private final int mSplitShadeMinContentHeight;
- /** Whether we are flinging the shade open or closed. */
- private boolean mIsFlinging;
-
/**
* The algorithm which calculates the properties for our children
*/
@@ -220,6 +217,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
private HashSet<View> mFromMoreCardAdditions = new HashSet<>();
private ArrayList<AnimationEvent> mAnimationEvents = new ArrayList<>();
private ArrayList<View> mSwipedOutViews = new ArrayList<>();
+ private NotificationStackSizeCalculator mNotificationStackSizeCalculator;
private final StackStateAnimator mStateAnimator = new StackStateAnimator(this);
private boolean mAnimationsEnabled;
private boolean mChangePositionInProgress;
@@ -407,12 +405,18 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
*/
private float mBackgroundXFactor = 1f;
- private boolean mQsExpanded;
+ /**
+ * Indicates QS are full screen and pushing notifications out of the screen.
+ * It's different from QS just being expanded as in split shade QS can be expanded and
+ * still don't take full screen nor influence notifications.
+ */
+ private boolean mQsFullScreen;
private boolean mForwardScrollable;
private boolean mBackwardScrollable;
private NotificationShelf mShelf;
private int mMaxDisplayedNotifications = -1;
private float mKeyguardBottomPadding = -1;
+ private float mKeyguardNotificationAvailableSpace = -1;
@VisibleForTesting int mStatusBarHeight;
private int mMinInteractionHeight;
private final Rect mClipRect = new Rect();
@@ -755,30 +759,46 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
} else {
mDebugTextUsedYPositions.clear();
}
- int y = mTopPadding;
- drawDebugInfo(canvas, y, Color.RED, /* label= */ "mTopPadding");
+ int y = 0;
+ drawDebugInfo(canvas, y, Color.RED, /* label= */ "y = " + y);
+
+ y = mTopPadding;
+ drawDebugInfo(canvas, y, Color.RED, /* label= */ "mTopPadding = " + y);
y = getLayoutHeight();
- drawDebugInfo(canvas, y, Color.YELLOW, /* label= */ "getLayoutHeight()");
+ drawDebugInfo(canvas, y, Color.YELLOW, /* label= */ "getLayoutHeight() = " + y);
y = (int) mMaxLayoutHeight;
- drawDebugInfo(canvas, y, Color.MAGENTA, /* label= */ "mMaxLayoutHeight");
+ drawDebugInfo(canvas, y, Color.MAGENTA, /* label= */ "mMaxLayoutHeight = " + y);
if (mKeyguardBottomPadding >= 0) {
y = getHeight() - (int) mKeyguardBottomPadding;
drawDebugInfo(canvas, y, Color.GRAY,
- /* label= */ "getHeight() - mKeyguardBottomPadding");
+ /* label= */ "getHeight() - mKeyguardBottomPadding = " + y);
}
y = getHeight() - getEmptyBottomMargin();
- drawDebugInfo(canvas, y, Color.GREEN, /* label= */ "getHeight() - getEmptyBottomMargin()");
+ drawDebugInfo(canvas, y, Color.GREEN,
+ /* label= */ "getHeight() - getEmptyBottomMargin() = " + y);
y = (int) (mAmbientState.getStackY());
- drawDebugInfo(canvas, y, Color.CYAN, /* label= */ "mAmbientState.getStackY()");
+ drawDebugInfo(canvas, y, Color.CYAN, /* label= */ "mAmbientState.getStackY() = " + y);
y = (int) (mAmbientState.getStackY() + mAmbientState.getStackHeight());
drawDebugInfo(canvas, y, Color.BLUE,
- /* label= */ "mAmbientState.getStackY() + mAmbientState.getStackHeight()");
+ /* label= */ "mAmbientState.getStackY() + mAmbientState.getStackHeight() = " + y);
+
+ y = (int) mAmbientState.getStackY() + mContentHeight;
+ drawDebugInfo(canvas, y, Color.MAGENTA,
+ /* label= */ "mAmbientState.getStackY() + mContentHeight = " + y);
+
+ y = (int) mAmbientState.getStackY() + mIntrinsicContentHeight;
+ drawDebugInfo(canvas, y, Color.YELLOW,
+ /* label= */ "mAmbientState.getStackY() + mIntrinsicContentHeight = " + y);
+
+ y = (int) (mAmbientState.getStackY() + mKeyguardNotificationAvailableSpace);
+ drawDebugInfo(canvas, y, Color.RED, /* label= */
+ "mAmbientState.getStackY() + mKeyguardNotificationAvailableSpace = " + y);
}
private void drawDebugInfo(Canvas canvas, int y, int color, String label) {
@@ -945,13 +965,15 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
}
private void reinitView() {
- initView(getContext(), mSwipeHelper);
+ initView(getContext(), mSwipeHelper, mNotificationStackSizeCalculator);
}
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- void initView(Context context, NotificationSwipeHelper swipeHelper) {
+ void initView(Context context, NotificationSwipeHelper swipeHelper,
+ NotificationStackSizeCalculator notificationStackSizeCalculator) {
mScroller = new OverScroller(getContext());
mSwipeHelper = swipeHelper;
+ mNotificationStackSizeCalculator = notificationStackSizeCalculator;
setDescendantFocusability(FOCUS_AFTER_DESCENDANTS);
setClipChildren(false);
@@ -1133,7 +1155,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
@ShadeViewRefactor(RefactorComponent.LAYOUT_ALGORITHM)
private void updateAlgorithmLayoutMinHeight() {
- mAmbientState.setLayoutMinHeight(mQsExpanded || isHeadsUpTransition()
+ mAmbientState.setLayoutMinHeight(mQsFullScreen || isHeadsUpTransition()
? getLayoutMinHeight() : 0);
}
@@ -1263,13 +1285,16 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
}
/**
- * @return Whether we should skip stack height update for lockscreen swipe-up or unlock hint.
+ * @return Whether we should skip stack height updates.
+ * True when
+ * 1) Unlock hint is running
+ * 2) Swiping up on lockscreen or flinging down after swipe up
*/
private boolean shouldSkipHeightUpdate() {
- // After the user swipes up on lockscreen and lets go,
- // {@link PanelViewController) flings the shade back down.
- return mAmbientState.isOnKeyguard() && (
- mAmbientState.isUnlockHintRunning() || mAmbientState.isSwipingUp() || mIsFlinging);
+ return mAmbientState.isOnKeyguard()
+ && (mAmbientState.isUnlockHintRunning()
+ || mAmbientState.isSwipingUp()
+ || mAmbientState.isFlingingAfterSwipeUpOnLockscreen());
}
/**
@@ -1287,14 +1312,13 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
mOnStackYChanged.accept(listenerNeedsAnimation);
}
if (mQsExpansionFraction <= 0 && !shouldSkipHeightUpdate()) {
- final float endHeight = updateStackEndHeight(
- getHeight(), getEmptyBottomMargin(), mTopPadding);
+ final float endHeight = updateStackEndHeight();
updateStackHeight(endHeight, fraction);
}
}
- public float updateStackEndHeight(float height, float bottomMargin, float topPadding) {
- final float stackEndHeight = Math.max(0f, height - bottomMargin - topPadding);
+ private float updateStackEndHeight() {
+ final float stackEndHeight = Math.max(0f, mIntrinsicContentHeight);
mAmbientState.setStackEndHeight(stackEndHeight);
return stackEndHeight;
}
@@ -1327,12 +1351,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
*/
@ShadeViewRefactor(RefactorComponent.COORDINATOR)
public void setExpandedHeight(float height) {
- final float shadeBottom = getHeight() - getEmptyBottomMargin();
final boolean skipHeightUpdate = shouldSkipHeightUpdate();
- if (!skipHeightUpdate) {
- final float expansionFraction = MathUtils.saturate(height / shadeBottom);
- mAmbientState.setExpansionFraction(expansionFraction);
- }
updateStackPosition();
if (!skipHeightUpdate) {
@@ -1361,7 +1380,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
translationY = 0;
if (mShouldShowShelfOnly) {
stackHeight = mTopPadding + mShelf.getIntrinsicHeight();
- } else if (mQsExpanded) {
+ } else if (mQsFullScreen) {
int stackStartPosition = mContentHeight - mTopPadding + mIntrinsicPadding;
int stackEndPosition = mMaxTopPadding + mShelf.getIntrinsicHeight();
if (stackStartPosition <= stackEndPosition) {
@@ -2240,48 +2259,10 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
@ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void updateContentHeight() {
final float scrimTopPadding = mAmbientState.isOnKeyguard() ? 0 : mMinimumPaddings;
- int height = (int) scrimTopPadding;
- float previousPaddingRequest = mPaddingBetweenElements;
- int numShownItems = 0;
- int numShownNotifs = 0;
- boolean finish = false;
- int maxDisplayedNotifications = mMaxDisplayedNotifications;
- ExpandableView previousView = null;
-
- for (int i = 0; i < getChildCount(); i++) {
- ExpandableView expandableView = (ExpandableView) getChildAt(i);
- boolean footerViewOnLockScreen = expandableView == mFooterView && onKeyguard();
-
- if (expandableView.getVisibility() != View.GONE
- && !expandableView.hasNoContentHeight() && !footerViewOnLockScreen) {
-
- boolean limitReached = maxDisplayedNotifications != -1
- && numShownNotifs >= maxDisplayedNotifications;
- final float viewHeight;
- if (limitReached) {
- viewHeight = mShelf.getIntrinsicHeight();
- finish = true;
- } else {
- viewHeight = expandableView.getIntrinsicHeight();
- }
- if (height != 0) {
- height += mPaddingBetweenElements;
- }
- float gapHeight = calculateGapHeight(previousView, expandableView, numShownNotifs);
- height += gapHeight;
- height += viewHeight;
-
- numShownItems++;
- if (viewHeight > 0 || !(expandableView instanceof MediaContainerView)) {
- // Only count the media as a notification if it has a positive height.
- numShownNotifs++;
- }
- previousView = expandableView;
- if (finish) {
- break;
- }
- }
- }
+ final int height =
+ (int) scrimTopPadding + (int) mNotificationStackSizeCalculator.computeHeight(
+ /* notificationStackScrollLayout= */ this, mMaxDisplayedNotifications,
+ mShelf != null ? mShelf.getIntrinsicHeight() : 0);
mIntrinsicContentHeight = height;
// The topPadding can be bigger than the regular padding when qs is expanded, in that
@@ -2318,7 +2299,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
private void updateScrollability() {
- boolean scrollable = !mQsExpanded && getScrollRange() > 0;
+ boolean scrollable = !mQsFullScreen && getScrollRange() > 0;
if (scrollable != mScrollable) {
mScrollable = scrollable;
setFocusable(scrollable);
@@ -4839,14 +4820,14 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
}
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- public void setQsExpanded(boolean qsExpanded) {
- mQsExpanded = qsExpanded;
+ public void setQsFullScreen(boolean qsFullScreen) {
+ mQsFullScreen = qsFullScreen;
updateAlgorithmLayoutMinHeight();
updateScrollability();
}
- boolean isQsExpanded() {
- return mQsExpanded;
+ boolean isQsFullScreen() {
+ return mQsFullScreen;
}
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
@@ -4924,6 +4905,15 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
mKeyguardBottomPadding = keyguardBottomPadding;
}
+ /**
+ * For debugging only. Enables to draw a line related to the available size for notifications in
+ * keyguard.
+ */
+ public void setKeyguardAvailableSpaceForDebug(float keyguardNotificationAvailableSpace) {
+ mKeyguardNotificationAvailableSpace = keyguardNotificationAvailableSpace;
+ }
+
+
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setShouldShowShelfOnly(boolean shouldShowShelfOnly) {
mShouldShowShelfOnly = shouldShowShelfOnly;
@@ -5009,13 +4999,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
mAmbientState.setUnlockHintRunning(running);
}
- /**
- * @param isFlinging Whether we are flinging the shade open or closed.
- */
- public void setIsFlinging(boolean isFlinging) {
- mIsFlinging = isFlinging;
- }
-
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setHeadsUpGoingAwayAnimationsAllowed(boolean headsUpGoingAwayAnimationsAllowed) {
mHeadsUpGoingAwayAnimationsAllowed = headsUpGoingAwayAnimationsAllowed;
@@ -5814,10 +5797,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
mSwipeHelper.resetExposedMenuView(animate, force);
}
- boolean isUsingSplitNotificationShade() {
- return mShouldUseSplitNotificationShade;
- }
-
static boolean matchesSelection(
ExpandableNotificationRow row,
@SelectedRows int selection) {
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 df6b8f59fc36..d98f8a77cc8d 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
@@ -111,13 +111,13 @@ import com.android.systemui.statusbar.notification.row.ExpandableView;
import com.android.systemui.statusbar.notification.row.NotificationGuts;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.notification.row.NotificationSnooze;
+import com.android.systemui.statusbar.phone.CentralSurfaces;
import com.android.systemui.statusbar.phone.HeadsUpAppearanceController;
import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
import com.android.systemui.statusbar.phone.HeadsUpTouchHelper;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.ScrimController;
import com.android.systemui.statusbar.phone.ShadeController;
-import com.android.systemui.statusbar.phone.CentralSurfaces;
import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
@@ -181,6 +181,7 @@ public class NotificationStackScrollLayoutController {
private final SectionHeaderController mSilentHeaderController;
private final LockscreenShadeTransitionController mLockscreenShadeTransitionController;
private final InteractionJankMonitor mJankMonitor;
+ private final NotificationStackSizeCalculator mNotificationStackSizeCalculator;
private final StackStateLogger mStackStateLogger;
private final NotificationStackScrollLogger mLogger;
@@ -307,6 +308,7 @@ public class NotificationStackScrollLayoutController {
R.dimen.lockscreen_shade_notification_movement);
mTotalDistanceForFullShadeTransition = mResources.getDimensionPixelSize(
R.dimen.lockscreen_shade_qs_transition_distance);
+ mNotificationStackSizeCalculator.updateResources();
}
private final StatusBarStateController.StateListener mStateListener =
@@ -662,7 +664,8 @@ public class NotificationStackScrollLayoutController {
ShadeController shadeController,
InteractionJankMonitor jankMonitor,
StackStateLogger stackLogger,
- NotificationStackScrollLogger logger) {
+ NotificationStackScrollLogger logger,
+ NotificationStackSizeCalculator notificationStackSizeCalculator) {
mStackStateLogger = stackLogger;
mLogger = logger;
mAllowLongPress = allowLongPress;
@@ -688,6 +691,7 @@ public class NotificationStackScrollLayoutController {
mCentralSurfaces = centralSurfaces;
mScrimController = scrimController;
mJankMonitor = jankMonitor;
+ mNotificationStackSizeCalculator = notificationStackSizeCalculator;
groupManager.registerGroupExpansionChangeListener(
(changedRow, expanded) -> mView.onGroupExpandChanged(changedRow, expanded));
legacyGroupManager.registerGroupChangeListener(new OnGroupChangeListener() {
@@ -758,7 +762,7 @@ public class NotificationStackScrollLayoutController {
});
}
- mView.initView(mView.getContext(), mSwipeHelper);
+ mView.initView(mView.getContext(), mSwipeHelper, mNotificationStackSizeCalculator);
mView.setKeyguardBypassEnabled(mKeyguardBypassController.getBypassEnabled());
mKeyguardBypassController
.registerOnBypassStateChangedListener(mView::setKeyguardBypassEnabled);
@@ -907,6 +911,13 @@ public class NotificationStackScrollLayoutController {
return mView.getTop();
}
+ /**
+ * @return the bottom of the view.
+ */
+ public int getBottom() {
+ return mView.getBottom();
+ }
+
public float getTranslationX() {
return mView.getTranslationX();
}
@@ -1086,8 +1097,8 @@ public class NotificationStackScrollLayoutController {
}
}
- public void setQsExpanded(boolean expanded) {
- mView.setQsExpanded(expanded);
+ public void setQsFullScreen(boolean fullScreen) {
+ mView.setQsFullScreen(fullScreen);
updateShowEmptyShadeView();
}
@@ -1181,13 +1192,6 @@ public class NotificationStackScrollLayoutController {
mView.setUnlockHintRunning(running);
}
- /**
- * @param isFlinging Whether we are flinging the shade open or close.
- */
- public void setIsFlinging(boolean isFlinging) {
- mView.setIsFlinging(isFlinging);
- }
-
public boolean isFooterViewNotGone() {
return mView.isFooterViewNotGone();
}
@@ -1211,7 +1215,7 @@ public class NotificationStackScrollLayoutController {
public void updateShowEmptyShadeView() {
Trace.beginSection("NSSLC.updateShowEmptyShadeView");
mShowEmptyShadeView = mBarState != KEYGUARD
- && (!mView.isQsExpanded() || mView.isUsingSplitNotificationShade())
+ && !mView.isQsFullScreen()
&& getVisibleNotificationCount() == 0;
mView.updateEmptyShadeView(
@@ -1240,10 +1244,6 @@ public class NotificationStackScrollLayoutController {
mView.forceNoOverlappingRendering(force);
}
- public void setTranslationX(float translation) {
- mView.setTranslationX(translation);
- }
-
public void setExpandingVelocity(float velocity) {
mView.setExpandingVelocity(velocity);
}
@@ -1307,10 +1307,16 @@ public class NotificationStackScrollLayoutController {
* appear on the keyguard.
* Setting a negative number will disable rendering this line.
*/
- public void setKeyguardBottomPadding(float keyguardBottomPadding) {
+ public void setKeyguardBottomPaddingForDebug(float keyguardBottomPadding) {
mView.setKeyguardBottomPadding(keyguardBottomPadding);
}
+ /** For debugging only. */
+ public void mKeyguardNotificationAvailableSpaceForDebug(
+ float keyguardNotificationAvailableSpace) {
+ mView.setKeyguardAvailableSpaceForDebug(keyguardNotificationAvailableSpace);
+ }
+
public RemoteInputController.Delegate createDelegate() {
return new RemoteInputController.Delegate() {
public void setRemoteInputActive(NotificationEntry entry,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculator.kt
new file mode 100644
index 000000000000..3f97155242b4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculator.kt
@@ -0,0 +1,261 @@
+/*
+ * 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.statusbar.notification.stack
+
+import android.content.res.Resources
+import android.util.Log
+import android.view.View.GONE
+import com.android.systemui.R
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.statusbar.NotificationLockscreenUserManager
+import com.android.systemui.statusbar.StatusBarState.KEYGUARD
+import com.android.systemui.statusbar.SysuiStatusBarStateController
+import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
+import com.android.systemui.statusbar.notification.row.ExpandableView
+import com.android.systemui.util.children
+import javax.inject.Inject
+import kotlin.math.max
+import kotlin.properties.Delegates.notNull
+
+private const val TAG = "NotificationStackSizeCalculator"
+private const val DEBUG = false
+
+/** Calculates number of notifications to display and the height of the notification stack. */
+@SysUISingleton
+class NotificationStackSizeCalculator
+@Inject
+constructor(
+ private val groupManager: NotificationGroupManagerLegacy,
+ private val lockscreenUserManager: NotificationLockscreenUserManager,
+ private val statusBarStateController: SysuiStatusBarStateController,
+ @Main private val resources: Resources
+) {
+
+ /**
+ * Maximum # notifications to show on Keyguard; extras will be collapsed in an overflow shelf.
+ * If there are exactly 1 + mMaxKeyguardNotifications, and they fit in the available space
+ * (considering the overflow shelf is not displayed in this case), then all notifications are
+ * shown.
+ */
+ private var maxKeyguardNotifications by notNull<Int>()
+
+ /**
+ * Minimum space between two notifications. There might be more space, see [calculateGapHeight].
+ */
+ private var notificationPadding by notNull<Int>()
+
+ init {
+ updateResources()
+ }
+
+ /**
+ * Given the [availableSpace] constraint, calculates how many notification to show.
+ *
+ * This number is only valid in keyguard.
+ *
+ * @param availableSpace space for notifications. This doesn't include the space for the shelf.
+ */
+ fun computeMaxKeyguardNotifications(
+ stack: NotificationStackScrollLayout,
+ availableSpace: Float,
+ shelfHeight: Float
+ ): Int {
+ log {
+ "computeMaxKeyguardNotifications(" +
+ "availableSpace=$availableSpace shelfHeight=$shelfHeight)"
+ }
+
+ val children: Sequence<ExpandableView> = stack.childrenSequence
+ var remainingSpace: Float = availableSpace
+ var count = 0
+ var previous: ExpandableView? = null
+ val onLockscreen = true
+ val showableRows = children.filter { it.isShowable(onLockscreen) }
+ val showableRowsCount = showableRows.count()
+ showableRows.forEachIndexed { i, current ->
+ val spaceNeeded = current.spaceNeeded(count, previous, stack, onLockscreen)
+ previous = current
+ log { "\ti=$i spaceNeeded=$spaceNeeded remainingSpace=$remainingSpace" }
+
+ if (remainingSpace - spaceNeeded >= 0 && count < maxKeyguardNotifications) {
+ count += 1
+ remainingSpace -= spaceNeeded
+ } else if (remainingSpace - spaceNeeded > -shelfHeight && i == showableRowsCount - 1) {
+ log { "Showing all notifications. Shelf is not be needed." }
+ // If this is the last one, and it fits using the space shelf would use, then we can
+ // display it, as the shelf will not be needed (as all notifications are shown).
+ return count + 1
+ } else {
+ log {
+ "No more fit. Returning $count. Space used: ${availableSpace - remainingSpace}"
+ }
+ return count
+ }
+ }
+ log { "All fit. Returning $count" }
+ return count
+ }
+
+ /**
+ * Given the [maxNotifications] constraint, calculates the height of the
+ * [NotificationStackScrollLayout]. This might or might not be in keyguard.
+ *
+ * @param stack stack containing notifications as children.
+ * @param maxNotifications Maximum number of notifications. When reached, the others will go
+ * into the shelf.
+ * @param shelfHeight height of the shelf. It might be zero.
+ *
+ * @return height of the stack, including shelf height, if needed.
+ */
+ fun computeHeight(
+ stack: NotificationStackScrollLayout,
+ maxNotifications: Int,
+ shelfHeight: Float
+ ): Float {
+ val children: Sequence<ExpandableView> = stack.childrenSequence
+ val maxNotificationsArg = infiniteIfNegative(maxNotifications)
+ var height = 0f
+ var previous: ExpandableView? = null
+ var count = 0
+ val onLockscreen = onLockscreen()
+
+ log { "computeHeight(maxNotification=$maxNotifications, shelf=$shelfHeight" }
+ children.filter { it.isShowable(onLockscreen) }.forEach { current ->
+ if (count < maxNotificationsArg) {
+ val spaceNeeded = current.spaceNeeded(count, previous, stack, onLockscreen)
+ log { "\ti=$count spaceNeeded=$spaceNeeded" }
+ height += spaceNeeded
+ count += 1
+ } else {
+ height += shelfHeight
+ log { "returning height with shelf -> $height" }
+ return height
+ }
+ previous = current
+ }
+ log { "Returning height without shelf -> $height" }
+ return height
+ }
+
+ fun updateResources() {
+ maxKeyguardNotifications =
+ infiniteIfNegative(resources.getInteger(R.integer.keyguard_max_notification_count))
+
+ notificationPadding =
+ max(1, resources.getDimensionPixelSize(R.dimen.notification_divider_height))
+ }
+
+ private val NotificationStackScrollLayout.childrenSequence: Sequence<ExpandableView>
+ get() = children.map { it as ExpandableView }
+
+ private fun onLockscreen() = statusBarStateController.state == KEYGUARD
+
+ private fun ExpandableView.spaceNeeded(
+ visibleIndex: Int,
+ previousView: ExpandableView?,
+ stack: NotificationStackScrollLayout,
+ onLockscreen: Boolean
+ ): Float {
+ assert(isShowable(onLockscreen))
+ var size =
+ if (onLockscreen) {
+ getMinHeight(/* ignoreTemporaryStates= */ true).toFloat()
+ } else {
+ intrinsicHeight.toFloat()
+ }
+ if (visibleIndex != 0) {
+ size += notificationPadding
+ }
+ size += calculateGapHeight(stack, previousView, visibleIndex)
+ return size
+ }
+
+ private fun ExpandableView.isShowable(onLockscreen: Boolean): Boolean {
+ if (visibility == GONE || hasNoContentHeight()) return false
+ if (onLockscreen) {
+ when (this) {
+ is ExpandableNotificationRow -> {
+ if (isSummaryOfSuppressedGroup() || !canShowViewOnLockscreen() || isRemoved) {
+ return false
+ }
+ }
+ is MediaContainerView -> if (intrinsicHeight == 0) return false
+ else -> return false
+ }
+ }
+ return true
+ }
+
+ private fun ExpandableView.calculateGapHeight(
+ stack: NotificationStackScrollLayout,
+ previous: ExpandableView?,
+ visibleIndex: Int
+ ) = stack.calculateGapHeight(previous, /* current= */ this, visibleIndex)
+
+ private fun ExpandableNotificationRow.isSummaryOfSuppressedGroup() =
+ groupManager.isSummaryOfSuppressedGroup(entry.sbn)
+
+ /**
+ * Can a view be shown on the lockscreen when calculating the number of allowed notifications to
+ * show?
+ *
+ * @return `true` if it can be shown.
+ */
+ private fun ExpandableView.canShowViewOnLockscreen(): Boolean {
+ if (hasNoContentHeight()) {
+ return false
+ }
+ if (this is ExpandableNotificationRow && !canShowRowOnLockscreen()) {
+ return false
+ } else if (visibility == GONE) {
+ return false
+ }
+ return true
+ }
+
+ /**
+ * Can a row be shown on the lockscreen when calculating the number of allowed notifications to
+ * show?
+ *
+ * @return true if it can be shown
+ */
+ private fun ExpandableNotificationRow.canShowRowOnLockscreen(): Boolean {
+ if (isSummaryOfSuppressedGroup()) {
+ return false
+ }
+ if (!lockscreenUserManager.shouldShowOnKeyguard(entry)) {
+ return false
+ }
+ return !isRemoved
+ }
+
+ private fun log(s: () -> String) {
+ if (DEBUG) {
+ Log.d(TAG, s())
+ }
+ }
+
+ /** Returns infinite when [v] is negative. Useful in case a resource doesn't limit when -1. */
+ private fun infiniteIfNegative(v: Int): Int =
+ if (v < 0) {
+ Int.MAX_VALUE
+ } else {
+ v
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
index 952cd9ae69bc..e1f8c35c3755 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
@@ -202,12 +202,10 @@ public class StackScrollAlgorithm {
float newHeight = state.height;
float newNotificationEnd = newYTranslation + newHeight;
boolean isHeadsUp = (child instanceof ExpandableNotificationRow) && child.isPinned();
- final boolean shadeClosedWithHUN =
- ambientState.isShadeOpening() && !ambientState.isShadeExpanded();
if (mClipNotificationScrollToTop
&& (!state.inShelf || (isHeadsUp && !firstHeadsUp))
&& newYTranslation < clipStart
- && shadeClosedWithHUN) {
+ && !ambientState.isShadeExpanded()) {
// The previous view is overlapping on top, clip!
float overlapAmount = clipStart - newYTranslation;
state.clipTopAmount = (int) overlapAmount;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
index fe637c14ee33..b46ed57fb866 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
@@ -20,6 +20,8 @@ import static android.app.StatusBarManager.SESSION_KEYGUARD;
import android.annotation.IntDef;
import android.content.res.Resources;
+import android.hardware.biometrics.BiometricFaceConstants;
+import android.hardware.biometrics.BiometricFingerprintConstants;
import android.hardware.biometrics.BiometricSourceType;
import android.hardware.fingerprint.FingerprintManager;
import android.metrics.LogMaker;
@@ -344,10 +346,18 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp
}
@Override
- public void onBiometricAcquired(BiometricSourceType biometricSourceType) {
+ public void onBiometricAcquired(BiometricSourceType biometricSourceType,
+ int acquireInfo) {
+ if (BiometricSourceType.FINGERPRINT == biometricSourceType
+ && acquireInfo != BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_GOOD) {
+ return;
+ } else if (BiometricSourceType.FACE == biometricSourceType
+ && acquireInfo != BiometricFaceConstants.FACE_ACQUIRED_GOOD) {
+ return;
+ }
Trace.beginSection("BiometricUnlockController#onBiometricAcquired");
releaseBiometricWakeLock();
- if (isWakeAndUnlock()) {
+ if (mStatusBarStateController.isDozing()) {
if (mLatencyTracker.isEnabled()) {
int action = LatencyTracker.ACTION_FINGERPRINT_WAKE_AND_UNLOCK;
if (biometricSourceType == BiometricSourceType.FACE) {
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 95a465989299..6a7e8eb5446b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
@@ -1695,12 +1695,20 @@ public class CentralSurfaces extends CoreStartable implements
public void startActivity(Intent intent, boolean dismissShade,
@Nullable ActivityLaunchAnimator.Controller animationController,
boolean showOverLockscreenWhenLocked) {
+ startActivity(intent, dismissShade, animationController, showOverLockscreenWhenLocked,
+ UserHandle.CURRENT);
+ }
+
+ @Override
+ public void startActivity(Intent intent, boolean dismissShade,
+ @Nullable ActivityLaunchAnimator.Controller animationController,
+ boolean showOverLockscreenWhenLocked, UserHandle userHandle) {
// Make sure that we dismiss the keyguard if it is directly dismissable or when we don't
// want to show the activity above it.
if (mKeyguardStateController.isUnlocked() || !showOverLockscreenWhenLocked) {
startActivityDismissingKeyguard(intent, false, dismissShade,
- false /* disallowEnterPictureInPictureWhileLaunching */, null /* callback */,
- 0 /* flags */, animationController);
+ false /* disallowEnterPictureInPictureWhileLaunching */, null /* callback */,
+ 0 /* flags */, animationController, userHandle);
return;
}
@@ -1755,7 +1763,7 @@ public class CentralSurfaces extends CoreStartable implements
.create(mContext)
.addNextIntent(intent)
.startActivities(getActivityOptions(getDisplayId(), adapter),
- UserHandle.CURRENT));
+ userHandle));
}
/**
@@ -1775,7 +1783,7 @@ public class CentralSurfaces extends CoreStartable implements
public void startActivity(Intent intent, boolean dismissShade, Callback callback) {
startActivityDismissingKeyguard(intent, false, dismissShade,
false /* disallowEnterPictureInPictureWhileLaunching */, callback, 0,
- null /* animationController */);
+ null /* animationController */, UserHandle.CURRENT);
}
public void setQsExpanded(boolean expanded) {
@@ -2417,7 +2425,7 @@ public class CentralSurfaces extends CoreStartable implements
boolean dismissShade, int flags) {
startActivityDismissingKeyguard(intent, onlyProvisioned, dismissShade,
false /* disallowEnterPictureInPictureWhileLaunching */, null /* callback */,
- flags, null /* animationController */);
+ flags, null /* animationController */, UserHandle.CURRENT);
}
public void startActivityDismissingKeyguard(final Intent intent, boolean onlyProvisioned,
@@ -2428,7 +2436,8 @@ public class CentralSurfaces extends CoreStartable implements
void startActivityDismissingKeyguard(final Intent intent, boolean onlyProvisioned,
final boolean dismissShade, final boolean disallowEnterPictureInPictureWhileLaunching,
final Callback callback, int flags,
- @Nullable ActivityLaunchAnimator.Controller animationController) {
+ @Nullable ActivityLaunchAnimator.Controller animationController,
+ final UserHandle userHandle) {
if (onlyProvisioned && !mDeviceProvisionedController.isDeviceProvisioned()) return;
final boolean willLaunchResolverActivity =
@@ -2487,7 +2496,7 @@ public class CentralSurfaces extends CoreStartable implements
intent,
intent.resolveTypeIfNeeded(mContext.getContentResolver()),
null, null, 0, Intent.FLAG_ACTIVITY_NEW_TASK, null,
- options.toBundle(), UserHandle.CURRENT.getIdentifier());
+ options.toBundle(), userHandle.getIdentifier());
} catch (RemoteException e) {
Log.w(TAG, "Unable to start activity", e);
}
@@ -2860,7 +2869,8 @@ public class CentralSurfaces extends CoreStartable implements
false /* disallowEnterPictureInPictureWhileLaunching */,
null /* callback */,
0 /* flags */,
- animationController),
+ animationController,
+ UserHandle.CURRENT),
delay);
}
@@ -2881,8 +2891,7 @@ public class CentralSurfaces extends CoreStartable implements
}
boolean updateIsKeyguard(boolean forceStateChange) {
- boolean wakeAndUnlocking = mBiometricUnlockController.getMode()
- == BiometricUnlockController.MODE_WAKE_AND_UNLOCK;
+ boolean wakeAndUnlocking = mBiometricUnlockController.isWakeAndUnlock();
// For dozing, keyguard needs to be shown whenever the device is non-interactive. Otherwise
// there's no surface we can show to the user. Note that the device goes fully interactive
@@ -2890,8 +2899,9 @@ public class CentralSurfaces extends CoreStartable implements
// turned off fully.
boolean keyguardForDozing = mDozeServiceHost.getDozingRequested()
&& (!mDeviceInteractive || (isGoingToSleep()
- && (isScreenFullyOff() || mKeyguardStateController.isShowing())));
- boolean isWakingAndOccluded = isOccluded() && isWaking();
+ && (isScreenFullyOff()
+ || (mKeyguardStateController.isShowing() && !isOccluded()))));
+ boolean isWakingAndOccluded = isOccluded() && isWakingOrAwake();
boolean shouldBeKeyguard = (mStatusBarStateController.isKeyguardRequested()
|| keyguardForDozing) && !wakeAndUnlocking && !isWakingAndOccluded;
if (keyguardForDozing) {
@@ -3075,7 +3085,6 @@ public class CentralSurfaces extends CoreStartable implements
mMessageRouter.cancelMessages(MSG_LAUNCH_TRANSITION_TIMEOUT);
releaseGestureWakeLock();
mNotificationPanelViewController.onAffordanceLaunchEnded();
- mNotificationPanelViewController.cancelAnimation();
mNotificationPanelViewController.resetAlpha();
mNotificationPanelViewController.resetTranslation();
mNotificationPanelViewController.resetViewGroupFade();
@@ -3701,8 +3710,9 @@ public class CentralSurfaces extends CoreStartable implements
== WakefulnessLifecycle.WAKEFULNESS_GOING_TO_SLEEP;
}
- boolean isWaking() {
- return mWakefulnessLifecycle.getWakefulness() == WakefulnessLifecycle.WAKEFULNESS_WAKING;
+ boolean isWakingOrAwake() {
+ return mWakefulnessLifecycle.getWakefulness() == WakefulnessLifecycle.WAKEFULNESS_WAKING
+ || mWakefulnessLifecycle.getWakefulness() == WakefulnessLifecycle.WAKEFULNESS_AWAKE;
}
public void notifyBiometricAuthModeChanged() {
@@ -3769,7 +3779,7 @@ public class CentralSurfaces extends CoreStartable implements
});
} else if (mDozing && !unlocking) {
mScrimController.transitionTo(ScrimState.AOD);
- } else if (mKeyguardStateController.isShowing() && !unlocking) {
+ } else if (mKeyguardStateController.isShowing() && !isOccluded() && !unlocking) {
mScrimController.transitionTo(ScrimState.KEYGUARD);
} else {
mScrimController.transitionTo(ScrimState.UNLOCKED, mUnlockScrimCallback);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java
index 536be1c1a866..c4e655a45ca6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java
@@ -371,7 +371,7 @@ public class CentralSurfacesCommandQueueCallbacks implements CommandQueue.Callba
mCentralSurfaces.startActivityDismissingKeyguard(cameraIntent,
false /* onlyProvisioned */, true /* dismissShade */,
true /* disallowEnterPictureInPictureWhileLaunching */, null /* callback */, 0,
- null /* animationController */);
+ null /* animationController */, UserHandle.CURRENT);
} else {
if (!mCentralSurfaces.isDeviceInteractive()) {
// Avoid flickering of the scrim when we instant launch the camera and the bouncer
@@ -428,7 +428,7 @@ public class CentralSurfacesCommandQueueCallbacks implements CommandQueue.Callba
mCentralSurfaces.startActivityDismissingKeyguard(emergencyIntent,
false /* onlyProvisioned */, true /* dismissShade */,
true /* disallowEnterPictureInPictureWhileLaunching */, null /* callback */, 0,
- null /* animationController */);
+ null /* animationController */, UserHandle.CURRENT);
return;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index 541aeab22a80..7f1611fec551 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -32,7 +32,6 @@ import android.app.ActivityManager;
import android.app.ActivityOptions;
import android.app.ActivityTaskManager;
import android.app.admin.DevicePolicyManager;
-import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
@@ -556,6 +555,7 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
mControlsButton.setImageResource(mControlsComponent.getTileImageId());
mControlsButton.setContentDescription(getContext()
.getString(mControlsComponent.getTileTitleId()));
+ updateAffordanceColors();
boolean hasFavorites = mControlsComponent.getControlsController()
.map(c -> c.getFavorites().size() > 0)
@@ -1109,8 +1109,13 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
Intent intent = mQRCodeScannerController.getIntent();
if (intent != null) {
try {
- mContext.startActivity(intent);
- } catch (ActivityNotFoundException e) {
+ ActivityTaskManager.getService().startActivityAsUser(
+ null, getContext().getBasePackageName(),
+ getContext().getAttributionTag(), intent,
+ intent.resolveTypeIfNeeded(getContext().getContentResolver()),
+ null, null, 0, Intent.FLAG_ACTIVITY_NEW_TASK, null, null,
+ UserHandle.CURRENT.getIdentifier());
+ } catch (RemoteException e) {
// This is unexpected. Nonetheless, just log the error and prevent the UI from
// crashing
Log.e(TAG, "Unexpected intent: " + intent
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
index 732e5f0343a2..602d075b167d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
@@ -23,6 +23,7 @@ import static com.android.systemui.statusbar.notification.NotificationUtils.inte
import android.content.res.Resources;
import android.util.MathUtils;
+import com.android.keyguard.BouncerPanelExpansionCalculator;
import com.android.keyguard.KeyguardStatusView;
import com.android.systemui.R;
import com.android.systemui.animation.Interpolators;
@@ -169,7 +170,8 @@ public class KeyguardClockPositionAlgorithm {
boolean isSplitShade, float udfpsTop, float clockBottom, boolean isClockTopAligned) {
mMinTopMargin = keyguardStatusBarHeaderHeight + Math.max(mContainerTopPadding,
userSwitchHeight);
- mPanelExpansion = panelExpansion;
+ mPanelExpansion = BouncerPanelExpansionCalculator
+ .getKeyguardClockScaledExpansion(panelExpansion);
mKeyguardStatusHeight = keyguardStatusHeight + mStatusViewBottomMargin;
mUserSwitchHeight = userSwitchHeight;
mUserSwitchPreferredY = userSwitchPreferredY;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt
index 571c10b3800f..64b0b4e2909f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt
@@ -16,34 +16,52 @@
package com.android.systemui.statusbar.phone
+import android.content.Context
+import android.content.pm.PackageManager
import android.hardware.Sensor
import android.hardware.TriggerEvent
import android.hardware.TriggerEventListener
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.keyguard.KeyguardUpdateMonitorCallback
+import com.android.systemui.CoreStartable
import com.android.systemui.Dumpable
+import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dump.DumpManager
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.util.Assert
import com.android.systemui.util.sensors.AsyncSensorManager
import java.io.FileDescriptor
import java.io.PrintWriter
+import javax.inject.Inject
-class KeyguardLiftController constructor(
+/**
+ * Triggers face auth on lift when the device is showing the lock screen. Only initialized
+ * if face auth is supported on the device. Not to be confused with the lift to wake gesture
+ * which is handled by {@link com.android.server.policy.PhoneWindowManager}.
+ */
+@SysUISingleton
+class KeyguardLiftController @Inject constructor(
+ private val context: Context,
private val statusBarStateController: StatusBarStateController,
private val asyncSensorManager: AsyncSensorManager,
private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
- dumpManager: DumpManager
-) : StatusBarStateController.StateListener, Dumpable, KeyguardUpdateMonitorCallback() {
+ private val dumpManager: DumpManager
+) : Dumpable, CoreStartable(context) {
private val pickupSensor = asyncSensorManager.getDefaultSensor(Sensor.TYPE_PICK_UP_GESTURE)
private var isListening = false
private var bouncerVisible = false
- init {
+ override fun start() {
+ if (context.packageManager.hasSystemFeature(PackageManager.FEATURE_FACE)) {
+ init()
+ }
+ }
+
+ private fun init() {
dumpManager.registerDumpable(javaClass.name, this)
- statusBarStateController.addCallback(this)
- keyguardUpdateMonitor.registerCallback(this)
+ statusBarStateController.addCallback(statusBarStateListener)
+ keyguardUpdateMonitor.registerCallback(keyguardUpdateMonitorCallback)
updateListeningState()
}
@@ -58,17 +76,21 @@ class KeyguardLiftController constructor(
}
}
- override fun onDozingChanged(isDozing: Boolean) {
- updateListeningState()
- }
+ private val keyguardUpdateMonitorCallback = object : KeyguardUpdateMonitorCallback() {
+ override fun onKeyguardBouncerChanged(bouncer: Boolean) {
+ bouncerVisible = bouncer
+ updateListeningState()
+ }
- override fun onKeyguardBouncerChanged(bouncer: Boolean) {
- bouncerVisible = bouncer
- updateListeningState()
+ override fun onKeyguardVisibilityChanged(showing: Boolean) {
+ updateListeningState()
+ }
}
- override fun onKeyguardVisibilityChanged(showing: Boolean) {
- updateListeningState()
+ private val statusBarStateListener = object : StatusBarStateController.StateListener {
+ override fun onDozingChanged(isDozing: Boolean) {
+ updateListeningState()
+ }
}
override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
index 65173a230871..cb332bdf59b1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
@@ -174,7 +174,7 @@ public class KeyguardStatusBarView extends RelativeLayout {
}
private void updateKeyguardStatusBarHeight() {
- MarginLayoutParams lp = (MarginLayoutParams) getLayoutParams();
+ MarginLayoutParams lp = (MarginLayoutParams) getLayoutParams();
lp.height = getStatusBarHeaderHeightKeyguard(mContext);
setLayoutParams(lp);
}
@@ -510,28 +510,6 @@ public class KeyguardStatusBarView extends RelativeLayout {
}
}
- void onSystemChromeAnimationStart(boolean isAnimatingOut) {
- if (isAnimatingOut) {
- mSystemIconsContainer.setVisibility(View.VISIBLE);
- mSystemIconsContainer.setAlpha(0f);
- }
- }
-
- void onSystemChromeAnimationEnd(boolean isAnimatingIn) {
- // Make sure the system icons are out of the way
- if (isAnimatingIn) {
- mSystemIconsContainer.setVisibility(View.INVISIBLE);
- mSystemIconsContainer.setAlpha(0f);
- } else {
- mSystemIconsContainer.setAlpha(1f);
- mSystemIconsContainer.setVisibility(View.VISIBLE);
- }
- }
-
- void onSystemChromeAnimationUpdate(float animatedValue) {
- mSystemIconsContainer.setAlpha(animatedValue);
- }
-
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
index 1df1aff38593..a70ba8236e9a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
@@ -17,8 +17,6 @@
package com.android.systemui.statusbar.phone;
import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
-import static com.android.systemui.statusbar.events.SystemStatusAnimationSchedulerKt.ANIMATING_IN;
-import static com.android.systemui.statusbar.events.SystemStatusAnimationSchedulerKt.ANIMATING_OUT;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -47,6 +45,7 @@ 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.notification.stack.StackStateAnimator;
+import com.android.systemui.statusbar.phone.fragment.StatusBarSystemEventAnimator;
import com.android.systemui.statusbar.phone.userswitcher.StatusBarUserInfoTracker;
import com.android.systemui.statusbar.phone.userswitcher.StatusBarUserSwitcherController;
import com.android.systemui.statusbar.phone.userswitcher.StatusBarUserSwitcherFeatureController;
@@ -59,7 +58,6 @@ import com.android.systemui.util.ViewController;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.Arrays;
-import java.util.Collections;
import java.util.List;
import javax.inject.Inject;
@@ -107,6 +105,8 @@ public class KeyguardStatusBarViewController extends ViewController<KeyguardStat
@Override
public void onDensityOrFontScaleChanged() {
mView.loadDimens();
+ // The animator is dependent on resources for offsets
+ mSystemEventAnimator = new StatusBarSystemEventAnimator(mView, getResources());
}
@Override
@@ -123,21 +123,16 @@ public class KeyguardStatusBarViewController extends ViewController<KeyguardStat
private final SystemStatusAnimationCallback mAnimationCallback =
new SystemStatusAnimationCallback() {
+ @NonNull
@Override
- public void onSystemChromeAnimationStart() {
- mView.onSystemChromeAnimationStart(
- mAnimationScheduler.getAnimationState() == ANIMATING_OUT);
+ public Animator onSystemEventAnimationFinish(boolean hasPersistentDot) {
+ return mSystemEventAnimator.onSystemEventAnimationFinish(hasPersistentDot);
}
+ @NonNull
@Override
- public void onSystemChromeAnimationEnd() {
- mView.onSystemChromeAnimationEnd(
- mAnimationScheduler.getAnimationState() == ANIMATING_IN);
- }
-
- @Override
- public void onSystemChromeAnimationUpdate(@NonNull ValueAnimator anim) {
- mView.onSystemChromeAnimationUpdate((float) anim.getAnimatedValue());
+ public Animator onSystemEventAnimationBegin() {
+ return mSystemEventAnimator.onSystemEventAnimationBegin();
}
};
@@ -232,6 +227,7 @@ public class KeyguardStatusBarViewController extends ViewController<KeyguardStat
private int mStatusBarState;
private boolean mDozing;
private boolean mShowingKeyguardHeadsUp;
+ private StatusBarSystemEventAnimator mSystemEventAnimator;
@Inject
public KeyguardStatusBarViewController(
@@ -292,16 +288,15 @@ public class KeyguardStatusBarViewController extends ViewController<KeyguardStat
);
Resources r = getResources();
- mBlockedIcons = Collections.unmodifiableList(Arrays.asList(
- r.getString(com.android.internal.R.string.status_bar_volume),
- r.getString(com.android.internal.R.string.status_bar_alarm_clock),
- r.getString(com.android.internal.R.string.status_bar_call_strength)));
+ mBlockedIcons = Arrays.asList(r.getStringArray(
+ R.array.config_keyguard_statusbar_icon_blocklist));
mNotificationsHeaderCollideDistance = r.getDimensionPixelSize(
R.dimen.header_notifications_collide_distance);
mView.setKeyguardUserAvatarEnabled(
!mFeatureController.isStatusBarUserSwitcherFeatureEnabled());
mFeatureController.addCallback(enabled -> mView.setKeyguardUserAvatarEnabled(!enabled));
+ mSystemEventAnimator = new StatusBarSystemEventAnimator(mView, r);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LSShadeTransitionLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LSShadeTransitionLogger.kt
index 868efa027f40..02b235493715 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LSShadeTransitionLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LSShadeTransitionLogger.kt
@@ -44,7 +44,7 @@ class LSShadeTransitionLogger @Inject constructor(
fun logDragDownAborted() {
buffer.log(TAG, LogLevel.INFO, {}, {
- "The drag down was reset"
+ "The drag down was aborted and reset to 0f."
})
}
@@ -82,6 +82,12 @@ class LSShadeTransitionLogger @Inject constructor(
LockscreenGestureLogger.LockscreenUiEvent.LOCKSCREEN_PULL_SHADE_OPEN)
}
+ fun logDragDownAmountReset() {
+ buffer.log(TAG, LogLevel.DEBUG, {}, {
+ "The drag down amount has been reset to 0f."
+ })
+ }
+
fun logDefaultGoToFullShadeAnimation(delay: Long) {
buffer.log(TAG, LogLevel.DEBUG, {
long1 = delay
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitchController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitchController.java
index 324d47eed1db..799e5feb1586 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitchController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitchController.java
@@ -19,6 +19,7 @@ package com.android.systemui.statusbar.phone;
import static com.android.systemui.DejankUtils.whitelistIpcs;
import android.content.Intent;
+import android.os.UserHandle;
import android.os.UserManager;
import android.view.View;
import android.view.ViewGroup;
@@ -62,7 +63,7 @@ public class MultiUserSwitchController extends ViewController<MultiUserSwitch> {
mActivityStarter.startActivity(intent, true /* dismissShade */,
ActivityLaunchAnimator.Controller.fromView(v, null),
- true /* showOverlockscreenwhenlocked */);
+ true /* showOverlockscreenwhenlocked */, UserHandle.SYSTEM);
} else {
mUserSwitchDialogController.showDialog(v);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotifActivityLaunchEvents.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotifActivityLaunchEvents.kt
new file mode 100644
index 000000000000..f46d07338206
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotifActivityLaunchEvents.kt
@@ -0,0 +1,39 @@
+/*
+ * 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.statusbar.phone
+
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
+
+/** Provides events about [android.app.Activity] launches from Notifications. */
+interface NotifActivityLaunchEvents {
+
+ /** Registers a [Listener] to be invoked when notification activity launch events occur. */
+ fun registerListener(listener: Listener)
+
+ /** Unregisters a [Listener] previously registered via [registerListener] */
+ fun unregisterListener(listener: Listener)
+
+ /** Listener for events about [android.app.Activity] launches from Notifications. */
+ interface Listener {
+
+ /** Invoked when an activity has started launching from a notification. */
+ fun onStartLaunchNotifActivity(entry: NotificationEntry)
+
+ /** Invoked when an activity has finished launching. */
+ fun onFinishLaunchNotifActivity(entry: NotificationEntry)
+ }
+}
diff --git a/core/java/com/android/internal/logging/UiEvent.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotifActivityLaunchEventsModule.java
index 0407b0704e80..84ff538677b0 100644
--- a/core/java/com/android/internal/logging/UiEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotifActivityLaunchEventsModule.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 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.
@@ -14,17 +14,17 @@
* limitations under the License.
*/
-package com.android.internal.logging;
+package com.android.systemui.statusbar.phone;
-import static java.lang.annotation.ElementType.FIELD;
-import static java.lang.annotation.RetentionPolicy.SOURCE;
+import com.android.systemui.dagger.SysUISingleton;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
+import dagger.Binds;
+import dagger.Module;
-@Retention(SOURCE)
-@Target(FIELD)
-public @interface UiEvent {
- /** An explanation, suitable for Android analysts, of the UI event that this log represents. */
- String doc();
+/** Provides a {@link NotifActivityLaunchEvents} in {@link SysUISingleton} scope. */
+@Module
+public abstract class NotifActivityLaunchEventsModule {
+ @Binds
+ abstract NotifActivityLaunchEvents bindLaunchEvents(
+ StatusBarNotificationActivityStarter.LaunchEventsEmitter impl);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotifPanelEvents.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotifPanelEvents.kt
new file mode 100644
index 000000000000..a385e22c1aff
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotifPanelEvents.kt
@@ -0,0 +1,39 @@
+/*
+ * 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.statusbar.phone
+
+/** Provides certain notification panel events. */
+interface NotifPanelEvents {
+
+ /** Registers callbacks to be invoked when notification panel events occur. */
+ fun registerListener(listener: Listener)
+
+ /** Unregisters callbacks previously registered via [registerListener] */
+ fun unregisterListener(listener: Listener)
+
+ /** Callbacks for certain notification panel events. */
+ interface Listener {
+
+ /** Invoked when the notification panel starts or stops collapsing. */
+ fun onPanelCollapsingChanged(isCollapsing: Boolean)
+
+ /**
+ * Invoked when the notification panel starts or stops launching an [android.app.Activity].
+ */
+ fun onLaunchingActivityChanged(isLaunchingActivity: Boolean)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotifPanelEventsModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotifPanelEventsModule.java
new file mode 100644
index 000000000000..2aaf6a5f4391
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotifPanelEventsModule.java
@@ -0,0 +1,30 @@
+/*
+ * 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.statusbar.phone;
+
+import com.android.systemui.dagger.SysUISingleton;
+
+import dagger.Binds;
+import dagger.Module;
+
+/** Provides a {@link NotifPanelEvents} in {@link SysUISingleton} scope. */
+@Module
+public abstract class NotifPanelEventsModule {
+ @Binds
+ abstract NotifPanelEvents bindPanelEvents(
+ NotificationPanelViewController.PanelEventsEmitter impl);
+}
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 01860a822503..5746ffb6debe 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -17,14 +17,9 @@
package com.android.systemui.statusbar.phone;
import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
-import static android.view.View.GONE;
-import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
-import static androidx.constraintlayout.widget.ConstraintSet.BOTTOM;
import static androidx.constraintlayout.widget.ConstraintSet.END;
import static androidx.constraintlayout.widget.ConstraintSet.PARENT_ID;
-import static androidx.constraintlayout.widget.ConstraintSet.START;
-import static androidx.constraintlayout.widget.ConstraintSet.TOP;
import static com.android.internal.jank.InteractionJankMonitor.CUJ_NOTIFICATION_SHADE_QS_EXPAND_COLLAPSE;
import static com.android.keyguard.KeyguardClockSwitch.LARGE;
@@ -120,14 +115,8 @@ import com.android.systemui.animation.LaunchAnimator;
import com.android.systemui.biometrics.AuthController;
import com.android.systemui.classifier.Classifier;
import com.android.systemui.classifier.FalsingCollector;
-import com.android.systemui.communal.CommunalHostView;
-import com.android.systemui.communal.CommunalHostViewController;
-import com.android.systemui.communal.CommunalHostViewPositionAlgorithm;
-import com.android.systemui.communal.CommunalSource;
-import com.android.systemui.communal.CommunalSourceMonitor;
-import com.android.systemui.communal.CommunalStateController;
-import com.android.systemui.communal.dagger.CommunalViewComponent;
import com.android.systemui.controls.dagger.ControlsComponent;
+import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.DisplayId;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.doze.DozeLog;
@@ -154,7 +143,6 @@ import com.android.systemui.statusbar.GestureRecorder;
import com.android.systemui.statusbar.KeyguardAffordanceView;
import com.android.systemui.statusbar.KeyguardIndicationController;
import com.android.systemui.statusbar.LockscreenShadeTransitionController;
-import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.NotificationShadeDepthController;
import com.android.systemui.statusbar.NotificationShadeWindowController;
@@ -175,18 +163,16 @@ import com.android.systemui.statusbar.notification.PropertyAnimator;
import com.android.systemui.statusbar.notification.ViewGroupFadeHelper;
import com.android.systemui.statusbar.notification.collection.ListEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
-import com.android.systemui.statusbar.notification.collection.render.NotifPanelEventSource;
import com.android.systemui.statusbar.notification.collection.render.ShadeViewManager;
import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.ExpandableView;
import com.android.systemui.statusbar.notification.stack.AmbientState;
import com.android.systemui.statusbar.notification.stack.AnimationProperties;
-import com.android.systemui.statusbar.notification.stack.MediaContainerView;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
+import com.android.systemui.statusbar.notification.stack.NotificationStackSizeCalculator;
import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
import com.android.systemui.statusbar.phone.LockscreenGestureLogger.LockscreenUiEvent;
import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent;
@@ -209,7 +195,6 @@ import com.android.wm.shell.animation.FlingAnimationUtils;
import java.io.FileDescriptor;
import java.io.PrintWriter;
-import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
@@ -223,8 +208,7 @@ import javax.inject.Inject;
import javax.inject.Provider;
@CentralSurfacesComponent.CentralSurfacesScope
-public class NotificationPanelViewController extends PanelViewController
- implements NotifPanelEventSource {
+public class NotificationPanelViewController extends PanelViewController {
private static final boolean DEBUG = false;
@@ -309,13 +293,10 @@ public class NotificationPanelViewController extends PanelViewController
private final PulseExpansionHandler mPulseExpansionHandler;
private final KeyguardBypassController mKeyguardBypassController;
private final KeyguardUpdateMonitor mUpdateMonitor;
- private final CommunalSourceMonitor mCommunalSourceMonitor;
- private final CommunalStateController mCommunalStateController;
private final ConversationNotificationManager mConversationNotificationManager;
private final AuthController mAuthController;
private final MediaHierarchyManager mMediaHierarchyManager;
private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
- private final CommunalViewComponent.Factory mCommunalViewComponentFactory;
private final KeyguardStatusViewComponent.Factory mKeyguardStatusViewComponentFactory;
private final KeyguardQsUserSwitchComponent.Factory mKeyguardQsUserSwitchComponentFactory;
private final KeyguardUserSwitcherComponent.Factory mKeyguardUserSwitcherComponentFactory;
@@ -328,16 +309,16 @@ public class NotificationPanelViewController extends PanelViewController
private final ControlsComponent mControlsComponent;
private final NotificationRemoteInputManager mRemoteInputManager;
- // Maximum # notifications to show on Keyguard; extras will be collapsed in an overflow card.
- // If there are exactly 1 + mMaxKeyguardNotifications, then still shows all notifications
- private final int mMaxKeyguardNotifications;
private final LockscreenShadeTransitionController mLockscreenShadeTransitionController;
private final TapAgainViewController mTapAgainViewController;
private final SplitShadeHeaderController mSplitShadeHeaderController;
private final RecordingController mRecordingController;
+ private final PanelEventsEmitter mPanelEventsEmitter;
private boolean mShouldUseSplitNotificationShade;
// The bottom padding reserved for elements of the keyguard measuring notifications
private float mKeyguardNotificationBottomPadding;
+ // Space available for notifications.
+ private float mKeyguardNotificationAvailableSpace;
// Current max allowed keyguard notifications determined by measuring the panel
private int mMaxAllowedKeyguardNotifications;
@@ -350,8 +331,6 @@ public class NotificationPanelViewController extends PanelViewController
@VisibleForTesting QS mQs;
private FrameLayout mQsFrame;
private QsFrameTranslateController mQsFrameTranslateController;
- @Nullable
- private CommunalHostViewController mCommunalViewController;
private KeyguardStatusViewController mKeyguardStatusViewController;
private LockIconViewController mLockIconViewController;
private NotificationsQuickSettingsContainer mNotificationContainerParent;
@@ -364,8 +343,6 @@ public class NotificationPanelViewController extends PanelViewController
private VelocityTracker mQsVelocityTracker;
private boolean mQsTracking;
- private CommunalHostView mCommunalView;
-
/**
* If set, the ongoing touch gesture might both trigger the expansion in {@link PanelView} and
* the expansion for quick settings.
@@ -373,6 +350,12 @@ public class NotificationPanelViewController extends PanelViewController
private boolean mConflictingQsExpansionGesture;
private boolean mPanelExpanded;
+
+ /**
+ * Indicates that QS is in expanded state which can happen by:
+ * - single pane shade: expanding shade and then expanding QS
+ * - split shade: just expanding shade (QS are expanded automatically)
+ */
private boolean mQsExpanded;
private boolean mQsExpandedWhenExpandingStarted;
private boolean mQsFullyExpanded;
@@ -413,16 +396,14 @@ public class NotificationPanelViewController extends PanelViewController
private final KeyguardClockPositionAlgorithm.Result
mClockPositionResult =
new KeyguardClockPositionAlgorithm.Result();
- private final CommunalHostViewPositionAlgorithm
- mCommunalPositionAlgorithm =
- new CommunalHostViewPositionAlgorithm();
- private final CommunalHostViewPositionAlgorithm.Result
- mCommunalPositionResult =
- new CommunalHostViewPositionAlgorithm.Result();
private boolean mIsExpanding;
private boolean mBlockTouches;
- // Used for two finger gesture as well as accessibility shortcut to QS.
+
+ /**
+ * Determines if QS should be already expanded when expanding shade.
+ * Used for split shade, two finger gesture as well as accessibility shortcut to QS.
+ */
private boolean mQsExpandImmediate;
private boolean mTwoFingerQsExpandPossible;
private String mHeaderDebugInfo;
@@ -461,8 +442,6 @@ public class NotificationPanelViewController extends PanelViewController
setHeadsUpAnimatingAway(false);
updatePanelExpansionAndVisibility();
};
- // TODO (b/162832756): once migrated to the new pipeline, delete legacy group manager
- private NotificationGroupManagerLegacy mGroupManager;
private boolean mShowIconsWhenExpanded;
private int mIndicationBottomPadding;
private int mAmbientIndicationBottomPadding;
@@ -523,12 +502,7 @@ public class NotificationPanelViewController extends PanelViewController
mPanelAlphaAnimator.getProperty(), Interpolators.ALPHA_IN);
private final NotificationEntryManager mEntryManager;
- private final CommunalSourceMonitor.Callback mCommunalSourceMonitorCallback;
-
- private WeakReference<CommunalSource> mCommunalSource;
-
private final CommandQueue mCommandQueue;
- private final NotificationLockscreenUserManager mLockscreenUserManager;
private final UserManager mUserManager;
private final MediaDataManager mMediaDataManager;
private final SysUiState mSysUiState;
@@ -635,6 +609,11 @@ public class NotificationPanelViewController extends PanelViewController
*/
private float mKeyguardOnlyContentAlpha = 1.0f;
+ /**
+ * The translationY of the views which only show on the keyguard but in shade / shade locked.
+ */
+ private int mKeyguardOnlyTransitionTranslationY = 0;
+
private float mUdfpsMaxYBurnInOffset;
/**
@@ -664,9 +643,8 @@ public class NotificationPanelViewController extends PanelViewController
private Optional<NotificationPanelUnfoldAnimationController>
mNotificationPanelUnfoldAnimationController;
- private final ListenerSet<Callbacks> mNotifEventSourceCallbacks = new ListenerSet<>();
-
private final NotificationListContainer mNotificationListContainer;
+ private final NotificationStackSizeCalculator mNotificationStackSizeCalculator;
private View.AccessibilityDelegate mAccessibilityDelegate = new View.AccessibilityDelegate() {
@Override
@@ -688,32 +666,6 @@ public class NotificationPanelViewController extends PanelViewController
}
};
- private final CommunalStateController.Callback mCommunalStateCallback =
- new CommunalStateController.Callback() {
- @Override
- public void onCommunalViewShowingChanged() {
- mKeyguardStatusViewController.setKeyguardStatusViewVisibility(
- mBarState,
- mKeyguardStateController.isKeyguardFadingAway(),
- mStatusBarStateController.goingToFullShade(),
- mBarState);
- if (mKeyguardUserSwitcherController != null) {
- mKeyguardUserSwitcherController.setKeyguardUserSwitcherVisibility(
- mBarState,
- mKeyguardStateController.isKeyguardFadingAway(),
- mStatusBarStateController.goingToFullShade(),
- mBarState);
- }
- if (mKeyguardQsUserSwitchController != null) {
- mKeyguardQsUserSwitchController.setKeyguardQsUserSwitchVisibility(
- mBarState,
- mKeyguardStateController.isKeyguardFadingAway(),
- mStatusBarStateController.goingToFullShade(),
- mBarState);
- }
- }
- };
-
private final FalsingTapListener mFalsingTapListener = new FalsingTapListener() {
@Override
public void onDoubleTapRequired() {
@@ -737,9 +689,7 @@ public class NotificationPanelViewController extends PanelViewController
DynamicPrivacyController dynamicPrivacyController,
KeyguardBypassController bypassController, FalsingManager falsingManager,
FalsingCollector falsingCollector,
- NotificationLockscreenUserManager notificationLockscreenUserManager,
NotificationEntryManager notificationEntryManager,
- CommunalStateController communalStateController,
KeyguardStateController keyguardStateController,
StatusBarStateController statusBarStateController,
StatusBarWindowStateController statusBarWindowStateController,
@@ -749,7 +699,7 @@ public class NotificationPanelViewController extends PanelViewController
LatencyTracker latencyTracker, PowerManager powerManager,
AccessibilityManager accessibilityManager, @DisplayId int displayId,
KeyguardUpdateMonitor keyguardUpdateMonitor,
- CommunalSourceMonitor communalSourceMonitor, MetricsLogger metricsLogger,
+ MetricsLogger metricsLogger,
ActivityManager activityManager,
ConfigurationController configurationController,
Provider<FlingAnimationUtils.Builder> flingAnimationUtilsBuilder,
@@ -763,9 +713,7 @@ public class NotificationPanelViewController extends PanelViewController
KeyguardQsUserSwitchComponent.Factory keyguardQsUserSwitchComponentFactory,
KeyguardUserSwitcherComponent.Factory keyguardUserSwitcherComponentFactory,
KeyguardStatusBarViewComponent.Factory keyguardStatusBarViewComponentFactory,
- CommunalViewComponent.Factory communalViewComponentFactory,
LockscreenShadeTransitionController lockscreenShadeTransitionController,
- NotificationGroupManagerLegacy groupManager,
NotificationIconAreaController notificationIconAreaController,
AuthController authController,
ScrimController scrimController,
@@ -796,7 +744,9 @@ public class NotificationPanelViewController extends PanelViewController
QsFrameTranslateController qsFrameTranslateController,
SysUiState sysUiState,
KeyguardUnlockAnimationController keyguardUnlockAnimationController,
- NotificationListContainer notificationListContainer) {
+ NotificationListContainer notificationListContainer,
+ PanelEventsEmitter panelEventsEmitter,
+ NotificationStackSizeCalculator notificationStackSizeCalculator) {
super(view,
falsingManager,
dozeLog,
@@ -828,12 +778,10 @@ public class NotificationPanelViewController extends PanelViewController
mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
mNotificationsQSContainerController = notificationsQSContainerController;
mNotificationListContainer = notificationListContainer;
+ mNotificationStackSizeCalculator = notificationStackSizeCalculator;
mNotificationsQSContainerController.init();
mNotificationStackScrollLayoutController = notificationStackScrollLayoutController;
- mGroupManager = groupManager;
mNotificationIconAreaController = notificationIconAreaController;
- mCommunalStateController = communalStateController;
- mCommunalViewComponentFactory = communalViewComponentFactory;
mKeyguardStatusViewComponentFactory = keyguardStatusViewComponentFactory;
mKeyguardStatusBarViewComponentFactory = keyguardStatusBarViewComponentFactory;
mDepthController = notificationShadeDepthController;
@@ -868,6 +816,7 @@ public class NotificationPanelViewController extends PanelViewController
mSecureSettings = secureSettings;
mInteractionJankMonitor = interactionJankMonitor;
mSysUiState = sysUiState;
+ mPanelEventsEmitter = panelEventsEmitter;
pulseExpansionHandler.setPulseExpandAbortListener(() -> {
if (mQs != null) {
mQs.animateHeaderSlidingOut();
@@ -877,7 +826,6 @@ public class NotificationPanelViewController extends PanelViewController
mThemeResId = mView.getContext().getThemeResId();
mKeyguardBypassController = bypassController;
mUpdateMonitor = keyguardUpdateMonitor;
- mCommunalSourceMonitor = communalSourceMonitor;
mLockscreenShadeTransitionController = lockscreenShadeTransitionController;
lockscreenShadeTransitionController.setNotificationPanelController(this);
DynamicPrivacyControlListener
@@ -894,7 +842,6 @@ public class NotificationPanelViewController extends PanelViewController
});
mBottomAreaShadeAlphaAnimator.setDuration(160);
mBottomAreaShadeAlphaAnimator.setInterpolator(Interpolators.ALPHA_OUT);
- mLockscreenUserManager = notificationLockscreenUserManager;
mEntryManager = notificationEntryManager;
mConversationNotificationManager = conversationNotificationManager;
mAuthController = authController;
@@ -919,14 +866,10 @@ public class NotificationPanelViewController extends PanelViewController
mView.getOverlay().add(new DebugDrawable());
}
- mMaxKeyguardNotifications = resources.getInteger(R.integer.keyguard_max_notification_count);
mKeyguardUnfoldTransition = unfoldComponent.map(c -> c.getKeyguardUnfoldTransition());
mNotificationPanelUnfoldAnimationController = unfoldComponent.map(
SysUIUnfoldComponent::getNotificationPanelUnfoldAnimationController);
- mCommunalSourceMonitorCallback = (source) -> {
- mUiExecutor.execute(() -> setCommunalSource(source));
- };
mQsFrameTranslateController = qsFrameTranslateController;
updateUserSwitcherFlags();
onFinishInflate();
@@ -962,7 +905,6 @@ public class NotificationPanelViewController extends PanelViewController
private void onFinishInflate() {
loadDimens();
mKeyguardStatusBar = mView.findViewById(R.id.keyguard_header);
- mCommunalView = mView.findViewById(R.id.communal_host);
FrameLayout userAvatarContainer = null;
KeyguardUserSwitcherView keyguardUserSwitcherView = null;
@@ -984,20 +926,11 @@ public class NotificationPanelViewController extends PanelViewController
.getKeyguardStatusBarViewController();
mKeyguardStatusBarViewController.init();
- if (mCommunalView != null) {
- CommunalViewComponent communalViewComponent =
- mCommunalViewComponentFactory.build(mCommunalView);
- mCommunalViewController =
- communalViewComponent.getCommunalHostViewController();
- mCommunalViewController.init();
- }
-
mNotificationContainerParent = mView.findViewById(R.id.notification_container_parent);
updateViewControllers(
mView.findViewById(R.id.keyguard_status_view),
userAvatarContainer,
- keyguardUserSwitcherView,
- mCommunalView);
+ keyguardUserSwitcherView);
NotificationStackScrollLayout stackScrollLayout = mView.findViewById(
R.id.notification_stack_scroller);
@@ -1088,8 +1021,7 @@ public class NotificationPanelViewController extends PanelViewController
private void updateViewControllers(KeyguardStatusView keyguardStatusView,
FrameLayout userAvatarView,
- KeyguardUserSwitcherView keyguardUserSwitcherView,
- CommunalHostView communalView) {
+ KeyguardUserSwitcherView keyguardUserSwitcherView) {
// Re-associate the KeyguardStatusViewController
KeyguardStatusViewComponent statusViewComponent =
mKeyguardStatusViewComponentFactory.build(keyguardStatusView);
@@ -1140,14 +1072,10 @@ public class NotificationPanelViewController extends PanelViewController
public void updateResources() {
mQuickQsOffsetHeight = SystemBarUtils.getQuickQsOffsetHeight(mView.getContext());
- mSplitShadeStatusBarHeight = Utils.getSplitShadeStatusBarHeight(mView.getContext());
mSplitShadeNotificationsScrimMarginBottom =
mResources.getDimensionPixelSize(
R.dimen.split_shade_notifications_scrim_margin_bottom);
- int panelMarginHorizontal = mResources.getDimensionPixelSize(
- R.dimen.notification_panel_margin_horizontal);
-
final boolean newShouldUseSplitNotificationShade =
Utils.shouldUseSplitNotificationShade(mResources);
final boolean splitNotificationShadeChanged =
@@ -1157,49 +1085,12 @@ public class NotificationPanelViewController extends PanelViewController
if (mQs != null) {
mQs.setInSplitShade(mShouldUseSplitNotificationShade);
}
-
- int notificationsBottomMargin = mResources.getDimensionPixelSize(
- R.dimen.notification_panel_margin_bottom);
+ mSplitShadeStatusBarHeight = Utils.getSplitShadeStatusBarHeight(mView.getContext());
int topMargin = mShouldUseSplitNotificationShade ? mSplitShadeStatusBarHeight :
mResources.getDimensionPixelSize(R.dimen.notification_panel_margin_top);
mSplitShadeHeaderController.setSplitShadeMode(mShouldUseSplitNotificationShade);
-
- // To change the constraints at runtime, all children of the ConstraintLayout must have ids
- ensureAllViewsHaveIds(mNotificationContainerParent);
- ConstraintSet constraintSet = new ConstraintSet();
- constraintSet.clone(mNotificationContainerParent);
- int statusViewMarginHorizontal = mResources.getDimensionPixelSize(
- R.dimen.status_view_margin_horizontal);
- constraintSet.setMargin(R.id.keyguard_status_view, START, statusViewMarginHorizontal);
- constraintSet.setMargin(R.id.keyguard_status_view, END, statusViewMarginHorizontal);
- if (mShouldUseSplitNotificationShade) {
- // width = 0 to take up all available space within constraints
- constraintSet.connect(R.id.qs_frame, END, R.id.qs_edge_guideline, END);
- constraintSet.connect(
- R.id.notification_stack_scroller, START,
- R.id.qs_edge_guideline, START);
- constraintSet.constrainHeight(R.id.split_shade_status_bar, mSplitShadeStatusBarHeight);
- } else {
- constraintSet.connect(R.id.qs_frame, END, PARENT_ID, END);
- constraintSet.connect(R.id.notification_stack_scroller, START, PARENT_ID, START);
- if (mUseCombinedQSHeaders) {
- constraintSet.constrainHeight(R.id.split_shade_status_bar, WRAP_CONTENT);
- }
- }
- constraintSet.setMargin(R.id.notification_stack_scroller, START,
- mShouldUseSplitNotificationShade ? 0 : panelMarginHorizontal);
- constraintSet.setMargin(R.id.notification_stack_scroller, END, panelMarginHorizontal);
- constraintSet.setMargin(R.id.notification_stack_scroller, TOP, topMargin);
- constraintSet.setMargin(R.id.notification_stack_scroller, BOTTOM,
- notificationsBottomMargin);
- constraintSet.setMargin(R.id.qs_frame, START, panelMarginHorizontal);
- constraintSet.setMargin(R.id.qs_frame, END,
- mShouldUseSplitNotificationShade ? 0 : panelMarginHorizontal);
- constraintSet.setMargin(R.id.qs_frame, TOP, topMargin);
- constraintSet.applyTo(mNotificationContainerParent);
mAmbientState.setStackTopMargin(topMargin);
- mNotificationsQSContainerController.updateMargins();
- mNotificationsQSContainerController.setSplitShadeEnabled(mShouldUseSplitNotificationShade);
+ mNotificationsQSContainerController.updateResources();
updateKeyguardStatusViewAlignment(/* animate= */false);
@@ -1210,15 +1101,6 @@ public class NotificationPanelViewController extends PanelViewController
}
}
- private static void ensureAllViewsHaveIds(ViewGroup parentView) {
- for (int i = 0; i < parentView.getChildCount(); i++) {
- View childView = parentView.getChildAt(i);
- if (childView.getId() == View.NO_ID) {
- childView.setId(View.generateViewId());
- }
- }
- }
-
private View reInflateStub(int viewId, int stubId, int layoutId, boolean enabled) {
View view = mView.findViewById(viewId);
if (view != null) {
@@ -1282,7 +1164,7 @@ public class NotificationPanelViewController extends PanelViewController
showKeyguardUserSwitcher /* enabled */);
updateViewControllers(mView.findViewById(R.id.keyguard_status_view), userAvatarView,
- keyguardUserSwitcherView, mCommunalView);
+ keyguardUserSwitcherView);
// Update keyguard bottom area
int index = mView.indexOfChild(mKeyguardBottomArea);
@@ -1347,12 +1229,14 @@ public class NotificationPanelViewController extends PanelViewController
if (mKeyguardShowing && !mKeyguardBypassController.getBypassEnabled()) {
mNotificationStackScrollLayoutController.setMaxDisplayedNotifications(
mMaxAllowedKeyguardNotifications);
- mNotificationStackScrollLayoutController.setKeyguardBottomPadding(
+ mNotificationStackScrollLayoutController.setKeyguardBottomPaddingForDebug(
mKeyguardNotificationBottomPadding);
+ mNotificationStackScrollLayoutController.mKeyguardNotificationAvailableSpaceForDebug(
+ mKeyguardNotificationAvailableSpace);
} else {
// no max when not on the keyguard
mNotificationStackScrollLayoutController.setMaxDisplayedNotifications(-1);
- mNotificationStackScrollLayoutController.setKeyguardBottomPadding(-1f);
+ mNotificationStackScrollLayoutController.setKeyguardBottomPaddingForDebug(-1f);
}
}
@@ -1428,10 +1312,6 @@ public class NotificationPanelViewController extends PanelViewController
int stackScrollerPadding;
boolean onKeyguard = isOnKeyguard();
- if (onKeyguard) {
- updateCommunalViewAppearance();
- }
-
if (onKeyguard || forceClockUpdate) {
updateClockAppearance();
}
@@ -1457,22 +1337,6 @@ public class NotificationPanelViewController extends PanelViewController
mAnimateNextPositionUpdate = false;
}
- private void updateCommunalViewAppearance() {
- if (mCommunalViewController == null) {
- return;
- }
-
- float expandedFraction =
- mScreenOffAnimationController.shouldExpandNotifications()
- ? 1.0f : getExpandedFraction();
- mCommunalPositionAlgorithm.setup(expandedFraction, mCommunalView.getHeight());
- mCommunalPositionAlgorithm.run(mCommunalPositionResult);
- boolean animate =
- mNotificationStackScrollLayoutController.isAddOrRemoveAnimationPending()
- || mAnimateNextPositionUpdate;
- mCommunalViewController.updatePosition(mCommunalPositionResult.communalY, animate);
- }
-
private void updateClockAppearance() {
int userSwitcherPreferredY = mStatusBarHeaderHeightKeyguard;
boolean bypassEnabled = mKeyguardBypassController.getBypassEnabled();
@@ -1547,9 +1411,8 @@ public class NotificationPanelViewController extends PanelViewController
private void updateKeyguardStatusViewAlignment(boolean animate) {
boolean hasVisibleNotifications = mNotificationStackScrollLayoutController
.getVisibleNotificationCount() != 0 || mMediaDataManager.hasActiveMedia();
- boolean hasCommunalSurface = mCommunalSource != null && mCommunalSource.get() != null;
- boolean shouldBeCentered = !mShouldUseSplitNotificationShade
- || (!hasVisibleNotifications && !hasCommunalSurface) || mDozing;
+ boolean shouldBeCentered = !mShouldUseSplitNotificationShade || !hasVisibleNotifications
+ || mDozing;
if (mStatusViewCentered != shouldBeCentered) {
mStatusViewCentered = shouldBeCentered;
ConstraintSet constraintSet = new ConstraintSet();
@@ -1558,6 +1421,11 @@ public class NotificationPanelViewController extends PanelViewController
constraintSet.connect(R.id.keyguard_status_view, END, statusConstraint, END);
if (animate) {
ChangeBounds transition = new ChangeBounds();
+ if (mShouldUseSplitNotificationShade) {
+ // Excluding media from the transition on split-shade, as it doesn't transition
+ // horizontally properly.
+ transition.excludeTarget(R.id.status_view_media_container, true);
+ }
transition.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
transition.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
TransitionManager.beginDelayedTransition(mNotificationContainerParent, transition);
@@ -1579,143 +1447,45 @@ public class NotificationPanelViewController extends PanelViewController
* @return the maximum keyguard notifications that can fit on the screen
*/
private int computeMaxKeyguardNotifications() {
- // Do not show any notifications on the keyguard if a communal source is set.
- if (mCommunalSource != null && mCommunalSource.get() != null) {
- return 0;
- }
-
- float minPadding = mClockPositionAlgorithm.getMinStackScrollerPadding();
int notificationPadding = Math.max(
1, mResources.getDimensionPixelSize(R.dimen.notification_divider_height));
- float shelfSize =
+ float topPadding = mNotificationStackScrollLayoutController.getTopPadding();
+ float shelfHeight =
mNotificationShelfController.getVisibility() == View.GONE
? 0
: mNotificationShelfController.getIntrinsicHeight() + notificationPadding;
+ // Padding to add to the bottom of the stack to keep a minimum distance from the top of
+ // the lock icon.
float lockIconPadding = 0;
if (mLockIconViewController.getTop() != 0) {
- lockIconPadding = mCentralSurfaces.getDisplayHeight() - mLockIconViewController.getTop()
- + mResources.getDimensionPixelSize(R.dimen.min_lock_icon_padding);
+ final float lockIconTopWithPadding = mLockIconViewController.getTop()
+ - mResources.getDimensionPixelSize(R.dimen.min_lock_icon_padding);
+ lockIconPadding = mNotificationStackScrollLayoutController.getBottom()
+ - lockIconTopWithPadding;
}
- float bottomPadding = Math.max(mIndicationBottomPadding, mAmbientIndicationBottomPadding);
- bottomPadding = Math.max(lockIconPadding, bottomPadding);
+ float bottomPadding = Math.max(lockIconPadding,
+ Math.max(mIndicationBottomPadding, mAmbientIndicationBottomPadding));
mKeyguardNotificationBottomPadding = bottomPadding;
float availableSpace =
mNotificationStackScrollLayoutController.getHeight()
- - minPadding
- - shelfSize
+ - topPadding
+ - shelfHeight
- bottomPadding;
+ mKeyguardNotificationAvailableSpace = availableSpace;
- int count = 0;
- ExpandableView previousView = null;
- for (int i = 0; i < mNotificationStackScrollLayoutController.getChildCount(); i++) {
- ExpandableView child = mNotificationStackScrollLayoutController.getChildAt(i);
- if (child instanceof ExpandableNotificationRow) {
- ExpandableNotificationRow row = (ExpandableNotificationRow) child;
- boolean suppressedSummary = mGroupManager != null
- && mGroupManager.isSummaryOfSuppressedGroup(row.getEntry().getSbn());
- if (suppressedSummary) {
- continue;
- }
- if (!canShowViewOnLockscreen(child)) {
- continue;
- }
- if (row.isRemoved()) {
- continue;
- }
- } else if (child instanceof MediaContainerView) {
- if (child.getVisibility() == GONE) {
- continue;
- }
- if (child.getIntrinsicHeight() == 0) {
- continue;
- }
- } else {
- continue;
- }
- availableSpace -= child.getMinHeight(true /* ignoreTemporaryStates */);
- availableSpace -= count == 0 ? 0 : notificationPadding;
- availableSpace -= mNotificationStackScrollLayoutController
- .calculateGapHeight(previousView, child, count);
- previousView = child;
- if (availableSpace >= 0
- && (mMaxKeyguardNotifications == -1 || count < mMaxKeyguardNotifications)) {
- count++;
- } else if (availableSpace > -shelfSize) {
- // if we are exactly the last view, then we can show us still!
- int childCount = mNotificationStackScrollLayoutController.getChildCount();
- for (int j = i + 1; j < childCount; j++) {
- ExpandableView view = mNotificationStackScrollLayoutController.getChildAt(j);
- if (view instanceof ExpandableNotificationRow
- && canShowViewOnLockscreen(view)) {
- return count;
- }
- }
- count++;
- return count;
- } else {
- return count;
- }
- }
- return count;
- }
-
- /**
- * Can a view be shown on the lockscreen when calculating the number of allowed notifications
- * to show?
- *
- * @param child the view in question
- * @return true if it can be shown
- */
- private boolean canShowViewOnLockscreen(ExpandableView child) {
- if (child.hasNoContentHeight()) {
- return false;
- }
- if (child instanceof ExpandableNotificationRow &&
- !canShowRowOnLockscreen((ExpandableNotificationRow) child)) {
- return false;
- } else if (child.getVisibility() == GONE) {
- // ENRs can be gone and count because their visibility is only set after
- // this calculation, but all other views should be up to date
- return false;
- }
- return true;
- }
-
- /**
- * Can a row be shown on the lockscreen when calculating the number of allowed notifications
- * to show?
- *
- * @param row the row in question
- * @return true if it can be shown
- */
- private boolean canShowRowOnLockscreen(ExpandableNotificationRow row) {
- boolean suppressedSummary =
- mGroupManager != null && mGroupManager.isSummaryOfSuppressedGroup(
- row.getEntry().getSbn());
- if (suppressedSummary) {
- return false;
- }
- if (!mLockscreenUserManager.shouldShowOnKeyguard(row.getEntry())) {
- return false;
- }
- if (row.isRemoved()) {
- return false;
- }
- return true;
- }
-
- private void updateCommunal() {
- if (mCommunalViewController != null) {
- mCommunalViewController.setAlpha(mKeyguardOnlyContentAlpha);
- }
+ return mNotificationStackSizeCalculator.computeMaxKeyguardNotifications(
+ mNotificationStackScrollLayoutController.getView(), availableSpace,
+ shelfHeight);
}
private void updateClock() {
float alpha = mClockPositionResult.clockAlpha * mKeyguardOnlyContentAlpha;
mKeyguardStatusViewController.setAlpha(alpha);
+ mKeyguardStatusViewController
+ .setTranslationYExcludingMedia(mKeyguardOnlyTransitionTranslationY);
if (mKeyguardQsUserSwitchController != null) {
mKeyguardQsUserSwitchController.setAlpha(alpha);
}
@@ -1786,11 +1556,16 @@ public class NotificationPanelViewController extends PanelViewController
if (mQsExpanded) {
mQsExpandImmediate = true;
- mNotificationStackScrollLayoutController.setShouldShowShelfOnly(true);
+ setShowShelfOnly(true);
}
super.collapse(delayed, speedUpFactor);
}
+ private void setShowShelfOnly(boolean shelfOnly) {
+ mNotificationStackScrollLayoutController.setShouldShowShelfOnly(
+ shelfOnly && !mShouldUseSplitNotificationShade);
+ }
+
public void closeQs() {
cancelQsAnimation();
setQsExpansion(mQsMinExpansionHeight);
@@ -1827,7 +1602,7 @@ public class NotificationPanelViewController extends PanelViewController
public void expandWithQs() {
if (isQsExpansionEnabled()) {
mQsExpandImmediate = true;
- mNotificationStackScrollLayoutController.setShouldShowShelfOnly(true);
+ setShowShelfOnly(true);
}
if (isFullyCollapsed()) {
expand(true /* animate */);
@@ -1860,14 +1635,14 @@ public class NotificationPanelViewController extends PanelViewController
mHeadsUpTouchHelper.notifyFling(!expand);
mKeyguardStateController.notifyPanelFlingStart(!expand /* flingingToDismiss */);
setClosingWithAlphaFadeout(!expand && !isOnKeyguard() && getFadeoutAlpha() == 1.0f);
- mNotificationStackScrollLayoutController.setIsFlinging(true);
+ mAmbientState.setIsFlinging(true);
super.flingToHeight(vel, expand, target, collapseSpeedUpFactor, expandBecauseOfFalsing);
}
@Override
protected void onFlingEnd(boolean cancelled) {
super.onFlingEnd(cancelled);
- mNotificationStackScrollLayoutController.setIsFlinging(false);
+ mAmbientState.setIsFlinging(false);
}
private boolean onQsIntercept(MotionEvent event) {
@@ -2026,7 +1801,15 @@ public class NotificationPanelViewController extends PanelViewController
mFalsingManager.isFalseTouch(QS_COLLAPSE);
}
- flingSettings(vel, expandsQs && !isCancelMotionEvent ? FLING_EXPAND : FLING_COLLAPSE);
+ int flingType;
+ if (expandsQs && !isCancelMotionEvent) {
+ flingType = FLING_EXPAND;
+ } else if (mShouldUseSplitNotificationShade) {
+ flingType = FLING_HIDE;
+ } else {
+ flingType = FLING_COLLAPSE;
+ }
+ flingSettings(vel, flingType);
}
private void logQsSwipeDown(float y) {
@@ -2091,8 +1874,10 @@ public class NotificationPanelViewController extends PanelViewController
return false;
}
final int action = event.getActionMasked();
- if (action == MotionEvent.ACTION_DOWN && getExpandedFraction() == 1f
- && mBarState != KEYGUARD && !mQsExpanded && isQsExpansionEnabled()) {
+ boolean collapsedQs = !mQsExpanded && !mShouldUseSplitNotificationShade;
+ boolean expandedShadeCollapsedQs = getExpandedFraction() == 1f && mBarState != KEYGUARD
+ && collapsedQs && isQsExpansionEnabled();
+ if (action == MotionEvent.ACTION_DOWN && expandedShadeCollapsedQs) {
// Down in the empty area while fully expanded - go to QS.
mQsTracking = true;
traceQsJank(true /* startTracing */, false /* wasCancelled */);
@@ -2107,7 +1892,7 @@ public class NotificationPanelViewController extends PanelViewController
}
if (!mQsExpandImmediate && mQsTracking) {
onQsTouch(event);
- if (!mConflictingQsExpansionGesture) {
+ if (!mConflictingQsExpansionGesture && !mShouldUseSplitNotificationShade) {
return true;
}
}
@@ -2121,7 +1906,7 @@ public class NotificationPanelViewController extends PanelViewController
< mStatusBarMinHeight) {
mMetricsLogger.count(COUNTER_PANEL_OPEN_QS, 1);
mQsExpandImmediate = true;
- mNotificationStackScrollLayoutController.setShouldShowShelfOnly(true);
+ setShowShelfOnly(true);
requestPanelHeightUpdate();
// Normally, we start listening when the panel is expanded, but here we need to start
@@ -2192,6 +1977,9 @@ public class NotificationPanelViewController extends PanelViewController
if (!isFullyCollapsed()) {
return;
}
+ if (mShouldUseSplitNotificationShade) {
+ mQsExpandImmediate = true;
+ }
mExpectingSynthesizedDown = true;
onTrackingStarted();
updatePanelExpanded();
@@ -2398,12 +2186,10 @@ public class NotificationPanelViewController extends PanelViewController
}
private void updateQsState() {
- mNotificationStackScrollLayoutController.setQsExpanded(mQsExpanded);
+ boolean qsFullScreen = mQsExpanded && !mShouldUseSplitNotificationShade;
+ mNotificationStackScrollLayoutController.setQsFullScreen(qsFullScreen);
mNotificationStackScrollLayoutController.setScrollingEnabled(
- mBarState != KEYGUARD
- && (!mQsExpanded
- || mQsExpansionFromOverscroll
- || mShouldUseSplitNotificationShade));
+ mBarState != KEYGUARD && (!qsFullScreen || mQsExpansionFromOverscroll));
if (mKeyguardUserSwitcherController != null && mQsExpanded
&& !mStackScrollerOverscrolling) {
@@ -2448,7 +2234,7 @@ public class NotificationPanelViewController extends PanelViewController
private void updateQsExpansion() {
if (mQs == null) return;
final float squishiness;
- if (mQsExpandImmediate || mQsExpanded) {
+ if ((mQsExpandImmediate || mQsExpanded) && !mShouldUseSplitNotificationShade) {
squishiness = 1;
} else if (mLockscreenShadeTransitionController.getQSDragProgress() > 0) {
squishiness = mLockscreenShadeTransitionController.getQSDragProgress();
@@ -2483,10 +2269,6 @@ public class NotificationPanelViewController extends PanelViewController
mSplitShadeHeaderController.setShadeExpandedFraction(shadeExpandedFraction);
mSplitShadeHeaderController.setQsExpandedFraction(qsExpansionFraction);
mSplitShadeHeaderController.setShadeExpanded(mQsVisible);
-
- if (mCommunalViewController != null) {
- mCommunalViewController.updateQsExpansion(qsExpansionFraction);
- }
}
private void onStackYChanged(boolean shouldAnimate) {
@@ -2849,10 +2631,6 @@ public class NotificationPanelViewController extends PanelViewController
}
mTransitionToFullShadeQSPosition = position;
updateQsExpansion();
-
- if (mCommunalViewController != null) {
- mCommunalViewController.updateShadeExpansion(mTransitioningToFullShadeProgress);
- }
}
/**
@@ -2865,18 +2643,18 @@ public class NotificationPanelViewController extends PanelViewController
}
/**
- * Set the alpha of the keyguard elements which only show on the lockscreen, but not in
- * shade locked / shade. This is used when dragging down to the full shade.
+ * Set the alpha and translationY of the keyguard elements which only show on the lockscreen,
+ * but not in shade locked / shade. This is used when dragging down to the full shade.
*/
- public void setKeyguardOnlyContentAlpha(float keyguardAlpha) {
+ public void setKeyguardTransitionProgress(float keyguardAlpha, int keyguardTranslationY) {
mKeyguardOnlyContentAlpha = Interpolators.ALPHA_IN.getInterpolation(keyguardAlpha);
+ mKeyguardOnlyTransitionTranslationY = keyguardTranslationY;
if (mBarState == KEYGUARD) {
// If the animator is running, it's already fading out the content and this is a reset
mBottomAreaShadeAlpha = mKeyguardOnlyContentAlpha;
updateKeyguardBottomAreaAlpha();
}
updateClock();
- updateCommunal();
}
private void trackMovement(MotionEvent event) {
@@ -3135,9 +2913,7 @@ public class NotificationPanelViewController extends PanelViewController
}
private int calculatePanelHeightShade() {
- int emptyBottomMargin = mNotificationStackScrollLayoutController.getEmptyBottomMargin();
- int maxHeight = mNotificationStackScrollLayoutController.getHeight() - emptyBottomMargin;
-
+ final int maxHeight = mNotificationStackScrollLayoutController.getHeight();
if (mBarState == KEYGUARD) {
int minKeyguardPanelBottom = mClockPositionAlgorithm.getLockscreenStatusViewHeight()
+ mNotificationStackScrollLayoutController.getIntrinsicContentHeight();
@@ -3305,7 +3081,7 @@ public class NotificationPanelViewController extends PanelViewController
setListening(true);
}
mQsExpandImmediate = false;
- mNotificationStackScrollLayoutController.setShouldShowShelfOnly(false);
+ setShowShelfOnly(false);
mTwoFingerQsExpandPossible = false;
updateTrackingHeadsUp(null);
mExpandingFromHeadsUp = false;
@@ -3361,9 +3137,7 @@ public class NotificationPanelViewController extends PanelViewController
mScrimController.onTrackingStarted();
if (mQsFullyExpanded) {
mQsExpandImmediate = true;
- if (!mShouldUseSplitNotificationShade) {
- mNotificationStackScrollLayoutController.setShouldShowShelfOnly(true);
- }
+ setShowShelfOnly(true);
}
if (mBarState == KEYGUARD || mBarState == StatusBarState.SHADE_LOCKED) {
mAffordanceHelper.animateHideLeftRightIcon();
@@ -3466,9 +3240,7 @@ public class NotificationPanelViewController extends PanelViewController
boolean wasRunning = isLaunchTransitionRunning();
super.setIsLaunchAnimationRunning(running);
if (wasRunning != isLaunchTransitionRunning()) {
- for (Callbacks cb : mNotifEventSourceCallbacks) {
- cb.onLaunchingActivityChanged(running);
- }
+ mPanelEventsEmitter.notifyLaunchingActivityChanged(running);
}
}
@@ -3477,9 +3249,7 @@ public class NotificationPanelViewController extends PanelViewController
boolean wasClosing = isClosing();
super.setIsClosing(isClosing);
if (wasClosing != isClosing) {
- for (Callbacks cb : mNotifEventSourceCallbacks) {
- cb.onPanelCollapsingChanged(isClosing);
- }
+ mPanelEventsEmitter.notifyPanelCollapsingChanged(isClosing);
}
}
@@ -4072,10 +3842,6 @@ public class NotificationPanelViewController extends PanelViewController
mNotificationStackScrollLayoutController.runAfterAnimationFinished(r);
}
- public void setScrollingEnabled(boolean b) {
- mNotificationStackScrollLayoutController.setScrollingEnabled(b);
- }
-
private Runnable mHideExpandedRunnable;
private final Runnable mMaybeHideExpandedRunnable = new Runnable() {
@Override
@@ -4381,16 +4147,6 @@ public class NotificationPanelViewController extends PanelViewController
.commitUpdate(mDisplayId);
}
- @Override
- public void registerCallbacks(Callbacks callbacks) {
- mNotifEventSourceCallbacks.addIfAbsent(callbacks);
- }
-
- @Override
- public void unregisterCallbacks(Callbacks callbacks) {
- mNotifEventSourceCallbacks.remove(callbacks);
- }
-
private class OnHeightChangedListener implements ExpandableView.OnHeightChangedListener {
@Override
public void onHeightChanged(ExpandableView view, boolean needsAnimation) {
@@ -4770,14 +4526,6 @@ public class NotificationPanelViewController extends PanelViewController
goingToFullShade,
mBarState);
- if (mCommunalViewController != null) {
- mCommunalViewController.setKeyguardStatusViewVisibility(
- statusBarState,
- keyguardFadingAway,
- goingToFullShade,
- mBarState);
- }
-
setKeyguardBottomAreaVisibility(statusBarState, goingToFullShade);
mBarState = statusBarState;
@@ -4905,25 +4653,6 @@ public class NotificationPanelViewController extends PanelViewController
setExpandedFraction(1f);
}
- private void setCommunalSource(WeakReference<CommunalSource> source) {
- CommunalSource existingSource = mCommunalSource != null ? mCommunalSource.get() : null;
-
- if (existingSource != null) {
- mCommunalViewController.show(null /*source*/);
- }
-
- mCommunalSource = source;
-
- CommunalSource currentSource = mCommunalSource != null ? mCommunalSource.get() : null;
- // Set source and register callback
- if (currentSource != null && mCommunalViewController != null) {
- mCommunalViewController.show(source);
- }
-
- updateKeyguardStatusViewAlignment(true /*animate*/);
- updateMaxDisplayedNotifications(true /*recompute*/);
- }
-
/**
* Sets the overstretch amount in raw pixels when dragging down.
*/
@@ -4941,7 +4670,6 @@ public class NotificationPanelViewController extends PanelViewController
.addTagListener(QS.TAG, mFragmentListener);
mStatusBarStateController.addCallback(mStatusBarStateListener);
mConfigurationController.addCallback(mConfigurationListener);
- mCommunalSourceMonitor.addCallback(mCommunalSourceMonitorCallback);
// Theme might have changed between inflating this view and attaching it to the
// window, so
// force a call to onThemeChanged
@@ -4949,7 +4677,6 @@ public class NotificationPanelViewController extends PanelViewController
mFalsingManager.addTapListener(mFalsingTapListener);
mKeyguardIndicationController.init();
registerSettingsChangeListener();
- mCommunalStateController.addCallback(mCommunalStateCallback);
}
@Override
@@ -4959,9 +4686,7 @@ public class NotificationPanelViewController extends PanelViewController
.removeTagListener(QS.TAG, mFragmentListener);
mStatusBarStateController.removeCallback(mStatusBarStateListener);
mConfigurationController.removeCallback(mConfigurationListener);
- mCommunalSourceMonitor.removeCallback(mCommunalSourceMonitorCallback);
mFalsingManager.removeTapListener(mFalsingTapListener);
- mCommunalStateController.removeCallback(mCommunalStateCallback);
}
}
@@ -5027,7 +4752,11 @@ public class NotificationPanelViewController extends PanelViewController
private void updateQSMinHeight() {
float previousMin = mQsMinExpansionHeight;
- mQsMinExpansionHeight = mKeyguardShowing ? 0 : mQs.getQsMinExpansionHeight();
+ if (mKeyguardShowing || mShouldUseSplitNotificationShade) {
+ mQsMinExpansionHeight = 0;
+ } else {
+ mQsMinExpansionHeight = mQs.getQsMinExpansionHeight();
+ }
if (mQsExpansionHeight == previousMin) {
mQsExpansionHeight = mQsMinExpansionHeight;
}
@@ -5058,6 +4787,8 @@ public class NotificationPanelViewController extends PanelViewController
"calculateNotificationsTopPadding()");
drawDebugInfo(canvas, mClockPositionResult.clockY, Color.GRAY,
"mClockPositionResult.clockY");
+ drawDebugInfo(canvas, (int) mLockIconViewController.getTop(), Color.GRAY,
+ "mLockIconViewController.getTop()");
mDebugPaint.setColor(Color.CYAN);
canvas.drawLine(0, mClockPositionResult.stackScrollerPadding, mView.getWidth(),
@@ -5164,4 +4895,35 @@ public class NotificationPanelViewController extends PanelViewController
1.0f /* speedUpFactor */);
}
}
+
+ @SysUISingleton
+ static class PanelEventsEmitter implements NotifPanelEvents {
+
+ private final ListenerSet<Listener> mListeners = new ListenerSet<>();
+
+ @Inject
+ PanelEventsEmitter() {}
+
+ @Override
+ public void registerListener(@NonNull Listener listener) {
+ mListeners.addIfAbsent(listener);
+ }
+
+ @Override
+ public void unregisterListener(@NonNull Listener listener) {
+ mListeners.remove(listener);
+ }
+
+ private void notifyLaunchingActivityChanged(boolean isLaunchingActivity) {
+ for (Listener cb : mListeners) {
+ cb.onLaunchingActivityChanged(isLaunchingActivity);
+ }
+ }
+
+ private void notifyPanelCollapsingChanged(boolean isCollapsing) {
+ for (NotifPanelEvents.Listener cb : mListeners) {
+ cb.onPanelCollapsingChanged(isCollapsing);
+ }
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java
index 0ff010aedfff..16e573280417 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java
@@ -386,10 +386,12 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW
}
visible = true;
}
- if (visible) {
- mNotificationShadeView.setVisibility(View.VISIBLE);
- } else {
- mNotificationShadeView.setVisibility(View.INVISIBLE);
+ if (mNotificationShadeView != null) {
+ if (visible) {
+ mNotificationShadeView.setVisibility(View.VISIBLE);
+ } else {
+ mNotificationShadeView.setVisibility(View.INVISIBLE);
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQSContainerController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQSContainerController.kt
index 7c9e597e74a1..a15feeb9cda8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQSContainerController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQSContainerController.kt
@@ -1,6 +1,18 @@
package com.android.systemui.statusbar.phone
+import android.view.View
+import android.view.ViewGroup
+import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
import android.view.WindowInsets
+import androidx.annotation.VisibleForTesting
+import androidx.constraintlayout.widget.ConstraintSet
+import androidx.constraintlayout.widget.ConstraintSet.BOTTOM
+import androidx.constraintlayout.widget.ConstraintSet.END
+import androidx.constraintlayout.widget.ConstraintSet.PARENT_ID
+import androidx.constraintlayout.widget.ConstraintSet.START
+import androidx.constraintlayout.widget.ConstraintSet.TOP
+import com.android.systemui.R
+import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.navigationbar.NavigationModeController
@@ -9,15 +21,21 @@ import com.android.systemui.plugins.qs.QSContainerController
import com.android.systemui.recents.OverviewProxyService
import com.android.systemui.recents.OverviewProxyService.OverviewProxyListener
import com.android.systemui.shared.system.QuickStepContract
+import com.android.systemui.util.Utils
import com.android.systemui.util.ViewController
+import com.android.systemui.util.concurrency.DelayableExecutor
import java.util.function.Consumer
import javax.inject.Inject
+@VisibleForTesting
+internal const val INSET_DEBOUNCE_MILLIS = 500L
+
class NotificationsQSContainerController @Inject constructor(
view: NotificationsQuickSettingsContainer,
private val navigationModeController: NavigationModeController,
private val overviewProxyService: OverviewProxyService,
- private val featureFlags: FeatureFlags
+ private val featureFlags: FeatureFlags,
+ @Main private val delayableExecutor: DelayableExecutor
) : ViewController<NotificationsQuickSettingsContainer>(view), QSContainerController {
var qsExpanded = false
@@ -27,22 +45,20 @@ class NotificationsQSContainerController @Inject constructor(
mView.invalidate()
}
}
- var splitShadeEnabled = false
- set(value) {
- if (field != value) {
- field = value
- // in case device configuration changed while showing QS details/customizer
- updateBottomSpacing()
- }
- }
-
+ private var splitShadeEnabled = false
private var isQSDetailShowing = false
private var isQSCustomizing = false
private var isQSCustomizerAnimating = false
+ private var splitShadeStatusBarHeight = 0
private var notificationsBottomMargin = 0
+ private var scrimShadeBottomMargin = 0
private var bottomStableInsets = 0
private var bottomCutoutInsets = 0
+ private var panelMarginHorizontal = 0
+ private var topMargin = 0
+
+ private val useCombinedQSHeaders = featureFlags.isEnabled(Flags.COMBINED_QS_HEADERS)
private var isGestureNavigation = true
private var taskbarVisible = false
@@ -51,11 +67,29 @@ class NotificationsQSContainerController @Inject constructor(
taskbarVisible = visible
}
}
- private val windowInsetsListener: Consumer<WindowInsets> = Consumer { insets ->
- // when taskbar is visible, stableInsetBottom will include its height
- bottomStableInsets = insets.stableInsetBottom
- bottomCutoutInsets = insets.displayCutout?.safeInsetBottom ?: 0
- updateBottomSpacing()
+
+ // With certain configuration changes (like light/dark changes), the nav bar will disappear
+ // for a bit, causing `bottomStableInsets` to be unstable for some time. Debounce the value
+ // for 500ms.
+ // All interactions with this object happen in the main thread.
+ private val delayedInsetSetter = object : Runnable, Consumer<WindowInsets> {
+ private var canceller: Runnable? = null
+ private var stableInsets = 0
+ private var cutoutInsets = 0
+
+ override fun accept(insets: WindowInsets) {
+ // when taskbar is visible, stableInsetBottom will include its height
+ stableInsets = insets.stableInsetBottom
+ cutoutInsets = insets.displayCutout?.safeInsetBottom ?: 0
+ canceller?.run()
+ canceller = delayableExecutor.executeDelayed(this, INSET_DEBOUNCE_MILLIS)
+ }
+
+ override fun run() {
+ bottomStableInsets = stableInsets
+ bottomCutoutInsets = cutoutInsets
+ updateBottomSpacing()
+ }
}
override fun onInit() {
@@ -66,20 +100,49 @@ class NotificationsQSContainerController @Inject constructor(
}
public override fun onViewAttached() {
- updateMargins()
+ updateResources()
overviewProxyService.addCallback(taskbarVisibilityListener)
- mView.setInsetsChangedListener(windowInsetsListener)
+ mView.setInsetsChangedListener(delayedInsetSetter)
mView.setQSFragmentAttachedListener { qs: QS -> qs.setContainerController(this) }
+ mView.setConfigurationChangedListener { updateResources() }
}
override fun onViewDetached() {
overviewProxyService.removeCallback(taskbarVisibilityListener)
mView.removeOnInsetsChangedListener()
mView.removeQSFragmentAttachedListener()
+ mView.setConfigurationChangedListener(null)
}
- fun updateMargins() {
- notificationsBottomMargin = mView.defaultNotificationsMarginBottom
+ fun updateResources() {
+ val newSplitShadeEnabled = Utils.shouldUseSplitNotificationShade(resources)
+ val splitShadeEnabledChanged = newSplitShadeEnabled != splitShadeEnabled
+ splitShadeEnabled = newSplitShadeEnabled
+ notificationsBottomMargin = resources.getDimensionPixelSize(
+ R.dimen.notification_panel_margin_bottom)
+ splitShadeStatusBarHeight = Utils.getSplitShadeStatusBarHeight(context)
+ panelMarginHorizontal = resources.getDimensionPixelSize(
+ R.dimen.notification_panel_margin_horizontal)
+ topMargin = if (splitShadeEnabled) {
+ splitShadeStatusBarHeight
+ } else {
+ resources.getDimensionPixelSize(R.dimen.notification_panel_margin_top)
+ }
+ updateConstraints()
+ if (splitShadeEnabledChanged) {
+ // Let's do it at the end when all margins/paddings were already applied.
+ // We need to updateBottomSpacing() in case device configuration changed while showing
+ // QS details/customizer
+ updateBottomSpacing()
+ }
+ val previousScrimShadeBottomMargin = scrimShadeBottomMargin
+ scrimShadeBottomMargin = resources.getDimensionPixelSize(
+ R.dimen.split_shade_notifications_scrim_margin_bottom
+ )
+
+ if (previousScrimShadeBottomMargin != scrimShadeBottomMargin) {
+ updateBottomSpacing()
+ }
}
override fun setCustomizerAnimating(animating: Boolean) {
@@ -111,7 +174,11 @@ class NotificationsQSContainerController @Inject constructor(
qsScrollPaddingBottom = bottomStableInsets
} else if (newFooter && !(isQSCustomizing || isQSDetailShowing)) {
// With the new footer, we also want this padding in the bottom in these cases
- qsScrollPaddingBottom = bottomStableInsets
+ qsScrollPaddingBottom = if (splitShadeEnabled) {
+ notificationsMargin - scrimShadeBottomMargin
+ } else {
+ bottomStableInsets
+ }
}
mView.setPadding(0, 0, 0, containerPadding)
mView.setNotificationsMarginBottom(notificationsMargin)
@@ -153,4 +220,66 @@ class NotificationsQSContainerController @Inject constructor(
}
return containerPadding to stackScrollMargin
}
-} \ No newline at end of file
+
+ fun updateConstraints() {
+ // To change the constraints at runtime, all children of the ConstraintLayout must have ids
+ ensureAllViewsHaveIds(mView)
+ val constraintSet = ConstraintSet()
+ constraintSet.clone(mView)
+ setKeyguardStatusViewConstraints(constraintSet)
+ setQsConstraints(constraintSet)
+ setNotificationsConstraints(constraintSet)
+ setSplitShadeStatusBarConstraints(constraintSet)
+ mView.applyConstraints(constraintSet)
+ }
+
+ private fun setSplitShadeStatusBarConstraints(constraintSet: ConstraintSet) {
+ if (splitShadeEnabled) {
+ constraintSet.constrainHeight(R.id.split_shade_status_bar, splitShadeStatusBarHeight)
+ } else {
+ if (useCombinedQSHeaders) {
+ constraintSet.constrainHeight(R.id.split_shade_status_bar, WRAP_CONTENT)
+ }
+ }
+ }
+
+ private fun setNotificationsConstraints(constraintSet: ConstraintSet) {
+ val startConstraintId = if (splitShadeEnabled) R.id.qs_edge_guideline else PARENT_ID
+ constraintSet.apply {
+ connect(R.id.notification_stack_scroller, START, startConstraintId, START)
+ setMargin(R.id.notification_stack_scroller, START,
+ if (splitShadeEnabled) 0 else panelMarginHorizontal)
+ setMargin(R.id.notification_stack_scroller, END, panelMarginHorizontal)
+ setMargin(R.id.notification_stack_scroller, TOP, topMargin)
+ setMargin(R.id.notification_stack_scroller, BOTTOM, notificationsBottomMargin)
+ }
+ }
+
+ private fun setQsConstraints(constraintSet: ConstraintSet) {
+ val endConstraintId = if (splitShadeEnabled) R.id.qs_edge_guideline else PARENT_ID
+ constraintSet.apply {
+ connect(R.id.qs_frame, END, endConstraintId, END)
+ setMargin(R.id.qs_frame, START, if (splitShadeEnabled) 0 else panelMarginHorizontal)
+ setMargin(R.id.qs_frame, END, if (splitShadeEnabled) 0 else panelMarginHorizontal)
+ setMargin(R.id.qs_frame, TOP, topMargin)
+ }
+ }
+
+ private fun setKeyguardStatusViewConstraints(constraintSet: ConstraintSet) {
+ val statusViewMarginHorizontal = resources.getDimensionPixelSize(
+ R.dimen.status_view_margin_horizontal)
+ constraintSet.apply {
+ setMargin(R.id.keyguard_status_view, START, statusViewMarginHorizontal)
+ setMargin(R.id.keyguard_status_view, END, statusViewMarginHorizontal)
+ }
+ }
+
+ private fun ensureAllViewsHaveIds(parentView: ViewGroup) {
+ for (i in 0 until parentView.childCount) {
+ val childView = parentView.getChildAt(i)
+ if (childView.id == View.NO_ID) {
+ childView.id = View.generateViewId()
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
index 95e3b70b4c5e..7caea06e6359 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
@@ -18,12 +18,15 @@ package com.android.systemui.statusbar.phone;
import android.app.Fragment;
import android.content.Context;
+import android.content.res.Configuration;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.View;
import android.view.WindowInsets;
+import androidx.annotation.Nullable;
import androidx.constraintlayout.widget.ConstraintLayout;
+import androidx.constraintlayout.widget.ConstraintSet;
import com.android.systemui.R;
import com.android.systemui.fragments.FragmentHostManager;
@@ -54,6 +57,9 @@ public class NotificationsQuickSettingsContainer extends ConstraintLayout
private View mQSScrollView;
private View mQSContainer;
+ @Nullable
+ private Consumer<Configuration> mConfigurationChangedListener;
+
public NotificationsQuickSettingsContainer(Context context, AttributeSet attrs) {
super(context, attrs);
}
@@ -79,6 +85,18 @@ public class NotificationsQuickSettingsContainer extends ConstraintLayout
invalidate();
}
+ @Override
+ protected void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ if (mConfigurationChangedListener != null) {
+ mConfigurationChangedListener.accept(newConfig);
+ }
+ }
+
+ public void setConfigurationChangedListener(Consumer<Configuration> listener) {
+ mConfigurationChangedListener = listener;
+ }
+
public void setNotificationsMarginBottom(int margin) {
LayoutParams params = (LayoutParams) mStackScroller.getLayoutParams();
params.bottomMargin = margin;
@@ -106,10 +124,6 @@ public class NotificationsQuickSettingsContainer extends ConstraintLayout
}
}
- public int getDefaultNotificationsMarginBottom() {
- return ((LayoutParams) mStackScroller.getLayoutParams()).bottomMargin;
- }
-
public void setInsetsChangedListener(Consumer<WindowInsets> onInsetsChangedListener) {
mInsetsChangedListener = onInsetsChangedListener;
}
@@ -180,4 +194,7 @@ public class NotificationsQuickSettingsContainer extends ConstraintLayout
}
}
+ public void applyConstraints(ConstraintSet constraintSet) {
+ constraintSet.applyTo(this);
+ }
}
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 7c1775ed2a5e..78edc07c8544 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
@@ -382,7 +382,7 @@ public abstract class PanelViewController {
protected void startExpandMotion(float newX, float newY, boolean startTracking,
float expandedHeight) {
- if (!mHandlingPointerUp) {
+ if (!mHandlingPointerUp && !mStatusBarStateController.isDozing()) {
beginJankMonitoring(CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE);
}
mInitialOffsetOnTouch = expandedHeight;
@@ -397,6 +397,7 @@ public abstract class PanelViewController {
private void endMotionEvent(MotionEvent event, float x, float y, boolean forceCancel) {
mTrackingPointer = -1;
+ mAmbientState.setSwipingUp(false);
if ((mTracking && mTouchSlopExceeded) || Math.abs(x - mInitialTouchX) > mTouchSlop
|| Math.abs(y - mInitialTouchY) > mTouchSlop
|| event.getActionMasked() == MotionEvent.ACTION_CANCEL || forceCancel) {
@@ -444,7 +445,7 @@ public abstract class PanelViewController {
mLockscreenGestureLogger.log(LockscreenUiEvent.LOCKSCREEN_UNLOCK);
}
@Classifier.InteractionType int interactionType = vel == 0 ? GENERIC
- : vel > 0 ? QUICK_SETTINGS
+ : y - mInitialTouchY > 0 ? QUICK_SETTINGS
: (mKeyguardStateController.canDismissLockScreen()
? UNLOCK : BOUNCER_UNLOCK);
@@ -460,7 +461,6 @@ public abstract class PanelViewController {
boolean expands = onEmptySpaceClick(mInitialTouchX);
onTrackingStopped(expands);
}
- mAmbientState.setSwipingUp(false);
mVelocityTracker.clear();
}
@@ -532,7 +532,7 @@ public abstract class PanelViewController {
return true;
}
- @Classifier.InteractionType int interactionType = vel > 0
+ @Classifier.InteractionType int interactionType = y - mInitialTouchY > 0
? QUICK_SETTINGS : (
mKeyguardStateController.canDismissLockScreen() ? UNLOCK : BOUNCER_UNLOCK);
@@ -654,7 +654,9 @@ public abstract class PanelViewController {
@Override
public void onAnimationStart(Animator animation) {
- beginJankMonitoring(CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE);
+ if (!mStatusBarStateController.isDozing()) {
+ beginJankMonitoring(CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE);
+ }
}
@Override
@@ -794,6 +796,7 @@ public abstract class PanelViewController {
}
mExpandedFraction = Math.min(1f,
maxPanelHeight == 0 ? 0 : mExpandedHeight / maxPanelHeight);
+ mAmbientState.setExpansionFraction(mExpandedFraction);
onHeightUpdated(mExpandedHeight);
updatePanelExpansionAndVisibility();
});
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index 0059c1b3642c..d7abf7430cac 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -349,7 +349,7 @@ public class PhoneStatusBarPolicy
}
private String getManagedProfileAccessibilityString() {
- return mDevicePolicyManager.getString(
+ return mDevicePolicyManager.getResources().getString(
STATUS_BAR_WORK_ICON_ACCESSIBILITY,
() -> mResources.getString(R.string.accessibility_managed_profile));
}
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 a3c795f36d5d..029a7a5fcdd5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -41,6 +41,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.colorextraction.ColorExtractor.GradientColors;
import com.android.internal.graphics.ColorUtils;
import com.android.internal.util.function.TriConsumer;
+import com.android.keyguard.BouncerPanelExpansionCalculator;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.settingslib.Utils;
@@ -116,6 +117,15 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
private float mTransitionToFullShadeProgress;
/**
+ * Same as {@link #mTransitionToFullShadeProgress}, but specifically for the notifications scrim
+ * on the lock screen.
+ *
+ * On split shade lock screen we want the different scrims to fade in at different times and
+ * rates.
+ */
+ private float mTransitionToLockScreenFullShadeNotificationsProgress;
+
+ /**
* If we're currently transitioning to the full shade.
*/
private boolean mTransitioningToFullShade;
@@ -574,11 +584,17 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
* Set the amount of progress we are currently in if we're transitioning to the full shade.
* 0.0f means we're not transitioning yet, while 1 means we're all the way in the full
* shade.
+ *
+ * @param progress the progress for all scrims.
+ * @param lockScreenNotificationsProgress the progress specifically for the notifications scrim.
*/
- public void setTransitionToFullShadeProgress(float progress) {
- if (progress != mTransitionToFullShadeProgress) {
+ public void setTransitionToFullShadeProgress(float progress,
+ float lockScreenNotificationsProgress) {
+ if (progress != mTransitionToFullShadeProgress || lockScreenNotificationsProgress
+ != mTransitionToLockScreenFullShadeNotificationsProgress) {
mTransitionToFullShadeProgress = progress;
- setTransitionToFullShade(progress > 0.0f);
+ mTransitionToLockScreenFullShadeNotificationsProgress = lockScreenNotificationsProgress;
+ setTransitionToFullShade(progress > 0.0f || lockScreenNotificationsProgress > 0.0f);
applyAndDispatchState();
}
}
@@ -754,12 +770,13 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
} else {
mNotificationsAlpha = Math.max(1.0f - getInterpolatedFraction(), mQsExpansion);
}
- if (mState == ScrimState.KEYGUARD && mTransitionToFullShadeProgress > 0.0f) {
+ if (mState == ScrimState.KEYGUARD
+ && mTransitionToLockScreenFullShadeNotificationsProgress > 0.0f) {
// Interpolate the notification alpha when transitioning!
mNotificationsAlpha = MathUtils.lerp(
mNotificationsAlpha,
getInterpolatedFraction(),
- mTransitionToFullShadeProgress);
+ mTransitionToLockScreenFullShadeNotificationsProgress);
}
mNotificationsTint = mState.getNotifTint();
mBehindTint = behindTint;
@@ -773,7 +790,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
}
if (mUnOcclusionAnimationRunning && mState == ScrimState.KEYGUARD) {
// We're unoccluding the keyguard and don't want to have a bright flash.
- mNotificationsAlpha = mScrimBehindAlphaKeyguard;
+ mNotificationsAlpha = ScrimState.KEYGUARD.getNotifAlpha();
mNotificationsTint = ScrimState.KEYGUARD.getNotifTint();
}
}
@@ -792,7 +809,15 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
private Pair<Integer, Float> calculateBackStateForState(ScrimState state) {
// Either darken of make the scrim transparent when you
// pull down the shade
- float interpolatedFract = getInterpolatedFraction();
+ float interpolatedFract;
+
+ if (state == ScrimState.KEYGUARD) {
+ interpolatedFract = BouncerPanelExpansionCalculator
+ .getBackScrimScaledExpansion(mPanelExpansionFraction);
+ } else {
+ interpolatedFract = getInterpolatedFraction();
+ }
+
float stateBehind = mClipsQsScrim ? state.getNotifAlpha() : state.getBehindAlpha();
float behindAlpha;
int behindTint;
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 c160c22203a5..23a1087edfd8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -1016,6 +1016,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
if (bouncerShowing != mLastBouncerShowing || mFirstUpdate) {
mNotificationShadeWindowController.setBouncerShowing(bouncerShowing);
mCentralSurfaces.setBouncerShowing(bouncerShowing);
+ mKeyguardMessageAreaController.setBouncerShowing(bouncerShowing);
}
if (occluded != mLastOccluded || mFirstUpdate) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
index edbddbb3c3e7..6fe92fafc075 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
@@ -41,6 +41,7 @@ import android.text.TextUtils;
import android.util.EventLog;
import android.view.View;
+import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
import com.android.internal.jank.InteractionJankMonitor;
@@ -51,6 +52,7 @@ import com.android.systemui.ActivityIntentHelper;
import com.android.systemui.EventLogTags;
import com.android.systemui.animation.ActivityLaunchAnimator;
import com.android.systemui.assist.AssistManager;
+import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.CommandQueue;
@@ -75,6 +77,7 @@ import com.android.systemui.statusbar.notification.row.OnUserInteractionCallback
import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent;
import com.android.systemui.statusbar.policy.HeadsUpUtil;
import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.systemui.util.ListenerSet;
import com.android.systemui.wmshell.BubblesManager;
import java.util.Optional;
@@ -128,6 +131,7 @@ class StatusBarNotificationActivityStarter implements NotificationActivityStarte
private final ActivityLaunchAnimator mActivityLaunchAnimator;
private final NotificationLaunchAnimatorControllerProvider mNotificationAnimationProvider;
private final OnUserInteractionCallback mOnUserInteractionCallback;
+ private final LaunchEventsEmitter mLaunchEventsEmitter;
private boolean mIsCollapsingToShowActivityOverLockscreen;
@@ -166,7 +170,8 @@ class StatusBarNotificationActivityStarter implements NotificationActivityStarte
NotificationPresenter presenter,
NotificationPanelViewController panel,
ActivityLaunchAnimator activityLaunchAnimator,
- NotificationLaunchAnimatorControllerProvider notificationAnimationProvider) {
+ NotificationLaunchAnimatorControllerProvider notificationAnimationProvider,
+ LaunchEventsEmitter launchEventsEmitter) {
mContext = context;
mCommandQueue = commandQueue;
mMainThreadHandler = mainThreadHandler;
@@ -192,18 +197,17 @@ class StatusBarNotificationActivityStarter implements NotificationActivityStarte
mLockPatternUtils = lockPatternUtils;
mStatusBarRemoteInputCallback = remoteInputCallback;
mActivityIntentHelper = activityIntentHelper;
-
mNotifPipelineFlags = notifPipelineFlags;
mMetricsLogger = metricsLogger;
mLogger = logger;
mOnUserInteractionCallback = onUserInteractionCallback;
-
// TODO: use KeyguardStateController#isOccluded to remove this dependency
mCentralSurfaces = centralSurfaces;
mPresenter = presenter;
mNotificationPanel = panel;
mActivityLaunchAnimator = activityLaunchAnimator;
mNotificationAnimationProvider = notificationAnimationProvider;
+ mLaunchEventsEmitter = launchEventsEmitter;
if (!mNotifPipelineFlags.isNewPipelineEnabled()) {
mEntryManager.addNotificationEntryListener(new NotificationEntryListener() {
@@ -254,6 +258,8 @@ class StatusBarNotificationActivityStarter implements NotificationActivityStarte
return;
}
+ mLaunchEventsEmitter.notifyStartLaunchNotifActivity(entry);
+
boolean isActivityIntent = intent != null && intent.isActivity() && !isBubble;
final boolean willLaunchResolverActivity = isActivityIntent
&& mActivityIntentHelper.wouldLaunchResolverActivity(intent.getIntent(),
@@ -280,7 +286,9 @@ class StatusBarNotificationActivityStarter implements NotificationActivityStarte
postKeyguardAction.onDismiss();
} else {
mActivityStarter.dismissKeyguardThenExecute(
- postKeyguardAction, null /* cancel */, willLaunchResolverActivity);
+ postKeyguardAction,
+ () -> mLaunchEventsEmitter.notifyFinishLaunchNotifActivity(entry),
+ willLaunchResolverActivity);
}
}
@@ -362,6 +370,8 @@ class StatusBarNotificationActivityStarter implements NotificationActivityStarte
mLogger.logExpandingBubble(notificationKey);
removeHunAfterClick(row);
expandBubbleStackOnMainThread(entry);
+ mMainThreadHandler.post(
+ () -> mLaunchEventsEmitter.notifyFinishLaunchNotifActivity(entry));
} else {
startNotificationIntent(intent, fillInIntent, entry, row, animate, isActivityIntent);
}
@@ -380,24 +390,32 @@ class StatusBarNotificationActivityStarter implements NotificationActivityStarte
// inform NMS that the notification was clicked
mClickNotifier.onNotificationClick(notificationKey, nv);
- if (!canBubble) {
- if (shouldAutoCancel || mRemoteInputManager.isNotificationKeptForRemoteInputHistory(
- notificationKey)) {
- // Immediately remove notification from visually showing.
- // We have to post the removal to the UI thread for synchronization.
- mMainThreadHandler.post(() -> {
- final Runnable removeNotification = () ->
- mOnUserInteractionCallback.onDismiss(
- entry, REASON_CLICK, summaryToRemove);
- if (mPresenter.isCollapsing()) {
- // To avoid lags we're only performing the remove
- // after the shade is collapsed
- mShadeController.addPostCollapseAction(removeNotification);
- } else {
- removeNotification.run();
+ if (!canBubble && (shouldAutoCancel
+ || mRemoteInputManager.isNotificationKeptForRemoteInputHistory(notificationKey))) {
+ // Immediately remove notification from visually showing.
+ // We have to post the removal to the UI thread for synchronization.
+ mMainThreadHandler.post(() -> {
+ final Runnable removeNotification = () -> {
+ mOnUserInteractionCallback.onDismiss(entry, REASON_CLICK, summaryToRemove);
+ if (!animate) {
+ // If we're animating, this would be invoked after the activity launch
+ // animation completes. Since we're not animating, the launch already
+ // happened synchronously, so we notify the launch is complete here after
+ // onDismiss.
+ mLaunchEventsEmitter.notifyFinishLaunchNotifActivity(entry);
}
- });
- }
+ };
+ if (mPresenter.isCollapsing()) {
+ // To avoid lags we're only performing the remove after the shade is collapsed
+ mShadeController.addPostCollapseAction(removeNotification);
+ } else {
+ removeNotification.run();
+ }
+ });
+ } else if (!canBubble && !animate) {
+ // Not animating, this is the end of the launch flow (see above comment for more info).
+ mMainThreadHandler.post(
+ () -> mLaunchEventsEmitter.notifyFinishLaunchNotifActivity(entry));
}
mIsCollapsingToShowActivityOverLockscreen = false;
@@ -473,14 +491,20 @@ class StatusBarNotificationActivityStarter implements NotificationActivityStarte
boolean isActivityIntent) {
mLogger.logStartNotificationIntent(entry.getKey(), intent);
try {
+ Runnable onFinishAnimationCallback = animate
+ ? () -> mLaunchEventsEmitter.notifyFinishLaunchNotifActivity(entry)
+ : null;
ActivityLaunchAnimator.Controller animationController =
new StatusBarLaunchAnimatorController(
- mNotificationAnimationProvider.getAnimatorController(row),
+ mNotificationAnimationProvider
+ .getAnimatorController(row, onFinishAnimationCallback),
mCentralSurfaces,
isActivityIntent);
-
- mActivityLaunchAnimator.startPendingIntentWithAnimation(animationController,
- animate, intent.getCreatorPackage(), (adapter) -> {
+ mActivityLaunchAnimator.startPendingIntentWithAnimation(
+ animationController,
+ animate,
+ intent.getCreatorPackage(),
+ (adapter) -> {
long eventTime = row.getAndResetLastActionUpTime();
Bundle options = eventTime > 0
? getActivityOptions(
@@ -659,4 +683,35 @@ class StatusBarNotificationActivityStarter implements NotificationActivityStarte
return entry.shouldSuppressFullScreenIntent();
}
+
+ @SysUISingleton
+ static class LaunchEventsEmitter implements NotifActivityLaunchEvents {
+
+ private final ListenerSet<Listener> mListeners = new ListenerSet<>();
+
+ @Inject
+ LaunchEventsEmitter() {}
+
+ @Override
+ public void registerListener(@NonNull Listener listener) {
+ mListeners.addIfAbsent(listener);
+ }
+
+ @Override
+ public void unregisterListener(@NonNull Listener listener) {
+ mListeners.remove(listener);
+ }
+
+ private void notifyStartLaunchNotifActivity(NotificationEntry entry) {
+ for (Listener listener : mListeners) {
+ listener.onStartLaunchNotifActivity(entry);
+ }
+ }
+
+ private void notifyFinishLaunchNotifActivity(NotificationEntry entry) {
+ for (Listener listener : mListeners) {
+ listener.onFinishLaunchNotifActivity(entry);
+ }
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/CentralSurfacesComponent.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/CentralSurfacesComponent.java
index 59c9d0baea3f..a86ad6bc7012 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/CentralSurfacesComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/CentralSurfacesComponent.java
@@ -27,7 +27,6 @@ import com.android.systemui.statusbar.NotificationShelfController;
import com.android.systemui.statusbar.core.StatusBarInitializer;
import com.android.systemui.statusbar.notification.NotificationActivityStarter;
import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl;
-import com.android.systemui.statusbar.notification.collection.render.StatusBarNotifPanelEventSourceModule;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutListContainerModule;
@@ -60,8 +59,8 @@ import dagger.Subcomponent;
* outside the component. Should more items be moved *into* this component to avoid so many getters?
*/
@Subcomponent(modules = {
+ CentralSurfacesStartableModule.class,
NotificationStackScrollLayoutListContainerModule.class,
- StatusBarNotifPanelEventSourceModule.class,
StatusBarViewModule.class,
StatusBarNotificationActivityStarterModule.class,
StatusBarNotificationPresenterModule.class,
diff --git a/packages/SystemUI/src/com/android/systemui/tv/TvSysUIComponentModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/CentralSurfacesStartableModule.java
index 9621e5f5f1a0..21e5ad5778b1 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/TvSysUIComponentModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/CentralSurfacesStartableModule.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 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.
@@ -14,13 +14,15 @@
* limitations under the License.
*/
-package com.android.systemui.tv;
+package com.android.systemui.statusbar.phone.dagger;
+
+import java.util.Set;
import dagger.Module;
+import dagger.multibindings.Multibinds;
-/**
- * Dagger module for including the SysUIComponent.
- */
-@Module(subcomponents = {TvSysUIComponent.class})
-public abstract class TvSysUIComponentModule {
+@Module
+interface CentralSurfacesStartableModule {
+ @Multibinds
+ Set<CentralSurfacesComponent.Startable> multibindStartables();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
index 2c84219dbfd0..8194957c52fc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
@@ -20,12 +20,10 @@ import static android.app.StatusBarManager.DISABLE_NOTIFICATION_ICONS;
import static android.app.StatusBarManager.DISABLE_ONGOING_CALL_CHIP;
import static android.app.StatusBarManager.DISABLE_SYSTEM_INFO;
-import static com.android.systemui.statusbar.events.SystemStatusAnimationSchedulerKt.ANIMATING_IN;
-import static com.android.systemui.statusbar.events.SystemStatusAnimationSchedulerKt.ANIMATING_OUT;
import static com.android.systemui.statusbar.events.SystemStatusAnimationSchedulerKt.IDLE;
import static com.android.systemui.statusbar.events.SystemStatusAnimationSchedulerKt.SHOWING_PERSISTENT_DOT;
-import android.animation.ValueAnimator;
+import android.animation.Animator;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SuppressLint;
@@ -74,6 +72,7 @@ import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.settings.SecureSettings;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import java.util.concurrent.Executor;
@@ -136,6 +135,7 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
}
};
private OperatorNameViewController mOperatorNameViewController;
+ private StatusBarSystemEventAnimator mSystemEventAnimator;
@SuppressLint("ValidFragment")
public CollapsedStatusBarFragment(
@@ -210,18 +210,31 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
initEmergencyCryptkeeperText();
initOperatorName();
initNotificationIconArea();
- mAnimationScheduler.addCallback(this);
+ mSystemEventAnimator =
+ new StatusBarSystemEventAnimator(mSystemIconArea, getResources());
}
@VisibleForTesting
void updateBlockedIcons() {
mBlockedIcons.clear();
- if (mSecureSettings.getInt(Settings.Secure.STATUS_BAR_SHOW_VIBRATE_ICON, 0) == 0) {
- mBlockedIcons.add(getString(com.android.internal.R.string.status_bar_volume));
+ // Reload the blocklist from res
+ List<String> blockList = Arrays.asList(getResources().getStringArray(
+ R.array.config_collapsed_statusbar_icon_blocklist));
+ String vibrateIconSlot = getString(com.android.internal.R.string.status_bar_volume);
+ boolean showVibrateIcon =
+ mSecureSettings.getInt(Settings.Secure.STATUS_BAR_SHOW_VIBRATE_ICON, 0) == 0;
+
+ // Filter out vibrate icon from the blocklist if the setting is on
+ for (int i = 0; i < blockList.size(); i++) {
+ if (blockList.get(i).equals(vibrateIconSlot)) {
+ if (showVibrateIcon) {
+ mBlockedIcons.add(blockList.get(i));
+ }
+ } else {
+ mBlockedIcons.add(blockList.get(i));
+ }
}
- mBlockedIcons.add(getString(com.android.internal.R.string.status_bar_alarm_clock));
- mBlockedIcons.add(getString(com.android.internal.R.string.status_bar_call_strength));
mMainExecutor.execute(() -> mDarkIconManager.setBlockList(mBlockedIcons));
}
@@ -245,6 +258,7 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
mCommandQueue.addCallback(this);
mStatusBarStateController.addCallback(this);
initOngoingCallChip();
+ mAnimationScheduler.addCallback(this);
mSecureSettings.registerContentObserver(
Settings.Secure.getUriFor(Settings.Secure.STATUS_BAR_SHOW_VIBRATE_ICON),
@@ -258,6 +272,7 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
mCommandQueue.removeCallback(this);
mStatusBarStateController.removeCallback(this);
mOngoingCallController.removeCallback(mOngoingCallListener);
+ mAnimationScheduler.removeCallback(this);
mSecureSettings.unregisterContentObserver(mVolumeSettingObserver);
}
@@ -265,7 +280,6 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
public void onDestroyView() {
super.onDestroyView();
mStatusBarIconController.removeIconGroup(mDarkIconManager);
- mAnimationScheduler.removeCallback(this);
if (mNetworkController.hasEmergencyCryptKeeperText()) {
mNetworkController.removeCallback(mSignalCallback);
}
@@ -576,35 +590,16 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
disable(getContext().getDisplayId(), mDisabled1, mDisabled2, false /* animate */);
}
+ @Nullable
@Override
- public void onSystemChromeAnimationStart() {
- if (mAnimationScheduler.getAnimationState() == ANIMATING_OUT
- && !isSystemIconAreaDisabled()) {
- mSystemIconArea.setVisibility(View.VISIBLE);
- mSystemIconArea.setAlpha(0f);
- }
- }
-
- @Override
- public void onSystemChromeAnimationEnd() {
- // Make sure the system icons are out of the way
- if (mAnimationScheduler.getAnimationState() == ANIMATING_IN) {
- mSystemIconArea.setVisibility(View.INVISIBLE);
- mSystemIconArea.setAlpha(0f);
- } else {
- if (isSystemIconAreaDisabled()) {
- // don't unhide
- return;
- }
-
- mSystemIconArea.setAlpha(1f);
- mSystemIconArea.setVisibility(View.VISIBLE);
- }
+ public Animator onSystemEventAnimationBegin() {
+ return mSystemEventAnimator.onSystemEventAnimationBegin();
}
+ @Nullable
@Override
- public void onSystemChromeAnimationUpdate(@NonNull ValueAnimator animator) {
- mSystemIconArea.setAlpha((float) animator.getAnimatedValue());
+ public Animator onSystemEventAnimationFinish(boolean hasPersistentDot) {
+ return mSystemEventAnimator.onSystemEventAnimationFinish(hasPersistentDot);
}
private boolean isSystemIconAreaDisabled() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/StatusBarSystemEventAnimator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/StatusBarSystemEventAnimator.kt
new file mode 100644
index 000000000000..f530ec83aec5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/StatusBarSystemEventAnimator.kt
@@ -0,0 +1,84 @@
+/*
+ * 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.statusbar.phone.fragment
+
+import android.animation.Animator
+import android.animation.AnimatorSet
+import android.animation.ValueAnimator
+import android.content.res.Resources
+import android.view.View
+import com.android.systemui.R
+import com.android.systemui.statusbar.events.STATUS_BAR_X_MOVE_IN
+import com.android.systemui.statusbar.events.STATUS_BAR_X_MOVE_OUT
+import com.android.systemui.statusbar.events.SystemStatusAnimationCallback
+
+/**
+ * Tied directly to [SystemStatusAnimationScheduler]. Any StatusBar-like thing (keyguard, collapsed
+ * status bar fragment), can just feed this an animatable view to get the default system status
+ * animation.
+ *
+ * This animator relies on resources, and should be recreated whenever resources are updated. While
+ * this class could be used directly as the animation callback, it's probably best to forward calls
+ * to it so that it can be recreated at any moment without needing to remove/add callback.
+ */
+class StatusBarSystemEventAnimator(
+ val animatedView: View,
+ resources: Resources
+) : SystemStatusAnimationCallback {
+ private val translationXIn: Int = resources.getDimensionPixelSize(
+ R.dimen.ongoing_appops_chip_animation_in_status_bar_translation_x)
+ private val translationXOut: Int = resources.getDimensionPixelSize(
+ R.dimen.ongoing_appops_chip_animation_out_status_bar_translation_x)
+
+ override fun onSystemEventAnimationBegin(): Animator {
+ val moveOut = ValueAnimator.ofFloat(0f, 1f).setDuration(383)
+ moveOut.interpolator = STATUS_BAR_X_MOVE_OUT
+ moveOut.addUpdateListener { animation: ValueAnimator ->
+ animatedView.translationX = -(translationXIn * animation.animatedValue as Float)
+ }
+ val alphaOut = ValueAnimator.ofFloat(1f, 0f).setDuration(133)
+ alphaOut.interpolator = null
+ alphaOut.addUpdateListener { animation: ValueAnimator ->
+ animatedView.alpha = animation.animatedValue as Float
+ }
+
+ val animSet = AnimatorSet()
+ animSet.playTogether(moveOut, alphaOut)
+ return animSet
+ }
+
+ override fun onSystemEventAnimationFinish(hasPersistentDot: Boolean): Animator {
+ animatedView.translationX = translationXOut.toFloat()
+ val moveIn = ValueAnimator.ofFloat(1f, 0f).setDuration(467)
+ moveIn.startDelay = 33
+ moveIn.interpolator = STATUS_BAR_X_MOVE_IN
+ moveIn.addUpdateListener { animation: ValueAnimator ->
+ animatedView.translationX = translationXOut * animation.animatedValue as Float
+ }
+ val alphaIn = ValueAnimator.ofFloat(0f, 1f).setDuration(167)
+ alphaIn.startDelay = 67
+ alphaIn.interpolator = null
+ alphaIn.addUpdateListener { animation: ValueAnimator ->
+ animatedView.alpha = animation.animatedValue as Float
+ }
+
+ val animatorSet = AnimatorSet()
+ animatorSet.playTogether(moveIn, alphaIn)
+
+ return animatorSet
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserSwitcherController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserSwitcherController.kt
index 909261f0eb7e..62549a70897b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserSwitcherController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserSwitcherController.kt
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.phone.userswitcher
import android.content.Intent
+import android.os.UserHandle
import android.view.View
import com.android.systemui.animation.ActivityLaunchAnimator
import com.android.systemui.flags.FeatureFlags
@@ -67,7 +68,7 @@ class StatusBarUserSwitcherControllerImpl @Inject constructor(
activityStarter.startActivity(intent, true /* dismissShade */,
ActivityLaunchAnimator.Controller.fromView(view, null),
- true /* showOverlockscreenwhenlocked */)
+ true /* showOverlockscreenwhenlocked */, UserHandle.SYSTEM)
} else {
userSwitcherDialogController.showDialog(view)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightControllerImpl.java
index ad47e2bc44a8..01fe8657fe47 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightControllerImpl.java
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.policy;
+import android.annotation.WorkerThread;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
@@ -219,6 +220,7 @@ public class FlashlightControllerImpl implements FlashlightController {
new CameraManager.TorchCallback() {
@Override
+ @WorkerThread
public void onTorchModeUnavailable(String cameraId) {
if (TextUtils.equals(cameraId, mCameraId)) {
setCameraAvailable(false);
@@ -229,6 +231,7 @@ public class FlashlightControllerImpl implements FlashlightController {
}
@Override
+ @WorkerThread
public void onTorchModeChanged(String cameraId, boolean enabled) {
if (TextUtils.equals(cameraId, mCameraId)) {
setCameraAvailable(true);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchController.java
index 7e2488f1dfab..e8bf89a6a90a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchController.java
@@ -35,7 +35,6 @@ import com.android.keyguard.KeyguardVisibilityHelper;
import com.android.keyguard.dagger.KeyguardUserSwitcherScope;
import com.android.settingslib.drawable.CircleFramedDrawable;
import com.android.systemui.R;
-import com.android.systemui.communal.CommunalStateController;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.keyguard.ScreenLifecycle;
import com.android.systemui.plugins.FalsingManager;
@@ -119,7 +118,6 @@ public class KeyguardQsUserSwitchController extends ViewController<FrameLayout>
@Main Resources resources,
ScreenLifecycle screenLifecycle,
UserSwitcherController userSwitcherController,
- CommunalStateController communalStateController,
KeyguardStateController keyguardStateController,
FalsingManager falsingManager,
ConfigurationController configurationController,
@@ -138,10 +136,9 @@ public class KeyguardQsUserSwitchController extends ViewController<FrameLayout>
mFalsingManager = falsingManager;
mConfigurationController = configurationController;
mStatusBarStateController = statusBarStateController;
- mKeyguardVisibilityHelper = new KeyguardVisibilityHelper(mView, communalStateController,
+ mKeyguardVisibilityHelper = new KeyguardVisibilityHelper(mView,
keyguardStateController, dozeParameters,
- screenOffAnimationController, /* animateYPos= */ false,
- /* visibleOnCommunal= */ false);
+ screenOffAnimationController, /* animateYPos= */ false);
mUserSwitchDialogController = userSwitchDialogController;
mUiEventLogger = uiEventLogger;
}
@@ -270,7 +267,7 @@ public class KeyguardQsUserSwitchController extends ViewController<FrameLayout>
drawable = new CircleFramedDrawable(mCurrentUser.picture, avatarSize);
}
- Drawable bg = mContext.getDrawable(R.drawable.kg_bg_avatar);
+ Drawable bg = mContext.getDrawable(R.drawable.user_avatar_bg);
drawable = new LayerDrawable(new Drawable[]{bg, drawable});
return drawable;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java
index 04a6a114a07d..03ab888d1253 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java
@@ -42,7 +42,6 @@ import com.android.keyguard.dagger.KeyguardUserSwitcherScope;
import com.android.settingslib.drawable.CircleFramedDrawable;
import com.android.systemui.R;
import com.android.systemui.animation.Interpolators;
-import com.android.systemui.communal.CommunalStateController;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.keyguard.ScreenLifecycle;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -158,7 +157,6 @@ public class KeyguardUserSwitcherController extends ViewController<KeyguardUserS
LayoutInflater layoutInflater,
ScreenLifecycle screenLifecycle,
UserSwitcherController userSwitcherController,
- CommunalStateController communalStateController,
KeyguardStateController keyguardStateController,
SysuiStatusBarStateController statusBarStateController,
KeyguardUpdateMonitor keyguardUpdateMonitor,
@@ -174,10 +172,9 @@ public class KeyguardUserSwitcherController extends ViewController<KeyguardUserS
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mAdapter = new KeyguardUserAdapter(mContext, resources, layoutInflater,
mUserSwitcherController, this);
- mKeyguardVisibilityHelper = new KeyguardVisibilityHelper(mView, communalStateController,
+ mKeyguardVisibilityHelper = new KeyguardVisibilityHelper(mView,
keyguardStateController, dozeParameters,
- screenOffAnimationController, /* animateYPos= */ false,
- /* visibleOnCommunal= */ false);
+ screenOffAnimationController, /* animateYPos= */ false);
mBackground = new KeyguardUserSwitcherScrim(context);
}
@@ -543,7 +540,7 @@ public class KeyguardUserSwitcherController extends ViewController<KeyguardUserS
}
drawable.setTint(mResources.getColor(iconColorRes, mContext.getTheme()));
- Drawable bg = mContext.getDrawable(R.drawable.kg_bg_avatar);
+ Drawable bg = mContext.getDrawable(R.drawable.user_avatar_bg);
drawable = new LayerDrawable(new Drawable[]{bg, drawable});
return drawable;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
index 48949f92413d..4d6d05f2b628 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
@@ -22,8 +22,6 @@ import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.app.ActivityManager;
import android.app.Notification;
-import android.app.PendingIntent;
-import android.app.RemoteInput;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.res.ColorStateList;
@@ -75,7 +73,6 @@ import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.collection.NotificationEntry.EditedSuggestionInfo;
import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewWrapper;
import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
import com.android.systemui.statusbar.phone.LightBarController;
@@ -111,21 +108,15 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
private ProgressBar mProgressBar;
private ImageView mDelete;
private ImageView mDeleteBg;
- // TODO(b/193539698): remove reveal param fields, turn them into parameters where needed
- private int mRevealCx;
- private int mRevealCy;
- private int mRevealR;
private boolean mColorized;
private int mTint;
private boolean mResetting;
+ @Nullable private RevealParams mRevealParams;
// TODO(b/193539698): move these to a Controller
private RemoteInputController mController;
private final UiEventLogger mUiEventLogger;
private NotificationEntry mEntry;
- private PendingIntent mPendingIntent;
- private RemoteInput mRemoteInput;
- private RemoteInput[] mRemoteInputs;
private boolean mRemoved;
private NotificationViewWrapper mWrapper;
@@ -397,9 +388,8 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
// During removal, we get reattached and lose focus. Not hiding in that
// case to prevent flicker.
if (!mRemoved) {
- if (animate && mRevealR > 0) {
- Animator reveal = ViewAnimationUtils.createCircularReveal(
- this, mRevealCx, mRevealCy, mRevealR, 0);
+ if (animate && mRevealParams != null && mRevealParams.radius > 0) {
+ Animator reveal = mRevealParams.createCircularHideAnimator(this);
reveal.setInterpolator(Interpolators.FAST_OUT_LINEAR_IN);
reveal.setDuration(StackStateAnimator.ANIMATION_DURATION_CLOSE_REMOTE_INPUT);
reveal.addListener(new AnimatorListenerAdapter() {
@@ -454,30 +444,12 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
mController.removeSpinning(mEntry.getKey(), mToken);
}
- public void setPendingIntent(PendingIntent pendingIntent) {
- mPendingIntent = pendingIntent;
+ public void setHintText(CharSequence hintText) {
+ mEditText.setHint(hintText);
}
- /**
- * Sets the remote input for this view.
- *
- * @param remoteInputs The remote inputs that need to be sent to the app.
- * @param remoteInput The remote input that needs to be activated.
- * @param editedSuggestionInfo The smart reply that should be inserted in the remote input, or
- * {@code null} if the user is not editing a smart reply.
- */
- public void setRemoteInput(RemoteInput[] remoteInputs, RemoteInput remoteInput,
- @Nullable EditedSuggestionInfo editedSuggestionInfo) {
- mRemoteInputs = remoteInputs;
- mRemoteInput = remoteInput;
- mEditText.setHint(mRemoteInput.getLabel());
- mEditText.setSupportedMimeTypes(remoteInput.getAllowedDataTypes());
-
- mEntry.editedSuggestionInfo = editedSuggestionInfo;
- if (editedSuggestionInfo != null) {
- mEntry.remoteInputText = editedSuggestionInfo.originalText;
- mEntry.remoteInputAttachment = null;
- }
+ public void setSupportedMimeTypes(Collection<String> mimeTypes) {
+ mEditText.setSupportedMimeTypes(mimeTypes);
}
/** Populates the text field of the remote input with the given content. */
@@ -486,9 +458,8 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
}
public void focusAnimated() {
- if (getVisibility() != VISIBLE) {
- Animator animator = ViewAnimationUtils.createCircularReveal(
- this, mRevealCx, mRevealCy, 0, mRevealR);
+ if (getVisibility() != VISIBLE && mRevealParams != null) {
+ Animator animator = mRevealParams.createCircularRevealAnimator(this);
animator.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
animator.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
animator.start();
@@ -587,30 +558,12 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
return mEditText.isFocused() && mEditText.isEnabled();
}
- // TODO(b/193539698): move this to the controller
- public void stealFocusFrom(RemoteInputView other) {
- other.close();
- setPendingIntent(other.mPendingIntent);
- setRemoteInput(other.mRemoteInputs, other.mRemoteInput, mEntry.editedSuggestionInfo);
- setRevealParameters(other.mRevealCx, other.mRevealCy, other.mRevealR);
- getController().setPendingIntent(other.mPendingIntent);
- getController().setRemoteInput(other.mRemoteInput);
- getController().setRemoteInputs(other.mRemoteInputs);
- focus();
- }
-
- public PendingIntent getPendingIntent() {
- return mPendingIntent;
- }
-
public void setRemoved() {
mRemoved = true;
}
- public void setRevealParameters(int cx, int cy, int r) {
- mRevealCx = cx;
- mRevealCy = cy;
- mRevealR = r;
+ public void setRevealParameters(@Nullable RevealParams revealParams) {
+ mRevealParams = revealParams;
}
@Override
@@ -938,4 +891,24 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
}
}
+
+ public static class RevealParams {
+ final int centerX;
+ final int centerY;
+ final int radius;
+
+ public RevealParams(int centerX, int centerY, int radius) {
+ this.centerX = centerX;
+ this.centerY = centerY;
+ this.radius = radius;
+ }
+
+ Animator createCircularRevealAnimator(View view) {
+ return ViewAnimationUtils.createCircularReveal(view, centerX, centerY, radius, 0);
+ }
+
+ Animator createCircularHideAnimator(View view) {
+ return ViewAnimationUtils.createCircularReveal(view, centerX, centerY, 0, radius);
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputViewController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputViewController.kt
index ef0a5b4235c7..f8451017b367 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputViewController.kt
@@ -33,7 +33,9 @@ import com.android.systemui.R
import com.android.systemui.statusbar.NotificationRemoteInputManager
import com.android.systemui.statusbar.RemoteInputController
import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.collection.NotificationEntry.EditedSuggestionInfo
import com.android.systemui.statusbar.policy.RemoteInputView.NotificationRemoteInputEvent
+import com.android.systemui.statusbar.policy.RemoteInputView.RevealParams
import com.android.systemui.statusbar.policy.dagger.RemoteInputViewScope
import javax.inject.Inject
@@ -41,6 +43,8 @@ interface RemoteInputViewController {
fun bind()
fun unbind()
+ val isActive: Boolean
+
/**
* A [NotificationRemoteInputManager.BouncerChecker] that will be used to determine if the
* device needs to be unlocked before sending the RemoteInput.
@@ -55,6 +59,14 @@ interface RemoteInputViewController {
/** Other [RemoteInput]s from the notification associated with this Controller. */
var remoteInputs: Array<RemoteInput>?
+ var revealParams: RevealParams?
+
+ /**
+ * Sets the smart reply that should be inserted in the remote input, or `null` if the user is
+ * not editing a smart reply.
+ */
+ fun setEditedSuggestionInfo(info: EditedSuggestionInfo?)
+
/**
* Tries to find an action in {@param actions} that matches the current pending intent
* of this view and updates its state to that of the found action
@@ -68,6 +80,19 @@ interface RemoteInputViewController {
/** Unregisters a listener previously registered via [addOnSendRemoteInputListener] */
fun removeOnSendRemoteInputListener(listener: OnSendRemoteInputListener)
+
+ fun close()
+
+ fun focus()
+
+ fun stealFocusFrom(other: RemoteInputViewController) {
+ other.close()
+ remoteInput = other.remoteInput
+ remoteInputs = other.remoteInputs
+ revealParams = other.revealParams
+ pendingIntent = other.pendingIntent
+ focus()
+ }
}
/** Listener for send events */
@@ -100,15 +125,41 @@ class RemoteInputViewControllerImpl @Inject constructor(
private var isBound = false
- override var pendingIntent: PendingIntent? = null
override var bouncerChecker: NotificationRemoteInputManager.BouncerChecker? = null
+
override var remoteInput: RemoteInput? = null
+ set(value) {
+ field = value
+ value?.takeIf { isBound }?.let {
+ view.setHintText(it.label)
+ view.setSupportedMimeTypes(it.allowedDataTypes)
+ }
+ }
+
+ override var pendingIntent: PendingIntent? = null
override var remoteInputs: Array<RemoteInput>? = null
+ override var revealParams: RevealParams? = null
+ set(value) {
+ field = value
+ if (isBound) {
+ view.setRevealParameters(value)
+ }
+ }
+
+ override val isActive: Boolean get() = view.isActive
+
override fun bind() {
if (isBound) return
isBound = true
+ // TODO: refreshUI method?
+ remoteInput?.let {
+ view.setHintText(it.label)
+ view.setSupportedMimeTypes(it.allowedDataTypes)
+ }
+ view.setRevealParameters(revealParams)
+
view.addOnEditTextFocusChangedListener(onFocusChangeListener)
view.addOnSendRemoteInputListener(onSendRemoteInputListener)
}
@@ -121,6 +172,14 @@ class RemoteInputViewControllerImpl @Inject constructor(
view.removeOnSendRemoteInputListener(onSendRemoteInputListener)
}
+ override fun setEditedSuggestionInfo(info: EditedSuggestionInfo?) {
+ entry.editedSuggestionInfo = info
+ if (info != null) {
+ entry.remoteInputText = info.originalText
+ entry.remoteInputAttachment = null
+ }
+ }
+
override fun updatePendingIntentFromActions(actions: Array<Notification.Action>?): Boolean {
actions ?: return false
val current: Intent = pendingIntent?.intent ?: return false
@@ -132,8 +191,7 @@ class RemoteInputViewControllerImpl @Inject constructor(
pendingIntent = actionIntent
remoteInput = input
remoteInputs = inputs
- view.pendingIntent = actionIntent
- view.setRemoteInput(inputs, input, null /* editedSuggestionInfo */)
+ setEditedSuggestionInfo(null)
return true
}
return false
@@ -148,6 +206,14 @@ class RemoteInputViewControllerImpl @Inject constructor(
onSendListeners.remove(listener)
}
+ override fun close() {
+ view.close()
+ }
+
+ override fun focus() {
+ view.focus()
+ }
+
private val onFocusChangeListener = View.OnFocusChangeListener { _, hasFocus ->
remoteInputQuickSettingsDisabler.setRemoteInputActive(hasFocus)
}
@@ -217,11 +283,12 @@ class RemoteInputViewControllerImpl @Inject constructor(
* @return returns intent with granted URI permissions that should be used immediately
*/
private fun prepareRemoteInput(remoteInput: RemoteInput): Intent =
- if (entry.remoteInputAttachment == null) prepareRemoteInputFromText(remoteInput)
- else prepareRemoteInputFromData(
- remoteInput,
- entry.remoteInputMimeType,
- entry.remoteInputUri)
+ if (entry.remoteInputAttachment == null)
+ prepareRemoteInputFromText(remoteInput)
+ else prepareRemoteInputFromData(
+ remoteInput,
+ entry.remoteInputMimeType,
+ entry.remoteInputUri)
private fun prepareRemoteInputFromText(remoteInput: RemoteInput): Intent {
val results = Bundle()
@@ -232,11 +299,7 @@ class RemoteInputViewControllerImpl @Inject constructor(
view.clearAttachment()
entry.remoteInputUri = null
entry.remoteInputMimeType = null
- if (entry.editedSuggestionInfo == null) {
- RemoteInput.setResultsSource(fillInIntent, RemoteInput.SOURCE_FREE_FORM_INPUT)
- } else {
- RemoteInput.setResultsSource(fillInIntent, RemoteInput.SOURCE_CHOICE)
- }
+ RemoteInput.setResultsSource(fillInIntent, remoteInputResultsSource)
return fillInIntent
}
@@ -266,11 +329,12 @@ class RemoteInputViewControllerImpl @Inject constructor(
entry.remoteInputText = fullText
// mirror prepareRemoteInputFromText for text input
- if (entry.editedSuggestionInfo == null) {
- RemoteInput.setResultsSource(fillInIntent, RemoteInput.SOURCE_FREE_FORM_INPUT)
- } else if (entry.remoteInputAttachment == null) {
- RemoteInput.setResultsSource(fillInIntent, RemoteInput.SOURCE_CHOICE)
- }
+ RemoteInput.setResultsSource(fillInIntent, remoteInputResultsSource)
return fillInIntent
}
+
+ private val remoteInputResultsSource
+ get() = entry.editedSuggestionInfo
+ ?.let { RemoteInput.SOURCE_CHOICE }
+ ?: RemoteInput.SOURCE_FREE_FORM_INPUT
}
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 ddc907666f1c..763f0417cac8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -67,6 +67,7 @@ import com.android.systemui.R;
import com.android.systemui.SystemUISecondaryUserService;
import com.android.systemui.animation.DialogLaunchAnimator;
import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.broadcast.BroadcastSender;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
@@ -122,6 +123,7 @@ public class UserSwitcherController implements Dumpable {
protected final Handler mHandler;
private final ActivityStarter mActivityStarter;
private final BroadcastDispatcher mBroadcastDispatcher;
+ private final BroadcastSender mBroadcastSender;
private final TelephonyListenerManager mTelephonyListenerManager;
private final InteractionJankMonitor mInteractionJankMonitor;
private final LatencyTracker mLatencyTracker;
@@ -165,6 +167,7 @@ public class UserSwitcherController implements Dumpable {
@Main Handler handler,
ActivityStarter activityStarter,
BroadcastDispatcher broadcastDispatcher,
+ BroadcastSender broadcastSender,
UiEventLogger uiEventLogger,
FalsingManager falsingManager,
TelephonyListenerManager telephonyListenerManager,
@@ -179,6 +182,7 @@ public class UserSwitcherController implements Dumpable {
mActivityManager = activityManager;
mUserTracker = userTracker;
mBroadcastDispatcher = broadcastDispatcher;
+ mBroadcastSender = broadcastSender;
mTelephonyListenerManager = telephonyListenerManager;
mUiEventLogger = uiEventLogger;
mFalsingManager = falsingManager;
@@ -982,9 +986,9 @@ public class UserSwitcherController implements Dumpable {
protected static Drawable getIconDrawable(Context context, UserRecord item) {
int iconRes;
if (item.isAddUser) {
- iconRes = R.drawable.ic_account_circle;
- } else if (item.isGuest) {
iconRes = R.drawable.ic_account_circle_filled;
+ } else if (item.isGuest) {
+ iconRes = R.drawable.ic_account_circle;
} else if (item.isAddSupervisedUser) {
iconRes = R.drawable.ic_add_supervised_user;
} else {
@@ -1194,7 +1198,7 @@ public class UserSwitcherController implements Dumpable {
}
// Use broadcast instead of ShadeController, as this dialog may have started in
// another process and normal dagger bindings are not available
- getContext().sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
+ mBroadcastSender.closeSystemDialogs();
getContext().startActivityAsUser(
CreateUserActivity.createIntentForStart(getContext()),
mUserTracker.getUserHandle());
diff --git a/packages/SystemUI/src/com/android/systemui/tv/TvGlobalRootComponent.java b/packages/SystemUI/src/com/android/systemui/tv/TvGlobalRootComponent.java
index 89ab23b50cd8..117cba7401e9 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/TvGlobalRootComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/TvGlobalRootComponent.java
@@ -18,7 +18,6 @@ package com.android.systemui.tv;
import com.android.systemui.dagger.GlobalModule;
import com.android.systemui.dagger.GlobalRootComponent;
-import com.android.systemui.dagger.WMModule;
import javax.inject.Singleton;
@@ -28,11 +27,7 @@ import dagger.Component;
* Root component for Dagger injection.
*/
@Singleton
-@Component(modules = {
- GlobalModule.class,
- TvSysUIComponentModule.class,
- WMModule.class
-})
+@Component(modules = {GlobalModule.class})
public interface TvGlobalRootComponent extends GlobalRootComponent {
/**
* Component Builder interface. This allows to bind Context instance in the component
@@ -42,9 +37,6 @@ public interface TvGlobalRootComponent extends GlobalRootComponent {
TvGlobalRootComponent build();
}
- /**
- * Builder for a WMComponent.
- */
@Override
TvWMComponent.Builder getWMComponentBuilder();
diff --git a/packages/SystemUI/src/com/android/systemui/user/UserSwitcherActivity.kt b/packages/SystemUI/src/com/android/systemui/user/UserSwitcherActivity.kt
index c0d7925cf2bb..9e9b74616d29 100644
--- a/packages/SystemUI/src/com/android/systemui/user/UserSwitcherActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/user/UserSwitcherActivity.kt
@@ -23,7 +23,6 @@ import android.content.IntentFilter
import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.Drawable
import android.graphics.drawable.GradientDrawable
-import android.graphics.drawable.InsetDrawable
import android.graphics.drawable.LayerDrawable
import android.os.Bundle
import android.os.UserManager
@@ -149,8 +148,8 @@ class UserSwitcherActivity @Inject constructor(
}
private fun getDrawable(item: UserRecord): Drawable {
- var drawable = if (item.isCurrent && item.isGuest) {
- getDrawable(R.drawable.ic_avatar_guest_user)
+ var drawable = if (item.isGuest) {
+ getDrawable(R.drawable.ic_account_circle)
} else {
findUserIcon(item)
}
@@ -168,7 +167,7 @@ class UserSwitcherActivity @Inject constructor(
val ld = getDrawable(R.drawable.user_switcher_icon_large).mutate()
as LayerDrawable
if (item == userSwitcherController.getCurrentUserRecord()) {
- (ld.getDrawable(1) as GradientDrawable).apply {
+ (ld.findDrawableByLayerId(R.id.ring) as GradientDrawable).apply {
val stroke = resources
.getDimensionPixelSize(R.dimen.user_switcher_icon_selected_width)
val color = Utils.getColorAttrDefaultColor(
@@ -180,15 +179,7 @@ class UserSwitcherActivity @Inject constructor(
}
}
- ld.addLayer(
- InsetDrawable(
- drawable,
- resources.getDimensionPixelSize(
- R.dimen.user_switcher_icon_large_margin
- )
- )
- )
-
+ ld.setDrawableByLayerId(R.id.user_avatar, drawable)
return ld
}
diff --git a/packages/SystemUI/src/com/android/systemui/util/Utils.java b/packages/SystemUI/src/com/android/systemui/util/Utils.java
index 71d8e3344937..7e3bce589f7e 100644
--- a/packages/SystemUI/src/com/android/systemui/util/Utils.java
+++ b/packages/SystemUI/src/com/android/systemui/util/Utils.java
@@ -199,10 +199,13 @@ public class Utils {
/**
* Gets the {@link R.dimen#split_shade_header_height}.
*
- * Currently, it's the same as {@link com.android.internal.R.dimen#quick_qs_offset_height}.
+ * It should be fine to not ignore cutouts as split shade might not want to react to them:
+ * for split shade header, which is only on bigger screens, either cutout won't be a problem
+ * (it's usually centered and in split shade that's likely empty area) or we probably want to
+ * handle it differently.
*/
public static int getSplitShadeStatusBarHeight(Context context) {
- return SystemBarUtils.getQuickQsOffsetHeight(context);
+ return context.getResources().getDimensionPixelSize(R.dimen.split_shade_header_height);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/util/animation/AnimationUtil.kt b/packages/SystemUI/src/com/android/systemui/util/animation/AnimationUtil.kt
new file mode 100644
index 000000000000..c0538c110426
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/animation/AnimationUtil.kt
@@ -0,0 +1,41 @@
+/*
+ * 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.util.animation
+
+import kotlin.math.roundToLong
+
+/** A generic util class for animations in SysUI. */
+class AnimationUtil {
+ companion object {
+ /**
+ * Returns the number of milliseconds there are in [numFrames] for a 60 fps device.
+ *
+ * Note that this method can be used on any device, not just 60 fps devices. Animation
+ * lengths are typically specified in terms of number of frames for a 60 fps device, and
+ * the value "5 frames" is often more meaningful than "83ms". This method allows us to
+ * write animation code in terms of the more meaningful "5" number.
+ *
+ * @param numFrames must be >= 0.
+ */
+ fun getMsForFrames(numFrames: Int): Long {
+ if (numFrames < 0) {
+ throw IllegalArgumentException("numFrames must be >= 0")
+ }
+ return (numFrames * 1000f / 60f).roundToLong()
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/util/concurrency/SysUIConcurrencyModule.java b/packages/SystemUI/src/com/android/systemui/util/concurrency/SysUIConcurrencyModule.java
index e8a9bc702352..8f61abcca4dc 100644
--- a/packages/SystemUI/src/com/android/systemui/util/concurrency/SysUIConcurrencyModule.java
+++ b/packages/SystemUI/src/com/android/systemui/util/concurrency/SysUIConcurrencyModule.java
@@ -25,10 +25,8 @@ import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.LongRunning;
import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.dagger.qualifiers.UiBackground;
import java.util.concurrent.Executor;
-import java.util.concurrent.Executors;
import dagger.Module;
import dagger.Provides;
@@ -149,18 +147,6 @@ public abstract class SysUIConcurrencyModule {
return new RepeatableExecutorImpl(exec);
}
- /**
- * Provide an Executor specifically for running UI operations on a separate thread.
- *
- * Keep submitted runnables short and to the point, just as with any other UI code.
- */
- @Provides
- @SysUISingleton
- @UiBackground
- public static Executor provideUiBackgroundExecutor() {
- return Executors.newSingleThreadExecutor();
- }
-
/** */
@Provides
@Main
diff --git a/packages/SystemUI/src/com/android/systemui/util/service/PackageObserver.java b/packages/SystemUI/src/com/android/systemui/util/service/PackageObserver.java
index 2ee7b20c1f93..0d47d73153c1 100644
--- a/packages/SystemUI/src/com/android/systemui/util/service/PackageObserver.java
+++ b/packages/SystemUI/src/com/android/systemui/util/service/PackageObserver.java
@@ -24,8 +24,6 @@ import android.content.IntentFilter;
import android.os.PatternMatcher;
import android.util.Log;
-import com.android.systemui.communal.CommunalSource;
-
import com.google.android.collect.Lists;
import java.lang.ref.WeakReference;
@@ -36,8 +34,8 @@ import javax.inject.Inject;
/**
* {@link PackageObserver} allows for monitoring the system for changes relating to a particular
- * package. This can be used by {@link CommunalSource} clients to detect when a related package
- * has changed and reloading is necessary.
+ * package. This can be used by clients to detect when a related package has changed and reloading
+ * is necessary.
*/
public class PackageObserver implements Observer {
private static final String TAG = "PackageObserver";
diff --git a/packages/SystemUI/src/com/android/systemui/util/settings/SettingsProxy.java b/packages/SystemUI/src/com/android/systemui/util/settings/SettingsProxy.java
index 5aaf7f680d5c..1bf5f076ac2f 100644
--- a/packages/SystemUI/src/com/android/systemui/util/settings/SettingsProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/util/settings/SettingsProxy.java
@@ -303,6 +303,7 @@ public interface SettingsProxy {
default boolean putInt(String name, int value) {
return putIntForUser(name, value, getUserId());
}
+
/** See {@link #putInt(String, int)}. */
default boolean putIntForUser(String name, int value, int userHandle) {
return putStringForUser(name, Integer.toString(value), userHandle);
@@ -310,6 +311,76 @@ public interface SettingsProxy {
/**
* Convenience function for retrieving a single secure settings value
+ * as a boolean. Note that internally setting values are always
+ * stored as strings; this function converts the string to a boolean
+ * for you. The default value will be returned if the setting is
+ * not defined or not a boolean.
+ *
+ * @param name The name of the setting to retrieve.
+ * @param def Value to return if the setting is not defined.
+ *
+ * @return The setting's current value, or 'def' if it is not defined
+ * or not a valid boolean.
+ */
+ default boolean getBool(String name, boolean def) {
+ return getBoolForUser(name, def, getUserId());
+ }
+
+ /** See {@link #getBool(String, boolean)}. */
+ default boolean getBoolForUser(String name, boolean def, int userHandle) {
+ return getIntForUser(name, def ? 1 : 0, userHandle) != 0;
+ }
+
+ /**
+ * Convenience function for retrieving a single secure settings value
+ * as a boolean. Note that internally setting values are always
+ * stored as strings; this function converts the string to a boolean
+ * for you.
+ * <p>
+ * This version does not take a default value. If the setting has not
+ * been set, or the string value is not a number,
+ * it throws {@link Settings.SettingNotFoundException}.
+ *
+ * @param name The name of the setting to retrieve.
+ *
+ * @throws Settings.SettingNotFoundException Thrown if a setting by the given
+ * name can't be found or the setting value is not a boolean.
+ *
+ * @return The setting's current value.
+ */
+ default boolean getBool(String name) throws Settings.SettingNotFoundException {
+ return getBoolForUser(name, getUserId());
+ }
+
+ /** See {@link #getBool(String)}. */
+ default boolean getBoolForUser(String name, int userHandle)
+ throws Settings.SettingNotFoundException {
+ return getIntForUser(name, userHandle) != 0;
+ }
+
+ /**
+ * Convenience function for updating a single settings value as a
+ * boolean. This will either create a new entry in the table if the
+ * given name does not exist, or modify the value of the existing row
+ * with that name. Note that internally setting values are always
+ * stored as strings, so this function converts the given value to a
+ * string before storing it.
+ *
+ * @param name The name of the setting to modify.
+ * @param value The new value for the setting.
+ * @return true if the value was set, false on database errors
+ */
+ default boolean putBool(String name, boolean value) {
+ return putBoolForUser(name, value, getUserId());
+ }
+
+ /** See {@link #putBool(String, boolean)}. */
+ default boolean putBoolForUser(String name, boolean value, int userHandle) {
+ return putIntForUser(name, value ? 1 : 0, userHandle);
+ }
+
+ /**
+ * Convenience function for retrieving a single secure settings value
* as a {@code long}. Note that internally setting values are always
* stored as strings; this function converts the string to a {@code long}
* for you. The default value will be returned if the setting is
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
index 69ebfe8012d1..8a961942123b 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
@@ -749,6 +749,8 @@ public class BubblesManager implements Dumpable {
return;
}
+ entry.setFlagBubble(shouldBubble);
+
// Update the state in NotificationManagerService
try {
int flags = Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION;
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
index c3c3f90539fd..60567c49bfdf 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
@@ -51,6 +51,7 @@ import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.shared.tracing.ProtoTraceable;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.UserInfoController;
import com.android.systemui.tracing.ProtoTracer;
import com.android.systemui.tracing.nano.SystemUiTraceProto;
@@ -116,6 +117,7 @@ public final class WMShell extends CoreStartable
private final CommandQueue mCommandQueue;
private final ConfigurationController mConfigurationController;
+ private final KeyguardStateController mKeyguardStateController;
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
private final NavigationModeController mNavigationModeController;
private final ScreenLifecycle mScreenLifecycle;
@@ -129,7 +131,7 @@ public final class WMShell extends CoreStartable
private KeyguardUpdateMonitorCallback mSplitScreenKeyguardCallback;
private KeyguardUpdateMonitorCallback mPipKeyguardCallback;
private KeyguardUpdateMonitorCallback mOneHandedKeyguardCallback;
- private KeyguardUpdateMonitorCallback mCompatUIKeyguardCallback;
+ private KeyguardStateController.Callback mCompatUIKeyguardCallback;
private WakefulnessLifecycle.Observer mWakefulnessObserver;
@Inject
@@ -143,6 +145,7 @@ public final class WMShell extends CoreStartable
Optional<DragAndDrop> dragAndDropOptional,
CommandQueue commandQueue,
ConfigurationController configurationController,
+ KeyguardStateController keyguardStateController,
KeyguardUpdateMonitor keyguardUpdateMonitor,
NavigationModeController navigationModeController,
ScreenLifecycle screenLifecycle,
@@ -154,6 +157,7 @@ public final class WMShell extends CoreStartable
super(context);
mCommandQueue = commandQueue;
mConfigurationController = configurationController;
+ mKeyguardStateController = keyguardStateController;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mNavigationModeController = navigationModeController;
mScreenLifecycle = screenLifecycle;
@@ -362,13 +366,13 @@ public final class WMShell extends CoreStartable
@VisibleForTesting
void initCompatUi(CompatUI sizeCompatUI) {
- mCompatUIKeyguardCallback = new KeyguardUpdateMonitorCallback() {
+ mCompatUIKeyguardCallback = new KeyguardStateController.Callback() {
@Override
- public void onKeyguardOccludedChanged(boolean occluded) {
- sizeCompatUI.onKeyguardOccludedChanged(occluded);
+ public void onKeyguardShowingChanged() {
+ sizeCompatUI.onKeyguardShowingChanged(mKeyguardStateController.isShowing());
}
};
- mKeyguardUpdateMonitor.registerCallback(mCompatUIKeyguardCallback);
+ mKeyguardStateController.addCallback(mCompatUIKeyguardCallback);
}
void initDragAndDrop(DragAndDrop dragAndDrop) {
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/BouncerPanelExpansionCalculatorTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/BouncerPanelExpansionCalculatorTest.kt
new file mode 100644
index 000000000000..6266bf146f5b
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/keyguard/BouncerPanelExpansionCalculatorTest.kt
@@ -0,0 +1,71 @@
+/*
+ * 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.keyguard
+
+import android.test.suitebuilder.annotation.SmallTest
+import android.testing.AndroidTestingRunner
+import com.android.systemui.SysuiTestCase
+import com.google.common.truth.Truth.assertThat
+import org.junit.Assert.assertEquals
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class BouncerPanelExpansionCalculatorTest : SysuiTestCase() {
+ @Test
+ fun testGetHostViewScaledExpansion() {
+ assertThat(BouncerPanelExpansionCalculator.getHostViewScaledExpansion(1f))
+ .isEqualTo(1f)
+ assertThat(BouncerPanelExpansionCalculator.getHostViewScaledExpansion(0.9f))
+ .isEqualTo(1f)
+ assertThat(BouncerPanelExpansionCalculator.getHostViewScaledExpansion(0.59f))
+ .isEqualTo(0f)
+ assertThat(BouncerPanelExpansionCalculator.getHostViewScaledExpansion(0f))
+ .isEqualTo(0f)
+ assertEquals(BouncerPanelExpansionCalculator
+ .getHostViewScaledExpansion(0.8f), 2f / 3f, 0.01f)
+ }
+
+ @Test
+ fun testGetBackScrimScaledExpansion() {
+ assertThat(BouncerPanelExpansionCalculator.getBackScrimScaledExpansion(1f))
+ .isEqualTo(1f)
+ assertEquals(BouncerPanelExpansionCalculator
+ .getBackScrimScaledExpansion(0.95f), 1f / 2f, 0.01f)
+ assertThat(BouncerPanelExpansionCalculator.getBackScrimScaledExpansion(0.9f))
+ .isEqualTo(0f)
+ assertThat(BouncerPanelExpansionCalculator.getBackScrimScaledExpansion(0.5f))
+ .isEqualTo(0f)
+ assertThat(BouncerPanelExpansionCalculator.getBackScrimScaledExpansion(0f))
+ .isEqualTo(0f)
+ }
+
+ @Test
+ fun testGetKeyguardClockScaledExpansion() {
+ assertThat(BouncerPanelExpansionCalculator.getKeyguardClockScaledExpansion(1f))
+ .isEqualTo(1f)
+ assertEquals(BouncerPanelExpansionCalculator
+ .getKeyguardClockScaledExpansion(0.8f), 1f / 3f, 0.01f)
+ assertThat(BouncerPanelExpansionCalculator.getKeyguardClockScaledExpansion(0.7f))
+ .isEqualTo(0f)
+ assertThat(BouncerPanelExpansionCalculator.getBackScrimScaledExpansion(0.5f))
+ .isEqualTo(0f)
+ assertThat(BouncerPanelExpansionCalculator.getBackScrimScaledExpansion(0f))
+ .isEqualTo(0f)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaControllerTest.java
index a7197cca530c..1518ea160016 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaControllerTest.java
@@ -84,4 +84,10 @@ public class KeyguardMessageAreaControllerTest extends SysuiTestCase {
mMessageAreaController.setMessage("");
verify(mKeyguardMessageArea).setMessage("");
}
+
+ @Test
+ public void testSetBouncerVisible() {
+ mMessageAreaController.setBouncerShowing(true);
+ verify(mKeyguardMessageArea).setBouncerShowing(true);
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaTest.java
index 31fb25a7a89c..013c298d69d7 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaTest.java
@@ -40,7 +40,7 @@ public class KeyguardMessageAreaTest extends SysuiTestCase {
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
mKeyguardMessageArea = new KeyguardMessageArea(mContext, null);
- mKeyguardMessageArea.setBouncerVisible(true);
+ mKeyguardMessageArea.setBouncerShowing(true);
}
@Test
@@ -53,7 +53,7 @@ public class KeyguardMessageAreaTest extends SysuiTestCase {
@Test
public void testHiddenWhenBouncerHidden() {
- mKeyguardMessageArea.setBouncerVisible(false);
+ mKeyguardMessageArea.setBouncerShowing(false);
mKeyguardMessageArea.setVisibility(View.INVISIBLE);
mKeyguardMessageArea.setMessage("oobleck");
assertThat(mKeyguardMessageArea.getVisibility()).isEqualTo(View.INVISIBLE);
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java
index 217092e6e4e5..1753157c631d 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java
@@ -22,7 +22,6 @@ import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.communal.CommunalStateController;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.statusbar.phone.ScreenOffAnimationController;
@@ -50,8 +49,6 @@ public class KeyguardStatusViewControllerTest extends SysuiTestCase {
@Mock
private KeyguardStateController mKeyguardStateController;
@Mock
- private CommunalStateController mCommunalStateController;
- @Mock
private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@Mock
ConfigurationController mConfigurationController;
@@ -76,7 +73,6 @@ public class KeyguardStatusViewControllerTest extends SysuiTestCase {
mKeyguardClockSwitchController,
mKeyguardStateController,
mKeyguardUpdateMonitor,
- mCommunalStateController,
mConfigurationController,
mDozeParameters,
mKeyguardUnlockAnimationController,
@@ -116,4 +112,13 @@ public class KeyguardStatusViewControllerTest extends SysuiTestCase {
mKeyguardUpdateMonitorCallbackCaptor.getValue().onUserSwitchComplete(0);
verify(mKeyguardClockSwitchController).refreshFormat();
}
+
+ @Test
+ public void setTranslationYExcludingMedia_forwardsCallToView() {
+ float translationY = 123f;
+
+ mController.setTranslationYExcludingMedia(translationY);
+
+ verify(mKeyguardStatusView).setChildrenTranslationYExcludingMediaView(translationY);
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.kt
new file mode 100644
index 000000000000..ce44f4d82d69
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.kt
@@ -0,0 +1,55 @@
+package com.android.keyguard
+
+import android.test.suitebuilder.annotation.SmallTest
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper.RunWithLooper
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.util.children
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@RunWithLooper(setAsMainLooper = true)
+class KeyguardStatusViewTest : SysuiTestCase() {
+
+ private lateinit var keyguardStatusView: KeyguardStatusView
+ private val mediaView: View
+ get() = keyguardStatusView.findViewById(R.id.status_view_media_container)
+ private val statusViewContainer: ViewGroup
+ get() = keyguardStatusView.findViewById(R.id.status_view_container)
+ private val childrenExcludingMedia
+ get() = statusViewContainer.children.filter { it != mediaView }
+
+ @Before
+ fun setUp() {
+ keyguardStatusView = LayoutInflater.from(context)
+ .inflate(R.layout.keyguard_status_view, /* root= */ null) as KeyguardStatusView
+ }
+
+ @Test
+ fun setChildrenTranslationYExcludingMediaView_mediaViewIsNotTranslated() {
+ val translationY = 1234f
+
+ keyguardStatusView.setChildrenTranslationYExcludingMediaView(translationY)
+
+ assertThat(mediaView.translationY).isEqualTo(0)
+ }
+
+ @Test
+ fun setChildrenTranslationYExcludingMediaView_childrenAreTranslated() {
+ val translationY = 1234f
+
+ keyguardStatusView.setChildrenTranslationYExcludingMediaView(translationY)
+
+ childrenExcludingMedia.forEach {
+ assertThat(it.translationY).isEqualTo(translationY)
+ }
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardVisibilityHelperTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardVisibilityHelperTest.java
deleted file mode 100644
index a93a15df5986..000000000000
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardVisibilityHelperTest.java
+++ /dev/null
@@ -1,92 +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.keyguard;
-
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.test.suitebuilder.annotation.SmallTest;
-import android.view.View;
-import android.view.ViewPropertyAnimator;
-
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.communal.CommunalStateController;
-import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.statusbar.phone.ScreenOffAnimationController;
-import com.android.systemui.statusbar.policy.KeyguardStateController;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-@SmallTest
-public class KeyguardVisibilityHelperTest extends SysuiTestCase {
- @Mock
- private CommunalStateController mCommunalStateController;
- @Mock
- private KeyguardStateController mKeyguardStateController;
- @Mock
- com.android.systemui.statusbar.phone.DozeParameters mDozeParameters;
- @Mock
- ScreenOffAnimationController mScreenOffAnimationController;
- @Mock
- ViewPropertyAnimator mViewPropertyAnimator;
- @Mock
- View mTargetView;
-
- private KeyguardVisibilityHelper mKeyguardVisibilityHelper;
- @Before
- public void setup() {
- MockitoAnnotations.initMocks(this);
- when(mTargetView.animate()).thenReturn(mViewPropertyAnimator);
- mKeyguardVisibilityHelper = new KeyguardVisibilityHelper(mTargetView,
- mCommunalStateController, mKeyguardStateController, mDozeParameters,
- mScreenOffAnimationController, false, false);
- }
-
- @Test
- public void testHideOnCommunal() {
- // Verify view is hidden when communal is visible.
- when(mCommunalStateController.getCommunalViewShowing()).thenReturn(true);
- mKeyguardVisibilityHelper.setViewVisibility(StatusBarState.KEYGUARD, false,
- false, StatusBarState.KEYGUARD);
- verify(mTargetView).setVisibility(View.GONE);
- verify(mTargetView).setAlpha(1.0f);
-
- // Verify view is shown when communal is not visible.
- when(mCommunalStateController.getCommunalViewShowing()).thenReturn(false);
- mKeyguardVisibilityHelper.setViewVisibility(StatusBarState.KEYGUARD, false,
- false, StatusBarState.KEYGUARD);
- verify(mTargetView).setVisibility(View.VISIBLE);
- }
-
- @Test
- public void testVisibleOnCommunal() {
- when(mCommunalStateController.getCommunalViewShowing()).thenReturn(true);
- when(mKeyguardStateController.isOccluded()).thenReturn(false);
-
- // Verify that helpers constructed with visibility on communal are not hidden when communal
- // is present.
- mKeyguardVisibilityHelper = new KeyguardVisibilityHelper(mTargetView,
- mCommunalStateController, mKeyguardStateController, mDozeParameters,
- mScreenOffAnimationController, false, true);
- mKeyguardVisibilityHelper.setViewVisibility(StatusBarState.KEYGUARD, false,
- false, StatusBarState.KEYGUARD);
- verify(mTargetView).setVisibility(View.VISIBLE);
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
index 70f325158624..ec92adb0f48c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
@@ -48,7 +48,6 @@ import android.content.res.Configuration;
import android.content.res.TypedArray;
import android.graphics.Insets;
import android.graphics.PixelFormat;
-import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.drawable.VectorDrawable;
import android.hardware.display.DisplayManager;
@@ -58,6 +57,7 @@ import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
import android.util.RotationUtils;
+import android.util.Size;
import android.view.Display;
import android.view.DisplayCutout;
import android.view.View;
@@ -73,6 +73,7 @@ import com.android.systemui.decor.DecorProvider;
import com.android.systemui.decor.OverlayWindow;
import com.android.systemui.decor.PrivacyDotCornerDecorProviderImpl;
import com.android.systemui.decor.PrivacyDotDecorProviderFactory;
+import com.android.systemui.decor.RoundedCornerResDelegate;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.events.PrivacyDotViewController;
import com.android.systemui.tuner.TunerService;
@@ -95,8 +96,6 @@ import java.util.ArrayList;
@SmallTest
public class ScreenDecorationsTest extends SysuiTestCase {
- private static final Rect ZERO_RECT = new Rect();
-
private ScreenDecorations mScreenDecorations;
private WindowManager mWindowManager;
private DisplayManager mDisplayManager;
@@ -424,7 +423,7 @@ public class ScreenDecorationsTest extends SysuiTestCase {
@Test
public void testRoundingRadius_NoCutout() {
- final Point testRadiusPoint = new Point(1, 1);
+ final Size testRadiusPoint = new Size(1, 1);
setupResources(1 /* radius */, 1 /* radiusTop */, 1 /* radiusBottom */,
0 /* roundedPadding */, false /* multipleRadius */,
false /* fillCutout */, true /* privacyDot */);
@@ -433,9 +432,9 @@ public class ScreenDecorationsTest extends SysuiTestCase {
mScreenDecorations.start();
// Size of corner view should same as rounded_corner_radius{_top|_bottom}
- assertThat(mScreenDecorations.mRoundedDefault).isEqualTo(testRadiusPoint);
- assertThat(mScreenDecorations.mRoundedDefaultTop).isEqualTo(testRadiusPoint);
- assertThat(mScreenDecorations.mRoundedDefaultBottom).isEqualTo(testRadiusPoint);
+ final RoundedCornerResDelegate resDelegate = mScreenDecorations.mRoundedCornerResDelegate;
+ assertThat(resDelegate.getTopRoundedSize()).isEqualTo(testRadiusPoint);
+ assertThat(resDelegate.getBottomRoundedSize()).isEqualTo(testRadiusPoint);
}
@Test
@@ -454,17 +453,17 @@ public class ScreenDecorationsTest extends SysuiTestCase {
View rightRoundedCorner = mScreenDecorations.mOverlays[BOUNDS_POSITION_TOP].getRootView()
.findViewById(R.id.right);
verify(mScreenDecorations, atLeastOnce())
- .setSize(leftRoundedCorner, new Point(testTopRadius, testTopRadius));
+ .setSize(leftRoundedCorner, new Size(testTopRadius, testTopRadius));
verify(mScreenDecorations, atLeastOnce())
- .setSize(rightRoundedCorner, new Point(testTopRadius, testTopRadius));
+ .setSize(rightRoundedCorner, new Size(testTopRadius, testTopRadius));
leftRoundedCorner = mScreenDecorations.mOverlays[BOUNDS_POSITION_BOTTOM].getRootView()
.findViewById(R.id.left);
rightRoundedCorner = mScreenDecorations.mOverlays[BOUNDS_POSITION_BOTTOM].getRootView()
.findViewById(R.id.right);
verify(mScreenDecorations, atLeastOnce())
- .setSize(leftRoundedCorner, new Point(testBottomRadius, testBottomRadius));
+ .setSize(leftRoundedCorner, new Size(testBottomRadius, testBottomRadius));
verify(mScreenDecorations, atLeastOnce())
- .setSize(rightRoundedCorner, new Point(testBottomRadius, testBottomRadius));
+ .setSize(rightRoundedCorner, new Size(testBottomRadius, testBottomRadius));
}
@Test
@@ -480,8 +479,8 @@ public class ScreenDecorationsTest extends SysuiTestCase {
.when(mScreenDecorations).getCutout();
mScreenDecorations.start();
- final Point topRadius = new Point(testTopRadius, testTopRadius);
- final Point bottomRadius = new Point(testBottomRadius, testBottomRadius);
+ final Size topRadius = new Size(testTopRadius, testTopRadius);
+ final Size bottomRadius = new Size(testBottomRadius, testBottomRadius);
View leftRoundedCorner = mScreenDecorations.mOverlays[BOUNDS_POSITION_LEFT].getRootView()
.findViewById(R.id.left);
boolean isTop = mScreenDecorations.isTopRoundedCorner(BOUNDS_POSITION_LEFT, R.id.left);
@@ -510,7 +509,7 @@ public class ScreenDecorationsTest extends SysuiTestCase {
@Test
public void testRoundingMultipleRadius_NoCutout_NoPrivacyDot() {
final VectorDrawable d = (VectorDrawable) mContext.getDrawable(R.drawable.rounded);
- final Point multipleRadiusSize = new Point(d.getIntrinsicWidth(), d.getIntrinsicHeight());
+ final Size multipleRadiusSize = new Size(d.getIntrinsicWidth(), d.getIntrinsicHeight());
setupResources(9999 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
9999 /* roundedPadding */, true /* multipleRadius */,
false /* fillCutout */, false /* privacyDot */);
@@ -536,15 +535,15 @@ public class ScreenDecorationsTest extends SysuiTestCase {
verify(mDotViewController, never()).initialize(any(), any(), any(), any());
// Size of corner view should exactly match max(width, height) of R.drawable.rounded
- assertThat(mScreenDecorations.mRoundedDefault).isEqualTo(multipleRadiusSize);
- assertThat(mScreenDecorations.mRoundedDefaultTop).isEqualTo(multipleRadiusSize);
- assertThat(mScreenDecorations.mRoundedDefaultBottom).isEqualTo(multipleRadiusSize);
+ final RoundedCornerResDelegate resDelegate = mScreenDecorations.mRoundedCornerResDelegate;
+ assertThat(resDelegate.getTopRoundedSize()).isEqualTo(multipleRadiusSize);
+ assertThat(resDelegate.getBottomRoundedSize()).isEqualTo(multipleRadiusSize);
}
@Test
public void testRoundingMultipleRadius_NoCutout_PrivacyDot() {
final VectorDrawable d = (VectorDrawable) mContext.getDrawable(R.drawable.rounded);
- final Point multipleRadiusSize = new Point(d.getIntrinsicWidth(), d.getIntrinsicHeight());
+ final Size multipleRadiusSize = new Size(d.getIntrinsicWidth(), d.getIntrinsicHeight());
setupResources(9999 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
9999 /* roundedPadding */, true /* multipleRadius */,
false /* fillCutout */, true /* privacyDot */);
@@ -571,9 +570,9 @@ public class ScreenDecorationsTest extends SysuiTestCase {
isA(View.class), isA(View.class), isA(View.class), isA(View.class));
// Size of corner view should exactly match max(width, height) of R.drawable.rounded
- assertThat(mScreenDecorations.mRoundedDefault).isEqualTo(multipleRadiusSize);
- assertThat(mScreenDecorations.mRoundedDefaultTop).isEqualTo(multipleRadiusSize);
- assertThat(mScreenDecorations.mRoundedDefaultBottom).isEqualTo(multipleRadiusSize);
+ final RoundedCornerResDelegate resDelegate = mScreenDecorations.mRoundedCornerResDelegate;
+ assertThat(resDelegate.getTopRoundedSize()).isEqualTo(multipleRadiusSize);
+ assertThat(resDelegate.getBottomRoundedSize()).isEqualTo(multipleRadiusSize);
}
@Test
@@ -944,12 +943,15 @@ public class ScreenDecorationsTest extends SysuiTestCase {
false /* fillCutout */, true /* privacyDot */);
mScreenDecorations.start();
- assertEquals(mScreenDecorations.mRoundedDefault, new Point(20, 20));
+ final RoundedCornerResDelegate resDelegate = mScreenDecorations.mRoundedCornerResDelegate;
+ assertEquals(resDelegate.getTopRoundedSize(), new Size(20, 20));
+ assertEquals(resDelegate.getBottomRoundedSize(), new Size(20, 20));
when(mContext.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.rounded_corner_radius)).thenReturn(5);
mScreenDecorations.onConfigurationChanged(null);
- assertEquals(mScreenDecorations.mRoundedDefault, new Point(5, 5));
+ assertEquals(resDelegate.getTopRoundedSize(), new Size(5, 5));
+ assertEquals(resDelegate.getBottomRoundedSize(), new Size(5, 5));
}
@Test
@@ -959,9 +961,9 @@ public class ScreenDecorationsTest extends SysuiTestCase {
false /* fillCutout */, true /* privacyDot */);
mScreenDecorations.start();
- assertEquals(new Point(0, 0), mScreenDecorations.mRoundedDefault);
- assertEquals(new Point(10, 10), mScreenDecorations.mRoundedDefaultTop);
- assertEquals(new Point(0, 0), mScreenDecorations.mRoundedDefaultBottom);
+ final RoundedCornerResDelegate resDelegate = mScreenDecorations.mRoundedCornerResDelegate;
+ assertEquals(new Size(10, 10), resDelegate.getTopRoundedSize());
+ assertEquals(new Size(0, 0), resDelegate.getBottomRoundedSize());
}
@Test
@@ -971,9 +973,9 @@ public class ScreenDecorationsTest extends SysuiTestCase {
false /* fillCutout */, true /* privacyDot */);
mScreenDecorations.start();
- assertEquals(new Point(0, 0), mScreenDecorations.mRoundedDefault);
- assertEquals(new Point(0, 0), mScreenDecorations.mRoundedDefaultTop);
- assertEquals(new Point(20, 20), mScreenDecorations.mRoundedDefaultBottom);
+ final RoundedCornerResDelegate resDelegate = mScreenDecorations.mRoundedCornerResDelegate;
+ assertEquals(new Size(0, 0), resDelegate.getTopRoundedSize());
+ assertEquals(new Size(20, 20), resDelegate.getBottomRoundedSize());
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
index 7a0db1fd975c..8c7927782d2d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
@@ -208,6 +208,11 @@ public abstract class SysuiTestCase {
}
}
+ /** Delegates to {@link android.testing.TestableResources#addOverride(int, Object)}. */
+ protected void overrideResource(int resourceId, Object value) {
+ mContext.getOrCreateTestableResources().addOverride(resourceId, value);
+ }
+
public static final class EmptyRunnable implements Runnable {
public void run() {
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
index a49c4d76445b..ee150ca9db1b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
@@ -80,6 +80,7 @@ import com.android.systemui.utils.os.FakeHandler;
import org.junit.After;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Answers;
@@ -172,11 +173,10 @@ public class WindowMagnificationControllerTest extends SysuiTestCase {
@Test
public void enableWindowMagnification_notifySourceBoundsChanged() {
- mInstrumentation.runOnMainSync(() -> {
- mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN,
- Float.NaN, /* magnificationFrameOffsetRatioX= */ 0,
- /* magnificationFrameOffsetRatioY= */ 0, null);
- });
+ mInstrumentation.runOnMainSync(
+ () -> mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN,
+ Float.NaN, /* magnificationFrameOffsetRatioX= */ 0,
+ /* magnificationFrameOffsetRatioY= */ 0, null));
// Waits for the surface created
verify(mWindowMagnifierCallback, timeout(LAYOUT_CHANGE_TIMEOUT_MS)).onSourceBoundsChanged(
@@ -184,6 +184,16 @@ public class WindowMagnificationControllerTest extends SysuiTestCase {
}
@Test
+ public void enableWindowMagnification_disabled_notifySourceBoundsChanged() {
+ enableWindowMagnification_notifySourceBoundsChanged();
+ mInstrumentation.runOnMainSync(
+ () -> mWindowMagnificationController.deleteWindowMagnification(null));
+ Mockito.reset(mWindowMagnifierCallback);
+
+ enableWindowMagnification_notifySourceBoundsChanged();
+ }
+
+ @Test
public void enableWindowMagnification_withAnimation_schedulesFrame() {
mInstrumentation.runOnMainSync(() -> {
mWindowMagnificationController.enableWindowMagnification(2.0f, 10,
@@ -293,6 +303,7 @@ public class WindowMagnificationControllerTest extends SysuiTestCase {
verify(mSfVsyncFrameProvider, atLeastOnce()).postFrameCallback(any());
}
+ @Ignore("b/224717753")
@Test
public void moveWindowMagnifierToPositionWithAnimation_expectedValuesAndInvokeCallback()
throws InterruptedException {
@@ -327,6 +338,7 @@ public class WindowMagnificationControllerTest extends SysuiTestCase {
assertEquals(mWindowMagnificationController.getCenterY(), targetCenterY, 0);
}
+ @Ignore("b/224717753")
@Test
public void moveWindowMagnifierToPositionMultipleTimes_expectedValuesAndInvokeCallback()
throws InterruptedException {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/ViewBoundAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/ViewBoundAnimatorTest.kt
new file mode 100644
index 000000000000..214fd4d28398
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/animation/ViewBoundAnimatorTest.kt
@@ -0,0 +1,277 @@
+package com.android.systemui.animation
+
+import android.animation.ObjectAnimator
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import android.view.View
+import android.view.ViewGroup
+import android.widget.LinearLayout
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import junit.framework.Assert.assertEquals
+import junit.framework.Assert.assertNotNull
+import junit.framework.Assert.assertNull
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper
+class ViewBoundAnimatorTest : SysuiTestCase() {
+ companion object {
+ private const val TEST_DURATION = 1000L
+ private val TEST_INTERPOLATOR = Interpolators.LINEAR
+ }
+
+ private lateinit var rootView: LinearLayout
+
+ @Before
+ fun setUp() {
+ rootView = LinearLayout(mContext)
+ }
+
+ @After
+ fun tearDown() {
+ ViewBoundAnimator.stopAnimating(rootView)
+ }
+
+ @Test
+ fun respectsAnimationParameters() {
+ rootView.layout(10 /* l */, 10 /* t */, 50 /* r */, 50 /* b */)
+
+ ViewBoundAnimator.animate(
+ rootView, interpolator = TEST_INTERPOLATOR, duration = TEST_DURATION
+ )
+ rootView.layout(0 /* l */, 0 /* t */, 100 /* r */, 100 /* b */)
+
+ assertNotNull(rootView.getTag(R.id.tag_animator))
+ val animator = rootView.getTag(R.id.tag_animator) as ObjectAnimator
+ assertEquals(animator.interpolator, TEST_INTERPOLATOR)
+ assertEquals(animator.duration, TEST_DURATION)
+ }
+
+ @Test
+ fun animatesFromStartToEnd() {
+ rootView.layout(10 /* l */, 10 /* t */, 50 /* r */, 50 /* b */)
+
+ ViewBoundAnimator.animate(rootView)
+ // Change all bounds.
+ rootView.layout(0 /* l */, 15 /* t */, 70 /* r */, 80 /* b */)
+
+ 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)
+ endAnimation(rootView)
+ assertNull(rootView.getTag(R.id.tag_animator))
+ // The end values should be those of the latest layout.
+ checkBounds(rootView, l = 0, t = 15, r = 70, b = 80)
+ }
+
+ @Test
+ fun animatesSuccessiveLayoutChanges() {
+ rootView.layout(10 /* l */, 10 /* t */, 50 /* r */, 50 /* b */)
+
+ ViewBoundAnimator.animate(rootView)
+ // Change all bounds.
+ rootView.layout(0 /* l */, 15 /* t */, 70 /* r */, 80 /* b */)
+
+ assertNotNull(rootView.getTag(R.id.tag_animator))
+ endAnimation(rootView)
+ assertNull(rootView.getTag(R.id.tag_animator))
+ checkBounds(rootView, l = 0, t = 15, r = 70, b = 80)
+
+ // Change only top and right.
+ rootView.layout(0 /* l */, 20 /* t */, 60 /* r */, 80 /* b */)
+
+ assertNotNull(rootView.getTag(R.id.tag_animator))
+ endAnimation(rootView)
+ assertNull(rootView.getTag(R.id.tag_animator))
+ checkBounds(rootView, l = 0, t = 20, r = 60, b = 80)
+
+ // Change all bounds again.
+ rootView.layout(5 /* l */, 25 /* t */, 55 /* r */, 95 /* b */)
+
+ assertNotNull(rootView.getTag(R.id.tag_animator))
+ endAnimation(rootView)
+ assertNull(rootView.getTag(R.id.tag_animator))
+ checkBounds(rootView, l = 5, t = 25, r = 55, b = 95)
+ }
+
+ @Test
+ fun animatesFromPreviousAnimationProgress() {
+ rootView.layout(10 /* l */, 10 /* t */, 50 /* r */, 50 /* b */)
+
+ ViewBoundAnimator.animateNextUpdate(rootView, interpolator = TEST_INTERPOLATOR)
+ // Change all bounds.
+ rootView.layout(0 /* l */, 20 /* t */, 70 /* r */, 80 /* b */)
+
+ assertNotNull(rootView.getTag(R.id.tag_animator))
+ advanceAnimation(rootView, fraction = 0.5f)
+ checkBounds(rootView, l = 5, t = 15, r = 60, b = 65)
+
+ // Change all bounds again.
+ rootView.layout(25 /* l */, 25 /* t */, 55 /* r */, 60 /* b */)
+
+ assertNotNull(rootView.getTag(R.id.tag_animator))
+ checkBounds(rootView, l = 5, t = 15, r = 60, b = 65)
+ endAnimation(rootView)
+ assertNull(rootView.getTag(R.id.tag_animator))
+ checkBounds(rootView, l = 25, t = 25, r = 55, b = 60)
+ }
+
+ @Test
+ fun animatesRootAndChildren() {
+ val firstChild = View(mContext)
+ rootView.addView(firstChild)
+ val secondChild = View(mContext)
+ rootView.addView(secondChild)
+ 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 */)
+
+ ViewBoundAnimator.animate(rootView)
+ // Change all bounds.
+ 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 */)
+
+ assertNotNull(rootView.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)
+ endAnimation(rootView)
+ assertNull(rootView.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)
+ }
+
+ @Test
+ fun doesNotAnimateInvisibleViews() {
+ rootView.layout(10 /* l */, 10 /* t */, 50 /* r */, 50 /* b */)
+
+ ViewBoundAnimator.animate(rootView)
+ // GONE.
+ rootView.visibility = View.GONE
+ rootView.layout(0 /* l */, 15 /* t */, 55 /* r */, 80 /* b */)
+
+ 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 */)
+ }
+
+ @Test
+ fun doesNotAnimateUnchangingBounds() {
+ rootView.layout(10 /* l */, 10 /* t */, 50 /* r */, 50 /* b */)
+
+ ViewBoundAnimator.animate(rootView)
+ // No bounds are changed.
+ rootView.layout(10 /* l */, 10 /* t */, 50 /* r */, 50 /* b */)
+
+ assertNull(rootView.getTag(R.id.tag_animator))
+ checkBounds(rootView, l = 10, t = 10, r = 50, b = 50)
+
+ // Change only right and bottom.
+ rootView.layout(10 /* l */, 10 /* t */, 70 /* r */, 80 /* b */)
+
+ assertNotNull(rootView.getTag(R.id.tag_animator))
+ endAnimation(rootView)
+ assertNull(rootView.getTag(R.id.tag_animator))
+ checkBounds(rootView, l = 10, t = 10, r = 70, b = 80)
+ }
+
+ @Test
+ fun doesNotAnimateExcludedBounds() {
+ rootView.layout(10 /* l */, 10 /* t */, 50 /* r */, 50 /* b */)
+
+ ViewBoundAnimator.animate(
+ rootView,
+ bounds = setOf(ViewBoundAnimator.Bound.LEFT, ViewBoundAnimator.Bound.TOP),
+ interpolator = TEST_INTERPOLATOR
+ )
+ // Change all bounds.
+ rootView.layout(0 /* l */, 20 /* t */, 70 /* r */, 80 /* b */)
+
+ assertNotNull(rootView.getTag(R.id.tag_animator))
+ advanceAnimation(rootView, 0.5f)
+ checkBounds(rootView, l = 5, t = 15, r = 70, b = 80)
+ endAnimation(rootView)
+ assertNull(rootView.getTag(R.id.tag_animator))
+ checkBounds(rootView, l = 0, t = 20, r = 70, b = 80)
+ }
+
+ @Test
+ fun stopsAnimatingAfterSingleLayout() {
+ rootView.layout(10 /* l */, 10 /* t */, 50 /* r */, 50 /* b */)
+
+ ViewBoundAnimator.animateNextUpdate(rootView)
+ // Change all bounds.
+ rootView.layout(0 /* l */, 15 /* t */, 70 /* r */, 80 /* b */)
+
+ assertNotNull(rootView.getTag(R.id.tag_animator))
+ endAnimation(rootView)
+ assertNull(rootView.getTag(R.id.tag_animator))
+ checkBounds(rootView, l = 0, t = 15, r = 70, b = 80)
+
+ // Change all bounds again.
+ rootView.layout(10 /* l */, 10 /* t */, 50/* r */, 50 /* b */)
+
+ assertNull(rootView.getTag(R.id.tag_animator))
+ checkBounds(rootView, l = 10, t = 10, r = 50, b = 50)
+ }
+
+ @Test
+ fun stopsAnimatingWhenInstructed() {
+ rootView.layout(10 /* l */, 10 /* t */, 50 /* r */, 50 /* b */)
+
+ ViewBoundAnimator.animate(rootView)
+ // Change all bounds.
+ rootView.layout(0 /* l */, 15 /* t */, 70 /* r */, 80 /* b */)
+
+ assertNotNull(rootView.getTag(R.id.tag_animator))
+ endAnimation(rootView)
+ assertNull(rootView.getTag(R.id.tag_animator))
+ checkBounds(rootView, l = 0, t = 15, r = 70, b = 80)
+
+ ViewBoundAnimator.stopAnimating(rootView)
+ // Change all bounds again.
+ rootView.layout(10 /* l */, 10 /* t */, 50/* r */, 50 /* b */)
+
+ assertNull(rootView.getTag(R.id.tag_animator))
+ checkBounds(rootView, l = 10, t = 10, r = 50, b = 50)
+ }
+
+ private fun checkBounds(v: View, l: Int, t: Int, r: Int, b: Int) {
+ assertEquals(l, v.left)
+ assertEquals(t, v.top)
+ assertEquals(r, v.right)
+ assertEquals(b, v.bottom)
+ }
+
+ private fun advanceAnimation(rootView: View, fraction: Float) {
+ (rootView.getTag(R.id.tag_animator) as? ObjectAnimator)?.setCurrentFraction(fraction)
+
+ if (rootView is ViewGroup) {
+ for (i in 0 until rootView.childCount) {
+ advanceAnimation(rootView.getChildAt(i), fraction)
+ }
+ }
+ }
+
+ private fun endAnimation(rootView: View) {
+ (rootView.getTag(R.id.tag_animator) as? ObjectAnimator)?.end()
+
+ if (rootView is ViewGroup) {
+ for (i in 0 until rootView.childCount) {
+ endAnimation(rootView.getChildAt(i))
+ }
+ }
+ }
+}
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 ec2c1de49b4c..a95da6295350 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt
@@ -114,12 +114,13 @@ class AuthRippleControllerTest : SysuiTestCase() {
}
@Test
- fun testFingerprintTrigger_Ripple() {
+ fun testFingerprintTrigger_KeyguardVisible_Ripple() {
// GIVEN fp exists, keyguard is visible, user doesn't need strong auth
val fpsLocation = PointF(5f, 5f)
`when`(authController.fingerprintSensorLocation).thenReturn(fpsLocation)
controller.onViewAttached()
`when`(keyguardUpdateMonitor.isKeyguardVisible).thenReturn(true)
+ `when`(keyguardUpdateMonitor.isDreaming).thenReturn(false)
`when`(keyguardUpdateMonitor.userNeedsStrongAuth()).thenReturn(false)
// WHEN fingerprint authenticated
@@ -136,7 +137,30 @@ class AuthRippleControllerTest : SysuiTestCase() {
}
@Test
- fun testFingerprintTrigger_KeyguardNotVisible_NoRipple() {
+ fun testFingerprintTrigger_Dreaming_Ripple() {
+ // GIVEN fp exists, keyguard is visible, user doesn't need strong auth
+ val fpsLocation = PointF(5f, 5f)
+ `when`(authController.fingerprintSensorLocation).thenReturn(fpsLocation)
+ controller.onViewAttached()
+ `when`(keyguardUpdateMonitor.isKeyguardVisible).thenReturn(false)
+ `when`(keyguardUpdateMonitor.isDreaming).thenReturn(true)
+ `when`(keyguardUpdateMonitor.userNeedsStrongAuth()).thenReturn(false)
+
+ // WHEN fingerprint authenticated
+ val captor = ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback::class.java)
+ verify(keyguardUpdateMonitor).registerCallback(captor.capture())
+ captor.value.onBiometricAuthenticated(
+ 0 /* userId */,
+ BiometricSourceType.FINGERPRINT /* type */,
+ false /* isStrongBiometric */)
+
+ // THEN update sensor location and show ripple
+ verify(rippleView).setFingerprintSensorLocation(fpsLocation, -1f)
+ verify(rippleView).startUnlockedRipple(any())
+ }
+
+ @Test
+ fun testFingerprintTrigger_KeyguardNotVisible_NotDreaming_NoRipple() {
// GIVEN fp exists & user doesn't need strong auth
val fpsLocation = PointF(5f, 5f)
`when`(authController.udfpsSensorLocation).thenReturn(fpsLocation)
@@ -145,6 +169,7 @@ class AuthRippleControllerTest : SysuiTestCase() {
// WHEN keyguard is NOT visible & fingerprint authenticated
`when`(keyguardUpdateMonitor.isKeyguardVisible).thenReturn(false)
+ `when`(keyguardUpdateMonitor.isDreaming).thenReturn(false)
val captor = ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback::class.java)
verify(keyguardUpdateMonitor).registerCallback(captor.capture())
captor.value.onBiometricAuthenticated(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt
index ef82c3ec3322..fd49766dafef 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt
@@ -61,6 +61,8 @@ import org.mockito.Mockito.verify
import org.mockito.junit.MockitoJUnit
import org.mockito.Mockito.`when` as whenever
+private const val REQUEST_ID = 2L
+
@SmallTest
@RunWith(AndroidTestingRunner::class)
@RunWithLooper(setAsMainLooper = true)
@@ -119,7 +121,7 @@ class UdfpsControllerOverlayTest : SysuiTestCase() {
statusBarStateController, panelExpansionStateManager, statusBarKeyguardViewManager,
keyguardUpdateMonitor, dialogManager, dumpManager, transitionController,
configurationController, systemClock, keyguardStateController,
- unlockedScreenOffAnimationController, sensorProps, hbmProvider, reason,
+ unlockedScreenOffAnimationController, sensorProps, hbmProvider, REQUEST_ID, reason,
controllerCallback, onTouch, activityLaunchAnimator)
block()
}
@@ -263,6 +265,12 @@ class UdfpsControllerOverlayTest : SysuiTestCase() {
controllerOverlay.hide()
verify(udfpsView).stopIllumination()
}
+
+ @Test
+ fun matchesRequestIds() = withReason(REASON_AUTH_BP) {
+ assertThat(controllerOverlay.matchesRequestId(REQUEST_ID)).isTrue()
+ assertThat(controllerOverlay.matchesRequestId(REQUEST_ID + 1)).isFalse()
+ }
}
private class EnrollListener(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
index 1856fda14e1b..406ed5c17b0c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
@@ -27,6 +27,7 @@ import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -48,6 +49,7 @@ import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper.RunWithLooper;
import android.view.LayoutInflater;
import android.view.MotionEvent;
+import android.view.View;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityManager;
@@ -64,8 +66,8 @@ import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.LockscreenShadeTransitionController;
import com.android.systemui.statusbar.VibratorHelper;
-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.StatusBarKeyguardViewManager;
import com.android.systemui.statusbar.phone.SystemUIDialogManager;
import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController;
@@ -101,6 +103,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
// Use this for inputs going into SystemUI. Use UdfpsController.mUdfpsSensorId for things
// leaving SystemUI.
private static final int TEST_UDFPS_SENSOR_ID = 1;
+ private static final long TEST_REQUEST_ID = 70;
@Rule
public MockitoRule rule = MockitoJUnit.rule();
@@ -188,6 +191,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
@Captor private ArgumentCaptor<IUdfpsOverlayController> mOverlayCaptor;
private IUdfpsOverlayController mOverlayController;
@Captor private ArgumentCaptor<UdfpsView.OnTouchListener> mTouchListenerCaptor;
+ @Captor private ArgumentCaptor<View.OnHoverListener> mHoverListenerCaptor;
@Captor private ArgumentCaptor<Runnable> mOnIlluminatedRunnableCaptor;
@Captor private ArgumentCaptor<ScreenLifecycle.Observer> mScreenObserverCaptor;
private ScreenLifecycle.Observer mScreenObserver;
@@ -276,7 +280,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
@Test
public void dozeTimeTick() throws RemoteException {
- mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
+ mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID,
BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
mFgExecutor.runAllReady();
mUdfpsController.dozeTimeTick();
@@ -291,7 +295,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
when(mUdfpsView.getAnimationViewController()).thenReturn(mUdfpsKeyguardViewController);
// GIVEN that the overlay is showing
- mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
+ mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID,
BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
mFgExecutor.runAllReady();
@@ -314,7 +318,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
when(mStatusBarStateController.isDozing()).thenReturn(true);
// GIVEN that the overlay is showing
- mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
+ mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID,
BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
mFgExecutor.runAllReady();
@@ -337,7 +341,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
when(mStatusBarStateController.isDozing()).thenReturn(false);
// GIVEN that the overlay is showing
- mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
+ mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID,
BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
mFgExecutor.runAllReady();
@@ -360,7 +364,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
(UdfpsAnimationViewController) mock(UdfpsEnrollViewController.class));
// GIVEN that the overlay is showing
- mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
+ mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID,
BiometricOverlayConstants.REASON_ENROLL_ENROLLING, mUdfpsOverlayControllerCallback);
mFgExecutor.runAllReady();
@@ -375,25 +379,42 @@ public class UdfpsControllerTest extends SysuiTestCase {
}
@Test
- public void onActionMoveTouch_whenCanDismissLockScreen_entersDevice() throws RemoteException {
+ public void onActionMoveTouch_whenCanDismissLockScreen_entersDevice()
+ throws RemoteException {
+ onActionMoveTouch_whenCanDismissLockScreen_entersDevice(false /* stale */);
+ }
+
+ @Test
+ public void onActionMoveTouch_whenCanDismissLockScreen_entersDevice_ignoreStale()
+ throws RemoteException {
+ onActionMoveTouch_whenCanDismissLockScreen_entersDevice(true /* stale */);
+ }
+
+ public void onActionMoveTouch_whenCanDismissLockScreen_entersDevice(boolean stale)
+ throws RemoteException {
// GIVEN can dismiss lock screen and the current animation is an UdfpsKeyguardViewController
when(mKeyguardStateController.canDismissLockScreen()).thenReturn(true);
when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(true);
when(mUdfpsView.getAnimationViewController()).thenReturn(mUdfpsKeyguardViewController);
// GIVEN that the overlay is showing
- mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
+ mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID,
BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
mFgExecutor.runAllReady();
// WHEN ACTION_MOVE is received
verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
MotionEvent moveEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, 0, 0, 0);
+ if (stale) {
+ mOverlayController.hideUdfpsOverlay(TEST_UDFPS_SENSOR_ID);
+ mFgExecutor.runAllReady();
+ }
mTouchListenerCaptor.getValue().onTouch(mUdfpsView, moveEvent);
moveEvent.recycle();
// THEN notify keyguard authenticate to dismiss the keyguard
- verify(mStatusBarKeyguardViewManager).notifyKeyguardAuthenticated(anyBoolean());
+ verify(mStatusBarKeyguardViewManager, stale ? never() : times(1))
+ .notifyKeyguardAuthenticated(anyBoolean());
}
@Test
@@ -404,7 +425,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
when(mUdfpsView.getAnimationViewController()).thenReturn(mUdfpsKeyguardViewController);
// GIVEN that the overlay is showing
- mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
+ mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID,
BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
mFgExecutor.runAllReady();
@@ -425,7 +446,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
@Test
public void hideUdfpsOverlay_resetsAltAuthBouncerWhenShowing() throws RemoteException {
// GIVEN overlay was showing and the udfps bouncer is showing
- mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
+ mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID,
BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
when(mStatusBarKeyguardViewManager.isShowingAlternateAuth()).thenReturn(true);
@@ -439,7 +460,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
@Test
public void testSubscribesToOrientationChangesWhenShowingOverlay() throws Exception {
- mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
+ mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID,
BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
mFgExecutor.runAllReady();
@@ -458,7 +479,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(true);
// GIVEN that the overlay is showing
- mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
+ mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID,
BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
mFgExecutor.runAllReady();
// WHEN ACTION_DOWN is received
@@ -470,8 +491,9 @@ public class UdfpsControllerTest extends SysuiTestCase {
mTouchListenerCaptor.getValue().onTouch(mUdfpsView, moveEvent);
moveEvent.recycle();
// THEN FingerprintManager is notified about onPointerDown
- verify(mFingerprintManager).onPointerDown(eq(mUdfpsController.mSensorProps.sensorId), eq(0),
- eq(0), eq(0f), eq(0f));
+ verify(mFingerprintManager).onPointerDown(eq(TEST_REQUEST_ID),
+ eq(mUdfpsController.mSensorProps.sensorId),
+ eq(0), eq(0), eq(0f), eq(0f));
verify(mLatencyTracker).onActionStart(eq(LatencyTracker.ACTION_UDFPS_ILLUMINATE));
// AND illumination begins
verify(mUdfpsView).startIllumination(mOnIlluminatedRunnableCaptor.capture());
@@ -479,14 +501,15 @@ public class UdfpsControllerTest extends SysuiTestCase {
// AND onIlluminatedRunnable notifies FingerprintManager about onUiReady
mOnIlluminatedRunnableCaptor.getValue().run();
InOrder inOrder = inOrder(mFingerprintManager, mLatencyTracker);
- inOrder.verify(mFingerprintManager).onUiReady(eq(mUdfpsController.mSensorProps.sensorId));
+ inOrder.verify(mFingerprintManager).onUiReady(
+ eq(TEST_REQUEST_ID), eq(mUdfpsController.mSensorProps.sensorId));
inOrder.verify(mLatencyTracker).onActionEnd(eq(LatencyTracker.ACTION_UDFPS_ILLUMINATE));
}
@Test
public void aodInterrupt() throws RemoteException {
// GIVEN that the overlay is showing and screen is on and fp is running
- mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
+ mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID,
BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
mScreenObserver.onScreenTurnedOn();
mFgExecutor.runAllReady();
@@ -497,14 +520,15 @@ public class UdfpsControllerTest extends SysuiTestCase {
// AND onIlluminatedRunnable that notifies FingerprintManager is set
verify(mUdfpsView).startIllumination(mOnIlluminatedRunnableCaptor.capture());
mOnIlluminatedRunnableCaptor.getValue().run();
- verify(mFingerprintManager).onPointerDown(eq(mUdfpsController.mSensorProps.sensorId), eq(0),
- eq(0), eq(3f) /* minor */, eq(2f) /* major */);
+ verify(mFingerprintManager).onPointerDown(eq(TEST_REQUEST_ID),
+ eq(mUdfpsController.mSensorProps.sensorId),
+ eq(0), eq(0), eq(3f) /* minor */, eq(2f) /* major */);
}
@Test
public void cancelAodInterrupt() throws RemoteException {
// GIVEN AOD interrupt
- mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
+ mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID,
BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
mScreenObserver.onScreenTurnedOn();
mFgExecutor.runAllReady();
@@ -520,7 +544,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
@Test
public void aodInterruptTimeout() throws RemoteException {
// GIVEN AOD interrupt
- mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
+ mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID,
BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
mScreenObserver.onScreenTurnedOn();
mFgExecutor.runAllReady();
@@ -537,7 +561,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
@Test
public void aodInterruptScreenOff() throws RemoteException {
// GIVEN screen off
- mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
+ mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID,
BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
mScreenObserver.onScreenTurnedOff();
mFgExecutor.runAllReady();
@@ -553,7 +577,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
@Test
public void aodInterrupt_fingerprintNotRunning() throws RemoteException {
// GIVEN showing overlay
- mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
+ mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID,
BiometricOverlayConstants.REASON_AUTH_KEYGUARD,
mUdfpsOverlayControllerCallback);
mScreenObserver.onScreenTurnedOn();
@@ -568,23 +592,24 @@ public class UdfpsControllerTest extends SysuiTestCase {
}
@Test
- public void playHapticOnTouchUdfpsArea() throws RemoteException {
+ public void playHapticOnTouchUdfpsArea_a11yTouchExplorationEnabled() throws RemoteException {
// Configure UdfpsView to accept the ACTION_DOWN event
when(mUdfpsView.isIlluminationRequested()).thenReturn(false);
when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(true);
- // GIVEN that the overlay is showing
- mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
+ // GIVEN that the overlay is showing and a11y touch exploration enabled
+ when(mAccessibilityManager.isTouchExplorationEnabled()).thenReturn(true);
+ mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID,
BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
mFgExecutor.runAllReady();
- // WHEN ACTION_DOWN is received
- verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
- MotionEvent downEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0, 0);
- mTouchListenerCaptor.getValue().onTouch(mUdfpsView, downEvent);
- downEvent.recycle();
- MotionEvent moveEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, 0, 0, 0);
- mTouchListenerCaptor.getValue().onTouch(mUdfpsView, moveEvent);
+ // WHEN ACTION_HOVER is received
+ verify(mUdfpsView).setOnHoverListener(mHoverListenerCaptor.capture());
+ MotionEvent enterEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_HOVER_ENTER, 0, 0, 0);
+ mHoverListenerCaptor.getValue().onHover(mUdfpsView, enterEvent);
+ enterEvent.recycle();
+ MotionEvent moveEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_HOVER_MOVE, 0, 0, 0);
+ mHoverListenerCaptor.getValue().onHover(mUdfpsView, moveEvent);
moveEvent.recycle();
// THEN tick haptic is played
@@ -600,4 +625,34 @@ public class UdfpsControllerTest extends SysuiTestCase {
assertEquals(VibrationAttributes.USAGE_COMMUNICATION_REQUEST,
UdfpsController.VIBRATION_ATTRIBUTES.getUsage());
}
+
+ @Test
+ public void noHapticOnTouchUdfpsArea_a11yTouchExplorationDisabled() throws RemoteException {
+ // Configure UdfpsView to accept the ACTION_DOWN event
+ when(mUdfpsView.isIlluminationRequested()).thenReturn(false);
+ when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(true);
+
+ // GIVEN that the overlay is showing and a11y touch exploration NOT enabled
+ when(mAccessibilityManager.isTouchExplorationEnabled()).thenReturn(false);
+ mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID,
+ BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
+ mFgExecutor.runAllReady();
+
+ // WHEN ACTION_DOWN is received
+ verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
+ MotionEvent downEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0, 0);
+ mTouchListenerCaptor.getValue().onTouch(mUdfpsView, downEvent);
+ downEvent.recycle();
+ MotionEvent moveEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, 0, 0, 0);
+ mTouchListenerCaptor.getValue().onTouch(mUdfpsView, moveEvent);
+ moveEvent.recycle();
+
+ // THEN NO haptic played
+ verify(mVibrator, never()).vibrate(
+ anyInt(),
+ anyString(),
+ any(),
+ anyString(),
+ any());
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/broadcast/BroadcastSenderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/broadcast/BroadcastSenderTest.kt
new file mode 100644
index 000000000000..fbd2c918648a
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/broadcast/BroadcastSenderTest.kt
@@ -0,0 +1,145 @@
+/*
+ * 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.broadcast
+
+import android.content.Context
+import android.content.Intent
+import android.os.Bundle
+import android.os.UserHandle
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.time.FakeSystemClock
+import com.android.systemui.util.wakelock.WakeLockFake
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.Mock
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class BroadcastSenderTest : SysuiTestCase() {
+
+ @Mock
+ private lateinit var mockContext: Context
+
+ private lateinit var broadcastSender: BroadcastSender
+ private lateinit var executor: FakeExecutor
+ private lateinit var wakeLock: WakeLockFake
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ executor = FakeExecutor(FakeSystemClock())
+ wakeLock = WakeLockFake()
+ val wakeLockBuilder = WakeLockFake.Builder(mContext)
+ wakeLockBuilder.setWakeLock(wakeLock)
+ broadcastSender = BroadcastSender(mockContext, wakeLockBuilder, executor)
+ }
+
+ @Test
+ fun sendBroadcast_dispatchesWithWakelock() {
+ val intent = Intent(Intent.ACTION_VIEW)
+ broadcastSender.sendBroadcast(intent)
+
+ runExecutorAssertingWakelock {
+ verify(mockContext).sendBroadcast(intent)
+ }
+ }
+
+ @Test
+ fun sendBroadcastWithPermission_dispatchesWithWakelock() {
+ val intent = Intent(Intent.ACTION_VIEW)
+ val permission = "Permission"
+ broadcastSender.sendBroadcast(intent, permission)
+
+ runExecutorAssertingWakelock {
+ verify(mockContext).sendBroadcast(intent, permission)
+ }
+ }
+
+ @Test
+ fun sendBroadcastAsUser_dispatchesWithWakelock() {
+ val intent = Intent(Intent.ACTION_VIEW)
+ broadcastSender.sendBroadcastAsUser(intent, UserHandle.ALL)
+
+ runExecutorAssertingWakelock {
+ verify(mockContext).sendBroadcastAsUser(intent, UserHandle.ALL)
+ }
+ }
+
+ @Test
+ fun sendBroadcastAsUserWithPermission_dispatchesWithWakelock() {
+ val intent = Intent(Intent.ACTION_VIEW)
+ val permission = "Permission"
+ broadcastSender.sendBroadcastAsUser(intent, UserHandle.ALL, permission)
+
+ runExecutorAssertingWakelock {
+ verify(mockContext).sendBroadcastAsUser(intent, UserHandle.ALL, permission)
+ }
+ }
+
+ @Test
+ fun sendBroadcastAsUserWithPermissionAndOptions_dispatchesWithWakelock() {
+ val intent = Intent(Intent.ACTION_VIEW)
+ val permission = "Permission"
+ val options = Bundle()
+ options.putString("key", "value")
+
+ broadcastSender.sendBroadcastAsUser(intent, UserHandle.ALL, permission, options)
+
+ runExecutorAssertingWakelock {
+ verify(mockContext).sendBroadcastAsUser(intent, UserHandle.ALL, permission, options)
+ }
+ }
+
+ @Test
+ fun sendBroadcastAsUserWithPermissionAndAppOp_dispatchesWithWakelock() {
+ val intent = Intent(Intent.ACTION_VIEW)
+ val permission = "Permission"
+
+ broadcastSender.sendBroadcastAsUser(intent, UserHandle.ALL, permission, 12)
+
+ runExecutorAssertingWakelock {
+ verify(mockContext).sendBroadcastAsUser(intent, UserHandle.ALL, permission, 12)
+ }
+ }
+
+ @Test
+ fun sendCloseSystemDialogs_dispatchesWithWakelock() {
+ val intentCaptor = ArgumentCaptor.forClass(Intent::class.java)
+
+ broadcastSender.closeSystemDialogs()
+
+ runExecutorAssertingWakelock {
+ verify(mockContext).sendBroadcast(intentCaptor.capture())
+ assertThat(intentCaptor.value.action).isEqualTo(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)
+ }
+ }
+
+ private fun runExecutorAssertingWakelock(verification: () -> Unit) {
+ assertThat(wakeLock.isHeld).isTrue()
+ executor.runAllReady()
+ verification.invoke()
+ assertThat(wakeLock.isHeld).isFalse()
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/communal/CommunalHostViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/communal/CommunalHostViewControllerTest.java
deleted file mode 100644
index 8bd5e793dcdd..000000000000
--- a/packages/SystemUI/tests/src/com/android/systemui/communal/CommunalHostViewControllerTest.java
+++ /dev/null
@@ -1,242 +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.systemui.communal;
-
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.clearInvocations;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.testing.AndroidTestingRunner;
-import android.view.View;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.keyguard.KeyguardUpdateMonitorCallback;
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.statusbar.phone.DozeParameters;
-import com.android.systemui.statusbar.phone.ScreenOffAnimationController;
-import com.android.systemui.statusbar.policy.KeyguardStateController;
-import com.android.systemui.util.concurrency.FakeExecutor;
-import com.android.systemui.util.time.FakeSystemClock;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.Mockito;
-import org.mockito.MockitoAnnotations;
-
-import java.lang.ref.WeakReference;
-
-@SmallTest
-@RunWith(AndroidTestingRunner.class)
-public class CommunalHostViewControllerTest extends SysuiTestCase {
- @Mock
- private CommunalStateController mCommunalStateController;
-
- @Mock
- private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
-
- @Mock
- private KeyguardStateController mKeyguardStateController;
-
- @Mock
- private StatusBarStateController mStatusBarStateController;
-
- @Mock
- private CommunalHostView mCommunalView;
-
- @Mock
- private DozeParameters mDozeParameters;
-
- @Mock
- private ScreenOffAnimationController mScreenOffAnimationController;
-
- private FakeExecutor mFakeExecutor = new FakeExecutor(new FakeSystemClock());
-
- private CommunalHostViewController mController;
-
- @Mock
- private CommunalSource mCommunalSource;
-
- @Mock
- private View mChildView;
-
- @Before
- public void setup() {
- MockitoAnnotations.initMocks(this);
-
- when(mKeyguardStateController.isShowing()).thenReturn(true);
- when(mCommunalView.isAttachedToWindow()).thenReturn(true);
- when(mStatusBarStateController.getState()).thenReturn(StatusBarState.KEYGUARD);
-
- mController = new CommunalHostViewController(mFakeExecutor, mCommunalStateController,
- mKeyguardUpdateMonitor, mKeyguardStateController, mDozeParameters,
- mScreenOffAnimationController, mStatusBarStateController, mCommunalView);
- mController.init();
- mFakeExecutor.runAllReady();
-
- Mockito.clearInvocations(mCommunalView);
- }
-
- @Test
- public void testShow() {
- ArgumentCaptor<KeyguardStateController.Callback> callbackCapture =
- ArgumentCaptor.forClass(KeyguardStateController.Callback.class);
-
- // Capture callback value for later use.
- verify(mKeyguardStateController).addCallback(callbackCapture.capture());
-
- // Verify the communal view is shown when the controller is initialized with keyguard
- // showing (see setup).
- mController.show(new WeakReference<>(mCommunalSource));
- mFakeExecutor.runAllReady();
- verify(mCommunalView).setVisibility(View.VISIBLE);
-
- // Trigger keyguard off to ensure visibility of communal view is changed accordingly.
- when(mKeyguardStateController.isShowing()).thenReturn(false);
- callbackCapture.getValue().onKeyguardShowingChanged();
- mFakeExecutor.runAllReady();
- verify(mCommunalView).setVisibility(View.INVISIBLE);
- }
-
- @Test
- public void testHideOnOcclude() {
- ArgumentCaptor<KeyguardUpdateMonitorCallback> callbackCapture =
- ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback.class);
-
- // Capture callback value for later use.
- verify(mKeyguardUpdateMonitor).registerCallback(callbackCapture.capture());
-
- // Establish a visible communal view.
- mController.show(new WeakReference<>(mCommunalSource));
- mFakeExecutor.runAllReady();
- verify(mCommunalView).setVisibility(View.VISIBLE);
- Mockito.clearInvocations(mCommunalView);
-
- // Occlude.
- Mockito.clearInvocations(mCommunalView);
- callbackCapture.getValue().onKeyguardOccludedChanged(true);
- mFakeExecutor.runAllReady();
- verify(mCommunalView).setVisibility(View.INVISIBLE);
-
- // Unocclude.
- Mockito.clearInvocations(mCommunalView);
- callbackCapture.getValue().onKeyguardOccludedChanged(false);
- mFakeExecutor.runAllReady();
- verify(mCommunalView).setVisibility(View.VISIBLE);
- }
-
- @Test
- public void testReportOcclusion() {
- // Ensure CommunalHostViewController reports view occluded when either the QS or Shade is
- // expanded.
- clearInvocations(mCommunalStateController);
- mController.updateShadeExpansion(0);
- verify(mCommunalStateController).setCommunalViewOccluded(false);
- clearInvocations(mCommunalStateController);
- mController.updateQsExpansion(.5f);
- verify(mCommunalStateController).setCommunalViewOccluded(true);
- clearInvocations(mCommunalStateController);
- mController.updateShadeExpansion(.7f);
- verify(mCommunalStateController).setCommunalViewOccluded(true);
- clearInvocations(mCommunalStateController);
- mController.updateShadeExpansion(0);
- verify(mCommunalStateController).setCommunalViewOccluded(true);
- clearInvocations(mCommunalStateController);
- mController.updateQsExpansion(0f);
- verify(mCommunalStateController).setCommunalViewOccluded(false);
- clearInvocations(mCommunalStateController);
- }
-
- @Test
- public void testCommunalStateControllerHideNotified() {
- ArgumentCaptor<KeyguardUpdateMonitorCallback> callbackCapture =
- ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback.class);
-
- // Capture callback value for later use.
- verify(mKeyguardUpdateMonitor).registerCallback(callbackCapture.capture());
-
- // Establish a visible communal view.
- mController.show(new WeakReference<>(mCommunalSource));
- mFakeExecutor.runAllReady();
-
- // Occlude
- clearInvocations(mCommunalStateController);
- callbackCapture.getValue().onKeyguardOccludedChanged(true);
- mFakeExecutor.runAllReady();
-
- // Verify state controller is notified communal view is hidden.
- verify(mCommunalStateController).setCommunalViewShowing(false);
- }
-
- @Test
- public void testAlphaPropagation() {
- final float alpha = 0.8f;
-
- // Ensure alpha setting is propagated to children.
- when(mCommunalView.getChildCount()).thenReturn(1);
- when(mCommunalView.getChildAt(0)).thenReturn(mChildView);
- mController.setAlpha(alpha);
- verify(mChildView).setAlpha(alpha);
- verify(mCommunalView).setAlpha(alpha);
- }
-
- @Test
- public void testMultipleShowRequestSuppression() {
- // Ensure first request invokes source.
- mController.show(new WeakReference<>(mCommunalSource));
- mFakeExecutor.runAllReady();
- verify(mCommunalSource).requestCommunalView(any());
- clearInvocations(mCommunalSource);
-
- // Ensure subsequent identical request is suppressed
- mController.show(new WeakReference<>(mCommunalSource));
- mFakeExecutor.runAllReady();
- verify(mCommunalSource, never()).requestCommunalView(any());
- }
-
- @Test
- public void testNoShowInvocationOnBouncer() {
- ArgumentCaptor<KeyguardUpdateMonitorCallback> callbackCapture =
- ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback.class);
-
- // Capture callback value for later use.
- verify(mKeyguardUpdateMonitor).registerCallback(callbackCapture.capture());
-
- // Set source so it will be cleared if in invalid state.
- mController.show(new WeakReference<>(mCommunalSource));
- mFakeExecutor.runAllReady();
- clearInvocations(mCommunalStateController, mCommunalView);
-
- // Change bouncer to showing.
- callbackCapture.getValue().onKeyguardBouncerChanged(true);
- mFakeExecutor.runAllReady();
-
- // Verify that there were no requests to remove all child views or set the communal
- // state to not showing.
- verify(mCommunalStateController, never()).setCommunalViewShowing(eq(false));
- verify(mCommunalView, never()).removeAllViews();
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/communal/CommunalHostViewPositionAlgorithmTest.java b/packages/SystemUI/tests/src/com/android/systemui/communal/CommunalHostViewPositionAlgorithmTest.java
deleted file mode 100644
index 0a0266bc1955..000000000000
--- a/packages/SystemUI/tests/src/com/android/systemui/communal/CommunalHostViewPositionAlgorithmTest.java
+++ /dev/null
@@ -1,44 +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.systemui.communal;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.test.suitebuilder.annotation.SmallTest;
-
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.communal.CommunalHostViewPositionAlgorithm.Result;
-
-import org.junit.Test;
-
-
-@SmallTest
-public class CommunalHostViewPositionAlgorithmTest extends SysuiTestCase {
- @Test
- public void testOutput() {
- final float expansion = 0.25f;
- final int height = 120;
-
- final CommunalHostViewPositionAlgorithm algorithm = new CommunalHostViewPositionAlgorithm();
- algorithm.setup(expansion, height);
- final Result result = new Result();
- algorithm.run(result);
-
- // Verify the communal view is shifted offscreen vertically by the correct amount.
- assertThat((1 - expansion) * -height).isEqualTo(result.communalY);
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/communal/CommunalSettingConditionTest.java b/packages/SystemUI/tests/src/com/android/systemui/communal/CommunalSettingConditionTest.java
deleted file mode 100644
index c5b1a1d8bac5..000000000000
--- a/packages/SystemUI/tests/src/com/android/systemui/communal/CommunalSettingConditionTest.java
+++ /dev/null
@@ -1,119 +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.systemui.communal;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.clearInvocations;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
-
-import android.os.Looper;
-import android.os.UserHandle;
-import android.provider.Settings;
-import android.testing.AndroidTestingRunner;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.communal.conditions.CommunalSettingCondition;
-import com.android.systemui.util.condition.Condition;
-import com.android.systemui.util.settings.FakeSettings;
-import com.android.systemui.utils.os.FakeHandler;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@SmallTest
-@RunWith(AndroidTestingRunner.class)
-public class CommunalSettingConditionTest extends SysuiTestCase {
- private FakeSettings mSecureSettings;
- private CommunalSettingCondition mCondition;
-
- @Before
- public void setup() {
- final FakeHandler handler = new FakeHandler(Looper.getMainLooper());
- mSecureSettings = new FakeSettings();
- mCondition = new CommunalSettingCondition(handler, mSecureSettings);
- }
-
- @Test
- public void addCallback_communalSettingEnabled_immediatelyReportsTrue() {
- updateCommunalSetting(true);
-
- final Condition.Callback callback = mock(Condition.Callback.class);
- mCondition.addCallback(callback);
- verify(callback).onConditionChanged(mCondition);
- assertThat(mCondition.isConditionMet()).isTrue();
- }
-
- @Test
- public void addCallback_communalSettingDisabled_noReport() {
- updateCommunalSetting(false);
-
- final Condition.Callback callback = mock(Condition.Callback.class);
- mCondition.addCallback(callback);
- verify(callback, never()).onConditionChanged(eq(mCondition));
- }
-
- @Test
- public void updateCallback_communalSettingEnabled_reportsTrue() {
- updateCommunalSetting(false);
-
- final Condition.Callback callback = mock(Condition.Callback.class);
- mCondition.addCallback(callback);
- clearInvocations(callback);
-
- updateCommunalSetting(true);
- verify(callback).onConditionChanged(mCondition);
- assertThat(mCondition.isConditionMet()).isTrue();
- }
-
- @Test
- public void updateCallback_communalSettingDisabled_reportsFalse() {
- updateCommunalSetting(true);
-
- final Condition.Callback callback = mock(Condition.Callback.class);
- mCondition.addCallback(callback);
- clearInvocations(callback);
-
- updateCommunalSetting(false);
- verify(callback).onConditionChanged(mCondition);
- assertThat(mCondition.isConditionMet()).isFalse();
- }
-
- @Test
- public void updateCallback_communalSettingDidNotChange_neverReportDup() {
- updateCommunalSetting(true);
-
- final Condition.Callback callback = mock(Condition.Callback.class);
- mCondition.addCallback(callback);
- clearInvocations(callback);
-
- updateCommunalSetting(true);
- verify(callback, never()).onConditionChanged(mCondition);
- assertThat(mCondition.isConditionMet()).isTrue();
- }
-
- private void updateCommunalSetting(boolean value) {
- mSecureSettings.putIntForUser(Settings.Secure.COMMUNAL_MODE_ENABLED, value ? 1 : 0,
- UserHandle.USER_SYSTEM);
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/communal/CommunalSourceMonitorTest.java b/packages/SystemUI/tests/src/com/android/systemui/communal/CommunalSourceMonitorTest.java
deleted file mode 100644
index df1cc766d162..000000000000
--- a/packages/SystemUI/tests/src/com/android/systemui/communal/CommunalSourceMonitorTest.java
+++ /dev/null
@@ -1,169 +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.systemui.communal;
-
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.clearInvocations;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
-
-import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.util.concurrency.FakeExecutor;
-import com.android.systemui.util.condition.Monitor;
-import com.android.systemui.util.time.FakeSystemClock;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Captor;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.lang.ref.WeakReference;
-
-@SmallTest
-@RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper
-public class CommunalSourceMonitorTest extends SysuiTestCase {
- @Mock private Monitor mCommunalConditionsMonitor;
-
- @Captor private ArgumentCaptor<Monitor.Callback> mConditionsCallbackCaptor;
-
- private CommunalSourceMonitor mCommunalSourceMonitor;
- private FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock());
-
- @Before
- public void setup() {
- MockitoAnnotations.initMocks(this);
- mCommunalSourceMonitor = new CommunalSourceMonitor(mExecutor, mCommunalConditionsMonitor);
- }
-
- @Test
- public void testSourceAddedBeforeCallbackAdded() {
- final CommunalSourceMonitor.Callback callback = mock(CommunalSourceMonitor.Callback.class);
- final CommunalSource source = mock(CommunalSource.class);
-
- setSource(source);
- mCommunalSourceMonitor.addCallback(callback);
- setConditionsMet(true);
-
- verifyOnSourceAvailableCalledWith(callback, source);
- }
-
- @Test
- public void testRemoveCallback() {
- final CommunalSourceMonitor.Callback callback = mock(CommunalSourceMonitor.Callback.class);
- final CommunalSource source = mock(CommunalSource.class);
-
- mCommunalSourceMonitor.addCallback(callback);
- mCommunalSourceMonitor.removeCallback(callback);
- setSource(source);
-
- verify(callback, never()).onSourceAvailable(any());
- }
-
- @Test
- public void testAddCallbackWithConditionsMet() {
- final CommunalSourceMonitor.Callback callback = mock(CommunalSourceMonitor.Callback.class);
- final CommunalSource source = mock(CommunalSource.class);
-
- mCommunalSourceMonitor.addCallback(callback);
- setConditionsMet(true);
- clearInvocations(callback);
- setSource(source);
-
- verifyOnSourceAvailableCalledWith(callback, source);
- }
-
- @Test
- public void testAddCallbackWithConditionsNotMet() {
- final CommunalSourceMonitor.Callback callback = mock(CommunalSourceMonitor.Callback.class);
- final CommunalSource source = mock(CommunalSource.class);
-
- mCommunalSourceMonitor.addCallback(callback);
- setConditionsMet(false);
- setSource(source);
-
- verify(callback, never()).onSourceAvailable(any());
- }
-
- @Test
- public void testConditionsAreMetAfterCallbackAdded() {
- final CommunalSourceMonitor.Callback callback = mock(CommunalSourceMonitor.Callback.class);
- final CommunalSource source = mock(CommunalSource.class);
-
- mCommunalSourceMonitor.addCallback(callback);
- setSource(source);
-
- // The callback should not have executed since communal is disabled.
- verify(callback, never()).onSourceAvailable(any());
-
- // The callback should execute when all conditions are met.
- setConditionsMet(true);
- verifyOnSourceAvailableCalledWith(callback, source);
- }
-
- @Test
- public void testConditionsNoLongerMetAfterCallbackAdded() {
- final CommunalSourceMonitor.Callback callback = mock(CommunalSourceMonitor.Callback.class);
- final CommunalSource source = mock(CommunalSource.class);
-
- mCommunalSourceMonitor.addCallback(callback);
- setSource(source);
- setConditionsMet(true);
- verifyOnSourceAvailableCalledWith(callback, source);
-
- // The callback should execute again when conditions are no longer met, with a value of
- // null.
- setConditionsMet(false);
- verify(callback).onSourceAvailable(null);
- }
-
- private void verifyOnSourceAvailableCalledWith(CommunalSourceMonitor.Callback callback,
- CommunalSource source) {
- final ArgumentCaptor<WeakReference<CommunalSource>> sourceCapture =
- ArgumentCaptor.forClass(WeakReference.class);
- verify(callback).onSourceAvailable(sourceCapture.capture());
- assertThat(sourceCapture.getValue().get()).isEqualTo(source);
- }
-
- // Pushes an update on whether the communal conditions are met, assuming that a callback has
- // been registered with the communal conditions monitor.
- private void setConditionsMet(boolean value) {
- mExecutor.runAllReady();
- verify(mCommunalConditionsMonitor).addCallback(mConditionsCallbackCaptor.capture());
- final Monitor.Callback conditionsCallback =
- mConditionsCallbackCaptor.getValue();
- conditionsCallback.onConditionsChanged(value);
- mExecutor.runAllReady();
- }
-
- private void setSource(CommunalSource source) {
- mCommunalSourceMonitor.setSource(source);
- mExecutor.runAllReady();
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/communal/CommunalSourcePrimerTest.java b/packages/SystemUI/tests/src/com/android/systemui/communal/CommunalSourcePrimerTest.java
deleted file mode 100644
index 1d9a0594d7e2..000000000000
--- a/packages/SystemUI/tests/src/com/android/systemui/communal/CommunalSourcePrimerTest.java
+++ /dev/null
@@ -1,205 +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.systemui.communal;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.clearInvocations;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.testing.AndroidTestingRunner;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.systemui.R;
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.util.concurrency.FakeExecutor;;
-import com.android.systemui.util.ref.GcWeakReference;
-import com.android.systemui.util.time.FakeSystemClock;
-
-import com.google.common.util.concurrent.ListenableFuture;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.Mockito;
-import org.mockito.MockitoAnnotations;
-
-import java.util.Optional;
-
-@SmallTest
-@RunWith(AndroidTestingRunner.class)
-public class CommunalSourcePrimerTest extends SysuiTestCase {
- private static final String TEST_COMPONENT_NAME = "com.google.tests/.CommunalService";
- private static final int MAX_RETRIES = 5;
- private static final int RETRY_DELAY_MS = 1000;
- private static final int CONNECTION_MIN_DURATION_MS = 5000;
-
- // A simple implementation of {@link CommunalSource.Observer} to capture a callback value.
- // Used to ensure the references to a {@link CommunalSource.Observer.Callback} can be fully
- // removed.
- private static class FakeObserver implements CommunalSource.Observer {
- public GcWeakReference<Callback> mLastCallback;
-
- @Override
- public void addCallback(Callback callback) {
- mLastCallback = new GcWeakReference<>(callback);
- }
-
- @Override
- public void removeCallback(Callback callback) {
- if (mLastCallback.get() == callback) {
- mLastCallback = null;
- }
- }
- }
-
- // A simple implementation of {@link CommunalSource} to capture callback values. This
- // implementation better emulates the {@link WeakReference} wrapping behavior of
- // {@link CommunalSource} implementations than a mock.
- private static class FakeSource implements CommunalSource {
- @Override
- public ListenableFuture<CommunalViewResult> requestCommunalView(Context context) {
- return null;
- }
- }
-
- @Mock
- private Context mContext;
-
- @Mock
- private Resources mResources;
-
- private FakeSystemClock mFakeClock = new FakeSystemClock();
- private FakeExecutor mFakeExecutor = new FakeExecutor(mFakeClock);
-
- private FakeSource mSource = new FakeSource();
-
- @Mock
- private CommunalSourceMonitor mCommunalSourceMonitor;
-
- @Mock
- private CommunalSource.Connector mConnector;
-
- @Mock
- private CommunalSource.Connection mConnection;
-
- private FakeObserver mObserver = new FakeObserver();
-
- private CommunalSourcePrimer mPrimer;
-
- @Before
- public void setup() {
- MockitoAnnotations.initMocks(this);
- when(mResources.getInteger(R.integer.config_communalSourceMaxReconnectAttempts))
- .thenReturn(MAX_RETRIES);
- when(mResources.getInteger(R.integer.config_communalSourceReconnectBaseDelay))
- .thenReturn(RETRY_DELAY_MS);
- when(mResources.getInteger(R.integer.config_communalSourceReconnectBaseDelay))
- .thenReturn(RETRY_DELAY_MS);
- when(mResources.getString(R.string.config_communalSourceComponent))
- .thenReturn(TEST_COMPONENT_NAME);
- when(mResources.getInteger(R.integer.config_connectionMinDuration))
- .thenReturn(CONNECTION_MIN_DURATION_MS);
-
- mPrimer = new CommunalSourcePrimer(mContext, mResources, mFakeClock, mFakeExecutor,
- mCommunalSourceMonitor, Optional.of(mConnector), Optional.of(mObserver));
- }
-
- private CommunalSource.Connection.Callback captureCallbackAndSend(
- CommunalSource.Connector connector, Optional<CommunalSource> source) {
- ArgumentCaptor<CommunalSource.Connection.Callback> connectionCallback =
- ArgumentCaptor.forClass(CommunalSource.Connection.Callback.class);
-
- verify(connector).connect(connectionCallback.capture());
- Mockito.clearInvocations(connector);
-
- final CommunalSource.Connection.Callback callback = connectionCallback.getValue();
- callback.onSourceEstablished(source);
-
- return callback;
- }
-
- @Test
- public void testConnect() {
- mPrimer.onBootCompleted();
- captureCallbackAndSend(mConnector, Optional.of(mSource));
- verify(mCommunalSourceMonitor).setSource(mSource);
- }
-
- @Test
- public void testRetryOnBindFailure() throws Exception {
- mPrimer.onBootCompleted();
-
- // Verify attempts happen. Note that we account for the retries plus initial attempt, which
- // is not scheduled.
- for (int attemptCount = 0; attemptCount < MAX_RETRIES + 1; attemptCount++) {
- captureCallbackAndSend(mConnector, Optional.empty());
- mFakeExecutor.advanceClockToNext();
- mFakeExecutor.runAllReady();
- }
-
- verify(mCommunalSourceMonitor, never()).setSource(Mockito.notNull());
- }
-
- @Test
- public void testRetryOnDisconnectFailure() throws Exception {
- mPrimer.onBootCompleted();
- // Verify attempts happen. Note that we account for the retries plus initial attempt, which
- // is not scheduled.
- for (int attemptCount = 0; attemptCount < MAX_RETRIES + 1; attemptCount++) {
- final CommunalSource.Connection.Callback callback =
- captureCallbackAndSend(mConnector, Optional.of(mSource));
- verify(mCommunalSourceMonitor).setSource(Mockito.notNull());
- clearInvocations(mCommunalSourceMonitor);
- callback.onDisconnected();
- mFakeExecutor.advanceClockToNext();
- mFakeExecutor.runAllReady();
- }
-
- verify(mConnector, never()).connect(any());
- }
-
- @Test
- public void testAttemptOnPackageChange() {
- mPrimer.onBootCompleted();
- captureCallbackAndSend(mConnector, Optional.empty());
-
- mObserver.mLastCallback.get().onSourceChanged();
-
- verify(mConnector, times(1)).connect(any());
- }
-
- @Test
- public void testDisconnect() {
- mPrimer.onBootCompleted();
- final CommunalSource.Connection.Callback callback =
- captureCallbackAndSend(mConnector, Optional.of(mSource));
- verify(mCommunalSourceMonitor).setSource(mSource);
-
- mFakeClock.advanceTime(CONNECTION_MIN_DURATION_MS + 1);
- callback.onDisconnected();
-
- verify(mConnector).connect(any());
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/communal/CommunalStateControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/communal/CommunalStateControllerTest.java
deleted file mode 100644
index 7f85c35af742..000000000000
--- a/packages/SystemUI/tests/src/com/android/systemui/communal/CommunalStateControllerTest.java
+++ /dev/null
@@ -1,91 +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.systemui.communal;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.Mockito.clearInvocations;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
-
-import android.testing.AndroidTestingRunner;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.systemui.SysuiTestCase;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-@SmallTest
-@RunWith(AndroidTestingRunner.class)
-public class CommunalStateControllerTest extends SysuiTestCase {
- @Mock
- private CommunalStateController.Callback mCallback;
-
- @Before
- public void setup() {
- MockitoAnnotations.initMocks(this);
- }
-
- @Test
- public void testDefaultCommunalViewShowingState() {
- // The state controller should report the communal view as not showing by default.
- final CommunalStateController stateController = new CommunalStateController();
- assertThat(stateController.getCommunalViewShowing()).isFalse();
- }
-
- @Test
- public void testNotifyCommunalSurfaceShow() {
- final CommunalStateController stateController = new CommunalStateController();
- stateController.addCallback(mCallback);
-
- // Verify setting communal view to showing propagates to callback.
- stateController.setCommunalViewShowing(true);
- verify(mCallback).onCommunalViewShowingChanged();
- assertThat(stateController.getCommunalViewShowing()).isTrue();
-
- clearInvocations(mCallback);
-
- // Verify setting communal view to not showing propagates to callback.
- stateController.setCommunalViewShowing(false);
- verify(mCallback).onCommunalViewShowingChanged();
- assertThat(stateController.getCommunalViewShowing()).isFalse();
- }
-
- @Test
- public void testCallbackRegistration() {
- final CommunalStateController stateController = new CommunalStateController();
- stateController.addCallback(mCallback);
-
- // Verify setting communal view to showing propagates to callback.
- stateController.setCommunalViewShowing(true);
- verify(mCallback).onCommunalViewShowingChanged();
-
- clearInvocations(mCallback);
-
- stateController.removeCallback(mCallback);
- clearInvocations(mCallback);
-
- // Verify callback not invoked after removing from state controller.
- stateController.setCommunalViewShowing(false);
- verify(mCallback, never()).onCommunalViewShowingChanged();
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/communal/PackageObserverTest.java b/packages/SystemUI/tests/src/com/android/systemui/communal/PackageObserverTest.java
deleted file mode 100644
index 1cd60698353b..000000000000
--- a/packages/SystemUI/tests/src/com/android/systemui/communal/PackageObserverTest.java
+++ /dev/null
@@ -1,77 +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.systemui.communal;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.Mockito.verify;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.testing.AndroidTestingRunner;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.systemui.SysuiTestCase;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-@SmallTest
-@RunWith(AndroidTestingRunner.class)
-public class PackageObserverTest extends SysuiTestCase {
- private static final String PACKAGE_NAME = "com.foo.bar";
-
- @Mock
- Context mContext;
-
- @Mock
- CommunalSource.Observer.Callback mCallback;
-
- @Before
- public void setup() {
- MockitoAnnotations.initMocks(this);
- }
-
- @Test
- public void testChange() {
- final PackageObserver observer = new PackageObserver(mContext, PACKAGE_NAME);
- final ArgumentCaptor<BroadcastReceiver> receiverCapture =
- ArgumentCaptor.forClass(BroadcastReceiver.class);
-
- observer.addCallback(mCallback);
-
- // Verify broadcast receiver registered.
- verify(mContext).registerReceiver(receiverCapture.capture(), any(), anyInt());
-
- // Simulate package change.
- receiverCapture.getValue().onReceive(mContext, new Intent());
-
- // Check that callback was informed.
- verify(mCallback).onSourceChanged();
-
- observer.removeCallback(mCallback);
-
- // Make sure receiver is unregistered on last callback removal
- verify(mContext).unregisterReceiver(receiverCapture.getValue());
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlActionCoordinatorImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlActionCoordinatorImplTest.kt
index da25c6202b21..49eaf8239ca0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlActionCoordinatorImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlActionCoordinatorImplTest.kt
@@ -23,6 +23,7 @@ import android.provider.Settings
import android.test.suitebuilder.annotation.SmallTest
import android.testing.AndroidTestingRunner
import com.android.systemui.SysuiTestCase
+import com.android.systemui.broadcast.BroadcastSender
import com.android.systemui.controls.ControlsMetricsLogger
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.statusbar.VibratorHelper
@@ -62,6 +63,8 @@ class ControlActionCoordinatorImplTest : SysuiTestCase() {
@Mock
private lateinit var activityStarter: ActivityStarter
@Mock
+ private lateinit var broadcastSender: BroadcastSender
+ @Mock
private lateinit var taskViewFactory: Optional<TaskViewFactory>
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private lateinit var cvh: ControlViewHolder
@@ -94,6 +97,7 @@ class ControlActionCoordinatorImplTest : SysuiTestCase() {
bgExecutor,
uiExecutor,
activityStarter,
+ broadcastSender,
keyguardStateController,
taskViewFactory,
metricsLogger,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/DetailDialogTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/DetailDialogTest.kt
index 87b9172dcefc..0166fa25d526 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/DetailDialogTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/DetailDialogTest.kt
@@ -21,6 +21,7 @@ import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.broadcast.BroadcastSender
import com.android.wm.shell.TaskView
import org.junit.Before
import org.junit.Test
@@ -39,6 +40,8 @@ class DetailDialogTest : SysuiTestCase() {
@Mock
private lateinit var taskView: TaskView
@Mock
+ private lateinit var broadcastSender: BroadcastSender
+ @Mock
private lateinit var controlViewHolder: ControlViewHolder
@Mock
private lateinit var pendingIntent: PendingIntent
@@ -63,6 +66,7 @@ class DetailDialogTest : SysuiTestCase() {
private fun createDialog(pendingIntent: PendingIntent): DetailDialog {
return DetailDialog(
mContext,
+ broadcastSender,
taskView,
pendingIntent,
controlViewHolder
diff --git a/packages/SystemUI/tests/src/com/android/systemui/decor/RoundedCornerResDelegateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/decor/RoundedCornerResDelegateTest.kt
new file mode 100644
index 000000000000..b536bfdb944e
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/decor/RoundedCornerResDelegateTest.kt
@@ -0,0 +1,139 @@
+/*
+ * 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.decor
+
+import android.content.res.TypedArray
+import android.graphics.drawable.VectorDrawable
+import android.testing.AndroidTestingRunner
+import android.testing.TestableResources
+import android.util.Size
+import androidx.test.filters.SmallTest
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import org.junit.Assert.assertEquals
+import org.junit.Before
+import org.junit.Test
+
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
+
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class RoundedCornerResDelegateTest : SysuiTestCase() {
+
+ private lateinit var roundedCornerResDelegate: RoundedCornerResDelegate
+ @Mock private lateinit var mockTypedArray: TypedArray
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ }
+
+ @Test
+ fun testReloadAllAndDefaultRadius() {
+ mContext.orCreateTestableResources.addOverrides(
+ mockTypeArray = mockTypedArray,
+ radius = 3,
+ radiusTop = 0,
+ radiusBottom = 4,
+ multipleRadius = false)
+
+ roundedCornerResDelegate = RoundedCornerResDelegate(mContext.resources, null)
+
+ assertEquals(Size(3, 3), roundedCornerResDelegate.topRoundedSize)
+ assertEquals(Size(4, 4), roundedCornerResDelegate.bottomRoundedSize)
+ assertEquals(false, roundedCornerResDelegate.isMultipleRadius)
+
+ mContext.orCreateTestableResources.addOverrides(
+ mockTypeArray = mockTypedArray,
+ radius = 5,
+ radiusTop = 6,
+ radiusBottom = 0)
+
+ roundedCornerResDelegate.reloadAll("test")
+
+ assertEquals(Size(6, 6), roundedCornerResDelegate.topRoundedSize)
+ assertEquals(Size(5, 5), roundedCornerResDelegate.bottomRoundedSize)
+ }
+
+ @Test
+ fun testUpdateTuningSizeFactor() {
+ mContext.orCreateTestableResources.addOverrides(
+ mockTypeArray = mockTypedArray,
+ radiusTop = 0,
+ radiusBottom = 0,
+ multipleRadius = false)
+
+ roundedCornerResDelegate = RoundedCornerResDelegate(mContext.resources, null)
+
+ val factor = 5
+ roundedCornerResDelegate.updateTuningSizeFactor(factor)
+ val length = (factor * mContext.resources.displayMetrics.density).toInt()
+
+ assertEquals(Size(length, length), roundedCornerResDelegate.topRoundedSize)
+ assertEquals(Size(length, length), roundedCornerResDelegate.bottomRoundedSize)
+ }
+
+ @Test
+ fun testReadDefaultRadiusWhen0() {
+ mContext.orCreateTestableResources.addOverrides(
+ mockTypeArray = mockTypedArray,
+ radius = 3,
+ radiusTop = 0,
+ radiusBottom = 0,
+ multipleRadius = false)
+
+ roundedCornerResDelegate = RoundedCornerResDelegate(mContext.resources, null)
+
+ assertEquals(Size(3, 3), roundedCornerResDelegate.topRoundedSize)
+ assertEquals(Size(3, 3), roundedCornerResDelegate.bottomRoundedSize)
+ }
+
+ @Test
+ fun testReadMultipleRadius() {
+ val d = mContext.getDrawable(R.drawable.rounded) as VectorDrawable
+ val multipleRadiusSize = Size(d.intrinsicWidth, d.intrinsicHeight)
+ mContext.orCreateTestableResources.addOverrides(
+ mockTypeArray = mockTypedArray,
+ multipleRadius = true)
+ roundedCornerResDelegate = RoundedCornerResDelegate(mContext.resources, null)
+ assertEquals(multipleRadiusSize, roundedCornerResDelegate.topRoundedSize)
+ assertEquals(multipleRadiusSize, roundedCornerResDelegate.bottomRoundedSize)
+ }
+}
+
+private fun TestableResources.addOverrides(
+ mockTypeArray: TypedArray,
+ radius: Int? = null,
+ radiusTop: Int? = null,
+ radiusBottom: Int? = null,
+ multipleRadius: Boolean? = null
+) {
+ addOverride(com.android.internal.R.array.config_displayUniqueIdArray, arrayOf<String>())
+ addOverride(com.android.internal.R.array.config_roundedCornerRadiusArray, mockTypeArray)
+ addOverride(com.android.internal.R.array.config_roundedCornerTopRadiusArray, mockTypeArray)
+ addOverride(com.android.internal.R.array.config_roundedCornerBottomRadiusArray, mockTypeArray)
+ addOverride(R.array.config_roundedCornerDrawableArray, mockTypeArray)
+ addOverride(R.array.config_roundedCornerTopDrawableArray, mockTypeArray)
+ addOverride(R.array.config_roundedCornerBottomDrawableArray, mockTypeArray)
+ addOverride(R.array.config_roundedCornerMultipleRadiusArray, mockTypeArray)
+ radius?.let { addOverride(com.android.internal.R.dimen.rounded_corner_radius, it) }
+ radiusTop?.let { addOverride(com.android.internal.R.dimen.rounded_corner_radius_top, it) }
+ radiusBottom?.let { addOverride(com.android.internal.R.dimen.rounded_corner_radius_bottom, it) }
+ multipleRadius?.let { addOverride(R.bool.config_roundedCornerMultipleRadius, it) }
+} \ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java
index badafa4cf5e5..f4b378e6c19c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java
@@ -27,6 +27,7 @@ import static com.android.systemui.doze.DozeMachine.State.DOZE_REQUEST_PULSE;
import static com.android.systemui.doze.DozeMachine.State.FINISH;
import static com.android.systemui.doze.DozeMachine.State.INITIALIZED;
import static com.android.systemui.doze.DozeMachine.State.UNINITIALIZED;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotSame;
@@ -468,37 +469,39 @@ public class DozeScreenBrightnessTest extends SysuiTestCase {
public void transitionToDoze_shouldClampBrightness_afterTimeout_clampsToDim() {
when(mWakefulnessLifecycle.getLastSleepReason()).thenReturn(
PowerManager.GO_TO_SLEEP_REASON_TIMEOUT);
- when(mDozeParameters.shouldControlUnlockedScreenOff()).thenReturn(true);
when(mDozeParameters.shouldClampToDimBrightness()).thenReturn(true);
mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
- mScreen.transitionTo(INITIALIZED, DOZE);
// If we're dozing after a timeout, and playing the unlocked screen animation, we should
// stay at or below dim brightness, because the screen dims just before timeout.
assertTrue(mServiceFake.screenBrightness <= DIM_BRIGHTNESS);
+
+ // Once we transition to Doze, use the doze brightness
+ mScreen.transitionTo(INITIALIZED, DOZE);
+ assertEquals(mServiceFake.screenBrightness, DEFAULT_BRIGHTNESS);
}
@Test
public void transitionToDoze_shouldClampBrightness_notAfterTimeout_doesNotClampToDim() {
when(mWakefulnessLifecycle.getLastSleepReason()).thenReturn(
PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON);
- when(mDozeParameters.shouldControlUnlockedScreenOff()).thenReturn(true);
when(mDozeParameters.shouldClampToDimBrightness()).thenReturn(true);
mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
- mScreen.transitionTo(INITIALIZED, DOZE);
// If we're playing the unlocked screen off animation after a power button press, we should
// leave the brightness alone.
assertEquals(mServiceFake.screenBrightness, DEFAULT_BRIGHTNESS);
+
+ mScreen.transitionTo(INITIALIZED, DOZE);
+ assertEquals(mServiceFake.screenBrightness, DEFAULT_BRIGHTNESS);
}
@Test
public void transitionToDoze_noClampBrightness_afterTimeout_noScreenOff_doesNotClampToDim() {
when(mWakefulnessLifecycle.getLastSleepReason()).thenReturn(
PowerManager.GO_TO_SLEEP_REASON_TIMEOUT);
- when(mDozeParameters.shouldControlUnlockedScreenOff()).thenReturn(false);
when(mDozeParameters.shouldClampToDimBrightness()).thenReturn(false);
mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
@@ -514,11 +517,9 @@ public class DozeScreenBrightnessTest extends SysuiTestCase {
PowerManager.GO_TO_SLEEP_REASON_TIMEOUT);
when(mWakefulnessLifecycle.getWakefulness()).thenReturn(
WakefulnessLifecycle.WAKEFULNESS_GOING_TO_SLEEP);
- when(mDozeParameters.shouldControlUnlockedScreenOff()).thenReturn(false);
when(mDozeParameters.shouldClampToDimBrightness()).thenReturn(false);
mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
- mScreen.transitionTo(INITIALIZED, DOZE);
assertTrue(mServiceFake.screenBrightness <= DIM_BRIGHTNESS);
}
@@ -529,7 +530,6 @@ public class DozeScreenBrightnessTest extends SysuiTestCase {
PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON);
when(mWakefulnessLifecycle.getWakefulness()).thenReturn(
WakefulnessLifecycle.WAKEFULNESS_GOING_TO_SLEEP);
- when(mDozeParameters.shouldControlUnlockedScreenOff()).thenReturn(false);
when(mDozeParameters.shouldClampToDimBrightness()).thenReturn(false);
mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java
index ff9e13a48bec..dcbdea0ac5a3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java
@@ -16,7 +16,6 @@
package com.android.systemui.dreams;
-import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.verify;
@@ -30,7 +29,6 @@ import android.view.ViewTreeObserver;
import androidx.test.filters.SmallTest;
-import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.dreams.complication.ComplicationHostViewController;
@@ -44,7 +42,6 @@ import org.mockito.MockitoAnnotations;
@SmallTest
@RunWith(AndroidTestingRunner.class)
public class DreamOverlayContainerViewControllerTest extends SysuiTestCase {
- private static final int DREAM_OVERLAY_NOTIFICATIONS_DRAG_AREA_HEIGHT = 100;
private static final int MAX_BURN_IN_OFFSET = 20;
private static final long BURN_IN_PROTECTION_UPDATE_INTERVAL = 10;
private static final long MILLIS_UNTIL_FULL_JITTER = 240 * 1000;
@@ -76,9 +73,6 @@ public class DreamOverlayContainerViewControllerTest extends SysuiTestCase {
public void setup() {
MockitoAnnotations.initMocks(this);
- when(mResources.getDimensionPixelSize(
- R.dimen.dream_overlay_notifications_drag_area_height)).thenReturn(
- DREAM_OVERLAY_NOTIFICATIONS_DRAG_AREA_HEIGHT);
when(mDreamOverlayContainerView.getResources()).thenReturn(mResources);
when(mDreamOverlayContainerView.getViewTreeObserver()).thenReturn(mViewTreeObserver);
@@ -100,13 +94,6 @@ public class DreamOverlayContainerViewControllerTest extends SysuiTestCase {
}
@Test
- public void testSetsDreamOverlayNotificationsDragAreaHeight() {
- assertEquals(
- mController.getDreamOverlayNotificationsDragAreaHeight(),
- DREAM_OVERLAY_NOTIFICATIONS_DRAG_AREA_HEIGHT);
- }
-
- @Test
public void testBurnInProtectionStartsWhenContentViewAttached() {
mController.onViewAttached();
verify(mHandler).postDelayed(any(Runnable.class), eq(BURN_IN_PROTECTION_UPDATE_INTERVAL));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java
index b3d54590dc99..3657192daede 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java
@@ -19,6 +19,7 @@ package com.android.systemui.dreams;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -222,4 +223,25 @@ public class DreamOverlayServiceTest extends SysuiTestCase {
verify(mLifecycleRegistry).setCurrentState(Lifecycle.State.DESTROYED);
verify(mStateController).setOverlayActive(false);
}
+
+ @Test
+ public void testDecorViewNotAddedToWindowAfterDestroy() throws Exception {
+ when(mDreamOverlayContainerView.getParent())
+ .thenReturn(mDreamOverlayContainerViewParent)
+ .thenReturn(null);
+
+ final IBinder proxy = mService.onBind(new Intent());
+ final IDreamOverlay overlay = IDreamOverlay.Stub.asInterface(proxy);
+
+ // Inform the overlay service of dream starting.
+ overlay.startDream(mWindowParams, mDreamOverlayCallback);
+
+ // Destroy the service.
+ mService.onDestroy();
+
+ // Run executor tasks.
+ mMainExecutor.runAllReady();
+
+ verify(mWindowManager, never()).addView(any(), any());
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarViewControllerTest.java
index a32ff801e824..a6921b441f17 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarViewControllerTest.java
@@ -53,6 +53,8 @@ import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.concurrent.Executor;
+
@SmallTest
@RunWith(AndroidTestingRunner.class)
public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase {
@@ -90,6 +92,8 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase {
@Mock
ZenModeController mZenModeController;
+ private final Executor mMainExecutor = Runnable::run;
+
DreamOverlayStatusBarViewController mController;
@Before
@@ -102,6 +106,7 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase {
mController = new DreamOverlayStatusBarViewController(
mView,
mResources,
+ mMainExecutor,
mConnectivityManager,
mTouchSession,
mAlarmManager,
@@ -134,7 +139,8 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase {
.thenReturn(false);
when(mConnectivityManager.getNetworkCapabilities(any())).thenReturn(mNetworkCapabilities);
mController.onViewAttached();
- verify(mView).showIcon(DreamOverlayStatusBarView.STATUS_ICON_WIFI_UNAVAILABLE, true);
+ verify(mView).showIcon(
+ DreamOverlayStatusBarView.STATUS_ICON_WIFI_UNAVAILABLE, true, null);
}
@Test
@@ -143,13 +149,16 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase {
.thenReturn(true);
when(mConnectivityManager.getNetworkCapabilities(any())).thenReturn(mNetworkCapabilities);
mController.onViewAttached();
- verify(mView).showIcon(DreamOverlayStatusBarView.STATUS_ICON_WIFI_UNAVAILABLE, false);
+ verify(mView).showIcon(
+ DreamOverlayStatusBarView.STATUS_ICON_WIFI_UNAVAILABLE, false, null);
}
@Test
public void testOnViewAttachedShowsWifiIconWhenNetworkCapabilitiesUnavailable() {
when(mConnectivityManager.getNetworkCapabilities(any())).thenReturn(null);
mController.onViewAttached();
+ verify(mView).showIcon(
+ DreamOverlayStatusBarView.STATUS_ICON_WIFI_UNAVAILABLE, true, null);
}
@Test
@@ -176,7 +185,8 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase {
when(mSensorPrivacyController.isSensorBlocked(SensorPrivacyManager.Sensors.CAMERA))
.thenReturn(true);
mController.onViewAttached();
- verify(mView).showIcon(DreamOverlayStatusBarView.STATUS_ICON_MIC_CAMERA_DISABLED, true);
+ verify(mView).showIcon(
+ DreamOverlayStatusBarView.STATUS_ICON_MIC_CAMERA_DISABLED, true, null);
}
@Test
@@ -186,7 +196,8 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase {
when(mSensorPrivacyController.isSensorBlocked(SensorPrivacyManager.Sensors.CAMERA))
.thenReturn(false);
mController.onViewAttached();
- verify(mView).showIcon(DreamOverlayStatusBarView.STATUS_ICON_MIC_CAMERA_DISABLED, false);
+ verify(mView).showIcon(
+ DreamOverlayStatusBarView.STATUS_ICON_MIC_CAMERA_DISABLED, false, null);
}
@Test
@@ -211,7 +222,8 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase {
when(mZenModeController.getZen()).thenReturn(
Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS);
mController.onViewAttached();
- verify(mView).showIcon(DreamOverlayStatusBarView.STATUS_ICON_PRIORITY_MODE_ON, true);
+ verify(mView).showIcon(
+ DreamOverlayStatusBarView.STATUS_ICON_PRIORITY_MODE_ON, true, null);
}
@Test
@@ -219,7 +231,8 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase {
when(mZenModeController.getZen()).thenReturn(
Settings.Global.ZEN_MODE_OFF);
mController.onViewAttached();
- verify(mView).showIcon(DreamOverlayStatusBarView.STATUS_ICON_PRIORITY_MODE_ON, false);
+ verify(mView).showIcon(
+ DreamOverlayStatusBarView.STATUS_ICON_PRIORITY_MODE_ON, false, null);
}
@Test
@@ -250,7 +263,9 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase {
ArgumentCaptor.forClass(ConnectivityManager.NetworkCallback.class);
verify(mConnectivityManager).registerNetworkCallback(any(), callbackCapture.capture());
callbackCapture.getValue().onAvailable(mNetwork);
- verify(mView).showIcon(DreamOverlayStatusBarView.STATUS_ICON_WIFI_UNAVAILABLE, false);
+
+ verify(mView).showIcon(
+ DreamOverlayStatusBarView.STATUS_ICON_WIFI_UNAVAILABLE, false, null);
}
@Test
@@ -266,7 +281,9 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase {
ArgumentCaptor.forClass(ConnectivityManager.NetworkCallback.class);
verify(mConnectivityManager).registerNetworkCallback(any(), callbackCapture.capture());
callbackCapture.getValue().onLost(mNetwork);
- verify(mView).showIcon(DreamOverlayStatusBarView.STATUS_ICON_WIFI_UNAVAILABLE, true);
+
+ verify(mView).showIcon(
+ DreamOverlayStatusBarView.STATUS_ICON_WIFI_UNAVAILABLE, true, null);
}
@Test
@@ -283,7 +300,9 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase {
when(mNetworkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI))
.thenReturn(true);
callbackCapture.getValue().onCapabilitiesChanged(mNetwork, mNetworkCapabilities);
- verify(mView).showIcon(DreamOverlayStatusBarView.STATUS_ICON_WIFI_UNAVAILABLE, false);
+
+ verify(mView).showIcon(
+ DreamOverlayStatusBarView.STATUS_ICON_WIFI_UNAVAILABLE, false, null);
}
@Test
@@ -333,7 +352,8 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase {
callbackCapture.getValue().onSensorBlockedChanged(
SensorPrivacyManager.Sensors.MICROPHONE, true);
- verify(mView).showIcon(DreamOverlayStatusBarView.STATUS_ICON_MIC_CAMERA_DISABLED, true);
+ verify(mView).showIcon(
+ DreamOverlayStatusBarView.STATUS_ICON_MIC_CAMERA_DISABLED, true, null);
}
@Test
@@ -350,7 +370,8 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase {
callbackCapture.getValue().onSensorBlockedChanged(
SensorPrivacyManager.Sensors.MICROPHONE, false);
- verify(mView).showIcon(DreamOverlayStatusBarView.STATUS_ICON_MIC_CAMERA_DISABLED, false);
+ verify(mView).showIcon(
+ DreamOverlayStatusBarView.STATUS_ICON_MIC_CAMERA_DISABLED, false, null);
}
@Test
@@ -364,7 +385,8 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase {
verify(mZenModeController).addCallback(callbackCapture.capture());
callbackCapture.getValue().onZenChanged(Settings.Global.ZEN_MODE_NO_INTERRUPTIONS);
- verify(mView).showIcon(DreamOverlayStatusBarView.STATUS_ICON_PRIORITY_MODE_ON, true);
+ verify(mView).showIcon(
+ DreamOverlayStatusBarView.STATUS_ICON_PRIORITY_MODE_ON, true, null);
}
@Test
@@ -373,12 +395,12 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase {
.thenReturn(Settings.Global.ZEN_MODE_OFF);
mController.onViewAttached();
-
final ArgumentCaptor<ZenModeController.Callback> callbackCapture =
ArgumentCaptor.forClass(ZenModeController.Callback.class);
verify(mZenModeController).addCallback(callbackCapture.capture());
callbackCapture.getValue().onZenChanged(Settings.Global.ZEN_MODE_OFF);
- verify(mView).showIcon(DreamOverlayStatusBarView.STATUS_ICON_PRIORITY_MODE_ON, false);
+ verify(mView).showIcon(
+ DreamOverlayStatusBarView.STATUS_ICON_PRIORITY_MODE_ON, false, null);
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/SmartSpaceComplicationTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/SmartSpaceComplicationTest.java
index 3b17a8071cb2..ed1cf69ad8c0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/SmartSpaceComplicationTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/SmartSpaceComplicationTest.java
@@ -15,26 +15,31 @@
*/
package com.android.systemui.dreams;
-import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.app.smartspace.SmartspaceTarget;
import android.content.Context;
import android.testing.AndroidTestingRunner;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.statusbar.lockscreen.LockscreenSmartspaceController;
+import com.android.systemui.dreams.smartspace.DreamsSmartspaceController;
+import com.android.systemui.plugins.BcSmartspaceDataPlugin;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
+import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
+import java.util.Arrays;
+
@SmallTest
@RunWith(AndroidTestingRunner.class)
public class SmartSpaceComplicationTest extends SysuiTestCase {
@@ -42,7 +47,7 @@ public class SmartSpaceComplicationTest extends SysuiTestCase {
private Context mContext;
@Mock
- private LockscreenSmartspaceController mSmartspaceController;
+ private DreamsSmartspaceController mSmartspaceController;
@Mock
private DreamOverlayStateController mDreamOverlayStateController;
@@ -60,7 +65,6 @@ public class SmartSpaceComplicationTest extends SysuiTestCase {
*/
@Test
public void testAvailability() {
- when(mSmartspaceController.isEnabled()).thenReturn(false);
final SmartSpaceComplication.Registrant registrant = new SmartSpaceComplication.Registrant(
mContext,
@@ -68,10 +72,22 @@ public class SmartSpaceComplicationTest extends SysuiTestCase {
mComplication,
mSmartspaceController);
registrant.start();
- verify(mDreamOverlayStateController, never()).addComplication(any());
+ verify(mDreamOverlayStateController, never()).addComplication(eq(mComplication));
- when(mSmartspaceController.isEnabled()).thenReturn(true);
- registrant.start();
+
+ final ArgumentCaptor<DreamOverlayStateController.Callback> dreamCallbackCaptor =
+ ArgumentCaptor.forClass(DreamOverlayStateController.Callback.class);
+ verify(mDreamOverlayStateController).addCallback(dreamCallbackCaptor.capture());
+
+ when(mDreamOverlayStateController.isOverlayActive()).thenReturn(true);
+ dreamCallbackCaptor.getValue().onStateChanged();
+
+ final ArgumentCaptor<BcSmartspaceDataPlugin.SmartspaceTargetListener> listenerCaptor =
+ ArgumentCaptor.forClass(BcSmartspaceDataPlugin.SmartspaceTargetListener.class);
+ verify(mSmartspaceController).addListener(listenerCaptor.capture());
+
+ final SmartspaceTarget target = Mockito.mock(SmartspaceTarget.class);
+ listenerCaptor.getValue().onSmartspaceTargetsUpdated(Arrays.asList(target));
verify(mDreamOverlayStateController).addComplication(eq(mComplication));
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamClockDateComplicationTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamClockDateComplicationTest.java
index b02c506be8be..86aa14d7a877 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamClockDateComplicationTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamClockDateComplicationTest.java
@@ -15,11 +15,16 @@
*/
package com.android.systemui.dreams.complication;
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
import android.content.Context;
import android.testing.AndroidTestingRunner;
+import android.view.View;
import androidx.test.filters.SmallTest;
@@ -32,6 +37,8 @@ import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import javax.inject.Provider;
+
@SmallTest
@RunWith(AndroidTestingRunner.class)
public class DreamClockDateComplicationTest extends SysuiTestCase {
@@ -45,9 +52,28 @@ public class DreamClockDateComplicationTest extends SysuiTestCase {
@Mock
private DreamClockDateComplication mComplication;
+ @Mock
+ private Provider<DreamClockDateComplication.DreamClockDateViewHolder>
+ mDreamClockDateViewHolderProvider;
+
+ @Mock
+ private DreamClockDateComplication.DreamClockDateViewHolder
+ mDreamClockDateViewHolder;
+
+ @Mock
+ private ComplicationViewModel mComplicationViewModel;
+
+ @Mock
+ private View mView;
+
+ @Mock
+ private ComplicationLayoutParams mLayoutParams;
+
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
+ when(mDreamClockDateViewHolderProvider.get()).thenReturn(mDreamClockDateViewHolder);
+
}
/**
@@ -63,4 +89,40 @@ public class DreamClockDateComplicationTest extends SysuiTestCase {
registrant.start();
verify(mDreamOverlayStateController).addComplication(eq(mComplication));
}
+
+ /**
+ * Verifies {@link DreamClockDateComplication} has the required type.
+ */
+ @Test
+ public void testComplicationRequiredTypeAvailability() {
+ final DreamClockDateComplication complication =
+ new DreamClockDateComplication(mDreamClockDateViewHolderProvider);
+ assertEquals(Complication.COMPLICATION_TYPE_DATE,
+ complication.getRequiredTypeAvailability());
+ }
+
+ /**
+ * Verifies {@link DreamClockDateComplication.DreamClockDateViewHolder} is obtainable from its
+ * provider when the complication creates view.
+ */
+ @Test
+ public void testComplicationViewHolderProviderOnCreateView() {
+ final DreamClockDateComplication complication =
+ new DreamClockDateComplication(mDreamClockDateViewHolderProvider);
+ final Complication.ViewHolder viewHolder = complication.createView(mComplicationViewModel);
+ verify(mDreamClockDateViewHolderProvider).get();
+ assertThat(viewHolder).isEqualTo(mDreamClockDateViewHolder);
+ }
+
+ /**
+ * Verifies {@link DreamClockDateComplication.DreamClockDateViewHolder} has the intended view
+ * and layout parameters from constructor.
+ */
+ @Test
+ public void testComplicationViewHolderContentAccessors() {
+ final DreamClockDateComplication.DreamClockDateViewHolder viewHolder =
+ new DreamClockDateComplication.DreamClockDateViewHolder(mView, mLayoutParams);
+ assertThat(viewHolder.getView()).isEqualTo(mView);
+ assertThat(viewHolder.getLayoutParams()).isEqualTo(mLayoutParams);
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamClockTimeComplicationTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamClockTimeComplicationTest.java
index 088b4d5136ff..314a30b2d14a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamClockTimeComplicationTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamClockTimeComplicationTest.java
@@ -15,11 +15,16 @@
*/
package com.android.systemui.dreams.complication;
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
import android.content.Context;
import android.testing.AndroidTestingRunner;
+import android.view.View;
import androidx.test.filters.SmallTest;
@@ -32,6 +37,8 @@ import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import javax.inject.Provider;
+
@SmallTest
@RunWith(AndroidTestingRunner.class)
public class DreamClockTimeComplicationTest extends SysuiTestCase {
@@ -45,9 +52,27 @@ public class DreamClockTimeComplicationTest extends SysuiTestCase {
@Mock
private DreamClockTimeComplication mComplication;
+ @Mock
+ private Provider<DreamClockTimeComplication.DreamClockTimeViewHolder>
+ mDreamClockTimeViewHolderProvider;
+
+ @Mock
+ private DreamClockTimeComplication.DreamClockTimeViewHolder
+ mDreamClockTimeViewHolder;
+
+ @Mock
+ private ComplicationViewModel mComplicationViewModel;
+
+ @Mock
+ private View mView;
+
+ @Mock
+ private ComplicationLayoutParams mLayoutParams;
+
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
+ when(mDreamClockTimeViewHolderProvider.get()).thenReturn(mDreamClockTimeViewHolder);
}
/**
@@ -63,4 +88,40 @@ public class DreamClockTimeComplicationTest extends SysuiTestCase {
registrant.start();
verify(mDreamOverlayStateController).addComplication(eq(mComplication));
}
+
+ /**
+ * Verifies {@link DreamClockTimeComplication} has the required type.
+ */
+ @Test
+ public void testComplicationRequiredTypeAvailability() {
+ final DreamClockTimeComplication complication =
+ new DreamClockTimeComplication(mDreamClockTimeViewHolderProvider);
+ assertEquals(Complication.COMPLICATION_TYPE_TIME,
+ complication.getRequiredTypeAvailability());
+ }
+
+ /**
+ * Verifies {@link DreamClockTimeComplication.DreamClockTimeViewHolder} is obtainable from its
+ * provider when the complication creates view.
+ */
+ @Test
+ public void testComplicationViewHolderProviderOnCreateView() {
+ final DreamClockTimeComplication complication =
+ new DreamClockTimeComplication(mDreamClockTimeViewHolderProvider);
+ final Complication.ViewHolder viewHolder = complication.createView(mComplicationViewModel);
+ verify(mDreamClockTimeViewHolderProvider).get();
+ assertThat(viewHolder).isEqualTo(mDreamClockTimeViewHolder);
+ }
+
+ /**
+ * Verifies {@link DreamClockTimeComplication.DreamClockTimeViewHolder} has the intended view
+ * and layout parameters from constructor.
+ */
+ @Test
+ public void testComplicationViewHolderContentAccessors() {
+ final DreamClockTimeComplication.DreamClockTimeViewHolder viewHolder =
+ new DreamClockTimeComplication.DreamClockTimeViewHolder(mView, mLayoutParams);
+ assertThat(viewHolder.getView()).isEqualTo(mView);
+ assertThat(viewHolder.getLayoutParams()).isEqualTo(mLayoutParams);
+ }
}
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 6e01541c75e0..ce92d5e30455 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
@@ -39,8 +39,8 @@ import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.shared.system.InputChannelCompat;
import com.android.systemui.statusbar.NotificationShadeWindowController;
-import com.android.systemui.statusbar.phone.KeyguardBouncer;
import com.android.systemui.statusbar.phone.CentralSurfaces;
+import com.android.systemui.statusbar.phone.KeyguardBouncer;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.wm.shell.animation.FlingAnimationUtils;
@@ -112,8 +112,10 @@ public class BouncerSwipeTouchHandlerTest extends SysuiTestCase {
TOUCH_REGION);
when(mCentralSurfaces.getDisplayHeight()).thenReturn((float) SCREEN_HEIGHT_PX);
+ when(mCentralSurfaces.isBouncerShowing()).thenReturn(false);
when(mValueAnimatorCreator.create(anyFloat(), anyFloat())).thenReturn(mValueAnimator);
when(mVelocityTrackerFactory.obtain()).thenReturn(mVelocityTracker);
+ when(mFlingAnimationUtils.getMinVelocityPxPerSecond()).thenReturn(Float.MAX_VALUE);
}
/**
@@ -154,7 +156,7 @@ public class BouncerSwipeTouchHandlerTest extends SysuiTestCase {
* Makes sure expansion amount is proportional to scroll.
*/
@Test
- public void testExpansionAmount() {
+ public void testExpansionAmount_whenBouncerHidden_setsCorrectValue() {
mTouchHandler.onSessionStart(mTouchSession);
ArgumentCaptor<GestureDetector.OnGestureListener> gestureListenerCaptor =
ArgumentCaptor.forClass(GestureDetector.OnGestureListener.class);
@@ -166,9 +168,9 @@ public class BouncerSwipeTouchHandlerTest extends SysuiTestCase {
final MotionEvent event1 = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE,
0, SCREEN_HEIGHT_PX, 0);
final MotionEvent event2 = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE,
- 0, SCREEN_HEIGHT_PX - distanceY, 0);
+ 0, SCREEN_HEIGHT_PX - distanceY, 0);
- assertThat(gestureListenerCaptor.getValue().onScroll(event1, event2, 0 , distanceY))
+ assertThat(gestureListenerCaptor.getValue().onScroll(event1, event2, 0, distanceY))
.isTrue();
// Ensure only called once
@@ -180,6 +182,38 @@ public class BouncerSwipeTouchHandlerTest extends SysuiTestCase {
.onPanelExpansionChanged(eq(1 - scrollAmount), eq(false), eq(true));
}
+ /**
+ * Makes sure expansion amount is proportional to scroll.
+ */
+ @Test
+ public void testExpansionAmount_whenBouncerShown_setsCorrectValue() {
+ when(mCentralSurfaces.isBouncerShowing()).thenReturn(true);
+
+ mTouchHandler.onSessionStart(mTouchSession);
+ ArgumentCaptor<GestureDetector.OnGestureListener> gestureListenerCaptor =
+ ArgumentCaptor.forClass(GestureDetector.OnGestureListener.class);
+ verify(mTouchSession).registerGestureListener(gestureListenerCaptor.capture());
+
+ final float scrollAmount = .3f;
+ final float distanceY = SCREEN_HEIGHT_PX * scrollAmount;
+
+ final MotionEvent event1 = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE,
+ 0, SCREEN_HEIGHT_PX, 0);
+ final MotionEvent event2 = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE,
+ 0, SCREEN_HEIGHT_PX - distanceY, 0);
+
+ assertThat(gestureListenerCaptor.getValue().onScroll(event1, event2, 0, distanceY))
+ .isTrue();
+
+ // Ensure only called once
+ verify(mStatusBarKeyguardViewManager)
+ .onPanelExpansionChanged(anyFloat(), anyBoolean(), anyBoolean());
+
+ // Ensure correct expansion passed in.
+ verify(mStatusBarKeyguardViewManager)
+ .onPanelExpansionChanged(eq(scrollAmount), eq(false), eq(true));
+ }
+
private void swipeToPosition(float position, float velocityY) {
mTouchHandler.onSessionStart(mTouchSession);
ArgumentCaptor<GestureDetector.OnGestureListener> gestureListenerCaptor =
@@ -196,9 +230,9 @@ public class BouncerSwipeTouchHandlerTest extends SysuiTestCase {
final MotionEvent event1 = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE,
0, SCREEN_HEIGHT_PX, 0);
final MotionEvent event2 = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE,
- 0, SCREEN_HEIGHT_PX - distanceY, 0);
+ 0, SCREEN_HEIGHT_PX - distanceY, 0);
- assertThat(gestureListenerCaptor.getValue().onScroll(event1, event2, 0 , distanceY))
+ assertThat(gestureListenerCaptor.getValue().onScroll(event1, event2, 0, distanceY))
.isTrue();
final MotionEvent upEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_UP,
@@ -212,14 +246,18 @@ public class BouncerSwipeTouchHandlerTest extends SysuiTestCase {
* down.
*/
@Test
- public void testCollapseOnThreshold() {
+ public void testSwipeBelowThreshold_collapsesBouncer() {
final float swipeUpPercentage = .3f;
- swipeToPosition(swipeUpPercentage, -1);
-
- verify(mValueAnimatorCreator).create(eq(1 - swipeUpPercentage),
- eq(KeyguardBouncer.EXPANSION_VISIBLE));
- verify(mFlingAnimationUtilsClosing).apply(eq(mValueAnimator), anyFloat(), anyFloat(),
- anyFloat(), anyFloat());
+ final float expansion = 1 - swipeUpPercentage;
+ // The upward velocity is ignored.
+ final float velocityY = -1;
+ swipeToPosition(swipeUpPercentage, velocityY);
+
+ verify(mValueAnimatorCreator).create(eq(expansion), eq(KeyguardBouncer.EXPANSION_HIDDEN));
+ verify(mFlingAnimationUtilsClosing).apply(eq(mValueAnimator),
+ eq(SCREEN_HEIGHT_PX * expansion),
+ eq(SCREEN_HEIGHT_PX * KeyguardBouncer.EXPANSION_HIDDEN),
+ eq(velocityY), eq((float) SCREEN_HEIGHT_PX));
verify(mValueAnimator).start();
}
@@ -227,14 +265,59 @@ public class BouncerSwipeTouchHandlerTest extends SysuiTestCase {
* Tests that ending a swipe above the set expansion threshold will continue the expansion.
*/
@Test
- public void testExpandOnThreshold() {
+ public void testSwipeAboveThreshold_expandsBouncer() {
final float swipeUpPercentage = .7f;
- swipeToPosition(swipeUpPercentage, 1);
+ final float expansion = 1 - swipeUpPercentage;
+ // The downward velocity is ignored.
+ final float velocityY = 1;
+ swipeToPosition(swipeUpPercentage, velocityY);
+
+ verify(mValueAnimatorCreator).create(eq(expansion), eq(KeyguardBouncer.EXPANSION_VISIBLE));
+ verify(mFlingAnimationUtils).apply(eq(mValueAnimator), eq(SCREEN_HEIGHT_PX * expansion),
+ eq(SCREEN_HEIGHT_PX * KeyguardBouncer.EXPANSION_VISIBLE),
+ eq(velocityY), eq((float) SCREEN_HEIGHT_PX));
+ verify(mValueAnimator).start();
+ }
- verify(mValueAnimatorCreator).create(eq(1 - swipeUpPercentage),
- eq(KeyguardBouncer.EXPANSION_HIDDEN));
- verify(mFlingAnimationUtils).apply(eq(mValueAnimator), anyFloat(), anyFloat(),
- anyFloat(), anyFloat());
+ /**
+ * Tests that swiping down with a speed above the set threshold leads to bouncer collapsing
+ * down.
+ */
+ @Test
+ public void testSwipeDownVelocityAboveMin_collapsesBouncer() {
+ when(mFlingAnimationUtils.getMinVelocityPxPerSecond()).thenReturn((float) 0);
+
+ // The swipe amount above the set expansion threshold is ignored.
+ final float swipeUpPercentage = .7f;
+ final float expansion = 1 - swipeUpPercentage;
+ final float velocityY = 1;
+ swipeToPosition(swipeUpPercentage, velocityY);
+
+ verify(mValueAnimatorCreator).create(eq(expansion), eq(KeyguardBouncer.EXPANSION_HIDDEN));
+ verify(mFlingAnimationUtilsClosing).apply(eq(mValueAnimator),
+ eq(SCREEN_HEIGHT_PX * expansion),
+ eq(SCREEN_HEIGHT_PX * KeyguardBouncer.EXPANSION_HIDDEN),
+ eq(velocityY), eq((float) SCREEN_HEIGHT_PX));
+ verify(mValueAnimator).start();
+ }
+
+ /**
+ * Tests that swiping up with a speed above the set threshold will continue the expansion.
+ */
+ @Test
+ public void testSwipeUpVelocityAboveMin_expandsBouncer() {
+ when(mFlingAnimationUtils.getMinVelocityPxPerSecond()).thenReturn((float) 0);
+
+ // The swipe amount below the set expansion threshold is ignored.
+ final float swipeUpPercentage = .3f;
+ final float expansion = 1 - swipeUpPercentage;
+ final float velocityY = -1;
+ swipeToPosition(swipeUpPercentage, velocityY);
+
+ verify(mValueAnimatorCreator).create(eq(expansion), eq(KeyguardBouncer.EXPANSION_VISIBLE));
+ verify(mFlingAnimationUtils).apply(eq(mValueAnimator), eq(SCREEN_HEIGHT_PX * expansion),
+ eq(SCREEN_HEIGHT_PX * KeyguardBouncer.EXPANSION_VISIBLE),
+ eq(velocityY), eq((float) SCREEN_HEIGHT_PX));
verify(mValueAnimator).start();
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsDebugTest.kt b/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsDebugTest.kt
index 23a5b2b2c5b7..50b779cb6bf5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsDebugTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsDebugTest.kt
@@ -67,9 +67,14 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
private lateinit var mBroadcastReceiver: BroadcastReceiver
private lateinit var mClearCacheAction: Consumer<Int>
+ private val teamfoodableFlagA = BooleanFlag(500, false, true)
+ private val teamfoodableFlagB = BooleanFlag(501, true, true)
+
@Before
fun setup() {
MockitoAnnotations.initMocks(this)
+ mFlagMap.put(teamfoodableFlagA.id, teamfoodableFlagA)
+ mFlagMap.put(teamfoodableFlagB.id, teamfoodableFlagB)
mFeatureFlagsDebug = FeatureFlagsDebug(
mFlagManager,
mMockContext,
@@ -77,7 +82,7 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
mSystemProperties,
mResources,
mDumpManager,
- { mFlagMap },
+ mFlagMap,
mBarService
)
verify(mFlagManager).onSettingsChangedAction = any()
@@ -93,12 +98,50 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
@Test
fun testReadBooleanFlag() {
+ // Remember that the TEAMFOOD flag is id#1 and has special behavior.
whenever(mFlagManager.readFlagValue<Boolean>(eq(3), any())).thenReturn(true)
whenever(mFlagManager.readFlagValue<Boolean>(eq(4), any())).thenReturn(false)
- assertThat(mFeatureFlagsDebug.isEnabled(BooleanFlag(1, false))).isFalse()
assertThat(mFeatureFlagsDebug.isEnabled(BooleanFlag(2, true))).isTrue()
assertThat(mFeatureFlagsDebug.isEnabled(BooleanFlag(3, false))).isTrue()
assertThat(mFeatureFlagsDebug.isEnabled(BooleanFlag(4, true))).isFalse()
+ assertThat(mFeatureFlagsDebug.isEnabled(BooleanFlag(5, false))).isFalse()
+ }
+
+ @Test
+ fun testTeamFoodFlag_False() {
+ whenever(mFlagManager.readFlagValue<Boolean>(eq(1), any())).thenReturn(false)
+ assertThat(mFeatureFlagsDebug.isEnabled(teamfoodableFlagA)).isFalse()
+ assertThat(mFeatureFlagsDebug.isEnabled(teamfoodableFlagB)).isTrue()
+
+ // Regular boolean flags should still test the same.
+ // Only our teamfoodableFlag should change.
+ testReadBooleanFlag()
+ }
+
+ @Test
+ fun testTeamFoodFlag_True() {
+ whenever(mFlagManager.readFlagValue<Boolean>(eq(1), any())).thenReturn(true)
+ assertThat(mFeatureFlagsDebug.isEnabled(teamfoodableFlagA)).isTrue()
+ assertThat(mFeatureFlagsDebug.isEnabled(teamfoodableFlagB)).isTrue()
+
+ // Regular boolean flags should still test the same.
+ // Only our teamfoodableFlag should change.
+ testReadBooleanFlag()
+ }
+
+ @Test
+ fun testTeamFoodFlag_Overridden() {
+ whenever(mFlagManager.readFlagValue<Boolean>(eq(teamfoodableFlagA.id), any()))
+ .thenReturn(true)
+ whenever(mFlagManager.readFlagValue<Boolean>(eq(teamfoodableFlagB.id), any()))
+ .thenReturn(false)
+ whenever(mFlagManager.readFlagValue<Boolean>(eq(1), any())).thenReturn(true)
+ assertThat(mFeatureFlagsDebug.isEnabled(teamfoodableFlagA)).isTrue()
+ assertThat(mFeatureFlagsDebug.isEnabled(teamfoodableFlagB)).isFalse()
+
+ // Regular boolean flags should still test the same.
+ // Only our teamfoodableFlag should change.
+ testReadBooleanFlag()
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java
index 6fead9efa767..f00fbe6ac4d7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java
@@ -341,6 +341,7 @@ public class GlobalActionsDialogLiteTest extends SysuiTestCase {
public void testCreateActionItems_lockdownEnabled_doesShowLockdown() {
mGlobalActionsDialogLite = spy(mGlobalActionsDialogLite);
doReturn(4).when(mGlobalActionsDialogLite).getMaxShownPowerItems();
+ doReturn(true).when(mGlobalActionsDialogLite).shouldDisplayEmergency();
doReturn(true).when(mGlobalActionsDialogLite).shouldDisplayLockdown(any());
doReturn(true).when(mGlobalActionsDialogLite).shouldShowAction(any());
String[] actions = {
@@ -365,8 +366,10 @@ public class GlobalActionsDialogLiteTest extends SysuiTestCase {
public void testCreateActionItems_lockdownDisabled_doesNotShowLockdown() {
mGlobalActionsDialogLite = spy(mGlobalActionsDialogLite);
doReturn(4).when(mGlobalActionsDialogLite).getMaxShownPowerItems();
+ doReturn(true).when(mGlobalActionsDialogLite).shouldDisplayEmergency();
// make sure lockdown action will NOT be shown
doReturn(false).when(mGlobalActionsDialogLite).shouldDisplayLockdown(any());
+ doReturn(true).when(mGlobalActionsDialogLite).shouldShowAction(any());
String[] actions = {
GlobalActionsDialogLite.GLOBAL_ACTION_KEY_EMERGENCY,
// lockdown action not allowed
@@ -386,6 +389,32 @@ public class GlobalActionsDialogLiteTest extends SysuiTestCase {
}
@Test
+ public void testCreateActionItems_emergencyDisabled_doesNotShowEmergency() {
+ mGlobalActionsDialogLite = spy(mGlobalActionsDialogLite);
+ doReturn(4).when(mGlobalActionsDialogLite).getMaxShownPowerItems();
+ // make sure emergency action will NOT be shown
+ doReturn(false).when(mGlobalActionsDialogLite).shouldDisplayEmergency();
+ doReturn(true).when(mGlobalActionsDialogLite).shouldDisplayLockdown(any());
+ doReturn(true).when(mGlobalActionsDialogLite).shouldShowAction(any());
+ String[] actions = {
+ // emergency action not allowed
+ GlobalActionsDialogLite.GLOBAL_ACTION_KEY_EMERGENCY,
+ GlobalActionsDialogLite.GLOBAL_ACTION_KEY_LOCKDOWN,
+ GlobalActionsDialogLite.GLOBAL_ACTION_KEY_POWER,
+ GlobalActionsDialogLite.GLOBAL_ACTION_KEY_RESTART,
+ };
+ doReturn(actions).when(mGlobalActionsDialogLite).getDefaultActions();
+ mGlobalActionsDialogLite.createActionItems();
+
+ assertItemsOfType(mGlobalActionsDialogLite.mItems,
+ GlobalActionsDialogLite.LockDownAction.class,
+ GlobalActionsDialogLite.ShutDownAction.class,
+ GlobalActionsDialogLite.RestartAction.class);
+ assertThat(mGlobalActionsDialogLite.mOverflowItems).isEmpty();
+ assertThat(mGlobalActionsDialogLite.mPowerItems).isEmpty();
+ }
+
+ @Test
public void testShouldLogLockdownPress() {
GlobalActionsDialogLite.LockDownAction lockDownAction =
mGlobalActionsDialogLite.new LockDownAction();
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 dcbe0ab96dac..daf81bdc6e82 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaCarouselControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaCarouselControllerTest.kt
@@ -37,7 +37,6 @@ import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.MockitoAnnotations
import javax.inject.Provider
-import org.mockito.Mockito.`when` as whenever
private val DATA = MediaData(
userId = -1,
@@ -83,7 +82,6 @@ class MediaCarouselControllerTest : SysuiTestCase() {
@Before
fun setup() {
MockitoAnnotations.initMocks(this)
- whenever(mediaFlags.areMediaSessionActionsEnabled()).thenReturn(true)
mediaCarouselController = MediaCarouselController(
context,
mediaControlPanelFactory,
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 708fc915410c..90eff1ae9804 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
@@ -40,6 +40,7 @@ import androidx.lifecycle.LiveData
import androidx.test.filters.SmallTest
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
+import com.android.systemui.broadcast.BroadcastSender
import com.android.systemui.media.dialog.MediaOutputDialogFactory
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.plugins.FalsingManager
@@ -59,6 +60,7 @@ import org.mockito.ArgumentMatchers.anyLong
import org.mockito.Mock
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
@@ -85,6 +87,7 @@ public class MediaControlPanelTest : SysuiTestCase() {
private lateinit var bgExecutor: FakeExecutor
@Mock private lateinit var activityStarter: ActivityStarter
+ @Mock private lateinit var broadcastSender: BroadcastSender
@Mock private lateinit var holder: PlayerViewHolder
@Mock private lateinit var sessionHolder: PlayerSessionViewHolder
@@ -98,7 +101,6 @@ public class MediaControlPanelTest : SysuiTestCase() {
@Mock private lateinit var mediaOutputDialogFactory: MediaOutputDialogFactory
@Mock private lateinit var mediaCarouselController: MediaCarouselController
@Mock private lateinit var falsingManager: FalsingManager
- @Mock private lateinit var mediaFlags: MediaFlags
private lateinit var appIcon: ImageView
private lateinit var albumView: ImageView
private lateinit var titleText: TextView
@@ -119,8 +121,6 @@ public class MediaControlPanelTest : SysuiTestCase() {
private lateinit var actionPlayPause: ImageButton
private lateinit var actionNext: ImageButton
private lateinit var actionPrev: ImageButton
- private lateinit var actionStart: ImageButton
- private lateinit var actionEnd: ImageButton
@Mock private lateinit var longPressText: TextView
@Mock private lateinit var handler: Handler
private lateinit var settings: View
@@ -144,9 +144,9 @@ public class MediaControlPanelTest : SysuiTestCase() {
whenever(mediaViewController.expandedLayout).thenReturn(expandedSet)
whenever(mediaViewController.collapsedLayout).thenReturn(collapsedSet)
- player = MediaControlPanel(context, bgExecutor, activityStarter, mediaViewController,
- seekBarViewModel, Lazy { mediaDataManager },
- mediaOutputDialogFactory, mediaCarouselController, falsingManager, mediaFlags, clock)
+ player = MediaControlPanel(context, bgExecutor, activityStarter, broadcastSender,
+ mediaViewController, seekBarViewModel, Lazy { mediaDataManager },
+ mediaOutputDialogFactory, mediaCarouselController, falsingManager, clock)
whenever(seekBarViewModel.progress).thenReturn(seekBarData)
// Set up mock views for the players
@@ -168,6 +168,17 @@ public class MediaControlPanelTest : SysuiTestCase() {
cancelText = TextView(context)
dismiss = FrameLayout(context)
dismissText = TextView(context)
+
+ action0 = ImageButton(context).also { it.setId(R.id.action0) }
+ action1 = ImageButton(context).also { it.setId(R.id.action1) }
+ action2 = ImageButton(context).also { it.setId(R.id.action2) }
+ action3 = ImageButton(context).also { it.setId(R.id.action3) }
+ action4 = ImageButton(context).also { it.setId(R.id.action4) }
+
+ actionPlayPause = ImageButton(context).also { it.setId(R.id.actionPlayPause) }
+ actionPrev = ImageButton(context).also { it.setId(R.id.actionPrev) }
+ actionNext = ImageButton(context).also { it.setId(R.id.actionNext) }
+
initPlayerHolderMocks()
initSessionHolderMocks()
@@ -203,95 +214,66 @@ public class MediaControlPanelTest : SysuiTestCase() {
device = device,
active = true,
resumeAction = null)
-
- whenever(mediaFlags.areMediaSessionActionsEnabled()).thenReturn(false)
- whenever(mediaFlags.useMediaSessionLayout()).thenReturn(false)
}
- /** Mock view holder for the notification player */
- private fun initPlayerHolderMocks() {
- whenever(holder.player).thenReturn(view)
- whenever(holder.appIcon).thenReturn(appIcon)
- whenever(holder.albumView).thenReturn(albumView)
- whenever(holder.titleText).thenReturn(titleText)
- whenever(holder.artistText).thenReturn(artistText)
+ /**
+ * Initialize elements common to both view holders
+ */
+ private fun initMediaViewHolderMocks(viewHolder: MediaViewHolder) {
+ whenever(viewHolder.player).thenReturn(view)
+ whenever(viewHolder.appIcon).thenReturn(appIcon)
+ whenever(viewHolder.albumView).thenReturn(albumView)
+ whenever(viewHolder.titleText).thenReturn(titleText)
+ whenever(viewHolder.artistText).thenReturn(artistText)
whenever(seamlessBackground.getDrawable(0)).thenReturn(mock(GradientDrawable::class.java))
- whenever(holder.seamless).thenReturn(seamless)
- whenever(holder.seamlessButton).thenReturn(seamlessButton)
- whenever(holder.seamlessIcon).thenReturn(seamlessIcon)
- whenever(holder.seamlessText).thenReturn(seamlessText)
- whenever(holder.seekBar).thenReturn(seekBar)
- whenever(holder.elapsedTimeView).thenReturn(elapsedTimeView)
- whenever(holder.totalTimeView).thenReturn(totalTimeView)
+ whenever(viewHolder.seamless).thenReturn(seamless)
+ whenever(viewHolder.seamlessButton).thenReturn(seamlessButton)
+ whenever(viewHolder.seamlessIcon).thenReturn(seamlessIcon)
+ whenever(viewHolder.seamlessText).thenReturn(seamlessText)
+ whenever(viewHolder.seekBar).thenReturn(seekBar)
// Action buttons
- action0 = ImageButton(context)
- whenever(holder.action0).thenReturn(action0)
- whenever(holder.getAction(R.id.action0)).thenReturn(action0)
- action1 = ImageButton(context)
- whenever(holder.action1).thenReturn(action1)
- whenever(holder.getAction(R.id.action1)).thenReturn(action1)
- action2 = ImageButton(context)
- whenever(holder.action2).thenReturn(action2)
- whenever(holder.getAction(R.id.action2)).thenReturn(action2)
- action3 = ImageButton(context)
- whenever(holder.action3).thenReturn(action3)
- whenever(holder.getAction(R.id.action3)).thenReturn(action3)
- action4 = ImageButton(context)
- whenever(holder.action4).thenReturn(action4)
- whenever(holder.getAction(R.id.action4)).thenReturn(action4)
+ whenever(viewHolder.action0).thenReturn(action0)
+ whenever(viewHolder.getAction(R.id.action0)).thenReturn(action0)
+ whenever(viewHolder.action1).thenReturn(action1)
+ whenever(viewHolder.getAction(R.id.action1)).thenReturn(action1)
+ whenever(viewHolder.action2).thenReturn(action2)
+ whenever(viewHolder.getAction(R.id.action2)).thenReturn(action2)
+ whenever(viewHolder.action3).thenReturn(action3)
+ whenever(viewHolder.getAction(R.id.action3)).thenReturn(action3)
+ whenever(viewHolder.action4).thenReturn(action4)
+ whenever(viewHolder.getAction(R.id.action4)).thenReturn(action4)
// Long press menu
- whenever(holder.longPressText).thenReturn(longPressText)
+ whenever(viewHolder.longPressText).thenReturn(longPressText)
whenever(longPressText.handler).thenReturn(handler)
- whenever(holder.settings).thenReturn(settings)
- whenever(holder.settingsText).thenReturn(settingsText)
- whenever(holder.cancel).thenReturn(cancel)
- whenever(holder.cancelText).thenReturn(cancelText)
- whenever(holder.dismiss).thenReturn(dismiss)
- whenever(holder.dismissText).thenReturn(dismissText)
+ whenever(viewHolder.settings).thenReturn(settings)
+ whenever(viewHolder.settingsText).thenReturn(settingsText)
+ whenever(viewHolder.cancel).thenReturn(cancel)
+ whenever(viewHolder.cancelText).thenReturn(cancelText)
+ whenever(viewHolder.dismiss).thenReturn(dismiss)
+ whenever(viewHolder.dismissText).thenReturn(dismissText)
+ }
+
+ /** Mock view holder for the notification player */
+ private fun initPlayerHolderMocks() {
+ initMediaViewHolderMocks(holder)
+
+ whenever(holder.elapsedTimeView).thenReturn(elapsedTimeView)
+ whenever(holder.totalTimeView).thenReturn(totalTimeView)
}
/** Mock view holder for session player */
private fun initSessionHolderMocks() {
- whenever(sessionHolder.player).thenReturn(view)
- whenever(sessionHolder.albumView).thenReturn(albumView)
- whenever(sessionHolder.appIcon).thenReturn(appIcon)
- whenever(sessionHolder.titleText).thenReturn(titleText)
- whenever(sessionHolder.artistText).thenReturn(artistText)
- val seamlessBackground = mock(RippleDrawable::class.java)
- whenever(seamlessBackground.getDrawable(0)).thenReturn(mock(GradientDrawable::class.java))
- whenever(sessionHolder.seamless).thenReturn(seamless)
- whenever(sessionHolder.seamlessButton).thenReturn(seamlessButton)
- whenever(sessionHolder.seamlessIcon).thenReturn(seamlessIcon)
- whenever(sessionHolder.seamlessText).thenReturn(seamlessText)
- whenever(sessionHolder.seekBar).thenReturn(seekBar)
+ initMediaViewHolderMocks(sessionHolder)
- // Action buttons
- actionPlayPause = ImageButton(context)
+ // Semantic action buttons
whenever(sessionHolder.actionPlayPause).thenReturn(actionPlayPause)
whenever(sessionHolder.getAction(R.id.actionPlayPause)).thenReturn(actionPlayPause)
- actionNext = ImageButton(context)
whenever(sessionHolder.actionNext).thenReturn(actionNext)
whenever(sessionHolder.getAction(R.id.actionNext)).thenReturn(actionNext)
- actionPrev = ImageButton(context)
whenever(sessionHolder.actionPrev).thenReturn(actionPrev)
whenever(sessionHolder.getAction(R.id.actionPrev)).thenReturn(actionPrev)
- actionStart = ImageButton(context)
- whenever(sessionHolder.actionStart).thenReturn(actionStart)
- whenever(sessionHolder.getAction(R.id.actionStart)).thenReturn(actionStart)
- actionEnd = ImageButton(context)
- whenever(sessionHolder.actionEnd).thenReturn(actionEnd)
- whenever(sessionHolder.getAction(R.id.actionEnd)).thenReturn(actionEnd)
-
- // Long press menu
- whenever(sessionHolder.longPressText).thenReturn(longPressText)
- whenever(sessionHolder.settings).thenReturn(settings)
- whenever(sessionHolder.settingsText).thenReturn(settingsText)
- whenever(sessionHolder.cancel).thenReturn(cancel)
- whenever(sessionHolder.cancelText).thenReturn(cancelText)
- whenever(sessionHolder.dismiss).thenReturn(dismiss)
- whenever(sessionHolder.dismissText).thenReturn(dismissText)
}
@After
@@ -309,15 +291,12 @@ public class MediaControlPanelTest : SysuiTestCase() {
@Test
fun bindSemanticActionsOldLayout() {
- whenever(mediaFlags.areMediaSessionActionsEnabled()).thenReturn(true)
- whenever(mediaFlags.useMediaSessionLayout()).thenReturn(false)
-
val icon = Icon.createWithResource(context, android.R.drawable.ic_media_play)
val semanticActions = MediaButton(
playOrPause = MediaAction(icon, Runnable {}, "play"),
nextOrCustom = MediaAction(icon, Runnable {}, "next"),
- startCustom = MediaAction(icon, null, "custom 1"),
- endCustom = MediaAction(icon, null, "custom 2")
+ custom0 = MediaAction(icon, null, "custom 0"),
+ custom1 = MediaAction(icon, null, "custom 1")
)
val state = mediaData.copy(semanticActions = semanticActions)
@@ -325,7 +304,7 @@ public class MediaControlPanelTest : SysuiTestCase() {
player.bindPlayer(state, PACKAGE)
verify(expandedSet).setVisibility(R.id.action0, ConstraintSet.VISIBLE)
- assertThat(action0.contentDescription).isEqualTo("custom 1")
+ assertThat(action0.contentDescription).isEqualTo("custom 0")
assertThat(action0.isEnabled()).isFalse()
verify(expandedSet).setVisibility(R.id.action1, ConstraintSet.INVISIBLE)
@@ -340,41 +319,103 @@ public class MediaControlPanelTest : SysuiTestCase() {
assertThat(action3.contentDescription).isEqualTo("next")
verify(expandedSet).setVisibility(R.id.action4, ConstraintSet.VISIBLE)
- assertThat(action4.contentDescription).isEqualTo("custom 2")
+ assertThat(action4.contentDescription).isEqualTo("custom 1")
assertThat(action4.isEnabled()).isFalse()
}
@Test
fun bindSemanticActionsNewLayout() {
- whenever(mediaFlags.areMediaSessionActionsEnabled()).thenReturn(true)
- whenever(mediaFlags.useMediaSessionLayout()).thenReturn(true)
-
val icon = Icon.createWithResource(context, android.R.drawable.ic_media_play)
val semanticActions = MediaButton(
playOrPause = MediaAction(icon, Runnable {}, "play"),
nextOrCustom = MediaAction(icon, Runnable {}, "next"),
- startCustom = MediaAction(icon, null, "custom 1"),
- endCustom = MediaAction(icon, null, "custom 2")
+ custom0 = MediaAction(icon, null, "custom 0"),
+ custom1 = MediaAction(icon, null, "custom 1")
)
val state = mediaData.copy(semanticActions = semanticActions)
player.attachPlayer(sessionHolder, MediaViewController.TYPE.PLAYER_SESSION)
player.bindPlayer(state, PACKAGE)
- assertThat(actionStart.contentDescription).isEqualTo("custom 1")
- assertThat(actionStart.isEnabled()).isFalse()
-
assertThat(actionPrev.isEnabled()).isFalse()
assertThat(actionPrev.drawable).isNull()
+ verify(collapsedSet).setVisibility(R.id.actionPrev, ConstraintSet.GONE)
assertThat(actionPlayPause.isEnabled()).isTrue()
assertThat(actionPlayPause.contentDescription).isEqualTo("play")
+ verify(collapsedSet).setVisibility(R.id.actionPlayPause, ConstraintSet.VISIBLE)
assertThat(actionNext.isEnabled()).isTrue()
assertThat(actionNext.contentDescription).isEqualTo("next")
+ verify(collapsedSet).setVisibility(R.id.actionNext, ConstraintSet.VISIBLE)
+
+ // Called twice since these IDs are used as generic buttons
+ assertThat(action0.contentDescription).isEqualTo("custom 0")
+ assertThat(action0.isEnabled()).isFalse()
+ verify(collapsedSet, times(2)).setVisibility(R.id.action0, ConstraintSet.GONE)
+
+ assertThat(action1.contentDescription).isEqualTo("custom 1")
+ assertThat(action1.isEnabled()).isFalse()
+ verify(collapsedSet, times(2)).setVisibility(R.id.action1, ConstraintSet.GONE)
+
+ // Verify generic buttons are hidden
+ verify(collapsedSet).setVisibility(R.id.action2, ConstraintSet.GONE)
+ verify(expandedSet).setVisibility(R.id.action2, ConstraintSet.GONE)
+
+ verify(collapsedSet).setVisibility(R.id.action3, ConstraintSet.GONE)
+ verify(expandedSet).setVisibility(R.id.action3, ConstraintSet.GONE)
+
+ verify(collapsedSet).setVisibility(R.id.action4, ConstraintSet.GONE)
+ verify(expandedSet).setVisibility(R.id.action4, ConstraintSet.GONE)
+ }
+
+ @Test
+ fun bindNotificationActionsNewLayout() {
+ val icon = Icon.createWithResource(context, android.R.drawable.ic_media_play)
+ val actions = listOf(
+ MediaAction(icon, Runnable {}, "previous"),
+ MediaAction(icon, Runnable {}, "play"),
+ MediaAction(icon, null, "next"),
+ MediaAction(icon, null, "custom 0"),
+ MediaAction(icon, Runnable {}, "custom 1")
+ )
+ val state = mediaData.copy(actions = actions,
+ actionsToShowInCompact = listOf(1, 2),
+ semanticActions = null)
+
+ player.attachPlayer(sessionHolder, MediaViewController.TYPE.PLAYER_SESSION)
+ player.bindPlayer(state, PACKAGE)
+
+ // Verify semantic actions are hidden
+ verify(collapsedSet).setVisibility(R.id.actionPrev, ConstraintSet.GONE)
+ verify(expandedSet).setVisibility(R.id.actionPrev, ConstraintSet.GONE)
+
+ verify(collapsedSet).setVisibility(R.id.actionPlayPause, ConstraintSet.GONE)
+ verify(expandedSet).setVisibility(R.id.actionPlayPause, ConstraintSet.GONE)
+
+ verify(collapsedSet).setVisibility(R.id.actionNext, ConstraintSet.GONE)
+ verify(expandedSet).setVisibility(R.id.actionNext, ConstraintSet.GONE)
+
+ // Generic actions all enabled
+ assertThat(action0.contentDescription).isEqualTo("previous")
+ assertThat(action0.isEnabled()).isTrue()
+ verify(collapsedSet).setVisibility(R.id.action0, ConstraintSet.GONE)
+
+ assertThat(action1.contentDescription).isEqualTo("play")
+ assertThat(action1.isEnabled()).isTrue()
+ verify(collapsedSet).setVisibility(R.id.action1, ConstraintSet.VISIBLE)
+
+ assertThat(action2.contentDescription).isEqualTo("next")
+ assertThat(action2.isEnabled()).isFalse()
+ verify(collapsedSet).setVisibility(R.id.action2, ConstraintSet.VISIBLE)
+
+ assertThat(action3.contentDescription).isEqualTo("custom 0")
+ assertThat(action3.isEnabled()).isFalse()
+ verify(collapsedSet).setVisibility(R.id.action3, ConstraintSet.GONE)
- assertThat(actionEnd.contentDescription).isEqualTo("custom 2")
- assertThat(actionEnd.isEnabled()).isFalse()
+ assertThat(action4.contentDescription).isEqualTo("custom 1")
+ assertThat(action4.isEnabled()).isTrue()
+ verify(collapsedSet).setVisibility(R.id.action4, ConstraintSet.GONE)
}
@Test
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 6b203bcf6828..82a48efafa3a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataFilterTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataFilterTest.kt
@@ -23,6 +23,7 @@ import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
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.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
@@ -65,6 +66,8 @@ class MediaDataFilterTest : SysuiTestCase() {
@Mock
private lateinit var broadcastDispatcher: BroadcastDispatcher
@Mock
+ private lateinit var broadcastSender: BroadcastSender
+ @Mock
private lateinit var mediaResumeListener: MediaResumeListener
@Mock
private lateinit var mediaDataManager: MediaDataManager
@@ -87,7 +90,7 @@ class MediaDataFilterTest : SysuiTestCase() {
fun setup() {
MockitoAnnotations.initMocks(this)
MediaPlayerData.clear()
- mediaDataFilter = MediaDataFilter(context, broadcastDispatcher,
+ mediaDataFilter = MediaDataFilter(context, broadcastDispatcher, broadcastSender,
lockscreenUserManager, executor, clock)
mediaDataFilter.mediaDataManager = mediaDataManager
mediaDataFilter.addListener(listener)
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 021f70e05b32..066f49a16f19 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
@@ -26,6 +26,7 @@ import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.statusbar.SbnBuilder
import com.android.systemui.tuner.TunerService
import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.capture
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.time.FakeSystemClock
@@ -167,7 +168,7 @@ class MediaDataManagerTest : SysuiTestCase() {
whenever(mediaSmartspaceTarget.featureType).thenReturn(SmartspaceTarget.FEATURE_MEDIA)
whenever(mediaSmartspaceTarget.iconGrid).thenReturn(listOf(mediaRecommendationItem))
whenever(mediaSmartspaceTarget.creationTimeMillis).thenReturn(1234L)
- whenever(mediaFlags.areMediaSessionActionsEnabled()).thenReturn(false)
+ whenever(mediaFlags.areMediaSessionActionsEnabled(any(), any())).thenReturn(false)
}
@After
@@ -594,7 +595,7 @@ class MediaDataManagerTest : SysuiTestCase() {
@Test
fun testPlaybackActions_noState_usesNotification() {
val desc = "Notification Action"
- whenever(mediaFlags.areMediaSessionActionsEnabled()).thenReturn(true)
+ whenever(mediaFlags.areMediaSessionActionsEnabled(any(), any())).thenReturn(true)
whenever(controller.playbackState).thenReturn(null)
val notifWithAction = SbnBuilder().run {
@@ -621,7 +622,7 @@ class MediaDataManagerTest : SysuiTestCase() {
@Test
fun testPlaybackActions_hasPrevNext() {
val customDesc = arrayOf("custom 1", "custom 2", "custom 3", "custom 4")
- whenever(mediaFlags.areMediaSessionActionsEnabled()).thenReturn(true)
+ whenever(mediaFlags.areMediaSessionActionsEnabled(any(), any())).thenReturn(true)
val stateActions = PlaybackState.ACTION_PLAY or
PlaybackState.ACTION_SKIP_TO_PREVIOUS or
PlaybackState.ACTION_SKIP_TO_NEXT
@@ -659,17 +660,17 @@ class MediaDataManagerTest : SysuiTestCase() {
actions.nextOrCustom!!.action!!.run()
verify(transportControls).skipToNext()
- assertThat(actions.startCustom).isNotNull()
- assertThat(actions.startCustom!!.contentDescription).isEqualTo(customDesc[0])
+ assertThat(actions.custom0).isNotNull()
+ assertThat(actions.custom0!!.contentDescription).isEqualTo(customDesc[0])
- assertThat(actions.endCustom).isNotNull()
- assertThat(actions.endCustom!!.contentDescription).isEqualTo(customDesc[1])
+ assertThat(actions.custom1).isNotNull()
+ assertThat(actions.custom1!!.contentDescription).isEqualTo(customDesc[1])
}
@Test
fun testPlaybackActions_noPrevNext_usesCustom() {
val customDesc = arrayOf("custom 1", "custom 2", "custom 3", "custom 4", "custom 5")
- whenever(mediaFlags.areMediaSessionActionsEnabled()).thenReturn(true)
+ whenever(mediaFlags.areMediaSessionActionsEnabled(any(), any())).thenReturn(true)
val stateActions = PlaybackState.ACTION_PLAY
val stateBuilder = PlaybackState.Builder()
.setActions(stateActions)
@@ -697,17 +698,17 @@ class MediaDataManagerTest : SysuiTestCase() {
assertThat(actions.nextOrCustom).isNotNull()
assertThat(actions.nextOrCustom!!.contentDescription).isEqualTo(customDesc[1])
- assertThat(actions.startCustom).isNotNull()
- assertThat(actions.startCustom!!.contentDescription).isEqualTo(customDesc[2])
+ assertThat(actions.custom0).isNotNull()
+ assertThat(actions.custom0!!.contentDescription).isEqualTo(customDesc[2])
- assertThat(actions.endCustom).isNotNull()
- assertThat(actions.endCustom!!.contentDescription).isEqualTo(customDesc[3])
+ assertThat(actions.custom1).isNotNull()
+ assertThat(actions.custom1!!.contentDescription).isEqualTo(customDesc[3])
}
@Test
fun testPlaybackActions_reservedSpace() {
val customDesc = arrayOf("custom 1", "custom 2", "custom 3", "custom 4")
- whenever(mediaFlags.areMediaSessionActionsEnabled()).thenReturn(true)
+ whenever(mediaFlags.areMediaSessionActionsEnabled(any(), any())).thenReturn(true)
val stateActions = PlaybackState.ACTION_PLAY
val stateBuilder = PlaybackState.Builder()
.setActions(stateActions)
@@ -737,10 +738,10 @@ class MediaDataManagerTest : SysuiTestCase() {
assertThat(actions.prevOrCustom).isNull()
assertThat(actions.nextOrCustom).isNull()
- assertThat(actions.startCustom).isNotNull()
- assertThat(actions.startCustom!!.contentDescription).isEqualTo(customDesc[0])
+ assertThat(actions.custom0).isNotNull()
+ assertThat(actions.custom0!!.contentDescription).isEqualTo(customDesc[0])
- assertThat(actions.endCustom).isNotNull()
- assertThat(actions.endCustom!!.contentDescription).isEqualTo(customDesc[1])
+ assertThat(actions.custom1).isNotNull()
+ assertThat(actions.custom1!!.contentDescription).isEqualTo(customDesc[1])
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt
index b359ae5317b1..203eb47165e0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt
@@ -117,9 +117,9 @@ class MediaHierarchyManagerTest : SysuiTestCase() {
dreamOverlayStateController)
verify(wakefulnessLifecycle).addObserver(wakefullnessObserver.capture())
verify(statusBarStateController).addCallback(statusBarCallback.capture())
- setupHost(lockHost, MediaHierarchyManager.LOCATION_LOCKSCREEN)
- setupHost(qsHost, MediaHierarchyManager.LOCATION_QS)
- setupHost(qqsHost, MediaHierarchyManager.LOCATION_QQS)
+ setupHost(lockHost, MediaHierarchyManager.LOCATION_LOCKSCREEN, LOCKSCREEN_TOP)
+ setupHost(qsHost, MediaHierarchyManager.LOCATION_QS, QS_TOP)
+ setupHost(qqsHost, MediaHierarchyManager.LOCATION_QQS, QQS_TOP)
`when`(statusBarStateController.state).thenReturn(StatusBarState.SHADE)
`when`(mediaCarouselController.mediaCarouselScrollHandler)
.thenReturn(mediaCarouselScrollHandler)
@@ -130,9 +130,9 @@ class MediaHierarchyManagerTest : SysuiTestCase() {
clearInvocations(mediaCarouselController)
}
- private fun setupHost(host: MediaHost, location: Int) {
+ private fun setupHost(host: MediaHost, location: Int, top: Int) {
`when`(host.location).thenReturn(location)
- `when`(host.currentBounds).thenReturn(Rect())
+ `when`(host.currentBounds).thenReturn(Rect(0, top, 0, top))
`when`(host.hostView).thenReturn(uniqueObjectHostView)
`when`(host.visible).thenReturn(true)
mediaHiearchyManager.register(host)
@@ -223,6 +223,18 @@ class MediaHierarchyManagerTest : SysuiTestCase() {
}
@Test
+ fun calculateTransformationType_onLockSplitShade_goingToFullShade_mediaInvisible_returnsFade() {
+ enableSplitShade()
+ goToLockscreen()
+ expandQS()
+ whenever(lockHost.visible).thenReturn(false)
+ mediaHiearchyManager.setTransitionToFullShadeAmount(10000f)
+
+ val transformType = mediaHiearchyManager.calculateTransformationType()
+ assertThat(transformType).isEqualTo(MediaHierarchyManager.TRANSFORMATION_TYPE_FADE)
+ }
+
+ @Test
fun calculateTransformationType_onLockShade_inSplitShade_notExpanding_returnsFade() {
enableSplitShade()
goToLockscreen()
@@ -257,6 +269,20 @@ class MediaHierarchyManagerTest : SysuiTestCase() {
verify(mediaCarouselController).closeGuts()
}
+ @Test
+ fun getGuidedTransformationTranslationY_notInGuidedTransformation_returnsNegativeNumber() {
+ assertThat(mediaHiearchyManager.getGuidedTransformationTranslationY()).isLessThan(0)
+ }
+
+ @Test
+ fun getGuidedTransformationTranslationY_inGuidedTransformation_returnsCurrentTranslation() {
+ enterGuidedTransformation()
+
+ val expectedTranslation = LOCKSCREEN_TOP - QS_TOP
+ assertThat(mediaHiearchyManager.getGuidedTransformationTranslationY())
+ .isEqualTo(expectedTranslation)
+ }
+
private fun enableSplitShade() {
context.getOrCreateTestableResources().addOverride(
R.bool.config_use_split_notification_shade, true
@@ -284,4 +310,16 @@ class MediaHierarchyManagerTest : SysuiTestCase() {
private fun expandQS() {
mediaHiearchyManager.qsExpansion = 1.0f
}
+
+ private fun enterGuidedTransformation() {
+ mediaHiearchyManager.qsExpansion = 1.0f
+ goToLockscreen()
+ mediaHiearchyManager.setTransitionToFullShadeAmount(123f)
+ }
+
+ companion object {
+ private const val QQS_TOP = 123
+ private const val QS_TOP = 456
+ private const val LOCKSCREEN_TOP = 789
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaViewControllerTest.kt
new file mode 100644
index 000000000000..b7d5ba170e6d
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaViewControllerTest.kt
@@ -0,0 +1,55 @@
+package com.android.systemui.media
+
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import android.view.View
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.util.animation.MeasurementInput
+import com.android.systemui.util.animation.TransitionLayout
+import com.android.systemui.util.animation.TransitionViewState
+import junit.framework.Assert.assertTrue
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/**
+ * Tests for {@link MediaViewController}.
+ */
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper
+class MediaViewControllerTest : SysuiTestCase() {
+ private val configurationController =
+ com.android.systemui.statusbar.phone.ConfigurationControllerImpl(context)
+ private val mediaHostStatesManager = MediaHostStatesManager()
+ private val mediaViewController =
+ MediaViewController(context, configurationController, mediaHostStatesManager)
+ private val mediaHostStateHolder = MediaHost.MediaHostStateHolder()
+ private var transitionLayout = TransitionLayout(context, /* attrs */ null, /* defStyleAttr */ 0)
+
+ @Before
+ fun setUp() {
+ mediaViewController.attach(transitionLayout, MediaViewController.TYPE.PLAYER)
+ }
+
+ @Test
+ fun testObtainViewState_applySquishFraction_toTransitionViewState_height() {
+ transitionLayout.measureState = TransitionViewState().apply {
+ this.height = 100
+ }
+ mediaHostStateHolder.expansion = 1f
+ val widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(100, View.MeasureSpec.EXACTLY)
+ val heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(100, View.MeasureSpec.EXACTLY)
+ mediaHostStateHolder.measurementInput =
+ MeasurementInput(widthMeasureSpec, heightMeasureSpec)
+
+ // Test no squish
+ mediaHostStateHolder.squishFraction = 1f
+ assertTrue(mediaViewController.obtainViewState(mediaHostStateHolder)!!.height == 100)
+
+ // Test half squish
+ mediaHostStateHolder.squishFraction = 0.5f
+ assertTrue(mediaViewController.obtainViewState(mediaHostStateHolder)!!.height == 50)
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarObserverTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarObserverTest.kt
index 3c2392a30731..7ac15125ea7e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarObserverTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarObserverTest.kt
@@ -26,29 +26,33 @@ import com.android.systemui.R
import com.android.systemui.SysuiTestCase
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.mockito.Mock
-import org.mockito.Mockito.mock
+import org.mockito.Mockito.verify
+import org.mockito.junit.MockitoJUnit
import org.mockito.Mockito.`when` as whenever
@SmallTest
@RunWith(AndroidTestingRunner::class)
@TestableLooper.RunWithLooper
-public class SeekBarObserverTest : SysuiTestCase() {
+class SeekBarObserverTest : SysuiTestCase() {
private val disabledHeight = 1
private val enabledHeight = 2
private lateinit var observer: SeekBarObserver
@Mock private lateinit var mockHolder: PlayerViewHolder
+ @Mock private lateinit var mockSquigglyProgress: SquigglyProgress
private lateinit var seekBarView: SeekBar
private lateinit var elapsedTimeView: TextView
private lateinit var totalTimeView: TextView
+ @JvmField @Rule val mockitoRule = MockitoJUnit.rule()
+
@Before
fun setUp() {
- mockHolder = mock(PlayerViewHolder::class.java)
context.orCreateTestableResources
.addOverride(R.dimen.qs_media_enabled_seekbar_height, enabledHeight)
@@ -56,6 +60,7 @@ public class SeekBarObserverTest : SysuiTestCase() {
.addOverride(R.dimen.qs_media_disabled_seekbar_height, disabledHeight)
seekBarView = SeekBar(context)
+ seekBarView.progressDrawable = mockSquigglyProgress
elapsedTimeView = TextView(context)
totalTimeView = TextView(context)
whenever(mockHolder.seekBar).thenReturn(seekBarView)
@@ -69,7 +74,7 @@ public class SeekBarObserverTest : SysuiTestCase() {
fun seekBarGone() {
// WHEN seek bar is disabled
val isEnabled = false
- val data = SeekBarViewModel.Progress(isEnabled, false, null, 0)
+ val data = SeekBarViewModel.Progress(isEnabled, false, false, null, 0)
observer.onChanged(data)
// THEN seek bar shows just a thin line with no text
assertThat(seekBarView.isEnabled()).isFalse()
@@ -84,7 +89,7 @@ public class SeekBarObserverTest : SysuiTestCase() {
fun seekBarVisible() {
// WHEN seek bar is enabled
val isEnabled = true
- val data = SeekBarViewModel.Progress(isEnabled, true, 3000, 12000)
+ val data = SeekBarViewModel.Progress(isEnabled, true, false, 3000, 12000)
observer.onChanged(data)
// THEN seek bar is visible and thick
assertThat(seekBarView.getVisibility()).isEqualTo(View.VISIBLE)
@@ -96,7 +101,7 @@ public class SeekBarObserverTest : SysuiTestCase() {
@Test
fun seekBarProgress() {
// WHEN part of the track has been played
- val data = SeekBarViewModel.Progress(true, true, 3000, 120000)
+ val data = SeekBarViewModel.Progress(true, true, true, 3000, 120000)
observer.onChanged(data)
// THEN seek bar shows the progress
assertThat(seekBarView.progress).isEqualTo(3000)
@@ -112,7 +117,7 @@ public class SeekBarObserverTest : SysuiTestCase() {
fun seekBarDisabledWhenSeekNotAvailable() {
// WHEN seek is not available
val isSeekAvailable = false
- val data = SeekBarViewModel.Progress(true, isSeekAvailable, 3000, 120000)
+ val data = SeekBarViewModel.Progress(true, isSeekAvailable, false, 3000, 120000)
observer.onChanged(data)
// THEN seek bar is not enabled
assertThat(seekBarView.isEnabled()).isFalse()
@@ -122,9 +127,29 @@ public class SeekBarObserverTest : SysuiTestCase() {
fun seekBarEnabledWhenSeekNotAvailable() {
// WHEN seek is available
val isSeekAvailable = true
- val data = SeekBarViewModel.Progress(true, isSeekAvailable, 3000, 120000)
+ val data = SeekBarViewModel.Progress(true, isSeekAvailable, false, 3000, 120000)
observer.onChanged(data)
// THEN seek bar is not enabled
assertThat(seekBarView.isEnabled()).isTrue()
}
+
+ @Test
+ fun seekBarPlaying() {
+ // WHEN playing
+ val isPlaying = true
+ val data = SeekBarViewModel.Progress(true, true, isPlaying, 3000, 120000)
+ observer.onChanged(data)
+ // THEN progress drawable is animating
+ verify(mockSquigglyProgress).animate = true
+ }
+
+ @Test
+ fun seekBarNotPlaying() {
+ // WHEN not playing
+ val isPlaying = false
+ val data = SeekBarViewModel.Progress(true, true, isPlaying, 3000, 120000)
+ observer.onChanged(data)
+ // THEN progress drawable is not animating
+ verify(mockSquigglyProgress).animate = false
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/SquigglyProgressTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/SquigglyProgressTest.kt
new file mode 100644
index 000000000000..0787fd65eae1
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/SquigglyProgressTest.kt
@@ -0,0 +1,118 @@
+package com.android.systemui.media
+
+import android.graphics.Canvas
+import android.graphics.Color
+import android.graphics.LightingColorFilter
+import android.graphics.Paint
+import android.graphics.Rect
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.util.mockito.any
+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.mockito.ArgumentCaptor
+import org.mockito.Captor
+import org.mockito.Mock
+import org.mockito.Mockito.anyFloat
+import org.mockito.Mockito.verify
+import org.mockito.junit.MockitoJUnit
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper
+class SquigglyProgressTest : SysuiTestCase() {
+
+ private val colorFilter = LightingColorFilter(Color.RED, Color.BLUE)
+ private val strokeWidth = 5f
+ private val alpha = 128
+ private val tint = Color.GREEN
+
+ lateinit var squigglyProgress: SquigglyProgress
+ @Mock lateinit var canvas: Canvas
+ @Captor lateinit var wavePaintCaptor: ArgumentCaptor<Paint>
+ @Captor lateinit var linePaintCaptor: ArgumentCaptor<Paint>
+ @JvmField @Rule val mockitoRule = MockitoJUnit.rule()
+
+ @Before
+ fun setup() {
+ squigglyProgress = SquigglyProgress()
+ squigglyProgress.waveLength = 30f
+ squigglyProgress.lineAmplitude = 10f
+ squigglyProgress.phaseSpeed = 8f
+ squigglyProgress.strokeWidth = strokeWidth
+ squigglyProgress.bounds = Rect(0, 0, 300, 30)
+ }
+
+ @Test
+ fun testDrawPathAndLine() {
+ squigglyProgress.draw(canvas)
+
+ verify(canvas).drawPath(any(), wavePaintCaptor.capture())
+ verify(canvas).drawLine(anyFloat(), anyFloat(), anyFloat(), anyFloat(),
+ linePaintCaptor.capture())
+ }
+
+ @Test
+ fun testOnLevelChanged() {
+ assertThat(squigglyProgress.setLevel(5)).isFalse()
+ squigglyProgress.animate = true
+ assertThat(squigglyProgress.setLevel(4)).isTrue()
+ }
+
+ @Test
+ fun testStrokeWidth() {
+ squigglyProgress.draw(canvas)
+
+ verify(canvas).drawPath(any(), wavePaintCaptor.capture())
+ verify(canvas).drawLine(anyFloat(), anyFloat(), anyFloat(), anyFloat(),
+ linePaintCaptor.capture())
+
+ assertThat(wavePaintCaptor.value.strokeWidth).isEqualTo(strokeWidth)
+ assertThat(linePaintCaptor.value.strokeWidth).isEqualTo(strokeWidth)
+ }
+
+ @Test
+ fun testAlpha() {
+ squigglyProgress.alpha = alpha
+ squigglyProgress.draw(canvas)
+
+ verify(canvas).drawPath(any(), wavePaintCaptor.capture())
+ verify(canvas).drawLine(anyFloat(), anyFloat(), anyFloat(), anyFloat(),
+ linePaintCaptor.capture())
+
+ assertThat(squigglyProgress.alpha).isEqualTo(alpha)
+ assertThat(wavePaintCaptor.value.alpha).isEqualTo(alpha)
+ assertThat(linePaintCaptor.value.alpha).isEqualTo((alpha / 255f * DISABLED_ALPHA).toInt())
+ }
+
+ @Test
+ fun testColorFilter() {
+ squigglyProgress.colorFilter = colorFilter
+ squigglyProgress.draw(canvas)
+
+ verify(canvas).drawPath(any(), wavePaintCaptor.capture())
+ verify(canvas).drawLine(anyFloat(), anyFloat(), anyFloat(), anyFloat(),
+ linePaintCaptor.capture())
+
+ assertThat(wavePaintCaptor.value.colorFilter).isEqualTo(colorFilter)
+ assertThat(linePaintCaptor.value.colorFilter).isEqualTo(colorFilter)
+ }
+
+ @Test
+ fun testTint() {
+ squigglyProgress.setTint(tint)
+ squigglyProgress.draw(canvas)
+
+ verify(canvas).drawPath(any(), wavePaintCaptor.capture())
+ verify(canvas).drawLine(anyFloat(), anyFloat(), anyFloat(), anyFloat(),
+ linePaintCaptor.capture())
+
+ assertThat(wavePaintCaptor.value.color).isEqualTo(tint)
+ assertThat(linePaintCaptor.value.color).isEqualTo(tint)
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java
index 2be30b39763e..380fa6d50df7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java
@@ -37,19 +37,21 @@ import android.widget.TextView;
import androidx.core.graphics.drawable.IconCompat;
import androidx.test.filters.SmallTest;
-import com.android.internal.logging.UiEventLogger;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.animation.DialogLaunchAnimator;
+import com.android.systemui.broadcast.BroadcastSender;
+import com.android.systemui.media.nearby.NearbyMediaDevicesManager;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
-import com.android.systemui.statusbar.phone.ShadeController;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.Optional;
+
@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
@@ -61,27 +63,28 @@ public class MediaOutputBaseDialogTest extends SysuiTestCase {
private MediaOutputBaseAdapter mMediaOutputBaseAdapter = mock(MediaOutputBaseAdapter.class);
private MediaSessionManager mMediaSessionManager = mock(MediaSessionManager.class);
private LocalBluetoothManager mLocalBluetoothManager = mock(LocalBluetoothManager.class);
- private ShadeController mShadeController = mock(ShadeController.class);
private ActivityStarter mStarter = mock(ActivityStarter.class);
+ private BroadcastSender mBroadcastSender = mock(BroadcastSender.class);
private NotificationEntryManager mNotificationEntryManager =
mock(NotificationEntryManager.class);
- private final UiEventLogger mUiEventLogger = mock(UiEventLogger.class);
+ private NearbyMediaDevicesManager mNearbyMediaDevicesManager = mock(
+ NearbyMediaDevicesManager.class);
private final DialogLaunchAnimator mDialogLaunchAnimator = mock(DialogLaunchAnimator.class);
private MediaOutputBaseDialogImpl mMediaOutputBaseDialogImpl;
private MediaOutputController mMediaOutputController;
private int mHeaderIconRes;
private IconCompat mIconCompat;
- private Drawable mAppSourceDrawable;
private CharSequence mHeaderTitle;
private CharSequence mHeaderSubtitle;
@Before
public void setUp() {
- mMediaOutputController = new MediaOutputController(mContext, TEST_PACKAGE, false,
- mMediaSessionManager, mLocalBluetoothManager, mShadeController, mStarter,
- mNotificationEntryManager, mUiEventLogger, mDialogLaunchAnimator);
- mMediaOutputBaseDialogImpl = new MediaOutputBaseDialogImpl(mContext,
+ mMediaOutputController = new MediaOutputController(mContext, TEST_PACKAGE,
+ mMediaSessionManager, mLocalBluetoothManager, mStarter,
+ mNotificationEntryManager, mDialogLaunchAnimator,
+ Optional.of(mNearbyMediaDevicesManager));
+ mMediaOutputBaseDialogImpl = new MediaOutputBaseDialogImpl(mContext, mBroadcastSender,
mMediaOutputController);
mMediaOutputBaseDialogImpl.onCreate(new Bundle());
}
@@ -172,15 +175,16 @@ public class MediaOutputBaseDialogTest extends SysuiTestCase {
class MediaOutputBaseDialogImpl extends MediaOutputBaseDialog {
- MediaOutputBaseDialogImpl(Context context, MediaOutputController mediaOutputController) {
- super(context, mediaOutputController);
+ MediaOutputBaseDialogImpl(Context context, BroadcastSender broadcastSender,
+ MediaOutputController mediaOutputController) {
+ super(context, broadcastSender, mediaOutputController);
mAdapter = mMediaOutputBaseAdapter;
}
@Override
Drawable getAppSourceIcon() {
- return mAppSourceDrawable;
+ return null;
}
@Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java
index 789822e262d5..d2dae745bcdc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java
@@ -33,9 +33,11 @@ import android.content.Context;
import android.graphics.drawable.Icon;
import android.media.MediaDescription;
import android.media.MediaMetadata;
+import android.media.NearbyDevice;
import android.media.RoutingSessionInfo;
import android.media.session.MediaController;
import android.media.session.MediaSessionManager;
+import android.os.RemoteException;
import android.service.notification.StatusBarNotification;
import android.testing.AndroidTestingRunner;
import android.text.TextUtils;
@@ -43,7 +45,6 @@ import android.text.TextUtils;
import androidx.core.graphics.drawable.IconCompat;
import androidx.test.filters.SmallTest;
-import com.android.internal.logging.UiEventLogger;
import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.media.LocalMediaManager;
@@ -51,10 +52,12 @@ import com.android.settingslib.media.MediaDevice;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.animation.DialogLaunchAnimator;
+import com.android.systemui.media.nearby.NearbyMediaDevicesManager;
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.ShadeController;
+
+import com.google.common.collect.ImmutableList;
import org.junit.Before;
import org.junit.Test;
@@ -62,6 +65,7 @@ import org.junit.runner.RunWith;
import java.util.ArrayList;
import java.util.List;
+import java.util.Optional;
@SmallTest
@RunWith(AndroidTestingRunner.class)
@@ -86,19 +90,22 @@ public class MediaOutputControllerTest extends SysuiTestCase {
private MediaOutputController.Callback mCb = mock(MediaOutputController.Callback.class);
private MediaDevice mMediaDevice1 = mock(MediaDevice.class);
private MediaDevice mMediaDevice2 = mock(MediaDevice.class);
+ private NearbyDevice mNearbyDevice1 = mock(NearbyDevice.class);
+ private NearbyDevice mNearbyDevice2 = mock(NearbyDevice.class);
private MediaMetadata mMediaMetadata = mock(MediaMetadata.class);
private RoutingSessionInfo mRemoteSessionInfo = mock(RoutingSessionInfo.class);
- private ShadeController mShadeController = mock(ShadeController.class);
private ActivityStarter mStarter = mock(ActivityStarter.class);
private CommonNotifCollection mNotifCollection = mock(CommonNotifCollection.class);
- private final UiEventLogger mUiEventLogger = mock(UiEventLogger.class);
private final DialogLaunchAnimator mDialogLaunchAnimator = mock(DialogLaunchAnimator.class);
+ private final NearbyMediaDevicesManager mNearbyMediaDevicesManager = mock(
+ NearbyMediaDevicesManager.class);
private Context mSpyContext;
private MediaOutputController mMediaOutputController;
private LocalMediaManager mLocalMediaManager;
private List<MediaController> mMediaControllers = new ArrayList<>();
private List<MediaDevice> mMediaDevices = new ArrayList<>();
+ private List<NearbyDevice> mNearbyDevices = new ArrayList<>();
private MediaDescription mMediaDescription;
private List<RoutingSessionInfo> mRoutingSessionInfos = new ArrayList<>();
@@ -113,9 +120,10 @@ public class MediaOutputControllerTest extends SysuiTestCase {
when(mLocalBluetoothManager.getCachedDeviceManager()).thenReturn(
mCachedBluetoothDeviceManager);
- mMediaOutputController = new MediaOutputController(mSpyContext, TEST_PACKAGE_NAME, false,
- mMediaSessionManager, mLocalBluetoothManager, mShadeController, mStarter,
- mNotifCollection, mUiEventLogger, mDialogLaunchAnimator);
+ mMediaOutputController = new MediaOutputController(mSpyContext, TEST_PACKAGE_NAME,
+ mMediaSessionManager, mLocalBluetoothManager, mStarter,
+ mNotifCollection, mDialogLaunchAnimator,
+ Optional.of(mNearbyMediaDevicesManager));
mLocalMediaManager = spy(mMediaOutputController.mLocalMediaManager);
mMediaOutputController.mLocalMediaManager = mLocalMediaManager;
MediaDescription.Builder builder = new MediaDescription.Builder();
@@ -127,6 +135,13 @@ public class MediaOutputControllerTest extends SysuiTestCase {
when(mMediaDevice2.getId()).thenReturn(TEST_DEVICE_2_ID);
mMediaDevices.add(mMediaDevice1);
mMediaDevices.add(mMediaDevice2);
+
+ when(mNearbyDevice1.getMediaRoute2Id()).thenReturn(TEST_DEVICE_1_ID);
+ when(mNearbyDevice1.getRangeZone()).thenReturn(NearbyDevice.RANGE_CLOSE);
+ when(mNearbyDevice2.getMediaRoute2Id()).thenReturn(TEST_DEVICE_2_ID);
+ when(mNearbyDevice2.getRangeZone()).thenReturn(NearbyDevice.RANGE_FAR);
+ mNearbyDevices.add(mNearbyDevice1);
+ mNearbyDevices.add(mNearbyDevice2);
}
@Test
@@ -157,9 +172,10 @@ public class MediaOutputControllerTest extends SysuiTestCase {
@Test
public void start_withoutPackageName_verifyMediaControllerInit() {
- mMediaOutputController = new MediaOutputController(mSpyContext, null, false,
- mMediaSessionManager, mLocalBluetoothManager, mShadeController, mStarter,
- mNotifCollection, mUiEventLogger, mDialogLaunchAnimator);
+ mMediaOutputController = new MediaOutputController(mSpyContext, null,
+ mMediaSessionManager, mLocalBluetoothManager, mStarter,
+ mNotifCollection, mDialogLaunchAnimator,
+ Optional.of(mNearbyMediaDevicesManager));
mMediaOutputController.start(mCb);
@@ -167,6 +183,13 @@ public class MediaOutputControllerTest extends SysuiTestCase {
}
@Test
+ public void start_nearbyMediaDevicesManagerNotNull_registersNearbyDevicesCallback() {
+ mMediaOutputController.start(mCb);
+
+ verify(mNearbyMediaDevicesManager).registerNearbyDevicesCallback(any());
+ }
+
+ @Test
public void stop_withPackageName_verifyMediaControllerDeinit() {
mMediaOutputController.start(mCb);
reset(mMediaController);
@@ -178,9 +201,10 @@ public class MediaOutputControllerTest extends SysuiTestCase {
@Test
public void stop_withoutPackageName_verifyMediaControllerDeinit() {
- mMediaOutputController = new MediaOutputController(mSpyContext, null, false,
- mMediaSessionManager, mLocalBluetoothManager, mShadeController, mStarter,
- mNotifCollection, mUiEventLogger, mDialogLaunchAnimator);
+ mMediaOutputController = new MediaOutputController(mSpyContext, null,
+ mMediaSessionManager, mLocalBluetoothManager, mStarter,
+ mNotifCollection, mDialogLaunchAnimator,
+ Optional.of(mNearbyMediaDevicesManager));
mMediaOutputController.start(mCb);
@@ -189,6 +213,39 @@ public class MediaOutputControllerTest extends SysuiTestCase {
verify(mMediaController, never()).unregisterCallback(any());
}
+
+ @Test
+ public void stop_nearbyMediaDevicesManagerNotNull_unregistersNearbyDevicesCallback() {
+ mMediaOutputController.start(mCb);
+ reset(mMediaController);
+
+ mMediaOutputController.stop();
+
+ verify(mNearbyMediaDevicesManager).unregisterNearbyDevicesCallback(any());
+ }
+
+ @Test
+ public void onDevicesUpdated_unregistersNearbyDevicesCallback() throws RemoteException {
+ mMediaOutputController.start(mCb);
+
+ mMediaOutputController.onDevicesUpdated(ImmutableList.of());
+
+ verify(mNearbyMediaDevicesManager).unregisterNearbyDevicesCallback(any());
+ }
+
+ @Test
+ public void onDeviceListUpdate_withNearbyDevices_updatesRangeInformation()
+ throws RemoteException {
+ mMediaOutputController.start(mCb);
+ reset(mCb);
+
+ mMediaOutputController.onDevicesUpdated(mNearbyDevices);
+ mMediaOutputController.onDeviceListUpdate(mMediaDevices);
+
+ verify(mMediaDevice1).setRangeZone(NearbyDevice.RANGE_CLOSE);
+ verify(mMediaDevice2).setRangeZone(NearbyDevice.RANGE_FAR);
+ }
+
@Test
public void onDeviceListUpdate_verifyDeviceListCallback() {
mMediaOutputController.start(mCb);
@@ -449,9 +506,10 @@ public class MediaOutputControllerTest extends SysuiTestCase {
@Test
public void getNotificationLargeIcon_withoutPackageName_returnsNull() {
- mMediaOutputController = new MediaOutputController(mSpyContext, null, false,
- mMediaSessionManager, mLocalBluetoothManager, mShadeController, mStarter,
- mNotifCollection, mUiEventLogger, mDialogLaunchAnimator);
+ mMediaOutputController = new MediaOutputController(mSpyContext, null,
+ mMediaSessionManager, mLocalBluetoothManager, mStarter,
+ mNotifCollection, mDialogLaunchAnimator,
+ Optional.of(mNearbyMediaDevicesManager));
assertThat(mMediaOutputController.getNotificationIcon()).isNull();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java
index 8a3ea562269d..db56f875dd5c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java
@@ -37,9 +37,10 @@ import com.android.settingslib.media.LocalMediaManager;
import com.android.settingslib.media.MediaDevice;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.animation.DialogLaunchAnimator;
+import com.android.systemui.broadcast.BroadcastSender;
+import com.android.systemui.media.nearby.NearbyMediaDevicesManager;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
-import com.android.systemui.statusbar.phone.ShadeController;
import org.junit.After;
import org.junit.Before;
@@ -48,6 +49,7 @@ import org.junit.runner.RunWith;
import java.util.ArrayList;
import java.util.List;
+import java.util.Optional;
@SmallTest
@RunWith(AndroidTestingRunner.class)
@@ -59,14 +61,16 @@ public class MediaOutputDialogTest extends SysuiTestCase {
// Mock
private final MediaSessionManager mMediaSessionManager = mock(MediaSessionManager.class);
private final LocalBluetoothManager mLocalBluetoothManager = mock(LocalBluetoothManager.class);
- private final ShadeController mShadeController = mock(ShadeController.class);
private final ActivityStarter mStarter = mock(ActivityStarter.class);
+ private final BroadcastSender mBroadcastSender = mock(BroadcastSender.class);
private final LocalMediaManager mLocalMediaManager = mock(LocalMediaManager.class);
private final MediaDevice mMediaDevice = mock(MediaDevice.class);
private final NotificationEntryManager mNotificationEntryManager =
mock(NotificationEntryManager.class);
private final UiEventLogger mUiEventLogger = mock(UiEventLogger.class);
private final DialogLaunchAnimator mDialogLaunchAnimator = mock(DialogLaunchAnimator.class);
+ private final NearbyMediaDevicesManager mNearbyMediaDevicesManager = mock(
+ NearbyMediaDevicesManager.class);
private MediaOutputDialog mMediaOutputDialog;
private MediaOutputController mMediaOutputController;
@@ -74,11 +78,12 @@ public class MediaOutputDialogTest extends SysuiTestCase {
@Before
public void setUp() {
- mMediaOutputController = new MediaOutputController(mContext, TEST_PACKAGE, false,
- mMediaSessionManager, mLocalBluetoothManager, mShadeController, mStarter,
- mNotificationEntryManager, mUiEventLogger, mDialogLaunchAnimator);
+ mMediaOutputController = new MediaOutputController(mContext, TEST_PACKAGE,
+ mMediaSessionManager, mLocalBluetoothManager, mStarter,
+ mNotificationEntryManager, mDialogLaunchAnimator,
+ Optional.of(mNearbyMediaDevicesManager));
mMediaOutputController.mLocalMediaManager = mLocalMediaManager;
- mMediaOutputDialog = new MediaOutputDialog(mContext, false,
+ mMediaOutputDialog = new MediaOutputDialog(mContext, false, mBroadcastSender,
mMediaOutputController, mUiEventLogger);
mMediaOutputDialog.show();
@@ -124,7 +129,7 @@ public class MediaOutputDialogTest extends SysuiTestCase {
// Check the visibility metric logging by creating a new MediaOutput dialog,
// and verify if the calling times increases.
public void onCreate_ShouldLogVisibility() {
- MediaOutputDialog testDialog = new MediaOutputDialog(mContext, false,
+ MediaOutputDialog testDialog = new MediaOutputDialog(mContext, false, mBroadcastSender,
mMediaOutputController, mUiEventLogger);
testDialog.show();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputGroupDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputGroupDialogTest.java
index e8cd6c88956d..0cdde0775b2d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputGroupDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputGroupDialogTest.java
@@ -28,16 +28,16 @@ import android.view.View;
import androidx.test.filters.SmallTest;
-import com.android.internal.logging.UiEventLogger;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.media.LocalMediaManager;
import com.android.settingslib.media.MediaDevice;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.animation.DialogLaunchAnimator;
+import com.android.systemui.broadcast.BroadcastSender;
+import com.android.systemui.media.nearby.NearbyMediaDevicesManager;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
-import com.android.systemui.statusbar.phone.ShadeController;
import org.junit.After;
import org.junit.Before;
@@ -46,6 +46,7 @@ import org.junit.runner.RunWith;
import java.util.ArrayList;
import java.util.List;
+import java.util.Optional;
@SmallTest
@RunWith(AndroidTestingRunner.class)
@@ -57,15 +58,16 @@ public class MediaOutputGroupDialogTest extends SysuiTestCase {
// Mock
private MediaSessionManager mMediaSessionManager = mock(MediaSessionManager.class);
private LocalBluetoothManager mLocalBluetoothManager = mock(LocalBluetoothManager.class);
- private ShadeController mShadeController = mock(ShadeController.class);
private ActivityStarter mStarter = mock(ActivityStarter.class);
+ private BroadcastSender mBroadcastSender = mock(BroadcastSender.class);
private LocalMediaManager mLocalMediaManager = mock(LocalMediaManager.class);
private MediaDevice mMediaDevice = mock(MediaDevice.class);
private MediaDevice mMediaDevice1 = mock(MediaDevice.class);
private NotificationEntryManager mNotificationEntryManager =
mock(NotificationEntryManager.class);
- private final UiEventLogger mUiEventLogger = mock(UiEventLogger.class);
private final DialogLaunchAnimator mDialogLaunchAnimator = mock(DialogLaunchAnimator.class);
+ private NearbyMediaDevicesManager mNearbyMediaDevicesManager = mock(
+ NearbyMediaDevicesManager.class);
private MediaOutputGroupDialog mMediaOutputGroupDialog;
private MediaOutputController mMediaOutputController;
@@ -73,11 +75,12 @@ public class MediaOutputGroupDialogTest extends SysuiTestCase {
@Before
public void setUp() {
- mMediaOutputController = new MediaOutputController(mContext, TEST_PACKAGE, false,
- mMediaSessionManager, mLocalBluetoothManager, mShadeController, mStarter,
- mNotificationEntryManager, mUiEventLogger, mDialogLaunchAnimator);
+ mMediaOutputController = new MediaOutputController(mContext, TEST_PACKAGE,
+ mMediaSessionManager, mLocalBluetoothManager, mStarter,
+ mNotificationEntryManager, mDialogLaunchAnimator,
+ Optional.of(mNearbyMediaDevicesManager));
mMediaOutputController.mLocalMediaManager = mLocalMediaManager;
- mMediaOutputGroupDialog = new MediaOutputGroupDialog(mContext, false,
+ mMediaOutputGroupDialog = new MediaOutputGroupDialog(mContext, false, mBroadcastSender,
mMediaOutputController);
mMediaOutputGroupDialog.show();
when(mLocalMediaManager.getSelectedMediaDevice()).thenReturn(mMediaDevices);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelperTest.kt
index 794bc09715af..2a130535c657 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelperTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelperTest.kt
@@ -21,13 +21,8 @@ import android.content.Context
import android.media.MediaRoute2Info
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
-import com.android.systemui.media.taptotransfer.sender.AlmostCloseToEndCast
-import com.android.systemui.media.taptotransfer.sender.AlmostCloseToStartCast
-import com.android.systemui.media.taptotransfer.sender.TransferFailed
-import com.android.systemui.media.taptotransfer.sender.TransferToReceiverTriggered
-import com.android.systemui.media.taptotransfer.sender.TransferToThisDeviceSucceeded
-import com.android.systemui.media.taptotransfer.sender.TransferToThisDeviceTriggered
-import com.android.systemui.media.taptotransfer.sender.TransferToReceiverSucceeded
+import com.android.systemui.media.taptotransfer.receiver.ChipStateReceiver
+import com.android.systemui.media.taptotransfer.sender.ChipStateSender
import com.android.systemui.statusbar.commandline.Command
import com.android.systemui.statusbar.commandline.CommandRegistry
import com.android.systemui.util.concurrency.FakeExecutor
@@ -88,7 +83,7 @@ class MediaTttCommandLineHelperTest : SysuiTestCase() {
@Test
fun sender_almostCloseToStartCast_serviceCallbackCalled() {
commandRegistry.onShellCommand(
- pw, getSenderCommand(AlmostCloseToStartCast::class.simpleName!!)
+ pw, getSenderCommand(ChipStateSender.ALMOST_CLOSE_TO_START_CAST.name)
)
val routeInfoCaptor = argumentCaptor<MediaRoute2Info>()
@@ -103,7 +98,7 @@ class MediaTttCommandLineHelperTest : SysuiTestCase() {
@Test
fun sender_almostCloseToEndCast_serviceCallbackCalled() {
commandRegistry.onShellCommand(
- pw, getSenderCommand(AlmostCloseToEndCast::class.simpleName!!)
+ pw, getSenderCommand(ChipStateSender.ALMOST_CLOSE_TO_END_CAST.name)
)
val routeInfoCaptor = argumentCaptor<MediaRoute2Info>()
@@ -118,7 +113,7 @@ class MediaTttCommandLineHelperTest : SysuiTestCase() {
@Test
fun sender_transferToReceiverTriggered_chipDisplayWithCorrectState() {
commandRegistry.onShellCommand(
- pw, getSenderCommand(TransferToReceiverTriggered::class.simpleName!!)
+ pw, getSenderCommand(ChipStateSender.TRANSFER_TO_RECEIVER_TRIGGERED.name)
)
val routeInfoCaptor = argumentCaptor<MediaRoute2Info>()
@@ -133,7 +128,7 @@ class MediaTttCommandLineHelperTest : SysuiTestCase() {
@Test
fun sender_transferToThisDeviceTriggered_chipDisplayWithCorrectState() {
commandRegistry.onShellCommand(
- pw, getSenderCommand(TransferToThisDeviceTriggered::class.simpleName!!)
+ pw, getSenderCommand(ChipStateSender.TRANSFER_TO_THIS_DEVICE_TRIGGERED.name)
)
verify(statusBarManager).updateMediaTapToTransferSenderDisplay(
@@ -146,7 +141,7 @@ class MediaTttCommandLineHelperTest : SysuiTestCase() {
@Test
fun sender_transferToReceiverSucceeded_chipDisplayWithCorrectState() {
commandRegistry.onShellCommand(
- pw, getSenderCommand(TransferToReceiverSucceeded::class.simpleName!!)
+ pw, getSenderCommand(ChipStateSender.TRANSFER_TO_RECEIVER_SUCCEEDED.name)
)
val routeInfoCaptor = argumentCaptor<MediaRoute2Info>()
@@ -161,7 +156,7 @@ class MediaTttCommandLineHelperTest : SysuiTestCase() {
@Test
fun sender_transferToThisDeviceSucceeded_chipDisplayWithCorrectState() {
commandRegistry.onShellCommand(
- pw, getSenderCommand(TransferToThisDeviceSucceeded::class.simpleName!!)
+ pw, getSenderCommand(ChipStateSender.TRANSFER_TO_THIS_DEVICE_SUCCEEDED.name)
)
val routeInfoCaptor = argumentCaptor<MediaRoute2Info>()
@@ -174,8 +169,10 @@ class MediaTttCommandLineHelperTest : SysuiTestCase() {
}
@Test
- fun sender_transferFailed_serviceCallbackCalled() {
- commandRegistry.onShellCommand(pw, getSenderCommand(TransferFailed::class.simpleName!!))
+ fun sender_transferToReceiverFailed_serviceCallbackCalled() {
+ commandRegistry.onShellCommand(
+ pw, getSenderCommand(ChipStateSender.TRANSFER_TO_RECEIVER_FAILED.name)
+ )
verify(statusBarManager).updateMediaTapToTransferSenderDisplay(
eq(StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_FAILED),
@@ -185,8 +182,23 @@ class MediaTttCommandLineHelperTest : SysuiTestCase() {
}
@Test
+ fun sender_transferToThisDeviceFailed_serviceCallbackCalled() {
+ commandRegistry.onShellCommand(
+ pw, getSenderCommand(ChipStateSender.TRANSFER_TO_THIS_DEVICE_FAILED.name)
+ )
+
+ verify(statusBarManager).updateMediaTapToTransferSenderDisplay(
+ eq(StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_FAILED),
+ any(),
+ nullable(),
+ nullable())
+ }
+
+ @Test
fun sender_farFromReceiver_serviceCallbackCalled() {
- commandRegistry.onShellCommand(pw, getSenderCommand(FAR_FROM_RECEIVER_STATE))
+ commandRegistry.onShellCommand(
+ pw, getSenderCommand(ChipStateSender.FAR_FROM_RECEIVER.name)
+ )
verify(statusBarManager).updateMediaTapToTransferSenderDisplay(
eq(StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_FAR_FROM_RECEIVER),
@@ -197,7 +209,9 @@ class MediaTttCommandLineHelperTest : SysuiTestCase() {
@Test
fun receiver_closeToSender_serviceCallbackCalled() {
- commandRegistry.onShellCommand(pw, getReceiverCommand(CLOSE_TO_SENDER_STATE))
+ commandRegistry.onShellCommand(
+ pw, getReceiverCommand(ChipStateReceiver.CLOSE_TO_SENDER.name)
+ )
verify(statusBarManager).updateMediaTapToTransferReceiverDisplay(
eq(StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_CLOSE_TO_SENDER),
@@ -209,7 +223,9 @@ class MediaTttCommandLineHelperTest : SysuiTestCase() {
@Test
fun receiver_farFromSender_serviceCallbackCalled() {
- commandRegistry.onShellCommand(pw, getReceiverCommand(FAR_FROM_SENDER_STATE))
+ commandRegistry.onShellCommand(
+ pw, getReceiverCommand(ChipStateReceiver.FAR_FROM_SENDER.name)
+ )
verify(statusBarManager).updateMediaTapToTransferReceiverDisplay(
eq(StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_FAR_FROM_SENDER),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommonTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommonTest.kt
index adb59eca1e08..b9a69bb8641a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommonTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommonTest.kt
@@ -17,7 +17,10 @@
package com.android.systemui.media.taptotransfer.common
import android.content.Context
+import android.content.pm.ApplicationInfo
+import android.content.pm.PackageManager
import android.graphics.drawable.Drawable
+import android.os.PowerManager
import android.view.MotionEvent
import android.view.View
import android.view.ViewGroup
@@ -40,6 +43,7 @@ import org.junit.Before
import org.junit.Test
import org.mockito.ArgumentCaptor
import org.mockito.Mock
+import org.mockito.Mockito.eq
import org.mockito.Mockito.never
import org.mockito.Mockito.reset
import org.mockito.Mockito.verify
@@ -48,12 +52,16 @@ import org.mockito.MockitoAnnotations
@SmallTest
class MediaTttChipControllerCommonTest : SysuiTestCase() {
- private lateinit var controllerCommon: MediaTttChipControllerCommon<MediaTttChipState>
+ private lateinit var controllerCommon: MediaTttChipControllerCommon<ChipInfo>
private lateinit var fakeClock: FakeSystemClock
private lateinit var fakeExecutor: FakeExecutor
- private lateinit var appIconDrawable: Drawable
+ private lateinit var appIconFromPackageName: Drawable
+ @Mock
+ private lateinit var packageManager: PackageManager
+ @Mock
+ private lateinit var applicationInfo: ApplicationInfo
@Mock
private lateinit var logger: MediaTttLogger
@Mock
@@ -62,25 +70,39 @@ class MediaTttChipControllerCommonTest : SysuiTestCase() {
private lateinit var viewUtil: ViewUtil
@Mock
private lateinit var tapGestureDetector: TapGestureDetector
+ @Mock
+ private lateinit var powerManager: PowerManager
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
- appIconDrawable = context.getDrawable(R.drawable.ic_cake)!!
+
+ appIconFromPackageName = context.getDrawable(R.drawable.ic_cake)!!
+ whenever(packageManager.getApplicationIcon(PACKAGE_NAME)).thenReturn(appIconFromPackageName)
+ whenever(applicationInfo.loadLabel(packageManager)).thenReturn(APP_NAME)
+ whenever(packageManager.getApplicationInfo(
+ any(), any<PackageManager.ApplicationInfoFlags>()
+ )).thenThrow(PackageManager.NameNotFoundException())
+ whenever(packageManager.getApplicationInfo(
+ eq(PACKAGE_NAME), any<PackageManager.ApplicationInfoFlags>()
+ )).thenReturn(applicationInfo)
+ context.setMockPackageManager(packageManager)
+
fakeClock = FakeSystemClock()
fakeExecutor = FakeExecutor(fakeClock)
controllerCommon = TestControllerCommon(
- context, logger, windowManager, viewUtil, fakeExecutor, tapGestureDetector
+ context, logger, windowManager, viewUtil, fakeExecutor, tapGestureDetector, powerManager
)
}
@Test
- fun displayChip_chipAddedAndGestureDetectionStarted() {
+ fun displayChip_chipAddedAndGestureDetectionStartedAndScreenOn() {
controllerCommon.displayChip(getState())
verify(windowManager).addView(any(), any())
verify(tapGestureDetector).addOnGestureDetectedCallback(any(), any())
+ verify(powerManager).wakeUp(any(), any(), any())
}
@Test
@@ -100,7 +122,7 @@ class MediaTttChipControllerCommonTest : SysuiTestCase() {
controllerCommon.displayChip(state)
reset(windowManager)
- fakeClock.advanceTime(state.getTimeoutMs() - 1)
+ fakeClock.advanceTime(TIMEOUT_MS - 1)
verify(windowManager, never()).removeView(any())
}
@@ -111,7 +133,7 @@ class MediaTttChipControllerCommonTest : SysuiTestCase() {
controllerCommon.displayChip(state)
reset(windowManager)
- fakeClock.advanceTime(state.getTimeoutMs() + 1)
+ fakeClock.advanceTime(TIMEOUT_MS + 1)
verify(windowManager).removeView(any())
}
@@ -128,7 +150,7 @@ class MediaTttChipControllerCommonTest : SysuiTestCase() {
controllerCommon.displayChip(getState())
// Wait until the timeout for the first display would've happened
- fakeClock.advanceTime(state.getTimeoutMs() - waitTime + 1)
+ fakeClock.advanceTime(TIMEOUT_MS - waitTime + 1)
// Verify we didn't hide the chip
verify(windowManager, never()).removeView(any())
@@ -145,7 +167,7 @@ class MediaTttChipControllerCommonTest : SysuiTestCase() {
controllerCommon.displayChip(getState())
// Ensure we still hide the chip eventually
- fakeClock.advanceTime(state.getTimeoutMs() + 1)
+ fakeClock.advanceTime(TIMEOUT_MS + 1)
verify(windowManager).removeView(any())
}
@@ -172,16 +194,104 @@ class MediaTttChipControllerCommonTest : SysuiTestCase() {
}
@Test
- fun setIcon_viewHasIconAndContentDescription() {
+ fun setIcon_nullAppIconDrawableAndNullPackageName_stillHasIcon() {
+ controllerCommon.displayChip(getState())
+ val chipView = getChipView()
+
+ controllerCommon.setIcon(chipView, appPackageName = null, appIconDrawableOverride = null)
+
+ assertThat(chipView.getAppIconView().drawable).isNotNull()
+ }
+
+ @Test
+ fun setIcon_nullAppIconDrawableAndInvalidPackageName_stillHasIcon() {
+ controllerCommon.displayChip(getState())
+ val chipView = getChipView()
+
+ controllerCommon.setIcon(
+ chipView, appPackageName = "fakePackageName", appIconDrawableOverride = null
+ )
+
+ assertThat(chipView.getAppIconView().drawable).isNotNull()
+ }
+
+ @Test
+ fun setIcon_nullAppIconDrawable_iconIsFromPackageName() {
+ controllerCommon.displayChip(getState())
+ val chipView = getChipView()
+
+ controllerCommon.setIcon(chipView, PACKAGE_NAME, appIconDrawableOverride = null, null)
+
+ assertThat(chipView.getAppIconView().drawable).isEqualTo(appIconFromPackageName)
+ }
+
+ @Test
+ fun setIcon_hasAppIconDrawable_iconIsDrawable() {
+ controllerCommon.displayChip(getState())
+ val chipView = getChipView()
+
+ val drawable = context.getDrawable(R.drawable.ic_alarm)!!
+ controllerCommon.setIcon(chipView, PACKAGE_NAME, drawable, null)
+
+ assertThat(chipView.getAppIconView().drawable).isEqualTo(drawable)
+ }
+
+ @Test
+ fun setIcon_nullAppNameAndNullPackageName_stillHasContentDescription() {
controllerCommon.displayChip(getState())
val chipView = getChipView()
- val state = TestChipState(PACKAGE_NAME)
- controllerCommon.setIcon(state, chipView)
+ controllerCommon.setIcon(chipView, appPackageName = null, appNameOverride = null)
+
+ assertThat(chipView.getAppIconView().contentDescription.toString()).isNotEmpty()
+ }
+
+ @Test
+ fun setIcon_nullAppNameAndInvalidPackageName_stillHasContentDescription() {
+ controllerCommon.displayChip(getState())
+ val chipView = getChipView()
+
+ controllerCommon.setIcon(
+ chipView, appPackageName = "fakePackageName", appNameOverride = null
+ )
- assertThat(chipView.getAppIconView().drawable).isEqualTo(appIconDrawable)
- assertThat(chipView.getAppIconView().contentDescription)
- .isEqualTo(state.getAppName(context))
+ assertThat(chipView.getAppIconView().contentDescription.toString()).isNotEmpty()
+ }
+
+ @Test
+ fun setIcon_nullAppName_iconContentDescriptionIsFromPackageName() {
+ controllerCommon.displayChip(getState())
+ val chipView = getChipView()
+
+ controllerCommon.setIcon(chipView, PACKAGE_NAME, null, appNameOverride = null)
+
+ assertThat(chipView.getAppIconView().contentDescription).isEqualTo(APP_NAME)
+ }
+
+ @Test
+ fun setIcon_hasAppName_iconContentDescriptionIsAppNameOverride() {
+ controllerCommon.displayChip(getState())
+ val chipView = getChipView()
+
+ val appName = "Override App Name"
+ controllerCommon.setIcon(chipView, PACKAGE_NAME, null, appName)
+
+ assertThat(chipView.getAppIconView().contentDescription).isEqualTo(appName)
+ }
+
+ @Test
+ fun setIcon_iconSizeMatchesGetIconSize() {
+ controllerCommon.displayChip(getState())
+ val chipView = getChipView()
+
+ controllerCommon.setIcon(chipView, PACKAGE_NAME)
+ chipView.measure(
+ View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
+ View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
+ )
+
+ assertThat(chipView.getAppIconView().measuredWidth).isEqualTo(ICON_SIZE)
+ assertThat(chipView.getAppIconView().measuredHeight).isEqualTo(ICON_SIZE)
}
@Test
@@ -218,7 +328,7 @@ class MediaTttChipControllerCommonTest : SysuiTestCase() {
verify(windowManager, never()).removeView(any())
}
- private fun getState() = MediaTttChipState(PACKAGE_NAME)
+ private fun getState() = ChipInfo()
private fun getChipView(): ViewGroup {
val viewCaptor = ArgumentCaptor.forClass(View::class.java)
@@ -235,22 +345,30 @@ class MediaTttChipControllerCommonTest : SysuiTestCase() {
viewUtil: ViewUtil,
@Main mainExecutor: DelayableExecutor,
tapGestureDetector: TapGestureDetector,
- ) : MediaTttChipControllerCommon<MediaTttChipState>(
+ powerManager: PowerManager
+ ) : MediaTttChipControllerCommon<ChipInfo>(
context,
logger,
windowManager,
viewUtil,
mainExecutor,
tapGestureDetector,
+ powerManager,
R.layout.media_ttt_chip
) {
- override fun updateChipView(chipState: MediaTttChipState, currentChipView: ViewGroup) {
+ override fun updateChipView(chipInfo: ChipInfo, currentChipView: ViewGroup) {
+
}
+
+ override fun getIconSize(isAppIcon: Boolean): Int? = ICON_SIZE
}
- inner class TestChipState(appPackageName: String?) : MediaTttChipState(appPackageName) {
- override fun getAppIcon(context: Context) = appIconDrawable
+ inner class ChipInfo : ChipInfoCommon {
+ override fun getTimeoutMs() = TIMEOUT_MS
}
}
private const val PACKAGE_NAME = "com.android.systemui"
+private const val APP_NAME = "Fake App Name"
+private const val TIMEOUT_MS = 10000L
+private const val ICON_SIZE = 47 \ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt
index 56f45896436c..067607f9b8ae 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt
@@ -22,6 +22,7 @@ import android.content.pm.PackageManager
import android.graphics.drawable.Drawable
import android.media.MediaRoute2Info
import android.os.Handler
+import android.os.PowerManager
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.view.View
@@ -29,6 +30,7 @@ import android.view.ViewGroup
import android.view.WindowManager
import android.widget.ImageView
import androidx.test.filters.SmallTest
+import com.android.internal.logging.testing.UiEventLoggerFake
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.media.taptotransfer.common.MediaTttLogger
@@ -63,6 +65,8 @@ class MediaTttChipControllerReceiverTest : SysuiTestCase() {
@Mock
private lateinit var logger: MediaTttLogger
@Mock
+ private lateinit var powerManager: PowerManager
+ @Mock
private lateinit var windowManager: WindowManager
@Mock
private lateinit var viewUtil: ViewUtil
@@ -70,6 +74,8 @@ class MediaTttChipControllerReceiverTest : SysuiTestCase() {
private lateinit var commandQueue: CommandQueue
private lateinit var commandQueueCallback: CommandQueue.Callbacks
private lateinit var fakeAppIconDrawable: Drawable
+ private lateinit var uiEventLoggerFake: UiEventLoggerFake
+ private lateinit var receiverUiEventLogger: MediaTttReceiverUiEventLogger
@Before
fun setUp() {
@@ -83,6 +89,9 @@ class MediaTttChipControllerReceiverTest : SysuiTestCase() {
)).thenReturn(applicationInfo)
context.setMockPackageManager(packageManager)
+ uiEventLoggerFake = UiEventLoggerFake()
+ receiverUiEventLogger = MediaTttReceiverUiEventLogger(uiEventLoggerFake)
+
controllerReceiver = MediaTttChipControllerReceiver(
commandQueue,
context,
@@ -91,7 +100,9 @@ class MediaTttChipControllerReceiverTest : SysuiTestCase() {
viewUtil,
FakeExecutor(FakeSystemClock()),
TapGestureDetector(context),
+ powerManager,
Handler.getMain(),
+ receiverUiEventLogger,
)
val callbackCaptor = ArgumentCaptor.forClass(CommandQueue.Callbacks::class.java)
@@ -110,6 +121,9 @@ class MediaTttChipControllerReceiverTest : SysuiTestCase() {
)
assertThat(getChipView().getAppIconView().contentDescription).isEqualTo(appName)
+ assertThat(uiEventLoggerFake.eventId(0)).isEqualTo(
+ MediaTttReceiverUiEvents.MEDIA_TTT_RECEIVER_CLOSE_TO_SENDER.id
+ )
}
@Test
@@ -122,6 +136,9 @@ class MediaTttChipControllerReceiverTest : SysuiTestCase() {
)
verify(windowManager, never()).addView(any(), any())
+ assertThat(uiEventLoggerFake.eventId(0)).isEqualTo(
+ MediaTttReceiverUiEvents.MEDIA_TTT_RECEIVER_FAR_FROM_SENDER.id
+ )
}
@Test
@@ -158,41 +175,35 @@ class MediaTttChipControllerReceiverTest : SysuiTestCase() {
}
@Test
- fun displayChip_nullAppIconDrawable_iconIsFromPackageName() {
- val state = ChipStateReceiver(PACKAGE_NAME, appIconDrawable = null, "appName")
-
- controllerReceiver.displayChip(state)
-
- assertThat(getChipView().getAppIconView().drawable).isEqualTo(fakeAppIconDrawable)
- }
-
- @Test
- fun displayChip_hasAppIconDrawable_iconIsDrawable() {
- val drawable = context.getDrawable(R.drawable.ic_alarm)!!
- val state = ChipStateReceiver(PACKAGE_NAME, drawable, "appName")
-
- controllerReceiver.displayChip(state)
-
- assertThat(getChipView().getAppIconView().drawable).isEqualTo(drawable)
- }
-
- @Test
- fun displayChip_nullAppName_iconContentDescriptionIsFromPackageName() {
- val state = ChipStateReceiver(PACKAGE_NAME, appIconDrawable = null, appName = null)
-
- controllerReceiver.displayChip(state)
+ fun setIcon_isAppIcon_usesAppIconSize() {
+ controllerReceiver.displayChip(getChipReceiverInfo())
+ val chipView = getChipView()
+
+ controllerReceiver.setIcon(chipView, PACKAGE_NAME)
+ chipView.measure(
+ View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
+ View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
+ )
- assertThat(getChipView().getAppIconView().contentDescription).isEqualTo(APP_NAME)
+ val expectedSize = controllerReceiver.getIconSize(isAppIcon = true)
+ assertThat(chipView.getAppIconView().measuredWidth).isEqualTo(expectedSize)
+ assertThat(chipView.getAppIconView().measuredHeight).isEqualTo(expectedSize)
}
@Test
- fun displayChip_hasAppName_iconContentDescriptionIsAppNameOverride() {
- val appName = "Override App Name"
- val state = ChipStateReceiver(PACKAGE_NAME, appIconDrawable = null, appName)
-
- controllerReceiver.displayChip(state)
+ fun setIcon_notAppIcon_usesGenericIconSize() {
+ controllerReceiver.displayChip(getChipReceiverInfo())
+ val chipView = getChipView()
+
+ controllerReceiver.setIcon(chipView, appPackageName = null)
+ chipView.measure(
+ View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
+ View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
+ )
- assertThat(getChipView().getAppIconView().contentDescription).isEqualTo(appName)
+ val expectedSize = controllerReceiver.getIconSize(isAppIcon = false)
+ assertThat(chipView.getAppIconView().measuredWidth).isEqualTo(expectedSize)
+ assertThat(chipView.getAppIconView().measuredHeight).isEqualTo(expectedSize)
}
private fun getChipView(): ViewGroup {
@@ -201,6 +212,9 @@ class MediaTttChipControllerReceiverTest : SysuiTestCase() {
return viewCaptor.value as ViewGroup
}
+ private fun getChipReceiverInfo(): ChipReceiverInfo =
+ ChipReceiverInfo(routeInfo, null, null)
+
private fun ViewGroup.getAppIconView() = this.requireViewById<ImageView>(R.id.app_icon)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttReceiverUiEventLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttReceiverUiEventLoggerTest.kt
new file mode 100644
index 000000000000..ee10ddc521f1
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttReceiverUiEventLoggerTest.kt
@@ -0,0 +1,30 @@
+package com.android.systemui.media.taptotransfer.receiver
+
+import androidx.test.filters.SmallTest
+import com.android.internal.logging.testing.UiEventLoggerFake
+import com.android.systemui.SysuiTestCase
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+
+@SmallTest
+class MediaTttReceiverUiEventLoggerTest : SysuiTestCase() {
+ private lateinit var uiEventLoggerFake: UiEventLoggerFake
+ private lateinit var logger: MediaTttReceiverUiEventLogger
+
+ @Before
+ fun setUp() {
+ uiEventLoggerFake = UiEventLoggerFake()
+ logger = MediaTttReceiverUiEventLogger(uiEventLoggerFake)
+ }
+
+ @Test
+ fun logReceiverStateChange_eventAssociatedWithStateIsLogged() {
+ val state = ChipStateReceiver.CLOSE_TO_SENDER
+
+ logger.logReceiverStateChange(state)
+
+ assertThat(uiEventLoggerFake.numLogs()).isEqualTo(1)
+ assertThat(uiEventLoggerFake.eventId(0)).isEqualTo(state.uiEvent.id)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSenderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSenderTest.kt
index fd1d76a5d02d..ef5315428a60 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSenderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSenderTest.kt
@@ -21,6 +21,7 @@ import android.content.pm.ApplicationInfo
import android.content.pm.PackageManager
import android.graphics.drawable.Drawable
import android.media.MediaRoute2Info
+import android.os.PowerManager
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.view.View
@@ -29,6 +30,7 @@ import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.TextView
import androidx.test.filters.SmallTest
+import com.android.internal.logging.testing.UiEventLoggerFake
import com.android.internal.statusbar.IUndoMediaTransferCallback
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
@@ -65,6 +67,8 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
@Mock
private lateinit var logger: MediaTttLogger
@Mock
+ private lateinit var powerManager: PowerManager
+ @Mock
private lateinit var windowManager: WindowManager
@Mock
private lateinit var viewUtil: ViewUtil
@@ -74,6 +78,8 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
private lateinit var fakeAppIconDrawable: Drawable
private lateinit var fakeClock: FakeSystemClock
private lateinit var fakeExecutor: FakeExecutor
+ private lateinit var uiEventLoggerFake: UiEventLoggerFake
+ private lateinit var senderUiEventLogger: MediaTttSenderUiEventLogger
@Before
fun setUp() {
@@ -89,6 +95,8 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
fakeClock = FakeSystemClock()
fakeExecutor = FakeExecutor(fakeClock)
+ uiEventLoggerFake = UiEventLoggerFake()
+ senderUiEventLogger = MediaTttSenderUiEventLogger(uiEventLoggerFake)
controllerSender = MediaTttChipControllerSender(
commandQueue,
@@ -97,7 +105,9 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
windowManager,
viewUtil,
fakeExecutor,
- TapGestureDetector(context)
+ TapGestureDetector(context),
+ powerManager,
+ senderUiEventLogger
)
val callbackCaptor = ArgumentCaptor.forClass(CommandQueue.Callbacks::class.java)
@@ -113,8 +123,12 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
null
)
- assertThat(getChipView().getChipText())
- .isEqualTo(almostCloseToStartCast().getChipTextString(context))
+ assertThat(getChipView().getChipText()).isEqualTo(
+ almostCloseToStartCast().state.getChipTextString(context, OTHER_DEVICE_NAME)
+ )
+ assertThat(uiEventLoggerFake.eventId(0)).isEqualTo(
+ MediaTttSenderUiEvents.MEDIA_TTT_SENDER_ALMOST_CLOSE_TO_START_CAST.id
+ )
}
@Test
@@ -125,8 +139,12 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
null
)
- assertThat(getChipView().getChipText())
- .isEqualTo(almostCloseToEndCast().getChipTextString(context))
+ assertThat(getChipView().getChipText()).isEqualTo(
+ almostCloseToEndCast().state.getChipTextString(context, OTHER_DEVICE_NAME)
+ )
+ assertThat(uiEventLoggerFake.eventId(0)).isEqualTo(
+ MediaTttSenderUiEvents.MEDIA_TTT_SENDER_ALMOST_CLOSE_TO_END_CAST.id
+ )
}
@Test
@@ -137,8 +155,12 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
null
)
- assertThat(getChipView().getChipText())
- .isEqualTo(transferToReceiverTriggered().getChipTextString(context))
+ assertThat(getChipView().getChipText()).isEqualTo(
+ transferToReceiverTriggered().state.getChipTextString(context, OTHER_DEVICE_NAME)
+ )
+ assertThat(uiEventLoggerFake.eventId(0)).isEqualTo(
+ MediaTttSenderUiEvents.MEDIA_TTT_SENDER_TRANSFER_TO_RECEIVER_TRIGGERED.id
+ )
}
@Test
@@ -149,8 +171,12 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
null
)
- assertThat(getChipView().getChipText())
- .isEqualTo(transferToThisDeviceTriggered().getChipTextString(context))
+ assertThat(getChipView().getChipText()).isEqualTo(
+ transferToThisDeviceTriggered().state.getChipTextString(context, OTHER_DEVICE_NAME)
+ )
+ assertThat(uiEventLoggerFake.eventId(0)).isEqualTo(
+ MediaTttSenderUiEvents.MEDIA_TTT_SENDER_TRANSFER_TO_THIS_DEVICE_TRIGGERED.id
+ )
}
@Test
@@ -161,8 +187,12 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
null
)
- assertThat(getChipView().getChipText())
- .isEqualTo(transferToReceiverSucceeded().getChipTextString(context))
+ assertThat(getChipView().getChipText()).isEqualTo(
+ transferToReceiverSucceeded().state.getChipTextString(context, OTHER_DEVICE_NAME)
+ )
+ assertThat(uiEventLoggerFake.eventId(0)).isEqualTo(
+ MediaTttSenderUiEvents.MEDIA_TTT_SENDER_TRANSFER_TO_RECEIVER_SUCCEEDED.id
+ )
}
@Test
@@ -173,8 +203,12 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
null
)
- assertThat(getChipView().getChipText())
- .isEqualTo(transferToThisDeviceSucceeded().getChipTextString(context))
+ assertThat(getChipView().getChipText()).isEqualTo(
+ transferToThisDeviceSucceeded().state.getChipTextString(context, OTHER_DEVICE_NAME)
+ )
+ assertThat(uiEventLoggerFake.eventId(0)).isEqualTo(
+ MediaTttSenderUiEvents.MEDIA_TTT_SENDER_TRANSFER_TO_THIS_DEVICE_SUCCEEDED.id
+ )
}
@Test
@@ -185,8 +219,12 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
null
)
- assertThat(getChipView().getChipText())
- .isEqualTo(transferFailed().getChipTextString(context))
+ assertThat(getChipView().getChipText()).isEqualTo(
+ transferToReceiverFailed().state.getChipTextString(context, OTHER_DEVICE_NAME)
+ )
+ assertThat(uiEventLoggerFake.eventId(0)).isEqualTo(
+ MediaTttSenderUiEvents.MEDIA_TTT_SENDER_TRANSFER_TO_RECEIVER_FAILED.id
+ )
}
@Test
@@ -197,8 +235,12 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
null
)
- assertThat(getChipView().getChipText())
- .isEqualTo(transferFailed().getChipTextString(context))
+ assertThat(getChipView().getChipText()).isEqualTo(
+ transferToThisDeviceFailed().state.getChipTextString(context, OTHER_DEVICE_NAME)
+ )
+ assertThat(uiEventLoggerFake.eventId(0)).isEqualTo(
+ MediaTttSenderUiEvents.MEDIA_TTT_SENDER_TRANSFER_TO_THIS_DEVICE_FAILED.id
+ )
}
@Test
@@ -210,6 +252,9 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
)
verify(windowManager, never()).addView(any(), any())
+ assertThat(uiEventLoggerFake.eventId(0)).isEqualTo(
+ MediaTttSenderUiEvents.MEDIA_TTT_SENDER_FAR_FROM_RECEIVER.id
+ )
}
@Test
@@ -250,7 +295,9 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
val chipView = getChipView()
assertThat(chipView.getAppIconView().drawable).isEqualTo(fakeAppIconDrawable)
assertThat(chipView.getAppIconView().contentDescription).isEqualTo(APP_NAME)
- assertThat(chipView.getChipText()).isEqualTo(state.getChipTextString(context))
+ assertThat(chipView.getChipText()).isEqualTo(
+ state.state.getChipTextString(context, OTHER_DEVICE_NAME)
+ )
assertThat(chipView.getLoadingIconVisibility()).isEqualTo(View.GONE)
assertThat(chipView.getUndoButton().visibility).isEqualTo(View.GONE)
assertThat(chipView.getFailureIcon().visibility).isEqualTo(View.GONE)
@@ -264,7 +311,9 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
val chipView = getChipView()
assertThat(chipView.getAppIconView().drawable).isEqualTo(fakeAppIconDrawable)
assertThat(chipView.getAppIconView().contentDescription).isEqualTo(APP_NAME)
- assertThat(chipView.getChipText()).isEqualTo(state.getChipTextString(context))
+ assertThat(chipView.getChipText()).isEqualTo(
+ state.state.getChipTextString(context, OTHER_DEVICE_NAME)
+ )
assertThat(chipView.getLoadingIconVisibility()).isEqualTo(View.GONE)
assertThat(chipView.getUndoButton().visibility).isEqualTo(View.GONE)
assertThat(chipView.getFailureIcon().visibility).isEqualTo(View.GONE)
@@ -278,7 +327,9 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
val chipView = getChipView()
assertThat(chipView.getAppIconView().drawable).isEqualTo(fakeAppIconDrawable)
assertThat(chipView.getAppIconView().contentDescription).isEqualTo(APP_NAME)
- assertThat(chipView.getChipText()).isEqualTo(state.getChipTextString(context))
+ assertThat(chipView.getChipText()).isEqualTo(
+ state.state.getChipTextString(context, OTHER_DEVICE_NAME)
+ )
assertThat(chipView.getLoadingIconVisibility()).isEqualTo(View.VISIBLE)
assertThat(chipView.getUndoButton().visibility).isEqualTo(View.GONE)
assertThat(chipView.getFailureIcon().visibility).isEqualTo(View.GONE)
@@ -292,7 +343,9 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
val chipView = getChipView()
assertThat(chipView.getAppIconView().drawable).isEqualTo(fakeAppIconDrawable)
assertThat(chipView.getAppIconView().contentDescription).isEqualTo(APP_NAME)
- assertThat(chipView.getChipText()).isEqualTo(state.getChipTextString(context))
+ assertThat(chipView.getChipText()).isEqualTo(
+ state.state.getChipTextString(context, OTHER_DEVICE_NAME)
+ )
assertThat(chipView.getLoadingIconVisibility()).isEqualTo(View.VISIBLE)
assertThat(chipView.getUndoButton().visibility).isEqualTo(View.GONE)
assertThat(chipView.getFailureIcon().visibility).isEqualTo(View.GONE)
@@ -306,7 +359,9 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
val chipView = getChipView()
assertThat(chipView.getAppIconView().drawable).isEqualTo(fakeAppIconDrawable)
assertThat(chipView.getAppIconView().contentDescription).isEqualTo(APP_NAME)
- assertThat(chipView.getChipText()).isEqualTo(state.getChipTextString(context))
+ assertThat(chipView.getChipText()).isEqualTo(
+ state.state.getChipTextString(context, OTHER_DEVICE_NAME)
+ )
assertThat(chipView.getLoadingIconVisibility()).isEqualTo(View.GONE)
assertThat(chipView.getFailureIcon().visibility).isEqualTo(View.GONE)
}
@@ -355,8 +410,12 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
getChipView().getUndoButton().performClick()
- assertThat(getChipView().getChipText())
- .isEqualTo(transferToThisDeviceTriggered().getChipTextString(context))
+ assertThat(getChipView().getChipText()).isEqualTo(
+ transferToThisDeviceTriggered().state.getChipTextString(context, OTHER_DEVICE_NAME)
+ )
+ assertThat(uiEventLoggerFake.eventId(0)).isEqualTo(
+ MediaTttSenderUiEvents.MEDIA_TTT_SENDER_UNDO_TRANSFER_TO_RECEIVER_CLICKED.id
+ )
}
@Test
@@ -367,7 +426,9 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
val chipView = getChipView()
assertThat(chipView.getAppIconView().drawable).isEqualTo(fakeAppIconDrawable)
assertThat(chipView.getAppIconView().contentDescription).isEqualTo(APP_NAME)
- assertThat(chipView.getChipText()).isEqualTo(state.getChipTextString(context))
+ assertThat(chipView.getChipText()).isEqualTo(
+ state.state.getChipTextString(context, OTHER_DEVICE_NAME)
+ )
assertThat(chipView.getLoadingIconVisibility()).isEqualTo(View.GONE)
assertThat(chipView.getFailureIcon().visibility).isEqualTo(View.GONE)
}
@@ -416,19 +477,41 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
getChipView().getUndoButton().performClick()
- assertThat(getChipView().getChipText())
- .isEqualTo(transferToReceiverTriggered().getChipTextString(context))
+ assertThat(getChipView().getChipText()).isEqualTo(
+ transferToReceiverTriggered().state.getChipTextString(context, OTHER_DEVICE_NAME)
+ )
+ assertThat(uiEventLoggerFake.eventId(0)).isEqualTo(
+ MediaTttSenderUiEvents.MEDIA_TTT_SENDER_UNDO_TRANSFER_TO_THIS_DEVICE_CLICKED.id
+ )
+ }
+
+ @Test
+ fun transferToReceiverFailed_appIcon_noDeviceName_noLoadingIcon_noUndo_failureIcon() {
+ val state = transferToReceiverFailed()
+ controllerSender.displayChip(state)
+
+ val chipView = getChipView()
+ assertThat(chipView.getAppIconView().drawable).isEqualTo(fakeAppIconDrawable)
+ assertThat(chipView.getAppIconView().contentDescription).isEqualTo(APP_NAME)
+ assertThat(getChipView().getChipText()).isEqualTo(
+ state.state.getChipTextString(context, OTHER_DEVICE_NAME)
+ )
+ assertThat(chipView.getLoadingIconVisibility()).isEqualTo(View.GONE)
+ assertThat(chipView.getUndoButton().visibility).isEqualTo(View.GONE)
+ assertThat(chipView.getFailureIcon().visibility).isEqualTo(View.VISIBLE)
}
@Test
- fun transferFailed_appIcon_noDeviceName_noLoadingIcon_noUndo_failureIcon() {
- val state = transferFailed()
+ fun transferToThisDeviceFailed_appIcon_noDeviceName_noLoadingIcon_noUndo_failureIcon() {
+ val state = transferToThisDeviceFailed()
controllerSender.displayChip(state)
val chipView = getChipView()
assertThat(chipView.getAppIconView().drawable).isEqualTo(fakeAppIconDrawable)
assertThat(chipView.getAppIconView().contentDescription).isEqualTo(APP_NAME)
- assertThat(chipView.getChipText()).isEqualTo(state.getChipTextString(context))
+ assertThat(getChipView().getChipText()).isEqualTo(
+ state.state.getChipTextString(context, OTHER_DEVICE_NAME)
+ )
assertThat(chipView.getLoadingIconVisibility()).isEqualTo(View.GONE)
assertThat(chipView.getUndoButton().visibility).isEqualTo(View.GONE)
assertThat(chipView.getFailureIcon().visibility).isEqualTo(View.VISIBLE)
@@ -475,7 +558,7 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
@Test
fun changeFromTransferTriggeredToTransferFailed_failureIconAppears() {
controllerSender.displayChip(transferToReceiverTriggered())
- controllerSender.displayChip(transferFailed())
+ controllerSender.displayChip(transferToReceiverFailed())
assertThat(getChipView().getFailureIcon().visibility).isEqualTo(View.VISIBLE)
}
@@ -498,7 +581,7 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
fakeClock.advanceTime(1000L)
controllerSender.removeChip("fakeRemovalReason")
- fakeClock.advanceTime(state.getTimeoutMs() + 1)
+ fakeClock.advanceTime(state.state.timeout + 1)
verify(windowManager).removeView(any())
}
@@ -521,7 +604,7 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
fakeClock.advanceTime(1000L)
controllerSender.removeChip("fakeRemovalReason")
- fakeClock.advanceTime(state.getTimeoutMs() + 1)
+ fakeClock.advanceTime(state.state.timeout + 1)
verify(windowManager).removeView(any())
}
@@ -546,34 +629,35 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
/** Helper method providing default parameters to not clutter up the tests. */
private fun almostCloseToStartCast() =
- AlmostCloseToStartCast(PACKAGE_NAME, OTHER_DEVICE_NAME)
+ ChipSenderInfo(ChipStateSender.ALMOST_CLOSE_TO_START_CAST, routeInfo)
/** Helper method providing default parameters to not clutter up the tests. */
private fun almostCloseToEndCast() =
- AlmostCloseToEndCast(PACKAGE_NAME, OTHER_DEVICE_NAME)
+ ChipSenderInfo(ChipStateSender.ALMOST_CLOSE_TO_END_CAST, routeInfo)
/** Helper method providing default parameters to not clutter up the tests. */
private fun transferToReceiverTriggered() =
- TransferToReceiverTriggered(PACKAGE_NAME, OTHER_DEVICE_NAME)
+ ChipSenderInfo(ChipStateSender.TRANSFER_TO_RECEIVER_TRIGGERED, routeInfo)
/** Helper method providing default parameters to not clutter up the tests. */
private fun transferToThisDeviceTriggered() =
- TransferToThisDeviceTriggered(PACKAGE_NAME)
+ ChipSenderInfo(ChipStateSender.TRANSFER_TO_THIS_DEVICE_TRIGGERED, routeInfo)
/** Helper method providing default parameters to not clutter up the tests. */
private fun transferToReceiverSucceeded(undoCallback: IUndoMediaTransferCallback? = null) =
- TransferToReceiverSucceeded(
- PACKAGE_NAME, OTHER_DEVICE_NAME, undoCallback
- )
+ ChipSenderInfo(ChipStateSender.TRANSFER_TO_RECEIVER_SUCCEEDED, routeInfo, undoCallback)
/** Helper method providing default parameters to not clutter up the tests. */
private fun transferToThisDeviceSucceeded(undoCallback: IUndoMediaTransferCallback? = null) =
- TransferToThisDeviceSucceeded(
- PACKAGE_NAME, OTHER_DEVICE_NAME, undoCallback
- )
+ ChipSenderInfo(ChipStateSender.TRANSFER_TO_THIS_DEVICE_SUCCEEDED, routeInfo, undoCallback)
+
+ /** Helper method providing default parameters to not clutter up the tests. */
+ private fun transferToReceiverFailed() =
+ ChipSenderInfo(ChipStateSender.TRANSFER_TO_RECEIVER_FAILED, routeInfo)
/** Helper method providing default parameters to not clutter up the tests. */
- private fun transferFailed() = TransferFailed(PACKAGE_NAME)
+ private fun transferToThisDeviceFailed() =
+ ChipSenderInfo(ChipStateSender.TRANSFER_TO_RECEIVER_FAILED, routeInfo)
}
private const val APP_NAME = "Fake app name"
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderUiEventLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderUiEventLoggerTest.kt
new file mode 100644
index 000000000000..263637a6b6e5
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderUiEventLoggerTest.kt
@@ -0,0 +1,46 @@
+package com.android.systemui.media.taptotransfer.sender
+
+import androidx.test.filters.SmallTest
+import com.android.internal.logging.testing.UiEventLoggerFake
+import com.android.systemui.SysuiTestCase
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+
+@SmallTest
+class MediaTttSenderUiEventLoggerTest : SysuiTestCase() {
+ private lateinit var uiEventLoggerFake: UiEventLoggerFake
+ private lateinit var logger: MediaTttSenderUiEventLogger
+
+ @Before
+ fun setUp () {
+ uiEventLoggerFake = UiEventLoggerFake()
+ logger = MediaTttSenderUiEventLogger(uiEventLoggerFake)
+ }
+
+ @Test
+ fun logSenderStateChange_eventAssociatedWithStateIsLogged() {
+ val state = ChipStateSender.ALMOST_CLOSE_TO_END_CAST
+ logger.logSenderStateChange(state)
+
+ assertThat(uiEventLoggerFake.numLogs()).isEqualTo(1)
+ assertThat(uiEventLoggerFake.eventId(0)).isEqualTo(state.uiEvent.id)
+ }
+
+ @Test
+ fun logUndoClicked_undoEventLogged() {
+ val undoEvent = MediaTttSenderUiEvents.MEDIA_TTT_SENDER_UNDO_TRANSFER_TO_THIS_DEVICE_CLICKED
+
+ logger.logUndoClicked(undoEvent)
+
+ assertThat(uiEventLoggerFake.numLogs()).isEqualTo(1)
+ assertThat(uiEventLoggerFake.eventId(0)).isEqualTo(undoEvent.id)
+ }
+
+ @Test
+ fun logUndoClicked_notUndoEvent_eventNotLogged() {
+ logger.logUndoClicked(MediaTttSenderUiEvents.MEDIA_TTT_SENDER_TRANSFER_TO_RECEIVER_FAILED)
+
+ assertThat(uiEventLoggerFake.numLogs()).isEqualTo(0)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/monet/ColorSchemeTest.java b/packages/SystemUI/tests/src/com/android/systemui/monet/ColorSchemeTest.java
index 6df56e98783c..51088b1d929b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/monet/ColorSchemeTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/monet/ColorSchemeTest.java
@@ -123,7 +123,7 @@ public class ColorSchemeTest extends SysuiTestCase {
Style.VIBRANT /* style */);
int neutralMid = colorScheme.getNeutral1().get(colorScheme.getNeutral1().size() / 2);
Cam cam = Cam.fromInt(neutralMid);
- Assert.assertEquals(cam.getChroma(), 8.0, 1.0);
+ Assert.assertTrue(cam.getChroma() <= 8.0);
}
@Test
@@ -133,7 +133,7 @@ public class ColorSchemeTest extends SysuiTestCase {
Style.EXPRESSIVE /* style */);
int neutralMid = colorScheme.getNeutral1().get(colorScheme.getNeutral1().size() / 2);
Cam cam = Cam.fromInt(neutralMid);
- Assert.assertEquals(cam.getChroma(), 12.0, 1.0);
+ Assert.assertTrue(cam.getChroma() <= 8.0);
}
/**
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
index eb1e1a2e3d04..a0aa267e850e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
@@ -91,10 +91,10 @@ import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.NotificationShadeDepthController;
import com.android.systemui.statusbar.phone.AutoHideController;
+import com.android.systemui.statusbar.phone.CentralSurfaces;
import com.android.systemui.statusbar.phone.LightBarController;
import com.android.systemui.statusbar.phone.NotificationShadeWindowView;
import com.android.systemui.statusbar.phone.ShadeController;
-import com.android.systemui.statusbar.phone.CentralSurfaces;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.utils.leaks.LeakCheckedTest;
@@ -387,14 +387,14 @@ public class NavigationBarTest extends SysuiTestCase {
DeviceProvisionedController deviceProvisionedController =
mock(DeviceProvisionedController.class);
when(deviceProvisionedController.isDeviceProvisioned()).thenReturn(true);
- NavigationBar.Factory factory = new NavigationBar.Factory(
+ return spy(new NavigationBar(context,
+ mWindowManager,
() -> mAssistManager,
mock(AccessibilityManager.class),
deviceProvisionedController,
new MetricsLogger(),
mOverviewProxyService,
mNavigationModeController,
- mock(AccessibilityButtonModeObserver.class),
mStatusBarStateController,
mMockSysUiState,
mBroadcastDispatcher,
@@ -415,8 +415,7 @@ public class NavigationBarTest extends SysuiTestCase {
mAutoHideControllerFactory,
Optional.of(mTelecomManager),
mInputMethodManager,
- Optional.of(mock(BackAnimation.class)));
- return spy(factory.create(context));
+ Optional.of(mock(BackAnimation.class))));
}
private void processAllMessages() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java b/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java
index afb63ab0ebcf..a156820ad141 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java
@@ -37,6 +37,7 @@ import androidx.test.runner.AndroidJUnit4;
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.broadcast.BroadcastSender;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.util.NotificationChannels;
@@ -59,7 +60,9 @@ public class PowerNotificationWarningsTest extends SysuiTestCase {
// Test Instance.
mContext.addMockSystemService(NotificationManager.class, mMockNotificationManager);
ActivityStarter starter = mDependency.injectMockDependency(ActivityStarter.class);
- mPowerNotificationWarnings = new PowerNotificationWarnings(mContext, starter);
+ BroadcastSender broadcastSender = mDependency.injectMockDependency(BroadcastSender.class);
+ mPowerNotificationWarnings = new PowerNotificationWarnings(mContext, starter,
+ broadcastSender);
BatteryStateSnapshot snapshot = new BatteryStateSnapshot(100, false, false, 1,
BatteryManager.BATTERY_HEALTH_GOOD, 5, 15);
mPowerNotificationWarnings.updateSnapshot(snapshot);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogControllerTest.kt
index 350822691121..38b448fb362c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogControllerTest.kt
@@ -19,8 +19,11 @@ package com.android.systemui.privacy
import android.app.ActivityManager
import android.content.Context
import android.content.Intent
+import android.content.pm.ActivityInfo
import android.content.pm.ApplicationInfo
import android.content.pm.PackageManager
+import android.content.pm.PackageManager.ResolveInfoFlags
+import android.content.pm.ResolveInfo
import android.content.pm.UserInfo
import android.os.Process.SYSTEM_UID
import android.os.UserHandle
@@ -648,6 +651,77 @@ class PrivacyDialogControllerTest : SysuiTestCase() {
}
}
+ @Test
+ fun testCorrectIntentSubAttribution() {
+ val usage = createMockPermGroupUsage(
+ attributionTag = TEST_ATTRIBUTION_TAG,
+ attributionLabel = "TEST_LABEL"
+ )
+
+ val activityInfo = createMockActivityInfo()
+ val resolveInfo = createMockResolveInfo(activityInfo)
+ `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(listOf(usage))
+ `when`(packageManager.resolveActivity(any(), any<ResolveInfoFlags>()))
+ .thenAnswer { resolveInfo }
+ controller.showDialog(context)
+ exhaustExecutors()
+
+ dialogProvider.list?.let { list ->
+ val navigationIntent = list.get(0).navigationIntent!!
+ assertThat(navigationIntent.action).isEqualTo(Intent.ACTION_MANAGE_PERMISSION_USAGE)
+ assertThat(navigationIntent.getStringExtra(Intent.EXTRA_PERMISSION_GROUP_NAME))
+ .isEqualTo(PERM_CAMERA)
+ assertThat(navigationIntent.getStringArrayExtra(Intent.EXTRA_ATTRIBUTION_TAGS))
+ .isEqualTo(arrayOf(TEST_ATTRIBUTION_TAG.toString()))
+ assertThat(navigationIntent.getBooleanExtra(Intent.EXTRA_SHOWING_ATTRIBUTION, false))
+ .isTrue()
+ }
+ }
+
+ @Test
+ fun testDefaultIntentOnMissingAttributionLabel() {
+ val usage = createMockPermGroupUsage(
+ attributionTag = TEST_ATTRIBUTION_TAG
+ )
+
+ val activityInfo = createMockActivityInfo()
+ val resolveInfo = createMockResolveInfo(activityInfo)
+ `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(listOf(usage))
+ `when`(packageManager.resolveActivity(any(), any<ResolveInfoFlags>()))
+ .thenAnswer { resolveInfo }
+ controller.showDialog(context)
+ exhaustExecutors()
+
+ dialogProvider.list?.let { list ->
+ assertThat(isIntentEqual(list.get(0).navigationIntent!!,
+ controller.getDefaultManageAppPermissionsIntent(TEST_PACKAGE_NAME, USER_ID)))
+ .isTrue()
+ }
+ }
+
+ @Test
+ fun testDefaultIntentOnIncorrectPermission() {
+ val usage = createMockPermGroupUsage(
+ attributionTag = TEST_ATTRIBUTION_TAG
+ )
+
+ val activityInfo = createMockActivityInfo(
+ permission = "INCORRECT_PERMISSION"
+ )
+ val resolveInfo = createMockResolveInfo(activityInfo)
+ `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(listOf(usage))
+ `when`(packageManager.resolveActivity(any(), any<ResolveInfoFlags>()))
+ .thenAnswer { resolveInfo }
+ controller.showDialog(context)
+ exhaustExecutors()
+
+ dialogProvider.list?.let { list ->
+ assertThat(isIntentEqual(list.get(0).navigationIntent!!,
+ controller.getDefaultManageAppPermissionsIntent(TEST_PACKAGE_NAME, USER_ID)))
+ .isTrue()
+ }
+ }
+
private fun exhaustExecutors() {
FakeExecutor.exhaustExecutors(backgroundExecutor, uiExecutor)
}
@@ -680,6 +754,24 @@ class PrivacyDialogControllerTest : SysuiTestCase() {
return user * UserHandle.PER_USER_RANGE + nextUid++
}
+ private fun createMockResolveInfo(
+ activityInfo: ActivityInfo? = null
+ ): ResolveInfo {
+ val resolveInfo = mock(ResolveInfo::class.java)
+ resolveInfo.activityInfo = activityInfo
+ return resolveInfo
+ }
+
+ private fun createMockActivityInfo(
+ permission: String = android.Manifest.permission.START_VIEW_PERMISSION_USAGE,
+ className: String = "TEST_CLASS_NAME"
+ ): ActivityInfo {
+ val activityInfo = mock(ActivityInfo::class.java)
+ activityInfo.permission = permission
+ activityInfo.name = className
+ return activityInfo
+ }
+
private fun createMockPermGroupUsage(
packageName: String = TEST_PACKAGE_NAME,
uid: Int = generateUidForUser(USER_ID),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
index 19a9863f6f5e..6b7e5b9335f2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
@@ -20,21 +20,18 @@ import static junit.framework.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyLong;
-import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Intent;
-import android.content.IntentFilter;
import android.os.Handler;
-import android.os.Looper;
+import android.os.RemoteException;
import android.os.UserHandle;
-import android.service.quicksettings.TileService;
+import android.service.quicksettings.IQSTileService;
import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
@@ -49,6 +46,7 @@ import com.android.systemui.qs.logging.QSLogger;
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.phone.AutoTileManager;
import com.android.systemui.statusbar.phone.CentralSurfaces;
import com.android.systemui.statusbar.phone.StatusBarIconController;
@@ -68,17 +66,25 @@ import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
import java.util.Optional;
+import javax.inject.Provider;
+
@SmallTest
@RunWith(AndroidTestingRunner.class)
@RunWithLooper
public class TileServicesTest extends SysuiTestCase {
private static int NUM_FAKES = TileServices.DEFAULT_MAX_BOUND * 2;
+ private static final ComponentName TEST_COMPONENT =
+ ComponentName.unflattenFromString("pkg/.cls");
+
private TileServices mTileService;
+ private TestableLooper mTestableLooper;
private ArrayList<TileServiceManager> mManagers;
@Mock
private BroadcastDispatcher mBroadcastDispatcher;
@Mock
+ private CommandQueue mCommandQueue;
+ @Mock
private StatusBarIconController mStatusBarIconController;
@Mock
private QSFactoryImpl mQSFactory;
@@ -116,17 +122,20 @@ public class TileServicesTest extends SysuiTestCase {
MockitoAnnotations.initMocks(this);
mDependency.injectMockDependency(BluetoothController.class);
mManagers = new ArrayList<>();
+ mTestableLooper = TestableLooper.get(this);
when(mTileServiceRequestControllerBuilder.create(any()))
.thenReturn(mTileServiceRequestController);
when(mTileLifecycleManagerFactory.create(any(Intent.class), any(UserHandle.class)))
.thenReturn(mTileLifecycleManager);
+ Provider<Handler> provider = () -> new Handler(mTestableLooper.getLooper());
+
QSTileHost host = new QSTileHost(mContext,
mStatusBarIconController,
mQSFactory,
- new Handler(),
- Looper.myLooper(),
+ provider.get(),
+ mTestableLooper.getLooper(),
mPluginManager,
mTunerService,
() -> mAutoTileManager,
@@ -140,8 +149,8 @@ public class TileServicesTest extends SysuiTestCase {
mock(CustomTileStatePersister.class),
mTileServiceRequestControllerBuilder,
mTileLifecycleManagerFactory);
- mTileService = new TestTileServices(host, Looper.getMainLooper(), mBroadcastDispatcher,
- mUserTracker, mKeyguardStateController);
+ mTileService = new TestTileServices(host, provider, mBroadcastDispatcher,
+ mUserTracker, mKeyguardStateController, mCommandQueue);
}
@After
@@ -152,24 +161,6 @@ public class TileServicesTest extends SysuiTestCase {
}
@Test
- public void testActiveTileListenerRegisteredOnAllUsers() {
- ArgumentCaptor<IntentFilter> captor = ArgumentCaptor.forClass(IntentFilter.class);
- verify(mBroadcastDispatcher).registerReceiver(any(), captor.capture(), any(), eq(
- UserHandle.ALL));
- assertTrue(captor.getValue().hasAction(TileService.ACTION_REQUEST_LISTENING));
- }
-
- @Test
- public void testBadComponentName_doesntCrash() {
- ArgumentCaptor<BroadcastReceiver> captor = ArgumentCaptor.forClass(BroadcastReceiver.class);
- verify(mBroadcastDispatcher).registerReceiver(captor.capture(), any(), any(), eq(
- UserHandle.ALL));
- Intent intent = new Intent(TileService.ACTION_REQUEST_LISTENING)
- .putExtra(Intent.EXTRA_COMPONENT_NAME, "abc");
- captor.getValue().onReceive(mContext, intent);
- }
-
- @Test
public void testRecalculateBindAllowance() {
// Add some fake tiles.
for (int i = 0; i < NUM_FAKES; i++) {
@@ -225,11 +216,36 @@ public class TileServicesTest extends SysuiTestCase {
}
}
+ @Test
+ public void testRegisterCommand() {
+ verify(mCommandQueue).addCallback(any());
+ }
+
+ @Test
+ public void testRequestListeningStatusCommand() throws RemoteException {
+ ArgumentCaptor<CommandQueue.Callbacks> captor =
+ ArgumentCaptor.forClass(CommandQueue.Callbacks.class);
+ verify(mCommandQueue).addCallback(captor.capture());
+
+ CustomTile mockTile = mock(CustomTile.class);
+ when(mockTile.getComponent()).thenReturn(TEST_COMPONENT);
+
+ TileServiceManager manager = mTileService.getTileWrapper(mockTile);
+ when(manager.isActiveTile()).thenReturn(true);
+ when(manager.getTileService()).thenReturn(mock(IQSTileService.class));
+
+ captor.getValue().requestTileServiceListeningState(TEST_COMPONENT);
+ mTestableLooper.processAllMessages();
+ verify(manager).setBindRequested(true);
+ verify(manager.getTileService()).onStartListening();
+ }
+
private class TestTileServices extends TileServices {
- TestTileServices(QSTileHost host, Looper looper,
+ TestTileServices(QSTileHost host, Provider<Handler> handlerProvider,
BroadcastDispatcher broadcastDispatcher, UserTracker userTracker,
- KeyguardStateController keyguardStateController) {
- super(host, looper, broadcastDispatcher, userTracker, keyguardStateController);
+ KeyguardStateController keyguardStateController, CommandQueue commandQueue) {
+ super(host, handlerProvider, broadcastDispatcher, userTracker, keyguardStateController,
+ commandQueue);
}
@Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QRCodeScannerTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QRCodeScannerTileTest.java
index 8297850d21a1..b652aee0f6aa 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QRCodeScannerTileTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QRCodeScannerTileTest.java
@@ -104,8 +104,6 @@ public class QRCodeScannerTileTest extends SysuiTestCase {
assertEquals(state.label, mContext.getString(R.string.qr_code_scanner_title));
assertEquals(state.contentDescription, mContext.getString(R.string.qr_code_scanner_title));
assertEquals(state.icon, QSTileImpl.ResourceIcon.get(R.drawable.ic_qr_code_scanner));
- assertEquals(state.secondaryLabel,
- mContext.getString(R.string.qr_code_scanner_description));
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetAdapterTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetAdapterTest.java
index d3bb241baad4..f306fd601136 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetAdapterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetAdapterTest.java
@@ -4,14 +4,19 @@ import static com.android.systemui.qs.tiles.dialog.InternetDialogController.MAX_
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.anyString;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.content.Context;
import android.graphics.drawable.Drawable;
import android.testing.AndroidTestingRunner;
import android.testing.TestableResources;
@@ -30,6 +35,7 @@ import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
+import org.mockito.Spy;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
@@ -40,6 +46,7 @@ import java.util.List;
@RunWith(AndroidTestingRunner.class)
public class InternetAdapterTest extends SysuiTestCase {
+ private static final String WIFI_KEY = "Wi-Fi_Key";
private static final String WIFI_TITLE = "Wi-Fi Title";
private static final String WIFI_SUMMARY = "Wi-Fi Summary";
private static final int GEAR_ICON_RES_ID = R.drawable.ic_settings_24dp;
@@ -47,6 +54,8 @@ public class InternetAdapterTest extends SysuiTestCase {
@Rule
public MockitoRule mRule = MockitoJUnit.rule();
+ @Spy
+ private Context mSpyContext = mContext;
@Mock
private WifiEntry mInternetWifiEntry;
@@ -74,6 +83,7 @@ public class InternetAdapterTest extends SysuiTestCase {
when(mInternetWifiEntry.getSummary(false)).thenReturn(WIFI_SUMMARY);
when(mInternetWifiEntry.isDefaultNetwork()).thenReturn(true);
when(mInternetWifiEntry.hasInternetAccess()).thenReturn(true);
+ when(mWifiEntry.getKey()).thenReturn(WIFI_KEY);
when(mWifiEntry.getTitle()).thenReturn(WIFI_TITLE);
when(mWifiEntry.getSummary(false)).thenReturn(WIFI_SUMMARY);
@@ -197,6 +207,66 @@ public class InternetAdapterTest extends SysuiTestCase {
}
@Test
+ public void viewHolderShouldEnabled_wifiCanConnect_returnTrue() {
+ when(mWifiEntry.canConnect()).thenReturn(true);
+
+ assertThat(mViewHolder.shouldEnabled(mWifiEntry)).isTrue();
+ }
+
+ @Test
+ public void viewHolderShouldEnabled_wifiCanNotConnect_returnFalse() {
+ when(mWifiEntry.canConnect()).thenReturn(false);
+
+ assertThat(mViewHolder.shouldEnabled(mWifiEntry)).isFalse();
+ }
+
+ @Test
+ public void viewHolderShouldEnabled_wifiCanNotConnectButCanDisconnect_returnTrue() {
+ when(mWifiEntry.canConnect()).thenReturn(false);
+ when(mWifiEntry.canConnect()).thenReturn(true);
+
+ assertThat(mViewHolder.shouldEnabled(mWifiEntry)).isTrue();
+ }
+
+ @Test
+ public void viewHolderShouldEnabled_wifiCanNotConnectButIsSaved_returnTrue() {
+ when(mWifiEntry.canConnect()).thenReturn(false);
+ when(mWifiEntry.isSaved()).thenReturn(true);
+
+ assertThat(mViewHolder.shouldEnabled(mWifiEntry)).isTrue();
+ }
+
+ @Test
+ public void viewHolderOnWifiClick_wifiShouldEditBeforeConnect_startActivity() {
+ when(mWifiEntry.shouldEditBeforeConnect()).thenReturn(true);
+ mViewHolder = mInternetAdapter.onCreateViewHolder(new LinearLayout(mSpyContext), 0);
+ doNothing().when(mSpyContext).startActivity(any());
+
+ mViewHolder.onWifiClick(mWifiEntry, mock(View.class));
+
+ verify(mSpyContext).startActivity(any());
+ }
+
+ @Test
+ public void viewHolderOnWifiClick_wifiCanConnect_connectWifi() {
+ when(mWifiEntry.canConnect()).thenReturn(true);
+
+ mViewHolder.onWifiClick(mWifiEntry, mock(View.class));
+
+ verify(mInternetDialogController).connect(mWifiEntry);
+ }
+
+ @Test
+ public void viewHolderOnWifiClick_wifiCanNotConnectButIsSaved_launchWifiDetailsSetting() {
+ when(mWifiEntry.canConnect()).thenReturn(false);
+ when(mWifiEntry.isSaved()).thenReturn(true);
+
+ mViewHolder.onWifiClick(mWifiEntry, mock(View.class));
+
+ verify(mInternetDialogController).launchWifiDetailsSetting(anyString(), any());
+ }
+
+ @Test
public void viewHolderUpdateEndIcon_wifiConnected_updateGearIcon() {
mTestableResources.addOverride(GEAR_ICON_RES_ID, mGearIcon);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java
index a2959e2fb917..633a9c3a03d8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java
@@ -385,18 +385,16 @@ public class InternetDialogControllerTest extends SysuiTestCase {
}
@Test
- public void launchWifiNetworkDetailsSetting_withNoWifiEntryKey_doNothing() {
- mInternetDialogController.launchWifiNetworkDetailsSetting(null /* key */,
- mDialogLaunchView);
+ public void launchWifiDetailsSetting_withNoWifiEntryKey_doNothing() {
+ mInternetDialogController.launchWifiDetailsSetting(null /* key */, mDialogLaunchView);
verify(mActivityStarter, never())
.postStartActivityDismissingKeyguard(any(Intent.class), anyInt());
}
@Test
- public void launchWifiNetworkDetailsSetting_withWifiEntryKey_startActivity() {
- mInternetDialogController.launchWifiNetworkDetailsSetting("wifi_entry_key",
- mDialogLaunchView);
+ public void launchWifiDetailsSetting_withWifiEntryKey_startActivity() {
+ mInternetDialogController.launchWifiDetailsSetting("wifi_entry_key", mDialogLaunchView);
verify(mActivityStarter).postStartActivityDismissingKeyguard(any(Intent.class), anyInt(),
any());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/smartspace/DreamSmartspaceControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/smartspace/DreamSmartspaceControllerTest.kt
new file mode 100644
index 000000000000..57803e874f93
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/smartspace/DreamSmartspaceControllerTest.kt
@@ -0,0 +1,181 @@
+/*
+ * 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.smartspace
+
+import android.app.smartspace.SmartspaceManager
+import android.app.smartspace.SmartspaceSession
+import android.app.smartspace.SmartspaceTarget
+import android.content.Context
+import android.graphics.drawable.Drawable
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import android.view.View
+import android.view.ViewGroup
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.dreams.smartspace.DreamsSmartspaceController
+import com.android.systemui.plugins.BcSmartspaceDataPlugin
+import com.android.systemui.plugins.FalsingManager
+import com.android.systemui.smartspace.dagger.SmartspaceViewComponent
+import com.android.systemui.util.concurrency.Execution
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.eq
+import com.android.systemui.util.mockito.withArgCaptor
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito
+import org.mockito.Mockito.`when`
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+import java.util.Optional
+import java.util.concurrent.Executor
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper
+class DreamSmartspaceControllerTest : SysuiTestCase() {
+ @Mock
+ private lateinit var smartspaceManager: SmartspaceManager
+
+ @Mock
+ private lateinit var execution: Execution
+
+ @Mock
+ private lateinit var uiExecutor: Executor
+
+ @Mock
+ private lateinit var viewComponentFactory: SmartspaceViewComponent.Factory
+
+ @Mock
+ private lateinit var viewComponent: SmartspaceViewComponent
+
+ @Mock
+ private lateinit var targetFilter: SmartspaceTargetFilter
+
+ @Mock
+ private lateinit var plugin: BcSmartspaceDataPlugin
+
+ @Mock
+ private lateinit var precondition: SmartspacePrecondition
+
+ @Mock
+ private lateinit var smartspaceView: BcSmartspaceDataPlugin.SmartspaceView
+
+ @Mock
+ private lateinit var listener: BcSmartspaceDataPlugin.SmartspaceTargetListener
+
+ @Mock
+ private lateinit var session: SmartspaceSession
+
+ @Before
+ fun setup() {
+ MockitoAnnotations.initMocks(this)
+ `when`(viewComponentFactory.create(any(), eq(plugin), any()))
+ .thenReturn(viewComponent)
+ `when`(viewComponent.getView()).thenReturn(smartspaceView)
+ `when`(smartspaceManager.createSmartspaceSession(any())).thenReturn(session)
+ }
+
+ /**
+ * Ensures smartspace session begins on a listener only flow.
+ */
+ @Test
+ fun testConnectOnListen() {
+ val controller = DreamsSmartspaceController(context,
+ smartspaceManager, execution, uiExecutor, viewComponentFactory, precondition,
+ Optional.of(targetFilter), Optional.of(plugin))
+
+ `when`(precondition.conditionsMet()).thenReturn(true)
+ controller.addListener(listener)
+
+ verify(smartspaceManager).createSmartspaceSession(any())
+
+ var targetListener = withArgCaptor<SmartspaceSession.OnTargetsAvailableListener> {
+ verify(session).addOnTargetsAvailableListener(any(), capture())
+ }
+
+ `when`(targetFilter.filterSmartspaceTarget(any())).thenReturn(true)
+
+ var target = Mockito.mock(SmartspaceTarget::class.java)
+ targetListener.onTargetsAvailable(listOf(target))
+
+ var targets = withArgCaptor<List<SmartspaceTarget>> {
+ verify(plugin).onTargetsAvailable(capture())
+ }
+
+ assertThat(targets.contains(target)).isTrue()
+
+ controller.removeListener(listener)
+
+ verify(session).close()
+ }
+
+ /**
+ * A class which implements SmartspaceView and extends View. This is mocked to provide the right
+ * object inheritance and interface implementation used in DreamSmartspaceController
+ */
+ private class TestView(context: Context?) : View(context),
+ BcSmartspaceDataPlugin.SmartspaceView {
+ override fun registerDataProvider(plugin: BcSmartspaceDataPlugin?) {}
+
+ override fun setPrimaryTextColor(color: Int) {}
+
+ override fun setDozeAmount(amount: Float) {}
+
+ override fun setIntentStarter(intentStarter: BcSmartspaceDataPlugin.IntentStarter?) {}
+
+ override fun setFalsingManager(falsingManager: FalsingManager?) {}
+
+ override fun setDnd(image: Drawable?, description: String?) {}
+
+ override fun setNextAlarm(image: Drawable?, description: String?) {}
+
+ override fun setMediaTarget(target: SmartspaceTarget?) {}
+
+ override fun getSelectedPage(): Int { return 0; }
+ }
+
+ /**
+ * Ensures session begins when a view is attached.
+ */
+ @Test
+ fun testConnectOnViewCreate() {
+ val controller = DreamsSmartspaceController(context,
+ smartspaceManager, execution, uiExecutor, viewComponentFactory, precondition,
+ Optional.of(targetFilter),
+ Optional.of(plugin))
+
+ `when`(precondition.conditionsMet()).thenReturn(true)
+ controller.buildAndConnectView(Mockito.mock(ViewGroup::class.java))
+
+ var stateChangeListener = withArgCaptor<View.OnAttachStateChangeListener> {
+ verify(viewComponentFactory).create(any(), eq(plugin), capture())
+ }
+
+ var mockView = Mockito.mock(TestView::class.java)
+ `when`(precondition.conditionsMet()).thenReturn(true)
+ stateChangeListener.onViewAttachedToWindow(mockView)
+
+ verify(smartspaceManager).createSmartspaceSession(any())
+
+ stateChangeListener.onViewDetachedFromWindow(mockView)
+
+ verify(session).close()
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/smartspace/LockscreenPreconditionTest.kt b/packages/SystemUI/tests/src/com/android/systemui/smartspace/LockscreenPreconditionTest.kt
new file mode 100644
index 000000000000..d29e9a66a331
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/smartspace/LockscreenPreconditionTest.kt
@@ -0,0 +1,132 @@
+/*
+ * 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.smartspace
+
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
+import com.android.systemui.smartspace.preconditions.LockscreenPrecondition
+import com.android.systemui.statusbar.policy.DeviceProvisionedController
+import com.android.systemui.util.concurrency.Execution
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+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.`when`
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper
+class LockscreenPreconditionTest : SysuiTestCase() {
+ @Mock
+ private lateinit var featureFlags: FeatureFlags
+
+ @Mock
+ private lateinit var deviceProvisionedController: DeviceProvisionedController
+
+ @Mock
+ private lateinit var execution: Execution
+
+ @Mock
+ private lateinit var listener: SmartspacePrecondition.Listener
+
+ @Before
+ fun setup() {
+ MockitoAnnotations.initMocks(this)
+ }
+
+ /**
+ * Ensures fully enabled state is published.
+ */
+ @Test
+ fun testFullyEnabled() {
+ `when`(deviceProvisionedController.isCurrentUserSetup).thenReturn(true)
+ `when`(deviceProvisionedController.isDeviceProvisioned).thenReturn(true)
+ `when`(featureFlags.isEnabled(Mockito.eq(Flags.SMARTSPACE) ?: Flags.SMARTSPACE))
+ .thenReturn(true)
+ val precondition = LockscreenPrecondition(featureFlags, deviceProvisionedController,
+ execution)
+ precondition.addListener(listener)
+
+ `verify`(listener).onCriteriaChanged()
+ assertThat(precondition.conditionsMet()).isTrue()
+ }
+
+ /**
+ * Ensures fully enabled state is published.
+ */
+ @Test
+ fun testProvisioning() {
+ `when`(deviceProvisionedController.isCurrentUserSetup).thenReturn(true)
+ `when`(deviceProvisionedController.isDeviceProvisioned).thenReturn(false)
+ `when`(featureFlags.isEnabled(Mockito.eq(Flags.SMARTSPACE) ?: Flags.SMARTSPACE))
+ .thenReturn(true)
+ val precondition =
+ LockscreenPrecondition(featureFlags, deviceProvisionedController, execution)
+ precondition.addListener(listener)
+
+ verify(listener).onCriteriaChanged()
+ assertThat(precondition.conditionsMet()).isFalse()
+
+ var argumentCaptor = ArgumentCaptor.forClass(DeviceProvisionedController
+ .DeviceProvisionedListener::class.java)
+ verify(deviceProvisionedController).addCallback(argumentCaptor.capture())
+
+ Mockito.clearInvocations(listener)
+
+ `when`(deviceProvisionedController.isDeviceProvisioned).thenReturn(true)
+ argumentCaptor.value.onDeviceProvisionedChanged()
+ verify(listener).onCriteriaChanged()
+ assertThat(precondition.conditionsMet()).isTrue()
+ }
+
+ /**
+ * Makes sure user setup changes are propagated.
+ */
+ @Test
+ fun testUserSetup() {
+ `when`(deviceProvisionedController.isCurrentUserSetup).thenReturn(false)
+ `when`(deviceProvisionedController.isDeviceProvisioned).thenReturn(true)
+ `when`(featureFlags.isEnabled(Mockito.eq(Flags.SMARTSPACE) ?: Flags.SMARTSPACE))
+ .thenReturn(true)
+ val precondition =
+ LockscreenPrecondition(featureFlags, deviceProvisionedController, execution)
+ precondition.addListener(listener)
+
+ verify(listener).onCriteriaChanged()
+ assertThat(precondition.conditionsMet()).isFalse()
+
+ var argumentCaptor = ArgumentCaptor.forClass(DeviceProvisionedController
+ .DeviceProvisionedListener::class.java)
+ verify(deviceProvisionedController).addCallback(argumentCaptor.capture())
+
+ Mockito.clearInvocations(listener)
+
+ `when`(deviceProvisionedController.isCurrentUserSetup).thenReturn(true)
+ argumentCaptor.value.onUserSetupChanged()
+ verify(listener).onCriteriaChanged()
+ assertThat(precondition.conditionsMet()).isTrue()
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/smartspace/LockscreenTargetFilterTest.kt b/packages/SystemUI/tests/src/com/android/systemui/smartspace/LockscreenTargetFilterTest.kt
new file mode 100644
index 000000000000..185a8384dd75
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/smartspace/LockscreenTargetFilterTest.kt
@@ -0,0 +1,149 @@
+/*
+ * 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.smartspace
+
+import android.app.smartspace.SmartspaceTarget
+import android.content.ContentResolver
+import android.database.ContentObserver
+import android.net.Uri
+import android.os.Handler
+import android.os.UserHandle
+import android.provider.Settings
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.settings.UserTracker
+import com.android.systemui.smartspace.filters.LockscreenTargetFilter
+import com.android.systemui.util.concurrency.Execution
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.eq
+import com.android.systemui.util.mockito.withArgCaptor
+import com.android.systemui.util.settings.SecureSettings
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+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.Mock
+import org.mockito.Mockito.`when`
+import org.mockito.Mockito.atLeast
+import org.mockito.Mockito.clearInvocations
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+import java.util.concurrent.Executor
+
+@SmallTest
+@TestableLooper.RunWithLooper
+@RunWith(AndroidTestingRunner::class)
+class LockscreenTargetFilterTest : SysuiTestCase() {
+ @Mock
+ private lateinit var secureSettings: SecureSettings
+
+ @Mock
+ private lateinit var userTracker: UserTracker
+
+ @Mock
+ private lateinit var execution: Execution
+
+ @Mock
+ private lateinit var handler: Handler
+
+ @Mock
+ private lateinit var contentResolver: ContentResolver
+
+ @Mock
+ private lateinit var uiExecution: Executor
+
+ @Mock
+ private lateinit var userHandle: UserHandle
+
+ @Mock
+ private lateinit var listener: SmartspaceTargetFilter.Listener
+
+ @Mock
+ private lateinit var lockScreenAllowPrivateNotificationsUri: Uri
+
+ @Before
+ fun setup() {
+ MockitoAnnotations.initMocks(this)
+ `when`(userTracker.userHandle).thenReturn(userHandle)
+ `when`(secureSettings
+ .getUriFor(eq(Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS)))
+ .thenReturn(lockScreenAllowPrivateNotificationsUri)
+ }
+
+ /**
+ * Ensures {@link Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS} is
+ * tracked.
+ */
+ @Test
+ fun testLockscreenAllowPrivateNotifications() {
+ var setting = Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS
+ `when`(secureSettings
+ .getIntForUser(eq(setting) ?: setting, anyInt(), anyInt()))
+ .thenReturn(0)
+ var filter = LockscreenTargetFilter(secureSettings, userTracker, execution, handler,
+ contentResolver, uiExecution)
+
+ filter.addListener(listener)
+ var smartspaceTarget = mock(SmartspaceTarget::class.java)
+ `when`(smartspaceTarget.userHandle).thenReturn(userHandle)
+ `when`(smartspaceTarget.isSensitive).thenReturn(true)
+ assertThat(filter.filterSmartspaceTarget(smartspaceTarget)).isFalse()
+
+ var settingCaptor = ArgumentCaptor.forClass(ContentObserver::class.java)
+
+ verify(contentResolver).registerContentObserver(eq(lockScreenAllowPrivateNotificationsUri),
+ anyBoolean(), settingCaptor.capture(), anyInt())
+
+ `when`(secureSettings
+ .getIntForUser(eq(setting) ?: setting, anyInt(), anyInt()))
+ .thenReturn(1)
+
+ clearInvocations(listener)
+ settingCaptor.value.onChange(false, mock(Uri::class.java))
+ verify(listener, atLeast(1)).onCriteriaChanged()
+ assertThat(filter.filterSmartspaceTarget(smartspaceTarget)).isTrue()
+ }
+
+ /**
+ * Ensures user switches are tracked.
+ */
+ @Test
+ fun testUserSwitchCallback() {
+ var setting = Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS
+ `when`(secureSettings
+ .getIntForUser(eq(setting) ?: setting, anyInt(), anyInt()))
+ .thenReturn(0)
+ var filter = LockscreenTargetFilter(secureSettings, userTracker, execution, handler,
+ contentResolver, uiExecution)
+
+ filter.addListener(listener)
+
+ var userTrackerCallback = withArgCaptor<UserTracker.Callback> {
+ verify(userTracker).addCallback(capture(), any())
+ }
+
+ clearInvocations(listener)
+ userTrackerCallback.onUserChanged(0, context)
+
+ verify(listener).onCriteriaChanged()
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
index 3c1a73eb672e..a2a02cd939ef 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
@@ -51,6 +51,7 @@ import static org.mockito.Mockito.when;
import android.app.IActivityManager;
import android.app.Instrumentation;
import android.app.admin.DevicePolicyManager;
+import android.app.admin.DevicePolicyResourcesManager;
import android.app.trust.TrustManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@@ -126,6 +127,8 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase {
@Mock
private DevicePolicyManager mDevicePolicyManager;
@Mock
+ private DevicePolicyResourcesManager mDevicePolicyResourcesManager;
+ @Mock
private ViewGroup mIndicationArea;
@Mock
private KeyguardStateController mKeyguardStateController;
@@ -210,12 +213,14 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase {
.thenReturn(mIndicationAreaBottom);
when(mIndicationArea.findViewById(R.id.keyguard_indication_text)).thenReturn(mTextView);
+ when(mDevicePolicyManager.getResources()).thenReturn(mDevicePolicyResourcesManager);
when(mDevicePolicyManager.getDeviceOwnerComponentOnAnyUser())
.thenReturn(DEVICE_OWNER_COMPONENT);
when(mDevicePolicyManager.getDeviceOwnerType(DEVICE_OWNER_COMPONENT))
.thenReturn(DEVICE_OWNER_TYPE_DEFAULT);
- when(mDevicePolicyManager.getString(anyString(), any())).thenReturn(mDisclosureGeneric);
- when(mDevicePolicyManager.getString(anyString(), any(), anyString()))
+ when(mDevicePolicyResourcesManager.getString(anyString(), any()))
+ .thenReturn(mDisclosureGeneric);
+ when(mDevicePolicyResourcesManager.getString(anyString(), any(), anyString()))
.thenReturn(mDisclosureWithOrganization);
mWakeLock = new WakeLockFake();
@@ -226,6 +231,10 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase {
@After
public void tearDown() throws Exception {
mTextView.setAnimationsEnabled(true);
+ if (mController != null) {
+ mController.destroy();
+ mController = null;
+ }
}
private void createController() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
index 25a5b900f15a..1d2a0ca3777a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
@@ -1,5 +1,6 @@
package com.android.systemui.statusbar
+import org.mockito.Mockito.`when` as whenever
import android.test.suitebuilder.annotation.SmallTest
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
@@ -18,11 +19,11 @@ import com.android.systemui.statusbar.notification.row.NotificationTestHelper
import com.android.systemui.statusbar.notification.stack.AmbientState
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
+import com.android.systemui.statusbar.phone.CentralSurfaces
import com.android.systemui.statusbar.phone.KeyguardBypassController
import com.android.systemui.statusbar.phone.LSShadeTransitionLogger
import com.android.systemui.statusbar.phone.NotificationPanelViewController
import com.android.systemui.statusbar.phone.ScrimController
-import com.android.systemui.statusbar.phone.CentralSurfaces
import com.android.systemui.statusbar.policy.FakeConfigurationController
import org.junit.After
import org.junit.Assert.assertFalse
@@ -37,13 +38,13 @@ import org.mockito.ArgumentMatchers.anyBoolean
import org.mockito.ArgumentMatchers.anyFloat
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.ArgumentMatchers.anyLong
+import org.mockito.ArgumentMatchers.eq
import org.mockito.Mock
import org.mockito.Mockito
import org.mockito.Mockito.clearInvocations
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
import org.mockito.junit.MockitoJUnit
-import org.mockito.Mockito.`when` as whenever
private fun <T> anyObject(): T {
return Mockito.anyObject<T>()
@@ -87,6 +88,8 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() {
row = helper.createRow()
context.getOrCreateTestableResources()
.addOverride(R.bool.config_use_split_notification_shade, false)
+ context.getOrCreateTestableResources()
+ .addOverride(R.dimen.lockscreen_shade_depth_controller_transition_distance, 100)
transitionController = LockscreenShadeTransitionController(
statusBarStateController = statusbarStateController,
logger = logger,
@@ -228,7 +231,7 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() {
transitionController.dragDownAmount = 10f
verify(nsslController, never()).setTransitionToFullShadeAmount(anyFloat(), anyFloat())
verify(mediaHierarchyManager, never()).setTransitionToFullShadeAmount(anyFloat())
- verify(scrimController, never()).setTransitionToFullShadeProgress(anyFloat())
+ verify(scrimController, never()).setTransitionToFullShadeProgress(anyFloat(), anyFloat())
verify(notificationPanelController, never()).setTransitionToFullShadeAmount(anyFloat(),
anyBoolean(), anyLong())
verify(qS, never()).setTransitionToFullShadeAmount(anyFloat(), anyFloat())
@@ -239,7 +242,7 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() {
transitionController.dragDownAmount = 10f
verify(nsslController).setTransitionToFullShadeAmount(anyFloat(), anyFloat())
verify(mediaHierarchyManager).setTransitionToFullShadeAmount(anyFloat())
- verify(scrimController).setTransitionToFullShadeProgress(anyFloat())
+ verify(scrimController).setTransitionToFullShadeProgress(anyFloat(), anyFloat())
verify(notificationPanelController).setTransitionToFullShadeAmount(anyFloat(),
anyBoolean(), anyLong())
verify(qS).setTransitionToFullShadeAmount(anyFloat(), anyFloat())
@@ -247,6 +250,60 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() {
}
@Test
+ fun testDragDownAmount_depthDistanceIsZero_doesNotSetProgress() {
+ context.getOrCreateTestableResources()
+ .addOverride(R.dimen.lockscreen_shade_depth_controller_transition_distance, 0)
+ configurationController.notifyConfigurationChanged()
+
+ transitionController.dragDownAmount = 10f
+
+ verify(depthController, never()).transitionToFullShadeProgress
+ }
+
+ @Test
+ fun setDragAmount_setsKeyguardTransitionProgress() {
+ transitionController.dragDownAmount = 10f
+
+ verify(notificationPanelController).setKeyguardTransitionProgress(anyFloat(), anyInt())
+ }
+
+ @Test
+ fun setDragAmount_setsKeyguardAlphaBasedOnDistance() {
+ val alphaDistance = context.resources.getDimensionPixelSize(
+ R.dimen.lockscreen_shade_npvc_keyguard_content_alpha_transition_distance)
+ transitionController.dragDownAmount = 10f
+
+ val expectedAlpha = 1 - 10f / alphaDistance
+ verify(notificationPanelController)
+ .setKeyguardTransitionProgress(eq(expectedAlpha), anyInt())
+ }
+
+ @Test
+ fun setDragAmount_notInSplitShade_setsKeyguardTranslationToZero() {
+ val mediaTranslationY = 123
+ disableSplitShade()
+ whenever(mediaHierarchyManager.getGuidedTransformationTranslationY())
+ .thenReturn(mediaTranslationY)
+
+ transitionController.dragDownAmount = 10f
+
+ verify(notificationPanelController).setKeyguardTransitionProgress(anyFloat(), eq(0))
+ }
+
+ @Test
+ fun setDragAmount_inSplitShade_setsKeyguardTranslationBasedOnMediaTranslation() {
+ val mediaTranslationY = 123
+ enableSplitShade()
+ whenever(mediaHierarchyManager.getGuidedTransformationTranslationY())
+ .thenReturn(mediaTranslationY)
+
+ transitionController.dragDownAmount = 10f
+
+ verify(notificationPanelController)
+ .setKeyguardTransitionProgress(anyFloat(), eq(mediaTranslationY))
+ }
+
+ @Test
fun setDragDownAmount_setsValueOnMediaHierarchyManager() {
transitionController.dragDownAmount = 10f
@@ -254,6 +311,75 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() {
}
@Test
+ fun setDragAmount_setsScrimProgressBasedOnScrimDistance() {
+ val distance = 10
+ context.orCreateTestableResources
+ .addOverride(R.dimen.lockscreen_shade_scrim_transition_distance, distance)
+ configurationController.notifyConfigurationChanged()
+
+ transitionController.dragDownAmount = 5f
+
+ verify(scrimController).transitionToFullShadeProgress(
+ progress = eq(0.5f),
+ lockScreenNotificationsProgress = anyFloat()
+ )
+ }
+
+ @Test
+ fun setDragAmount_setsNotificationsScrimProgressBasedOnNotificationsScrimDistanceAndDelay() {
+ val distance = 100
+ val delay = 10
+ context.orCreateTestableResources.addOverride(
+ R.dimen.lockscreen_shade_notifications_scrim_transition_distance, distance)
+ context.orCreateTestableResources.addOverride(
+ R.dimen.lockscreen_shade_notifications_scrim_transition_delay, delay)
+ configurationController.notifyConfigurationChanged()
+
+ transitionController.dragDownAmount = 20f
+
+ verify(scrimController).transitionToFullShadeProgress(
+ progress = anyFloat(),
+ lockScreenNotificationsProgress = eq(0.1f)
+ )
+ }
+
+ @Test
+ fun setDragAmount_dragAmountLessThanNotifDelayDistance_setsNotificationsScrimProgressToZero() {
+ val distance = 100
+ val delay = 50
+ context.orCreateTestableResources.addOverride(
+ R.dimen.lockscreen_shade_notifications_scrim_transition_distance, distance)
+ context.orCreateTestableResources.addOverride(
+ R.dimen.lockscreen_shade_notifications_scrim_transition_delay, delay)
+ configurationController.notifyConfigurationChanged()
+
+ transitionController.dragDownAmount = 20f
+
+ verify(scrimController).transitionToFullShadeProgress(
+ progress = anyFloat(),
+ lockScreenNotificationsProgress = eq(0f)
+ )
+ }
+
+ @Test
+ fun setDragAmount_dragAmountMoreThanTotalDistance_setsNotificationsScrimProgressToOne() {
+ val distance = 100
+ val delay = 50
+ context.orCreateTestableResources.addOverride(
+ R.dimen.lockscreen_shade_notifications_scrim_transition_distance, distance)
+ context.orCreateTestableResources.addOverride(
+ R.dimen.lockscreen_shade_notifications_scrim_transition_delay, delay)
+ configurationController.notifyConfigurationChanged()
+
+ transitionController.dragDownAmount = 999999f
+
+ verify(scrimController).transitionToFullShadeProgress(
+ progress = anyFloat(),
+ lockScreenNotificationsProgress = eq(1f)
+ )
+ }
+
+ @Test
fun setDragDownAmount_inSplitShade_setsValueOnMediaHierarchyManager() {
enableSplitShade()
@@ -263,9 +389,29 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() {
}
private fun enableSplitShade() {
- context.getOrCreateTestableResources().addOverride(
- R.bool.config_use_split_notification_shade, true
- )
+ setSplitShadeEnabled(true)
+ }
+
+ private fun disableSplitShade() {
+ setSplitShadeEnabled(false)
+ }
+
+ private fun setSplitShadeEnabled(enabled: Boolean) {
+ overrideResource(R.bool.config_use_split_notification_shade, enabled)
configurationController.notifyConfigurationChanged()
}
+
+ /**
+ * Wrapper around [ScrimController.transitionToFullShadeProgress] that has named parameters for
+ * clarify and easier refactoring of parameter names.
+ */
+ private fun ScrimController.transitionToFullShadeProgress(
+ progress: Float,
+ lockScreenNotificationsProgress: Float
+ ) {
+ scrimController.setTransitionToFullShadeProgress(
+ progress,
+ lockScreenNotificationsProgress
+ )
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationUiAdjustmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationUiAdjustmentTest.java
index 353647b65cc0..4d8949562e08 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationUiAdjustmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationUiAdjustmentTest.java
@@ -80,8 +80,8 @@ public class NotificationUiAdjustmentTest extends SysuiTestCase {
Notification.Action firstAction =
createActionBuilder("same", R.drawable.ic_corp_icon, pendingIntent).build();
Notification.Action secondAction =
- createActionBuilder("same", R.drawable.ic_account_circle, pendingIntent)
- .build();
+ createActionBuilder("same", com.android.settingslib.R.drawable.ic_account_circle,
+ pendingIntent).build();
assertThat(NotificationUiAdjustment.needReinflate(
createUiAdjustmentFromSmartActions("first", Collections.singletonList(firstAction)),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorControllerTest.kt
index 3a60c049b3f3..9f82a5673c6e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorControllerTest.kt
@@ -31,6 +31,7 @@ class NotificationLaunchAnimatorControllerTest : SysuiTestCase() {
@Mock lateinit var notificationListContainer: NotificationListContainer
@Mock lateinit var headsUpManager: HeadsUpManagerPhone
@Mock lateinit var jankMonitor: InteractionJankMonitor
+ @Mock lateinit var onFinishAnimationCallback: Runnable
private lateinit var notificationTestHelper: NotificationTestHelper
private lateinit var notification: ExpandableNotificationRow
@@ -52,7 +53,8 @@ class NotificationLaunchAnimatorControllerTest : SysuiTestCase() {
notificationListContainer,
headsUpManager,
notification,
- jankMonitor
+ jankMonitor,
+ onFinishAnimationCallback
)
}
@@ -61,7 +63,7 @@ class NotificationLaunchAnimatorControllerTest : SysuiTestCase() {
}
@Test
- fun testHunIsRemovedIfWeDontAnimateLaunch() {
+ fun testHunIsRemovedAndCallbackIsInvokedIfWeDontAnimateLaunch() {
flagNotificationAsHun()
controller.onIntentStarted(willAnimate = false)
@@ -69,10 +71,11 @@ class NotificationLaunchAnimatorControllerTest : SysuiTestCase() {
assertFalse(notification.entry.isExpandAnimationRunning)
verify(headsUpManager).removeNotification(
notificationKey, true /* releaseImmediately */, true /* animate */)
+ verify(onFinishAnimationCallback).run()
}
@Test
- fun testHunIsRemovedWhenAnimationIsCancelled() {
+ fun testHunIsRemovedAndCallbackIsInvokedWhenAnimationIsCancelled() {
flagNotificationAsHun()
controller.onLaunchAnimationCancelled()
@@ -80,10 +83,11 @@ class NotificationLaunchAnimatorControllerTest : SysuiTestCase() {
assertFalse(notification.entry.isExpandAnimationRunning)
verify(headsUpManager).removeNotification(
notificationKey, true /* releaseImmediately */, true /* animate */)
+ verify(onFinishAnimationCallback).run()
}
@Test
- fun testHunIsRemovedWhenAnimationEnds() {
+ fun testHunIsRemovedAndCallbackIsInvokedWhenAnimationEnds() {
flagNotificationAsHun()
controller.onLaunchAnimationEnd(isExpandingFullyAbove = true)
@@ -91,6 +95,7 @@ class NotificationLaunchAnimatorControllerTest : SysuiTestCase() {
assertFalse(notification.entry.isExpandAnimationRunning)
verify(headsUpManager).removeNotification(
notificationKey, true /* releaseImmediately */, false /* animate */)
+ verify(onFinishAnimationCallback).run()
}
@Test
@@ -99,4 +104,4 @@ class NotificationLaunchAnimatorControllerTest : SysuiTestCase() {
assertTrue(notification.entry.isExpandAnimationRunning)
}
-} \ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ActivityLaunchAnimCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ActivityLaunchAnimCoordinatorTest.kt
new file mode 100644
index 000000000000..c6c043aafb20
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ActivityLaunchAnimCoordinatorTest.kt
@@ -0,0 +1,138 @@
+/*
+ * 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.statusbar.notification.collection.coordinator
+
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.notification.collection.NotifPipeline
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope
+import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender
+import com.android.systemui.statusbar.phone.NotifActivityLaunchEvents
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.withArgCaptor
+import dagger.BindsInstance
+import dagger.Component
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertTrue
+import org.junit.Test
+import org.mockito.Mockito.never
+import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when` as whenever
+
+@SmallTest
+class ActivityLaunchAnimCoordinatorTest : SysuiTestCase() {
+
+ val activityLaunchEvents: NotifActivityLaunchEvents = mock()
+ val pipeline: NotifPipeline = mock()
+
+ val coordinator: ActivityLaunchAnimCoordinator =
+ DaggerTestActivityStarterCoordinatorComponent
+ .factory()
+ .create(activityLaunchEvents)
+ .coordinator
+
+ @Test
+ fun testNoLifetimeExtensionIfNoAssociatedActivityLaunch() {
+ coordinator.attach(pipeline)
+ val lifetimeExtender = withArgCaptor<NotifLifetimeExtender> {
+ verify(pipeline).addNotificationLifetimeExtender(capture())
+ }
+ val fakeEntry = mock<NotificationEntry>().also {
+ whenever(it.key).thenReturn("0")
+ }
+ assertFalse(lifetimeExtender.maybeExtendLifetime(fakeEntry, 0))
+ }
+
+ @Test
+ fun testNoLifetimeExtensionIfAssociatedActivityLaunchAlreadyEnded() {
+ coordinator.attach(pipeline)
+ val lifetimeExtender = withArgCaptor<NotifLifetimeExtender> {
+ verify(pipeline).addNotificationLifetimeExtender(capture())
+ }
+ val eventListener = withArgCaptor<NotifActivityLaunchEvents.Listener> {
+ verify(activityLaunchEvents).registerListener(capture())
+ }
+ val fakeEntry = mock<NotificationEntry>().also {
+ whenever(it.key).thenReturn("0")
+ }
+ eventListener.onStartLaunchNotifActivity(fakeEntry)
+ eventListener.onFinishLaunchNotifActivity(fakeEntry)
+ assertFalse(lifetimeExtender.maybeExtendLifetime(fakeEntry, 0))
+ }
+
+ @Test
+ fun testLifetimeExtensionWhileActivityLaunchInProgress() {
+ coordinator.attach(pipeline)
+ val lifetimeExtender = withArgCaptor<NotifLifetimeExtender> {
+ verify(pipeline).addNotificationLifetimeExtender(capture())
+ }
+ val eventListener = withArgCaptor<NotifActivityLaunchEvents.Listener> {
+ verify(activityLaunchEvents).registerListener(capture())
+ }
+ val onEndLifetimeExtensionCallback =
+ mock<NotifLifetimeExtender.OnEndLifetimeExtensionCallback>()
+ lifetimeExtender.setCallback(onEndLifetimeExtensionCallback)
+
+ val fakeEntry = mock<NotificationEntry>().also {
+ whenever(it.key).thenReturn("0")
+ }
+ eventListener.onStartLaunchNotifActivity(fakeEntry)
+ assertTrue(lifetimeExtender.maybeExtendLifetime(fakeEntry, 0))
+
+ eventListener.onFinishLaunchNotifActivity(fakeEntry)
+ verify(onEndLifetimeExtensionCallback).onEndLifetimeExtension(lifetimeExtender, fakeEntry)
+ }
+
+ @Test
+ fun testCancelLifetimeExtensionDoesNotInvokeCallback() {
+ coordinator.attach(pipeline)
+ val lifetimeExtender = withArgCaptor<NotifLifetimeExtender> {
+ verify(pipeline).addNotificationLifetimeExtender(capture())
+ }
+ val eventListener = withArgCaptor<NotifActivityLaunchEvents.Listener> {
+ verify(activityLaunchEvents).registerListener(capture())
+ }
+ val onEndLifetimeExtensionCallback =
+ mock<NotifLifetimeExtender.OnEndLifetimeExtensionCallback>()
+ lifetimeExtender.setCallback(onEndLifetimeExtensionCallback)
+
+ val fakeEntry = mock<NotificationEntry>().also {
+ whenever(it.key).thenReturn("0")
+ }
+ eventListener.onStartLaunchNotifActivity(fakeEntry)
+ assertTrue(lifetimeExtender.maybeExtendLifetime(fakeEntry, 0))
+
+ lifetimeExtender.cancelLifetimeExtension(fakeEntry)
+ eventListener.onFinishLaunchNotifActivity(fakeEntry)
+ verify(onEndLifetimeExtensionCallback, never())
+ .onEndLifetimeExtension(lifetimeExtender, fakeEntry)
+ }
+}
+
+@CoordinatorScope
+@Component(modules = [ActivityLaunchAnimCoordinatorModule::class])
+interface TestActivityStarterCoordinatorComponent {
+ val coordinator: ActivityLaunchAnimCoordinator
+
+ @Component.Factory
+ interface Factory {
+ fun create(
+ @BindsInstance activityLaunchEvents: NotifActivityLaunchEvents
+ ): TestActivityStarterCoordinatorComponent
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/CommunalCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/CommunalCoordinatorTest.java
deleted file mode 100644
index 1f52b9cc4195..000000000000
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/CommunalCoordinatorTest.java
+++ /dev/null
@@ -1,106 +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.systemui.statusbar.notification.collection.coordinator;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.test.suitebuilder.annotation.SmallTest;
-
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.communal.CommunalStateController;
-import com.android.systemui.statusbar.NotificationLockscreenUserManager;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
-import com.android.systemui.statusbar.notification.collection.NotifPipeline;
-import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
-import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.Pluggable;
-import com.android.systemui.util.concurrency.FakeExecutor;
-import com.android.systemui.util.time.FakeSystemClock;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-
-@SmallTest
-public class CommunalCoordinatorTest extends SysuiTestCase {
- private final FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock());
-
- @Mock
- CommunalStateController mCommunalStateController;
- @Mock
- NotificationEntryManager mNotificationEntryManager;
- @Mock
- NotificationLockscreenUserManager mNotificationLockscreenUserManager;
- @Mock
- NotifPipeline mNotifPipeline;
- @Mock
- NotificationEntry mNotificationEntry;
- @Mock
- Pluggable.PluggableListener mFilterListener;
-
- CommunalCoordinator mCoordinator;
-
- @Before
- public void setup() {
- MockitoAnnotations.initMocks(this);
- mCoordinator = new CommunalCoordinator(mExecutor, mNotificationEntryManager,
- mNotificationLockscreenUserManager, mCommunalStateController);
- }
-
- @Test
- public void testNotificationSuppressionInCommunal() {
- mCoordinator.attach(mNotifPipeline);
- final ArgumentCaptor<CommunalStateController.Callback> stateCallbackCaptor =
- ArgumentCaptor.forClass(CommunalStateController.Callback.class);
- verify(mCommunalStateController).addCallback(stateCallbackCaptor.capture());
-
- final CommunalStateController.Callback stateCallback = stateCallbackCaptor.getValue();
-
- final ArgumentCaptor<NotifFilter> filterCaptor =
- ArgumentCaptor.forClass(NotifFilter.class);
- verify(mNotifPipeline).addPreGroupFilter(filterCaptor.capture());
-
- final NotifFilter filter = filterCaptor.getValue();
-
- // Verify that notifications are not filtered out by default.
- assertThat(filter.shouldFilterOut(mNotificationEntry, 0)).isFalse();
-
- filter.setInvalidationListener(mFilterListener);
-
- // Verify that notifications are filtered out when communal is showing and that the filter
- // pipeline is notified.
- when(mCommunalStateController.getCommunalViewShowing()).thenReturn(true);
- stateCallback.onCommunalViewShowingChanged();
- // Make sure callback depends on executor to run.
- verify(mFilterListener, never()).onPluggableInvalidated(any());
- verify(mNotificationEntryManager, never()).updateNotifications(any());
-
- mExecutor.runAllReady();
-
- verify(mFilterListener).onPluggableInvalidated(any());
- verify(mNotificationEntryManager).updateNotifications(any());
- assertThat(filter.shouldFilterOut(mNotificationEntry, 0)).isTrue();
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt
index 144eefb17283..699f77f9b7bb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt
@@ -170,11 +170,41 @@ class HeadsUpCoordinatorTest : SysuiTestCase() {
}
@Test
+ fun testCancelAndReAddStickyNotification() {
+ whenever(mHeadsUpManager.isSticky(anyString())).thenReturn(true)
+ addHUN(mEntry)
+ whenever(mHeadsUpManager.canRemoveImmediately(anyString())).thenReturn(false, true, false)
+ whenever(mHeadsUpManager.getEarliestRemovalTime(anyString())).thenReturn(1000L)
+ assertTrue(mNotifLifetimeExtender.maybeExtendLifetime(mEntry, 0))
+ addHUN(mEntry)
+ assertFalse(mNotifLifetimeExtender.maybeExtendLifetime(mEntry, 0))
+ mExecutor.advanceClockToLast()
+ mExecutor.runAllReady()
+ assertTrue(mNotifLifetimeExtender.maybeExtendLifetime(mEntry, 0))
+ verify(mHeadsUpManager, times(0)).removeNotification(anyString(), eq(false))
+ verify(mHeadsUpManager, times(0)).removeNotification(anyString(), eq(true))
+ }
+
+ @Test
+ fun hunNotRemovedWhenExtensionCancelled() {
+ whenever(mHeadsUpManager.isSticky(anyString())).thenReturn(true)
+ addHUN(mEntry)
+ whenever(mHeadsUpManager.canRemoveImmediately(anyString())).thenReturn(false)
+ whenever(mHeadsUpManager.getEarliestRemovalTime(anyString())).thenReturn(1000L)
+ assertTrue(mNotifLifetimeExtender.maybeExtendLifetime(mEntry, 0))
+ mNotifLifetimeExtender.cancelLifetimeExtension(mEntry)
+ mExecutor.advanceClockToLast()
+ mExecutor.runAllReady()
+ verify(mHeadsUpManager, times(0)).removeNotification(anyString(), any())
+ }
+
+ @Test
fun testCancelUpdatedStickyNotification() {
whenever(mHeadsUpManager.isSticky(anyString())).thenReturn(true)
addHUN(mEntry)
whenever(mHeadsUpManager.getEarliestRemovalTime(anyString())).thenReturn(1000L, 500L)
assertTrue(mNotifLifetimeExtender.maybeExtendLifetime(mEntry, 0))
+ addHUN(mEntry)
mExecutor.advanceClockToLast()
mExecutor.runAllReady()
verify(mHeadsUpManager, times(0)).removeNotification(anyString(), eq(false))
@@ -305,6 +335,7 @@ class HeadsUpCoordinatorTest : SysuiTestCase() {
mHuns.add(entry)
whenever(mHeadsUpManager.topEntry).thenReturn(entry)
mOnHeadsUpChangedListener.onHeadsUpStateChanged(entry, true)
+ mNotifLifetimeExtender.cancelLifetimeExtension(entry)
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.java
index d0947497f0ec..52bacd2360b3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.java
@@ -16,18 +16,8 @@
package com.android.systemui.statusbar.notification.collection.coordinator;
-import static android.app.Notification.VISIBILITY_PUBLIC;
-import static android.app.Notification.VISIBILITY_SECRET;
-import static android.app.NotificationManager.IMPORTANCE_HIGH;
-import static android.app.NotificationManager.IMPORTANCE_MIN;
-
-import static com.android.systemui.statusbar.notification.collection.EntryUtilKt.modifyEntry;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
import android.os.Handler;
import android.os.UserHandle;
@@ -39,40 +29,41 @@ import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.NotificationLockscreenUserManager;
-import com.android.systemui.statusbar.RankingBuilder;
import com.android.systemui.statusbar.notification.SectionHeaderVisibilityProvider;
-import com.android.systemui.statusbar.notification.collection.GroupEntry;
-import com.android.systemui.statusbar.notification.collection.GroupEntryBuilder;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
+import com.android.systemui.statusbar.notification.interruption.KeyguardNotificationVisibilityProvider;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import org.junit.Before;
-import org.junit.Test;
+import org.junit.Ignore;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+/**
+ * TODO(b/224771204) Create test cases
+ */
@SmallTest
@RunWith(AndroidTestingRunner.class)
+@Ignore
public class KeyguardCoordinatorTest extends SysuiTestCase {
private static final int NOTIF_USER_ID = 0;
private static final int CURR_USER_ID = 1;
@Mock private Handler mMainHandler;
@Mock private KeyguardStateController mKeyguardStateController;
- @Mock private NotificationLockscreenUserManager mLockscreenUserManager;
@Mock private BroadcastDispatcher mBroadcastDispatcher;
@Mock private StatusBarStateController mStatusBarStateController;
@Mock private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@Mock private HighPriorityProvider mHighPriorityProvider;
@Mock private SectionHeaderVisibilityProvider mSectionHeaderVisibilityProvider;
@Mock private NotifPipeline mNotifPipeline;
+ @Mock private KeyguardNotificationVisibilityProvider mKeyguardNotificationVisibilityProvider;
private NotificationEntry mEntry;
private NotifFilter mKeyguardFilter;
@@ -81,9 +72,9 @@ public class KeyguardCoordinatorTest extends SysuiTestCase {
public void setup() {
MockitoAnnotations.initMocks(this);
KeyguardCoordinator keyguardCoordinator = new KeyguardCoordinator(
- mContext, mMainHandler, mKeyguardStateController, mLockscreenUserManager,
- mBroadcastDispatcher, mStatusBarStateController,
- mKeyguardUpdateMonitor, mHighPriorityProvider, mSectionHeaderVisibilityProvider);
+ mStatusBarStateController,
+ mKeyguardUpdateMonitor, mHighPriorityProvider, mSectionHeaderVisibilityProvider,
+ mKeyguardNotificationVisibilityProvider);
mEntry = new NotificationEntryBuilder()
.setUser(new UserHandle(NOTIF_USER_ID))
@@ -94,171 +85,4 @@ public class KeyguardCoordinatorTest extends SysuiTestCase {
verify(mNotifPipeline, times(1)).addFinalizeFilter(filterCaptor.capture());
mKeyguardFilter = filterCaptor.getValue();
}
-
- @Test
- public void unfilteredState() {
- // GIVEN an 'unfiltered-keyguard-showing' state
- setupUnfilteredState(mEntry);
-
- // THEN don't filter out the entry
- assertFalse(mKeyguardFilter.shouldFilterOut(mEntry, 0));
- }
-
- @Test
- public void keyguardNotShowing() {
- // GIVEN the lockscreen isn't showing
- setupUnfilteredState(mEntry);
- when(mKeyguardStateController.isShowing()).thenReturn(false);
-
- // THEN don't filter out the entry
- assertFalse(mKeyguardFilter.shouldFilterOut(mEntry, 0));
- }
-
- @Test
- public void doNotShowLockscreenNotifications() {
- // GIVEN an 'unfiltered-keyguard-showing' state
- setupUnfilteredState(mEntry);
-
- // WHEN we shouldn't show any lockscreen notifications
- when(mLockscreenUserManager.shouldShowLockscreenNotifications()).thenReturn(false);
-
- // THEN filter out the entry
- assertTrue(mKeyguardFilter.shouldFilterOut(mEntry, 0));
- }
-
- @Test
- public void lockdown() {
- // GIVEN an 'unfiltered-keyguard-showing' state
- setupUnfilteredState(mEntry);
-
- // WHEN the notification's user is in lockdown:
- when(mKeyguardUpdateMonitor.isUserInLockdown(NOTIF_USER_ID)).thenReturn(true);
-
- // THEN filter out the entry
- assertTrue(mKeyguardFilter.shouldFilterOut(mEntry, 0));
- }
-
- @Test
- public void publicMode_settingsDisallow() {
- // GIVEN an 'unfiltered-keyguard-showing' state
- setupUnfilteredState(mEntry);
-
- // WHEN the notification's user is in public mode and settings are configured to disallow
- // notifications in public mode
- when(mLockscreenUserManager.isLockscreenPublicMode(NOTIF_USER_ID)).thenReturn(true);
- when(mLockscreenUserManager.userAllowsNotificationsInPublic(NOTIF_USER_ID))
- .thenReturn(false);
-
- // THEN filter out the entry
- assertTrue(mKeyguardFilter.shouldFilterOut(mEntry, 0));
- }
-
- @Test
- public void publicMode_notifDisallowed() {
- // GIVEN an 'unfiltered-keyguard-showing' state
- setupUnfilteredState(mEntry);
-
- // WHEN the notification's user is in public mode and settings are configured to disallow
- // notifications in public mode
- when(mLockscreenUserManager.isLockscreenPublicMode(CURR_USER_ID)).thenReturn(true);
- mEntry.setRanking(new RankingBuilder()
- .setKey(mEntry.getKey())
- .setVisibilityOverride(VISIBILITY_SECRET).build());
-
- // THEN filter out the entry
- assertTrue(mKeyguardFilter.shouldFilterOut(mEntry, 0));
- }
-
- @Test
- public void doesNotExceedThresholdToShow() {
- // GIVEN an 'unfiltered-keyguard-showing' state
- setupUnfilteredState(mEntry);
-
- // WHEN the notification doesn't exceed the threshold to show on the lockscreen
- mEntry.setRanking(new RankingBuilder()
- .setKey(mEntry.getKey())
- .setImportance(IMPORTANCE_MIN)
- .build());
- when(mHighPriorityProvider.isHighPriority(mEntry)).thenReturn(false);
-
- // THEN filter out the entry
- assertTrue(mKeyguardFilter.shouldFilterOut(mEntry, 0));
- }
-
- @Test
- public void summaryExceedsThresholdToShow() {
- // GIVEN the notification doesn't exceed the threshold to show on the lockscreen
- // but it's part of a group (has a parent)
- final NotificationEntry entryWithParent = new NotificationEntryBuilder()
- .setUser(new UserHandle(NOTIF_USER_ID))
- .build();
-
- final GroupEntry parent = new GroupEntryBuilder()
- .setKey("test_group_key")
- .setSummary(new NotificationEntryBuilder()
- .setImportance(IMPORTANCE_HIGH)
- .build())
- .addChild(entryWithParent)
- .build();
-
- setupUnfilteredState(entryWithParent);
- entryWithParent.setRanking(new RankingBuilder()
- .setKey(entryWithParent.getKey())
- .setImportance(IMPORTANCE_MIN)
- .build());
-
- // WHEN its parent does exceed threshold tot show on the lockscreen
- when(mHighPriorityProvider.isHighPriority(parent)).thenReturn(true);
-
- // THEN don't filter out the entry
- assertFalse(mKeyguardFilter.shouldFilterOut(entryWithParent, 0));
-
- // WHEN its parent doesn't exceed threshold to show on lockscreen
- when(mHighPriorityProvider.isHighPriority(parent)).thenReturn(false);
- modifyEntry(parent.getSummary(), builder -> builder
- .setImportance(IMPORTANCE_MIN)
- .done());
-
- // THEN filter out the entry
- assertTrue(mKeyguardFilter.shouldFilterOut(entryWithParent, 0));
- }
-
- /**
- * setup a state where the notification will not be filtered by the
- * KeyguardNotificationCoordinator when the keyguard is showing.
- */
- private void setupUnfilteredState(NotificationEntry entry) {
- // keyguard is showing
- when(mKeyguardStateController.isShowing()).thenReturn(true);
-
- // show notifications on the lockscreen
- when(mLockscreenUserManager.shouldShowLockscreenNotifications()).thenReturn(true);
-
- // neither the current user nor the notification's user is in lockdown
- when(mLockscreenUserManager.getCurrentUserId()).thenReturn(CURR_USER_ID);
- when(mKeyguardUpdateMonitor.isUserInLockdown(NOTIF_USER_ID)).thenReturn(false);
- when(mKeyguardUpdateMonitor.isUserInLockdown(CURR_USER_ID)).thenReturn(false);
-
- // not in public mode
- when(mLockscreenUserManager.isLockscreenPublicMode(CURR_USER_ID)).thenReturn(false);
- when(mLockscreenUserManager.isLockscreenPublicMode(NOTIF_USER_ID)).thenReturn(false);
-
- // entry's ranking - should show on all lockscreens
- // + priority of the notification exceeds the threshold to be shown on the lockscreen
- entry.setRanking(new RankingBuilder()
- .setKey(mEntry.getKey())
- .setVisibilityOverride(VISIBILITY_PUBLIC)
- .setImportance(IMPORTANCE_HIGH)
- .build());
-
- // settings allows notifications in public mode
- when(mLockscreenUserManager.userAllowsNotificationsInPublic(CURR_USER_ID)).thenReturn(true);
- when(mLockscreenUserManager.userAllowsNotificationsInPublic(NOTIF_USER_ID))
- .thenReturn(true);
-
- // notification doesn't have a summary
-
- // notification is high priority, so it shouldn't be filtered
- when(mHighPriorityProvider.isHighPriority(mEntry)).thenReturn(true);
- }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinatorTest.java
index ee111715e5ea..6f8e5d8e514e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinatorTest.java
@@ -41,7 +41,7 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntryB
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifStabilityManager;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.Pluggable;
import com.android.systemui.statusbar.notification.collection.provider.VisualStabilityProvider;
-import com.android.systemui.statusbar.notification.collection.render.NotifPanelEventSource;
+import com.android.systemui.statusbar.phone.NotifPanelEvents;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.time.FakeSystemClock;
@@ -67,12 +67,12 @@ public class VisualStabilityCoordinatorTest extends SysuiTestCase {
@Mock private StatusBarStateController mStatusBarStateController;
@Mock private Pluggable.PluggableListener<NotifStabilityManager> mInvalidateListener;
@Mock private HeadsUpManager mHeadsUpManager;
- @Mock private NotifPanelEventSource mNotifPanelEventSource;
+ @Mock private NotifPanelEvents mNotifPanelEvents;
@Mock private VisualStabilityProvider mVisualStabilityProvider;
@Captor private ArgumentCaptor<WakefulnessLifecycle.Observer> mWakefulnessObserverCaptor;
@Captor private ArgumentCaptor<StatusBarStateController.StateListener> mSBStateListenerCaptor;
- @Captor private ArgumentCaptor<NotifPanelEventSource.Callbacks> mNotifPanelEventsCallbackCaptor;
+ @Captor private ArgumentCaptor<NotifPanelEvents.Listener> mNotifPanelEventsCallbackCaptor;
@Captor private ArgumentCaptor<NotifStabilityManager> mNotifStabilityManagerCaptor;
private FakeSystemClock mFakeSystemClock = new FakeSystemClock();
@@ -80,7 +80,7 @@ public class VisualStabilityCoordinatorTest extends SysuiTestCase {
private WakefulnessLifecycle.Observer mWakefulnessObserver;
private StatusBarStateController.StateListener mStatusBarStateListener;
- private NotifPanelEventSource.Callbacks mNotifPanelEventsCallback;
+ private NotifPanelEvents.Listener mNotifPanelEventsCallback;
private NotifStabilityManager mNotifStabilityManager;
private NotificationEntry mEntry;
@@ -92,7 +92,7 @@ public class VisualStabilityCoordinatorTest extends SysuiTestCase {
mFakeExecutor,
mDumpManager,
mHeadsUpManager,
- mNotifPanelEventSource,
+ mNotifPanelEvents,
mStatusBarStateController,
mVisualStabilityProvider,
mWakefulnessLifecycle);
@@ -106,7 +106,7 @@ public class VisualStabilityCoordinatorTest extends SysuiTestCase {
verify(mStatusBarStateController).addCallback(mSBStateListenerCaptor.capture());
mStatusBarStateListener = mSBStateListenerCaptor.getValue();
- verify(mNotifPanelEventSource).registerCallbacks(mNotifPanelEventsCallbackCaptor.capture());
+ verify(mNotifPanelEvents).registerListener(mNotifPanelEventsCallbackCaptor.capture());
mNotifPanelEventsCallback = mNotifPanelEventsCallbackCaptor.getValue();
verify(mNotifPipeline).setVisualStabilityManager(mNotifStabilityManagerCaptor.capture());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/KeyguardNotificationVisibilityProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/KeyguardNotificationVisibilityProviderTest.java
new file mode 100644
index 000000000000..32d625c707cf
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/KeyguardNotificationVisibilityProviderTest.java
@@ -0,0 +1,440 @@
+/*
+ * 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.statusbar.notification.interruption;
+
+import static android.app.Notification.VISIBILITY_PUBLIC;
+import static android.app.Notification.VISIBILITY_SECRET;
+import static android.app.NotificationManager.IMPORTANCE_HIGH;
+import static android.app.NotificationManager.IMPORTANCE_MIN;
+
+import static com.android.systemui.statusbar.notification.collection.EntryUtilKt.modifyEntry;
+import static com.android.systemui.util.mockito.KotlinMockitoHelpersKt.argThat;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.isNull;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.keyguard.KeyguardUpdateMonitorCallback;
+import com.android.systemui.CoreStartable;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.NotificationLockscreenUserManager;
+import com.android.systemui.statusbar.RankingBuilder;
+import com.android.systemui.statusbar.notification.collection.GroupEntry;
+import com.android.systemui.statusbar.notification.collection.GroupEntryBuilder;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
+import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.systemui.util.settings.FakeSettings;
+import com.android.systemui.util.settings.GlobalSettings;
+import com.android.systemui.util.settings.SecureSettings;
+import com.android.systemui.utils.os.FakeHandler;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.Map;
+import java.util.function.Consumer;
+
+import dagger.BindsInstance;
+import dagger.Component;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class KeyguardNotificationVisibilityProviderTest extends SysuiTestCase {
+ private static final int NOTIF_USER_ID = 0;
+ private static final int CURR_USER_ID = 1;
+
+ @Mock private KeyguardStateController mKeyguardStateController;
+ @Mock private NotificationLockscreenUserManager mLockscreenUserManager;
+ @Mock private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+ @Mock private HighPriorityProvider mHighPriorityProvider;
+ @Mock private StatusBarStateController mStatusBarStateController;
+ @Mock private BroadcastDispatcher mBroadcastDispatcher;
+ private final FakeSettings mFakeSettings = new FakeSettings();
+
+ private KeyguardNotificationVisibilityProvider mKeyguardNotificationVisibilityProvider;
+ private NotificationEntry mEntry;
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ TestComponent component =
+ DaggerKeyguardNotificationVisibilityProviderTest_TestComponent
+ .factory()
+ .create(
+ mContext,
+ new FakeHandler(TestableLooper.get(this).getLooper()),
+ mKeyguardStateController,
+ mLockscreenUserManager,
+ mKeyguardUpdateMonitor,
+ mHighPriorityProvider,
+ mStatusBarStateController,
+ mBroadcastDispatcher,
+ mFakeSettings,
+ mFakeSettings);
+ mKeyguardNotificationVisibilityProvider = component.getProvider();
+ for (CoreStartable startable : component.getCoreStartables().values()) {
+ startable.start();
+ }
+ mEntry = new NotificationEntryBuilder()
+ .setUser(new UserHandle(NOTIF_USER_ID))
+ .build();
+ }
+
+ @Test
+ public void notifyListeners_onUnlockedChanged() {
+ ArgumentCaptor<KeyguardStateController.Callback> callbackCaptor =
+ ArgumentCaptor.forClass(KeyguardStateController.Callback.class);
+ verify(mKeyguardStateController).addCallback(callbackCaptor.capture());
+ KeyguardStateController.Callback callback = callbackCaptor.getValue();
+
+ Consumer<String> listener = mock(Consumer.class);
+ mKeyguardNotificationVisibilityProvider.addOnStateChangedListener(listener);
+
+ callback.onUnlockedChanged();
+
+ verify(listener).accept(anyString());
+ }
+
+ @Test
+ public void notifyListeners_onKeyguardShowingChanged() {
+ ArgumentCaptor<KeyguardStateController.Callback> callbackCaptor =
+ ArgumentCaptor.forClass(KeyguardStateController.Callback.class);
+ verify(mKeyguardStateController).addCallback(callbackCaptor.capture());
+ KeyguardStateController.Callback callback = callbackCaptor.getValue();
+
+ Consumer<String> listener = mock(Consumer.class);
+ mKeyguardNotificationVisibilityProvider.addOnStateChangedListener(listener);
+
+ callback.onKeyguardShowingChanged();
+
+ verify(listener).accept(anyString());
+ }
+
+ @Test
+ public void notifyListeners_onStrongAuthStateChanged() {
+ ArgumentCaptor<KeyguardUpdateMonitorCallback> callbackCaptor =
+ ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback.class);
+ verify(mKeyguardUpdateMonitor).registerCallback(callbackCaptor.capture());
+ KeyguardUpdateMonitorCallback callback = callbackCaptor.getValue();
+
+ Consumer<String> listener = mock(Consumer.class);
+ mKeyguardNotificationVisibilityProvider.addOnStateChangedListener(listener);
+
+ callback.onStrongAuthStateChanged(0);
+
+ verify(listener).accept(anyString());
+ }
+
+ @Test
+ public void notifyListeners_onStatusBarStateChanged() {
+ ArgumentCaptor<StatusBarStateController.StateListener> callbackCaptor =
+ ArgumentCaptor.forClass(StatusBarStateController.StateListener.class);
+ verify(mStatusBarStateController).addCallback(callbackCaptor.capture());
+ StatusBarStateController.StateListener callback = callbackCaptor.getValue();
+
+ Consumer<String> listener = mock(Consumer.class);
+ mKeyguardNotificationVisibilityProvider.addOnStateChangedListener(listener);
+
+ callback.onStateChanged(0);
+
+ verify(listener).accept(anyString());
+ }
+
+ @Test
+ public void notifyListeners_onReceiveUserSwitchBroadcast() {
+ ArgumentCaptor<BroadcastReceiver> callbackCaptor =
+ ArgumentCaptor.forClass(BroadcastReceiver.class);
+ verify(mBroadcastDispatcher).registerReceiver(
+ callbackCaptor.capture(),
+ argThat(intentFilter -> intentFilter.hasAction(Intent.ACTION_USER_SWITCHED)),
+ isNull(),
+ isNull(),
+ eq(Context.RECEIVER_EXPORTED));
+ BroadcastReceiver callback = callbackCaptor.getValue();
+
+ Consumer<String> listener = mock(Consumer.class);
+ mKeyguardNotificationVisibilityProvider.addOnStateChangedListener(listener);
+
+ when(mKeyguardStateController.isShowing()).thenReturn(true);
+ callback.onReceive(mContext, new Intent(Intent.ACTION_USER_SWITCHED));
+
+ verify(listener).accept(anyString());
+ }
+
+ @Test
+ public void notifyListeners_onSettingChange_lockScreenShowNotifs() {
+ when(mKeyguardStateController.isShowing()).thenReturn(true);
+ Consumer<String> listener = mock(Consumer.class);
+ mKeyguardNotificationVisibilityProvider.addOnStateChangedListener(listener);
+
+ mFakeSettings.putInt(Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 1);
+
+ verify(listener).accept(anyString());
+ }
+
+ @Test
+ public void notifyListeners_onSettingChange_lockScreenAllowPrivateNotifs() {
+ when(mKeyguardStateController.isShowing()).thenReturn(true);
+ Consumer<String> listener = mock(Consumer.class);
+ mKeyguardNotificationVisibilityProvider.addOnStateChangedListener(listener);
+
+ mFakeSettings.putInt(Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 1);
+
+ verify(listener).accept(anyString());
+ }
+
+ @Test
+ public void notifyListeners_onSettingChange_zenMode() {
+ when(mKeyguardStateController.isShowing()).thenReturn(true);
+ Consumer<String> listener = mock(Consumer.class);
+ mKeyguardNotificationVisibilityProvider.addOnStateChangedListener(listener);
+
+ mFakeSettings.putInt(Settings.Global.ZEN_MODE, 1);
+
+ verify(listener).accept(anyString());
+ }
+
+ @Test
+ public void notifyListeners_onSettingChange_lockScreenShowSilentNotifs() {
+ when(mKeyguardStateController.isShowing()).thenReturn(true);
+ Consumer<String> listener = mock(Consumer.class);
+ mKeyguardNotificationVisibilityProvider.addOnStateChangedListener(listener);
+
+ mFakeSettings.putInt(Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, 1);
+
+ verify(listener).accept(anyString());
+ }
+
+ @Test
+ public void unfilteredState() {
+ // GIVEN an 'unfiltered-keyguard-showing' state
+ setupUnfilteredState(mEntry);
+
+ // THEN don't filter out the entry
+ assertFalse(mKeyguardNotificationVisibilityProvider.shouldHideNotification(mEntry));
+ }
+
+ @Test
+ public void keyguardNotShowing() {
+ // GIVEN the lockscreen isn't showing
+ setupUnfilteredState(mEntry);
+ when(mKeyguardStateController.isShowing()).thenReturn(false);
+
+ // THEN don't filter out the entry
+ assertFalse(mKeyguardNotificationVisibilityProvider.shouldHideNotification(mEntry));
+ }
+
+ @Test
+ public void doNotShowLockscreenNotifications() {
+ // GIVEN an 'unfiltered-keyguard-showing' state
+ setupUnfilteredState(mEntry);
+
+ // WHEN we shouldn't show any lockscreen notifications
+ when(mLockscreenUserManager.shouldShowLockscreenNotifications()).thenReturn(false);
+
+ // THEN filter out the entry
+ assertTrue(mKeyguardNotificationVisibilityProvider.shouldHideNotification(mEntry));
+ }
+
+ @Test
+ public void lockdown() {
+ // GIVEN an 'unfiltered-keyguard-showing' state
+ setupUnfilteredState(mEntry);
+
+ // WHEN the notification's user is in lockdown:
+ when(mKeyguardUpdateMonitor.isUserInLockdown(NOTIF_USER_ID)).thenReturn(true);
+
+ // THEN filter out the entry
+ assertTrue(mKeyguardNotificationVisibilityProvider.shouldHideNotification(mEntry));
+ }
+
+ @Test
+ public void publicMode_settingsDisallow() {
+ // GIVEN an 'unfiltered-keyguard-showing' state
+ setupUnfilteredState(mEntry);
+
+ // WHEN the notification's user is in public mode and settings are configured to disallow
+ // notifications in public mode
+ when(mLockscreenUserManager.isLockscreenPublicMode(NOTIF_USER_ID)).thenReturn(true);
+ when(mLockscreenUserManager.userAllowsNotificationsInPublic(NOTIF_USER_ID))
+ .thenReturn(false);
+
+ // THEN filter out the entry
+ assertTrue(mKeyguardNotificationVisibilityProvider.shouldHideNotification(mEntry));
+ }
+
+ @Test
+ public void publicMode_notifDisallowed() {
+ // GIVEN an 'unfiltered-keyguard-showing' state
+ setupUnfilteredState(mEntry);
+
+ // WHEN the notification's user is in public mode and settings are configured to disallow
+ // notifications in public mode
+ when(mLockscreenUserManager.isLockscreenPublicMode(CURR_USER_ID)).thenReturn(true);
+ mEntry.setRanking(new RankingBuilder()
+ .setKey(mEntry.getKey())
+ .setVisibilityOverride(VISIBILITY_SECRET).build());
+
+ // THEN filter out the entry
+ assertTrue(mKeyguardNotificationVisibilityProvider.shouldHideNotification(mEntry));
+ }
+
+ @Test
+ public void doesNotExceedThresholdToShow() {
+ // GIVEN an 'unfiltered-keyguard-showing' state
+ setupUnfilteredState(mEntry);
+
+ // WHEN the notification doesn't exceed the threshold to show on the lockscreen
+ mEntry.setRanking(new RankingBuilder()
+ .setKey(mEntry.getKey())
+ .setImportance(IMPORTANCE_MIN)
+ .build());
+ when(mHighPriorityProvider.isHighPriority(mEntry)).thenReturn(false);
+
+ // THEN filter out the entry
+ assertTrue(mKeyguardNotificationVisibilityProvider.shouldHideNotification(mEntry));
+ }
+
+ @Test
+ public void summaryExceedsThresholdToShow() {
+ // GIVEN the notification doesn't exceed the threshold to show on the lockscreen
+ // but it's part of a group (has a parent)
+ final NotificationEntry entryWithParent = new NotificationEntryBuilder()
+ .setUser(new UserHandle(NOTIF_USER_ID))
+ .build();
+
+ final GroupEntry parent = new GroupEntryBuilder()
+ .setKey("test_group_key")
+ .setSummary(new NotificationEntryBuilder()
+ .setImportance(IMPORTANCE_HIGH)
+ .build())
+ .addChild(entryWithParent)
+ .build();
+
+ setupUnfilteredState(entryWithParent);
+ entryWithParent.setRanking(new RankingBuilder()
+ .setKey(entryWithParent.getKey())
+ .setImportance(IMPORTANCE_MIN)
+ .build());
+
+ // WHEN its parent does exceed threshold tot show on the lockscreen
+ when(mHighPriorityProvider.isHighPriority(parent)).thenReturn(true);
+
+ // THEN don't filter out the entry
+ assertFalse(
+ mKeyguardNotificationVisibilityProvider.shouldHideNotification(entryWithParent));
+
+ // WHEN its parent doesn't exceed threshold to show on lockscreen
+ when(mHighPriorityProvider.isHighPriority(parent)).thenReturn(false);
+ modifyEntry(parent.getSummary(), builder -> builder
+ .setImportance(IMPORTANCE_MIN)
+ .done());
+
+ // THEN filter out the entry
+ assertTrue(mKeyguardNotificationVisibilityProvider.shouldHideNotification(entryWithParent));
+ }
+
+ /**
+ * setup a state where the notification will not be filtered by the
+ * KeyguardNotificationCoordinator when the keyguard is showing.
+ */
+ private void setupUnfilteredState(NotificationEntry entry) {
+ // keyguard is showing
+ when(mKeyguardStateController.isShowing()).thenReturn(true);
+
+ // show notifications on the lockscreen
+ when(mLockscreenUserManager.shouldShowLockscreenNotifications()).thenReturn(true);
+
+ // neither the current user nor the notification's user is in lockdown
+ when(mLockscreenUserManager.getCurrentUserId()).thenReturn(CURR_USER_ID);
+ when(mKeyguardUpdateMonitor.isUserInLockdown(NOTIF_USER_ID)).thenReturn(false);
+ when(mKeyguardUpdateMonitor.isUserInLockdown(CURR_USER_ID)).thenReturn(false);
+
+ // not in public mode
+ when(mLockscreenUserManager.isLockscreenPublicMode(CURR_USER_ID)).thenReturn(false);
+ when(mLockscreenUserManager.isLockscreenPublicMode(NOTIF_USER_ID)).thenReturn(false);
+
+ // entry's ranking - should show on all lockscreens
+ // + priority of the notification exceeds the threshold to be shown on the lockscreen
+ entry.setRanking(new RankingBuilder()
+ .setKey(mEntry.getKey())
+ .setVisibilityOverride(VISIBILITY_PUBLIC)
+ .setImportance(IMPORTANCE_HIGH)
+ .build());
+
+ // settings allows notifications in public mode
+ when(mLockscreenUserManager.userAllowsNotificationsInPublic(CURR_USER_ID)).thenReturn(true);
+ when(mLockscreenUserManager.userAllowsNotificationsInPublic(NOTIF_USER_ID))
+ .thenReturn(true);
+
+ // notification doesn't have a summary
+
+ // notification is high priority, so it shouldn't be filtered
+ when(mHighPriorityProvider.isHighPriority(mEntry)).thenReturn(true);
+ }
+
+ @SysUISingleton
+ @Component(modules = { KeyguardNotificationVisibilityProviderModule.class })
+ interface TestComponent {
+ KeyguardNotificationVisibilityProvider getProvider();
+ Map<Class<?>, CoreStartable> getCoreStartables();
+
+ @Component.Factory
+ interface Factory {
+ TestComponent create(
+ @BindsInstance Context context,
+ @BindsInstance @Main Handler handler,
+ @BindsInstance KeyguardStateController keyguardStateController,
+ @BindsInstance NotificationLockscreenUserManager lockscreenUserManager,
+ @BindsInstance KeyguardUpdateMonitor keyguardUpdateMonitor,
+ @BindsInstance HighPriorityProvider highPriorityProvider,
+ @BindsInstance StatusBarStateController statusBarStateController,
+ @BindsInstance BroadcastDispatcher broadcastDispatcher,
+ @BindsInstance SecureSettings secureSettings,
+ @BindsInstance GlobalSettings globalSettings
+ );
+ }
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java
index 2e1297b8b9f6..8a2dc263cf36 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java
@@ -30,6 +30,9 @@ import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.Notification;
@@ -48,6 +51,7 @@ import androidx.test.filters.SmallTest;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.notification.NotifPipelineFlags;
import com.android.systemui.statusbar.notification.NotificationFilter;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
@@ -86,6 +90,10 @@ public class NotificationInterruptStateProviderImplTest extends SysuiTestCase {
BatteryController mBatteryController;
@Mock
Handler mMockHandler;
+ @Mock
+ NotifPipelineFlags mFlags;
+ @Mock
+ KeyguardNotificationVisibilityProvider mKeyguardNotificationVisibilityProvider;
private NotificationInterruptStateProviderImpl mNotifInterruptionStateProvider;
@@ -104,8 +112,9 @@ public class NotificationInterruptStateProviderImplTest extends SysuiTestCase {
mStatusBarStateController,
mHeadsUpManager,
mLogger,
- mMockHandler);
-
+ mMockHandler,
+ mFlags,
+ mKeyguardNotificationVisibilityProvider);
mNotifInterruptionStateProvider.mUseHeadsUp = true;
}
@@ -194,6 +203,16 @@ public class NotificationInterruptStateProviderImplTest extends SysuiTestCase {
}
@Test
+ public void testDoNotRunFilterOnNewPipeline() {
+ when(mFlags.isNewPipelineEnabled()).thenReturn(true);
+ // WHEN this entry should be filtered out
+ NotificationEntry entry = createNotification(IMPORTANCE_DEFAULT);
+ mNotifInterruptionStateProvider.shouldHeadsUp(entry);
+ verify(mFlags, times(1)).isNewPipelineEnabled();
+ verify(mNotificationFilter, times(0)).shouldFilterOut(eq(entry));
+ }
+
+ @Test
public void testShouldNotHeadsUp_suppressedForGroups() throws RemoteException {
// GIVEN state for "heads up when awake" is true
ensureStateForHeadsUpWhenAwake();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java
index 7fc5ece670d4..251ac7d250fe 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java
@@ -41,6 +41,7 @@ import android.testing.TestableLooper;
import androidx.asynclayoutinflater.view.AsyncLayoutInflater;
import androidx.test.filters.SmallTest;
+import com.android.internal.logging.MetricsLogger;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.util.NotificationMessagingUtil;
import com.android.systemui.R;
@@ -87,6 +88,7 @@ import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.policy.InflatedSmartReplyState;
import com.android.systemui.statusbar.policy.InflatedSmartReplyViewHolder;
+import com.android.systemui.statusbar.policy.SmartReplyConstants;
import com.android.systemui.statusbar.policy.SmartReplyStateInflater;
import com.android.systemui.statusbar.policy.dagger.RemoteInputViewSubcomponent;
import com.android.systemui.util.concurrency.FakeExecutor;
@@ -252,13 +254,17 @@ public class NotificationEntryManagerInflationTest extends SysuiTestCase {
.thenAnswer((Answer<ExpandableNotificationRowController>) invocation ->
new ExpandableNotificationRowController(
viewCaptor.getValue(),
- mListContainer,
- mock(RemoteInputViewSubcomponent.Factory.class),
mock(ActivatableNotificationViewController.class),
+ mock(RemoteInputViewSubcomponent.Factory.class),
+ mock(MetricsLogger.class),
+ mListContainer,
mNotificationMediaManager,
+ mock(SmartReplyConstants.class),
+ mock(SmartReplyController.class),
mock(PluginManager.class),
new FakeSystemClock(),
- "FOOBAR", "FOOBAR",
+ "FOOBAR",
+ "FOOBAR",
mKeyguardBypassController,
mGroupMembershipManager,
mGroupExpansionManager,
@@ -275,8 +281,7 @@ public class NotificationEntryManagerInflationTest extends SysuiTestCase {
mock(FeatureFlags.class),
mPeopleNotificationIdentifier,
Optional.of(mock(BubblesManager.class)),
- mock(ExpandableNotificationRowDragController.class)
- ));
+ mock(ExpandableNotificationRowDragController.class)));
when(mNotificationRowComponentBuilder.activatableNotificationView(any()))
.thenReturn(mNotificationRowComponentBuilder);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
index 72f8f70058fc..1ecb09bc8514 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
@@ -44,6 +44,7 @@ import android.text.TextUtils;
import android.view.LayoutInflater;
import android.widget.RemoteViews;
+import com.android.internal.logging.MetricsLogger;
import com.android.systemui.TestableDependency;
import com.android.systemui.classifier.FalsingCollectorFake;
import com.android.systemui.classifier.FalsingManagerFake;
@@ -54,6 +55,7 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.NotificationMediaManager;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.NotificationShadeWindowController;
+import com.android.systemui.statusbar.SmartReplyController;
import com.android.systemui.statusbar.notification.ConversationNotificationProcessor;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
@@ -73,6 +75,7 @@ import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.policy.HeadsUpManagerLogger;
import com.android.systemui.statusbar.policy.InflatedSmartReplyState;
import com.android.systemui.statusbar.policy.InflatedSmartReplyViewHolder;
+import com.android.systemui.statusbar.policy.SmartReplyConstants;
import com.android.systemui.statusbar.policy.SmartReplyStateInflater;
import com.android.systemui.statusbar.policy.dagger.RemoteInputViewSubcomponent;
import com.android.systemui.tests.R;
@@ -505,7 +508,10 @@ public class NotificationTestHelper {
mPeopleNotificationIdentifier,
mOnUserInteractionCallback,
Optional.of(mock(BubblesManager.class)),
- mock(NotificationGutsManager.class));
+ mock(NotificationGutsManager.class),
+ mock(MetricsLogger.class),
+ mock(SmartReplyConstants.class),
+ mock(SmartReplyController.class));
row.setAboveShelfChangedListener(aboveShelf -> { });
mBindStage.getStageParams(entry).requireContentViews(extraInflationFlags);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
index 1561b5a5d22e..c9de60806b66 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
@@ -69,11 +69,11 @@ import com.android.systemui.statusbar.notification.collection.render.SectionHead
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController.NotificationPanelEvent;
+import com.android.systemui.statusbar.phone.CentralSurfaces;
import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.ScrimController;
import com.android.systemui.statusbar.phone.ShadeController;
-import com.android.systemui.statusbar.phone.CentralSurfaces;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.ZenModeController;
@@ -134,6 +134,7 @@ public class NotificationStackScrollLayoutControllerTest extends SysuiTestCase {
@Mock private InteractionJankMonitor mJankMonitor;
@Mock private StackStateLogger mStackLogger;
@Mock private NotificationStackScrollLogger mLogger;
+ @Mock private NotificationStackSizeCalculator mNotificationStackSizeCalculator;
@Captor
private ArgumentCaptor<StatusBarStateController.StateListener> mStateListenerArgumentCaptor;
@@ -186,7 +187,8 @@ public class NotificationStackScrollLayoutControllerTest extends SysuiTestCase {
mShadeController,
mJankMonitor,
mStackLogger,
- mLogger
+ mLogger,
+ mNotificationStackSizeCalculator
);
when(mNotificationStackScrollLayout.isAttachedToWindow()).thenReturn(true);
@@ -278,18 +280,17 @@ public class NotificationStackScrollLayoutControllerTest extends SysuiTestCase {
mStateListenerArgumentCaptor.capture(), anyInt());
StatusBarStateController.StateListener stateListener =
mStateListenerArgumentCaptor.getValue();
- when(mNotificationStackScrollLayout.isUsingSplitNotificationShade()).thenReturn(true);
stateListener.onStateChanged(SHADE);
mController.getView().removeAllViews();
- mController.setQsExpanded(false);
+ mController.setQsFullScreen(false);
reset(mNotificationStackScrollLayout);
mController.updateShowEmptyShadeView();
verify(mNotificationStackScrollLayout).updateEmptyShadeView(
/* visible= */ true,
/* notifVisibleInShade= */ false);
- mController.setQsExpanded(true);
+ mController.setQsFullScreen(true);
reset(mNotificationStackScrollLayout);
mController.updateShowEmptyShadeView();
verify(mNotificationStackScrollLayout).updateEmptyShadeView(
@@ -411,11 +412,11 @@ public class NotificationStackScrollLayoutControllerTest extends SysuiTestCase {
boolean toShow) {
if (toShow) {
statusBarStateListener.onStateChanged(SHADE);
- mController.setQsExpanded(false);
+ mController.setQsFullScreen(false);
mController.getView().removeAllViews();
} else {
statusBarStateListener.onStateChanged(KEYGUARD);
- mController.setQsExpanded(true);
+ mController.setQsFullScreen(true);
mController.getView().addContainerView(mock(ExpandableNotificationRow.class));
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
index eafcc354fac4..7a92b96f40db 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
@@ -103,6 +103,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
@Mock private NotificationStackScrollLayoutController mStackScrollLayoutController;
@Mock private UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
@Mock private NotificationShelf mNotificationShelf;
+ @Mock private NotificationStackSizeCalculator mNotificationStackSizeCalculator;
@Before
@UiThreadTest
@@ -138,7 +139,8 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
// holds a copy of the CUT's instances of these KeyguardBypassController, so they still
// refer to the CUT's member variables, not the spy's member variables.
mStackScrollerInternal = new NotificationStackScrollLayout(getContext(), null);
- mStackScrollerInternal.initView(getContext(), mNotificationSwipeHelper);
+ mStackScrollerInternal.initView(getContext(), mNotificationSwipeHelper,
+ mNotificationStackSizeCalculator);
mStackScroller = spy(mStackScrollerInternal);
mStackScroller.setShelfController(notificationShelfController);
mStackScroller.setCentralSurfaces(mCentralSurfaces);
@@ -161,17 +163,6 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
}
@Test
- public void testUpdateStackEndHeight_forEndOfStackHeightAnimation() {
- final float nsslHeight = 10f;
- final float bottomMargin = 1f;
- final float topPadding = 1f;
-
- mStackScroller.updateStackEndHeight(nsslHeight, bottomMargin, topPadding);
- final float stackEndHeight = nsslHeight - bottomMargin - topPadding;
- assertTrue(mAmbientState.getStackEndHeight() == stackEndHeight);
- }
-
- @Test
public void testUpdateStackHeight_withDozeAmount_whenDozeChanging() {
final float dozeAmount = 0.5f;
mAmbientState.setDozeAmount(dozeAmount);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculatorTest.kt
new file mode 100644
index 000000000000..d1848e38ca06
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculatorTest.kt
@@ -0,0 +1,266 @@
+/*
+ * 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.statusbar.notification.stack
+
+import android.service.notification.StatusBarNotification
+import android.testing.AndroidTestingRunner
+import android.view.View.VISIBLE
+import androidx.test.filters.SmallTest
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.NotificationLockscreenUserManager
+import com.android.systemui.statusbar.StatusBarState.KEYGUARD
+import com.android.systemui.statusbar.StatusBarState.SHADE
+import com.android.systemui.statusbar.SysuiStatusBarStateController
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
+import com.android.systemui.statusbar.notification.row.ExpandableView
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.nullable
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.`when` as whenever
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class NotificationStackSizeCalculatorTest : SysuiTestCase() {
+
+ @Mock private lateinit var groupManager: NotificationGroupManagerLegacy
+
+ @Mock private lateinit var notificationLockscreenUserManager: NotificationLockscreenUserManager
+
+ @Mock private lateinit var sysuiStatusBarStateController: SysuiStatusBarStateController
+
+ @Mock private lateinit var stackLayout: NotificationStackScrollLayout
+
+ private val testableResources = mContext.getOrCreateTestableResources()
+
+ private lateinit var sizeCalculator: NotificationStackSizeCalculator
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+
+ whenever(stackLayout.calculateGapHeight(nullable(), nullable(), any()))
+ .thenReturn(GAP_HEIGHT)
+ whenever(groupManager.isSummaryOfSuppressedGroup(any())).thenReturn(false)
+ with(testableResources) {
+ addOverride(R.integer.keyguard_max_notification_count, -1)
+ addOverride(R.dimen.notification_divider_height, NOTIFICATION_PADDING.toInt())
+ }
+
+ sizeCalculator =
+ NotificationStackSizeCalculator(
+ groupManager = groupManager,
+ lockscreenUserManager = notificationLockscreenUserManager,
+ statusBarStateController = sysuiStatusBarStateController,
+ testableResources.resources)
+ }
+
+ @Test
+ fun computeMaxKeyguardNotifications_zeroSpace_returnZero() {
+ val rows = listOf(createMockRow(height = ROW_HEIGHT, visibleOnLockscreen = true))
+
+ val maxNotifications =
+ computeMaxKeyguardNotifications(rows, availableSpace = 0f, shelfHeight = 0f)
+
+ assertThat(maxNotifications).isEqualTo(0)
+ }
+
+ @Test
+ fun computeMaxKeyguardNotifications_infiniteSpace_returnsAll() {
+ val numberOfRows = 30
+ val rows = createLockscreenRows(numberOfRows)
+
+ val maxNotifications = computeMaxKeyguardNotifications(rows, Float.MAX_VALUE)
+
+ assertThat(maxNotifications).isEqualTo(numberOfRows)
+ }
+
+ @Test
+ fun computeMaxKeyguardNotifications_spaceForOne_returnsOne() {
+ val rowHeight = ROW_HEIGHT
+ val totalSpaceForEachRow = GAP_HEIGHT + rowHeight
+ val shelfHeight =
+ totalSpaceForEachRow / 2 // In this way shelf absence will not leave room for another.
+ val spaceForOne = totalSpaceForEachRow
+ val rows =
+ listOf(
+ createMockRow(rowHeight, visibleOnLockscreen = true),
+ createMockRow(rowHeight, visibleOnLockscreen = true))
+
+ val maxNotifications =
+ computeMaxKeyguardNotifications(
+ rows, availableSpace = spaceForOne, shelfHeight = shelfHeight)
+
+ assertThat(maxNotifications).isEqualTo(1)
+ }
+
+ @Test
+ fun computeMaxKeyguardNotifications_spaceForOne_shelfUsableForLastNotification_returnsTwo() {
+ val rowHeight = ROW_HEIGHT
+ val totalSpaceForEachRow = GAP_HEIGHT + rowHeight
+ val shelfHeight = totalSpaceForEachRow + NOTIFICATION_PADDING
+ val spaceForOne = totalSpaceForEachRow
+ val rows =
+ listOf(
+ createMockRow(rowHeight, visibleOnLockscreen = true),
+ createMockRow(rowHeight, visibleOnLockscreen = true))
+
+ val maxNotifications =
+ computeMaxKeyguardNotifications(
+ rows, availableSpace = spaceForOne, shelfHeight = shelfHeight)
+
+ assertThat(maxNotifications).isEqualTo(1)
+ }
+
+ @Test
+ fun computeMaxKeyguardNotifications_invisibleOnLockscreen_returnsZero() {
+ val rows = listOf(createMockRow(visibleOnLockscreen = false))
+
+ val maxNotifications = computeMaxKeyguardNotifications(rows, Float.MAX_VALUE)
+
+ assertThat(maxNotifications).isEqualTo(0)
+ }
+
+ @Test
+ fun computeMaxKeyguardNotifications_spaceForTwo_returnsTwo() {
+ val rowHeight = ROW_HEIGHT
+ val totalSpaceForEachRow = GAP_HEIGHT + rowHeight
+ val spaceForTwo = totalSpaceForEachRow * 2 + NOTIFICATION_PADDING
+ val rows =
+ listOf(
+ createMockRow(rowHeight, visibleOnLockscreen = true),
+ createMockRow(rowHeight, visibleOnLockscreen = true),
+ createMockRow(rowHeight, visibleOnLockscreen = true))
+
+ val maxNotifications = computeMaxKeyguardNotifications(rows, spaceForTwo, shelfHeight = 0f)
+
+ assertThat(maxNotifications).isEqualTo(2)
+ }
+
+ @Test
+ fun computeHeight_returnsLessThanAvailableSpaceUsedToCalculateMaxNotifications() {
+ val rowHeight = ROW_HEIGHT
+ val shelfHeight = SHELF_HEIGHT
+ val totalSpaceForEachRow = GAP_HEIGHT + rowHeight + NOTIFICATION_PADDING
+ val availableSpace = totalSpaceForEachRow * 2
+ val rows =
+ listOf(
+ createMockRow(rowHeight, visibleOnLockscreen = true),
+ createMockRow(rowHeight, visibleOnLockscreen = true),
+ createMockRow(rowHeight, visibleOnLockscreen = true))
+
+ val maxNotifications = computeMaxKeyguardNotifications(rows, availableSpace, shelfHeight)
+ assertThat(maxNotifications).isEqualTo(2)
+
+ val height = sizeCalculator.computeHeight(stackLayout, maxNotifications, SHELF_HEIGHT)
+ assertThat(height).isAtMost(availableSpace + SHELF_HEIGHT)
+ }
+
+ @Test
+ fun computeHeight_allInvisibleToLockscreen_NotInLockscreen_returnsHigherThanZero() {
+ setOnLockscreen(false)
+ val rowHeight = 10f
+ setupChildren(listOf(createMockRow(rowHeight, visibleOnLockscreen = false)))
+
+ val height =
+ sizeCalculator.computeHeight(
+ stackLayout, maxNotifications = Int.MAX_VALUE, SHELF_HEIGHT)
+
+ assertThat(height).isGreaterThan(rowHeight)
+ }
+
+ @Test
+ fun computeHeight_allInvisibleToLockscreen_onLockscreen_returnsZero() {
+ setOnLockscreen(true)
+ setupChildren(listOf(createMockRow(visibleOnLockscreen = false)))
+
+ val height =
+ sizeCalculator.computeHeight(
+ stackLayout, maxNotifications = Int.MAX_VALUE, SHELF_HEIGHT)
+
+ assertThat(height).isEqualTo(0)
+ }
+
+ private fun computeMaxKeyguardNotifications(
+ rows: List<ExpandableView>,
+ availableSpace: Float,
+ shelfHeight: Float = SHELF_HEIGHT
+ ): Int {
+ setupChildren(rows)
+ return sizeCalculator.computeMaxKeyguardNotifications(
+ stackLayout, availableSpace, shelfHeight)
+ }
+
+ private fun setupChildren(children: List<ExpandableView>) {
+ whenever(stackLayout.getChildAt(any())).thenAnswer { invocation ->
+ val inx = invocation.getArgument<Int>(0)
+ return@thenAnswer children[inx]
+ }
+ whenever(stackLayout.childCount).thenReturn(children.size)
+ }
+
+ private fun createLockscreenRows(number: Int): List<ExpandableNotificationRow> =
+ (1..number).map { createMockRow(visibleOnLockscreen = true) }.toList()
+
+ private fun createMockRow(
+ height: Float = ROW_HEIGHT,
+ visibleOnLockscreen: Boolean = true,
+ isRemoved: Boolean = false,
+ visibility: Int = VISIBLE,
+ summaryOfSuppressed: Boolean = false
+ ): ExpandableNotificationRow {
+ val row = mock(ExpandableNotificationRow::class.java)
+ val entry = mock(NotificationEntry::class.java)
+ val sbn = mock(StatusBarNotification::class.java)
+ whenever(entry.sbn).thenReturn(sbn)
+ whenever(row.entry).thenReturn(entry)
+ whenever(row.isRemoved).thenReturn(isRemoved)
+ whenever(row.visibility).thenReturn(visibility)
+ whenever(notificationLockscreenUserManager.shouldShowOnKeyguard(entry))
+ .thenReturn(visibleOnLockscreen)
+ whenever(groupManager.isSummaryOfSuppressedGroup(sbn)).thenReturn(summaryOfSuppressed)
+ whenever(row.getMinHeight(any())).thenReturn(height.toInt())
+ whenever(row.intrinsicHeight).thenReturn(height.toInt())
+ return row
+ }
+
+ private fun setOnLockscreen(onLockscreen: Boolean) {
+ whenever(sysuiStatusBarStateController.state)
+ .thenReturn(
+ if (onLockscreen) {
+ KEYGUARD
+ } else {
+ SHADE
+ })
+ }
+
+ /** Default dimensions for tests that don't overwrite them. */
+ companion object {
+ const val GAP_HEIGHT = 12f
+ const val NOTIFICATION_PADDING = 3f
+ const val SHELF_HEIGHT = 14f
+ const val ROW_HEIGHT = SHELF_HEIGHT * 3
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesTest.java
index 3810783d4f76..c72f89512230 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesTest.java
@@ -131,6 +131,7 @@ import com.android.systemui.statusbar.notification.collection.legacy.VisualStabi
import com.android.systemui.statusbar.notification.collection.render.NotifShadeEventSource;
import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider;
import com.android.systemui.statusbar.notification.init.NotificationsController;
+import com.android.systemui.statusbar.notification.interruption.KeyguardNotificationVisibilityProvider;
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptLogger;
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderImpl;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
@@ -309,7 +310,9 @@ public class CentralSurfacesTest extends SysuiTestCase {
mDreamManager, mAmbientDisplayConfiguration, mNotificationFilter,
mStatusBarStateController, mBatteryController, mHeadsUpManager,
mock(NotificationInterruptLogger.class),
- new Handler(TestableLooper.get(this).getLooper()));
+ new Handler(TestableLooper.get(this).getLooper()),
+ mock(NotifPipelineFlags.class),
+ mock(KeyguardNotificationVisibilityProvider.class));
mContext.addMockSystemService(TrustManager.class, mock(TrustManager.class));
mContext.addMockSystemService(FingerprintManager.class, mock(FingerprintManager.class));
@@ -994,9 +997,12 @@ public class CentralSurfacesTest extends SysuiTestCase {
BatteryController batteryController,
HeadsUpManager headsUpManager,
NotificationInterruptLogger logger,
- Handler mainHandler) {
+ Handler mainHandler,
+ NotifPipelineFlags flags,
+ KeyguardNotificationVisibilityProvider keyguardNotificationVisibilityProvider) {
super(contentResolver, powerManager, dreamManager, ambientDisplayConfiguration, filter,
- batteryController, controller, headsUpManager, logger, mainHandler);
+ batteryController, controller, headsUpManager, logger, mainHandler,
+ flags, keyguardNotificationVisibilityProvider);
mUseHeadsUp = true;
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java
index 1af7035a441b..06b20380c0ab 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java
@@ -28,7 +28,6 @@ import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
-import static org.mockito.ArgumentMatchers.anyFloat;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.atLeast;
@@ -57,13 +56,11 @@ import android.util.DisplayMetrics;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
-import android.view.ViewGroup;
import android.view.ViewPropertyAnimator;
import android.view.ViewStub;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityNodeInfo;
-import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.constraintlayout.widget.ConstraintSet;
import androidx.test.filters.SmallTest;
@@ -88,12 +85,6 @@ import com.android.systemui.SysuiTestCase;
import com.android.systemui.biometrics.AuthController;
import com.android.systemui.classifier.FalsingCollectorFake;
import com.android.systemui.classifier.FalsingManagerFake;
-import com.android.systemui.communal.CommunalHostView;
-import com.android.systemui.communal.CommunalHostViewController;
-import com.android.systemui.communal.CommunalSource;
-import com.android.systemui.communal.CommunalSourceMonitor;
-import com.android.systemui.communal.CommunalStateController;
-import com.android.systemui.communal.dagger.CommunalViewComponent;
import com.android.systemui.controls.dagger.ControlsComponent;
import com.android.systemui.doze.DozeLog;
import com.android.systemui.dump.DumpManager;
@@ -113,7 +104,6 @@ import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.KeyguardAffordanceView;
import com.android.systemui.statusbar.KeyguardIndicationController;
import com.android.systemui.statusbar.LockscreenShadeTransitionController;
-import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.NotificationShadeDepthController;
import com.android.systemui.statusbar.NotificationShadeWindowController;
@@ -128,12 +118,12 @@ import com.android.systemui.statusbar.notification.ConversationNotificationManag
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
-import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
import com.android.systemui.statusbar.notification.stack.AmbientState;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
import com.android.systemui.statusbar.notification.stack.NotificationRoundnessManager;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
+import com.android.systemui.statusbar.notification.stack.NotificationStackSizeCalculator;
import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardQsUserSwitchController;
@@ -157,7 +147,6 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.stubbing.Answer;
-import java.lang.ref.WeakReference;
import java.util.List;
import java.util.Optional;
@@ -184,8 +173,6 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase {
@Mock
private NotificationShelfController mNotificationShelfController;
@Mock
- private NotificationGroupManagerLegacy mGroupManager;
- @Mock
private KeyguardStatusBarView mKeyguardStatusBar;
@Mock
private KeyguardUserSwitcherView mUserSwitcherView;
@@ -210,10 +197,6 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase {
@Mock
private DynamicPrivacyController mDynamicPrivacyController;
@Mock
- private ShadeController mShadeController;
- @Mock
- private NotificationLockscreenUserManager mNotificationLockscreenUserManager;
- @Mock
private NotificationEntryManager mNotificationEntryManager;
@Mock
private StatusBarTouchableRegionManager mStatusBarTouchableRegionManager;
@@ -271,21 +254,6 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase {
@Mock
private KeyguardStatusBarViewComponent mKeyguardStatusBarViewComponent;
@Mock
- private CommunalViewComponent.Factory mCommunalViewComponentFactory;
- @Mock
- private CommunalViewComponent mCommunalViewComponent;
- @Mock
- private CommunalHostViewController mCommunalHostViewController;
- @Mock
- private CommunalSourceMonitor mCommunalSourceMonitor;
- @Mock
- private CommunalSource mCommunalSource;
- @Mock
- private CommunalHostView mCommunalHostView;
- @Mock
- private CommunalStateController mCommunalStateController;
- private CommunalStateController.Callback mCommunalStateControllerCallback;
- @Mock
private KeyguardClockSwitchController mKeyguardClockSwitchController;
@Mock
private KeyguardStatusViewController mKeyguardStatusViewController;
@@ -361,6 +329,9 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase {
private SysUiState mSysUiState;
@Mock
private NotificationListContainer mNotificationListContainer;
+ @Mock
+ private NotificationStackSizeCalculator mNotificationStackSizeCalculator;
+ private NotificationPanelViewController.PanelEventsEmitter mPanelEventsEmitter;
private Optional<SysUIUnfoldComponent> mSysUIUnfoldComponent = Optional.empty();
private SysuiStatusBarStateController mStatusBarStateController;
private NotificationPanelViewController mNotificationPanelViewController;
@@ -400,7 +371,6 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase {
when(mView.findViewById(R.id.keyguard_clock_container)).thenReturn(mKeyguardClockSwitch);
when(mView.findViewById(R.id.notification_stack_scroller))
.thenReturn(mNotificationStackScrollLayout);
- when(mView.findViewById(R.id.communal_host)).thenReturn(mCommunalHostView);
when(mNotificationStackScrollLayoutController.getHeight()).thenReturn(1000);
when(mNotificationStackScrollLayoutController.getHeadsUpCallback())
.thenReturn(mHeadsUpCallback);
@@ -412,8 +382,6 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase {
when(mView.findViewById(R.id.keyguard_status_view))
.thenReturn(mock(KeyguardStatusView.class));
mNotificationContainerParent = new NotificationsQuickSettingsContainer(getContext(), null);
- mNotificationContainerParent.addView(newViewWithId(R.id.qs_frame));
- mNotificationContainerParent.addView(newViewWithId(R.id.notification_stack_scroller));
mNotificationContainerParent.addView(mKeyguardStatusView);
mNotificationContainerParent.onFinishInflate();
when(mView.findViewById(R.id.notification_container_parent))
@@ -466,10 +434,6 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase {
.thenReturn(mKeyguardStatusBarViewComponent);
when(mKeyguardStatusBarViewComponent.getKeyguardStatusBarViewController())
.thenReturn(mKeyguardStatusBarViewController);
- when(mCommunalViewComponentFactory.build(any()))
- .thenReturn(mCommunalViewComponent);
- when(mCommunalViewComponent.getCommunalHostViewController())
- .thenReturn(mCommunalHostViewController);
when(mLayoutInflater.inflate(eq(R.layout.keyguard_status_view), any(), anyBoolean()))
.thenReturn(mKeyguardStatusView);
when(mLayoutInflater.inflate(eq(R.layout.keyguard_user_switcher), any(), anyBoolean()))
@@ -488,6 +452,7 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase {
}).when(mNotificationShadeWindowController).batchApplyWindowLayoutParams(any());
mMainHandler = new Handler(Looper.getMainLooper());
+ mPanelEventsEmitter = new NotificationPanelViewController.PanelEventsEmitter();
mNotificationPanelViewController = new NotificationPanelViewController(mView,
mResources,
@@ -496,14 +461,14 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase {
mFeatureFlags,
coordinator, expansionHandler, mDynamicPrivacyController, mKeyguardBypassController,
mFalsingManager, new FalsingCollectorFake(),
- mNotificationLockscreenUserManager, mNotificationEntryManager,
- mCommunalStateController, mKeyguardStateController,
+ mNotificationEntryManager,
+ mKeyguardStateController,
mStatusBarStateController,
mStatusBarWindowStateController,
mNotificationShadeWindowController,
mDozeLog, mDozeParameters, mCommandQueue, mVibratorHelper,
mLatencyTracker, mPowerManager, mAccessibilityManager, 0, mUpdateMonitor,
- mCommunalSourceMonitor, mMetricsLogger, mActivityManager, mConfigurationController,
+ mMetricsLogger, mActivityManager, mConfigurationController,
() -> flingAnimationUtilsBuilder, mStatusBarTouchableRegionManager,
mConversationNotificationManager, mMediaHiearchyManager,
mStatusBarKeyguardViewManager,
@@ -513,9 +478,7 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase {
mKeyguardQsUserSwitchComponentFactory,
mKeyguardUserSwitcherComponentFactory,
mKeyguardStatusBarViewComponentFactory,
- mCommunalViewComponentFactory,
mLockscreenShadeTransitionController,
- mGroupManager,
mNotificationAreaController,
mAuthController,
mScrimController,
@@ -546,7 +509,9 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase {
mQsFrameTranslateController,
mSysUiState,
mKeyguardUnlockAnimationController,
- mNotificationListContainer);
+ mNotificationListContainer,
+ mPanelEventsEmitter,
+ mNotificationStackSizeCalculator);
mNotificationPanelViewController.initDependencies(
mCentralSurfaces,
() -> {},
@@ -705,31 +670,6 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase {
}
@Test
- public void testAllChildrenOfNotificationContainer_haveIds() {
- enableSplitShade(/* enabled= */ true);
- mNotificationContainerParent.removeAllViews();
- mNotificationContainerParent.addView(newViewWithId(1));
- mNotificationContainerParent.addView(newViewWithId(View.NO_ID));
-
- mNotificationPanelViewController.updateResources();
-
- assertThat(mNotificationContainerParent.getChildAt(0).getId()).isEqualTo(1);
- assertThat(mNotificationContainerParent.getChildAt(1).getId()).isNotEqualTo(View.NO_ID);
- }
-
- @Test
- public void testSinglePaneShadeLayout_isAlignedToParent() {
- enableSplitShade(/* enabled= */ false);
-
- mNotificationPanelViewController.updateResources();
-
- assertThat(getConstraintSetLayout(R.id.qs_frame).endToEnd)
- .isEqualTo(ConstraintSet.PARENT_ID);
- assertThat(getConstraintSetLayout(R.id.notification_stack_scroller).startToStart)
- .isEqualTo(ConstraintSet.PARENT_ID);
- }
-
- @Test
public void testKeyguardStatusViewInSplitShade_changesConstraintsDependingOnNotifications() {
mStatusBarStateController.setState(KEYGUARD);
enableSplitShade(/* enabled= */ true);
@@ -778,46 +718,6 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase {
}
@Test
- public void testSplitShadeLayout_isAlignedToGuideline() {
- enableSplitShade(/* enabled= */ true);
-
- mNotificationPanelViewController.updateResources();
-
- assertThat(getConstraintSetLayout(R.id.qs_frame).endToEnd)
- .isEqualTo(R.id.qs_edge_guideline);
- assertThat(getConstraintSetLayout(R.id.notification_stack_scroller).startToStart)
- .isEqualTo(R.id.qs_edge_guideline);
- }
-
- @Test
- public void testSplitShadeLayout_childrenHaveInsideMarginsOfZero() {
- enableSplitShade(/* enabled= */ true);
-
- mNotificationPanelViewController.updateResources();
-
- assertThat(getConstraintSetLayout(R.id.qs_frame).startMargin).isEqualTo(10);
- assertThat(getConstraintSetLayout(R.id.qs_frame).endMargin).isEqualTo(0);
- assertThat(getConstraintSetLayout(R.id.notification_stack_scroller).startMargin)
- .isEqualTo(0);
- assertThat(getConstraintSetLayout(R.id.notification_stack_scroller).endMargin)
- .isEqualTo(10);
- }
-
- @Test
- public void testSinglePaneLayout_childrenHaveEqualMargins() {
- enableSplitShade(/* enabled= */ false);
-
- mNotificationPanelViewController.updateResources();
-
- assertThat(getConstraintSetLayout(R.id.qs_frame).startMargin).isEqualTo(10);
- assertThat(getConstraintSetLayout(R.id.qs_frame).endMargin).isEqualTo(10);
- assertThat(getConstraintSetLayout(R.id.notification_stack_scroller).startMargin)
- .isEqualTo(10);
- assertThat(getConstraintSetLayout(R.id.notification_stack_scroller).endMargin)
- .isEqualTo(10);
- }
-
- @Test
public void testCanCollapsePanelOnTouch_trueForKeyGuard() {
mStatusBarStateController.setState(KEYGUARD);
@@ -1018,81 +918,6 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase {
verify(mKeyguardStatusViewController, never()).displayClock(LARGE, /* animate */ true);
}
- @Test
- public void testCommunalhostViewControllerInit() {
- verify(mCommunalHostViewController, times(1)).init();
- clearInvocations(mCommunalHostViewController);
- givenViewAttached();
- verify(mCommunalHostViewController, never()).init();
- }
-
- @Test
- public void testCommunalSourceListening() {
- final ArgumentCaptor<CommunalSourceMonitor.Callback> monitorCallback =
- ArgumentCaptor.forClass(CommunalSourceMonitor.Callback.class);
-
- givenViewAttached();
- verify(mCommunalSourceMonitor).addCallback(monitorCallback.capture());
-
- final ArgumentCaptor<WeakReference<CommunalSource>> sourceCapture =
- ArgumentCaptor.forClass(WeakReference.class);
-
- monitorCallback.getValue().onSourceAvailable(new WeakReference<>(mCommunalSource));
- mExecutor.runAllReady();
- verify(mCommunalHostViewController).show(sourceCapture.capture());
- assertThat(sourceCapture.getValue().get()).isEqualTo(mCommunalSource);
-
- clearInvocations(mCommunalHostViewController);
- givenViewDetached();
- verify(mCommunalSourceMonitor).removeCallback(any());
- }
-
- @Test
- public void testKeyguardStatusViewUpdatedWithCommunalPresence() {
- givenViewAttached();
-
- when(mResources.getBoolean(
- com.android.internal.R.bool.config_keyguardUserSwitcher)).thenReturn(true);
- updateMultiUserSetting(true);
-
- ArgumentCaptor<CommunalStateController.Callback> communalCallbackCapture =
- ArgumentCaptor.forClass(CommunalStateController.Callback.class);
- verify(mCommunalStateController).addCallback(communalCallbackCapture.capture());
- final CommunalStateController.Callback communalStateControllerCallback =
- communalCallbackCapture.getValue();
-
- clearInvocations(mKeyguardStatusViewController, mKeyguardUserSwitcherController);
- // Ensure changes in communal visibility leads to setting the keyguard status view
- // visibility.
- communalStateControllerCallback.onCommunalViewShowingChanged();
- verify(mKeyguardStatusViewController).setKeyguardStatusViewVisibility(anyInt(),
- anyBoolean(), anyBoolean(), anyInt());
- verify(mKeyguardUserSwitcherController).setKeyguardUserSwitcherVisibility(anyInt(),
- anyBoolean(), anyBoolean(), anyInt());
- }
-
- @Test
- public void testCommunalAlphaUpdate() {
- // Verify keyguard content alpha changes are propagate. Note the actual value set is not
- // checked since an interpolation is applied to the incoming value.
- mNotificationPanelViewController.setKeyguardOnlyContentAlpha(0.8f);
- verify(mCommunalHostViewController).setAlpha(anyFloat());
- }
-
- @Test
- public void testCommunalPositionUpdate() {
- // Verify that the communal position is updated on interaction with the
- // NotificationPanelViewController. Note that there a number of paths where the position
- // might be updated and therefore the check isn't strictly on a single invocation.
- clearInvocations(mCommunalHostViewController);
- final View.OnLayoutChangeListener layoutChangeListener =
- mNotificationPanelViewController.createLayoutChangeListener();
- mNotificationPanelViewController.mStatusBarStateController.setState(KEYGUARD);
- layoutChangeListener.onLayoutChange(mView, 0, 0, 200, 200, 0, 0, 200, 200);
- verify(mCommunalHostViewController, atLeast(1))
- .updatePosition(anyInt(), anyBoolean());
- }
-
private void triggerPositionClockAndNotifications() {
mNotificationPanelViewController.closeQs();
}
@@ -1117,17 +942,6 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase {
}
}
-
- private View newViewWithId(int id) {
- View view = new View(mContext);
- view.setId(id);
- ConstraintLayout.LayoutParams layoutParams = new ConstraintLayout.LayoutParams(
- ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
- // required as cloning ConstraintSet fails if view doesn't have layout params
- view.setLayoutParams(layoutParams);
- return view;
- }
-
private ConstraintSet.Layout getConstraintSetLayout(@IdRes int id) {
ConstraintSet constraintSet = new ConstraintSet();
constraintSet.clone(mNotificationContainerParent);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationQSContainerControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationQSContainerControllerTest.kt
index 00af446ded3d..9e7b6c514ca3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationQSContainerControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationQSContainerControllerTest.kt
@@ -2,9 +2,15 @@ package com.android.systemui.statusbar.phone
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
+import android.view.View
+import android.view.ViewGroup
import android.view.WindowInsets
import android.view.WindowManagerPolicyConstants
+import androidx.annotation.IdRes
+import androidx.constraintlayout.widget.ConstraintLayout
+import androidx.constraintlayout.widget.ConstraintSet
import androidx.test.filters.SmallTest
+import com.android.systemui.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
@@ -12,6 +18,9 @@ import com.android.systemui.navigationbar.NavigationModeController
import com.android.systemui.navigationbar.NavigationModeController.ModeChangedListener
import com.android.systemui.recents.OverviewProxyService
import com.android.systemui.recents.OverviewProxyService.OverviewProxyListener
+import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.time.FakeSystemClock
+import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -24,6 +33,7 @@ import org.mockito.Mockito.anyInt
import org.mockito.Mockito.doNothing
import org.mockito.Mockito.eq
import org.mockito.Mockito.mock
+import org.mockito.Mockito.never
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
import java.util.function.Consumer
@@ -40,6 +50,7 @@ class NotificationQSContainerControllerTest : SysuiTestCase() {
const val GESTURES_NAVIGATION = WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL
const val BUTTONS_NAVIGATION = WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON
const val NOTIFICATIONS_MARGIN = 50
+ const val SCRIM_MARGIN = 10
}
@Mock
@@ -56,31 +67,44 @@ class NotificationQSContainerControllerTest : SysuiTestCase() {
lateinit var taskbarVisibilityCaptor: ArgumentCaptor<OverviewProxyListener>
@Captor
lateinit var windowInsetsCallbackCaptor: ArgumentCaptor<Consumer<WindowInsets>>
+ @Captor
+ lateinit var constraintSetCaptor: ArgumentCaptor<ConstraintSet>
- private lateinit var notificationsQSContainerController: NotificationsQSContainerController
+ private lateinit var controller: NotificationsQSContainerController
private lateinit var navigationModeCallback: ModeChangedListener
private lateinit var taskbarVisibilityCallback: OverviewProxyListener
private lateinit var windowInsetsCallback: Consumer<WindowInsets>
+ private lateinit var delayableExecutor: FakeExecutor
+ private lateinit var fakeSystemClock: FakeSystemClock
@Before
fun setup() {
MockitoAnnotations.initMocks(this)
- notificationsQSContainerController = NotificationsQSContainerController(
+ mContext.ensureTestableResources()
+ whenever(notificationsQSContainer.context).thenReturn(mContext)
+ whenever(notificationsQSContainer.resources).thenReturn(mContext.resources)
+ fakeSystemClock = FakeSystemClock()
+ delayableExecutor = FakeExecutor(fakeSystemClock)
+ controller = NotificationsQSContainerController(
notificationsQSContainer,
navigationModeController,
overviewProxyService,
- featureFlags
+ featureFlags,
+ delayableExecutor
)
- whenever(notificationsQSContainer.defaultNotificationsMarginBottom)
- .thenReturn(NOTIFICATIONS_MARGIN)
+
+ overrideResource(R.dimen.split_shade_notifications_scrim_margin_bottom, SCRIM_MARGIN)
+ overrideResource(R.dimen.notification_panel_margin_bottom, NOTIFICATIONS_MARGIN)
+ overrideResource(R.bool.config_use_split_notification_shade, false)
whenever(navigationModeController.addListener(navigationModeCaptor.capture()))
.thenReturn(GESTURES_NAVIGATION)
doNothing().`when`(overviewProxyService).addCallback(taskbarVisibilityCaptor.capture())
doNothing().`when`(notificationsQSContainer)
.setInsetsChangedListener(windowInsetsCallbackCaptor.capture())
+ doNothing().`when`(notificationsQSContainer).applyConstraints(constraintSetCaptor.capture())
- notificationsQSContainerController.init()
- notificationsQSContainerController.onViewAttached()
+ controller.init()
+ controller.onViewAttached()
navigationModeCallback = navigationModeCaptor.value
taskbarVisibilityCallback = taskbarVisibilityCaptor.value
@@ -89,7 +113,7 @@ class NotificationQSContainerControllerTest : SysuiTestCase() {
@Test
fun testTaskbarVisibleInSplitShade() {
- notificationsQSContainerController.splitShadeEnabled = true
+ enableSplitShade()
useNewFooter(false)
given(taskbarVisible = true,
@@ -107,7 +131,7 @@ class NotificationQSContainerControllerTest : SysuiTestCase() {
@Test
fun testTaskbarVisibleInSplitShade_newFooter() {
- notificationsQSContainerController.splitShadeEnabled = true
+ enableSplitShade()
useNewFooter(true)
given(taskbarVisible = true,
@@ -115,20 +139,20 @@ class NotificationQSContainerControllerTest : SysuiTestCase() {
insets = windowInsets().withStableBottom())
then(expectedContainerPadding = 0, // taskbar should disappear when shade is expanded
expectedNotificationsMargin = NOTIFICATIONS_MARGIN,
- expectedQsPadding = STABLE_INSET_BOTTOM)
+ expectedQsPadding = NOTIFICATIONS_MARGIN - SCRIM_MARGIN)
given(taskbarVisible = true,
navigationMode = BUTTONS_NAVIGATION,
insets = windowInsets().withStableBottom())
then(expectedContainerPadding = STABLE_INSET_BOTTOM,
expectedNotificationsMargin = NOTIFICATIONS_MARGIN,
- expectedQsPadding = STABLE_INSET_BOTTOM)
+ expectedQsPadding = NOTIFICATIONS_MARGIN - SCRIM_MARGIN)
}
@Test
fun testTaskbarNotVisibleInSplitShade() {
// when taskbar is not visible, it means we're on the home screen
- notificationsQSContainerController.splitShadeEnabled = true
+ enableSplitShade()
useNewFooter(false)
given(taskbarVisible = false,
@@ -146,26 +170,26 @@ class NotificationQSContainerControllerTest : SysuiTestCase() {
@Test
fun testTaskbarNotVisibleInSplitShade_newFooter() {
// when taskbar is not visible, it means we're on the home screen
- notificationsQSContainerController.splitShadeEnabled = true
+ enableSplitShade()
useNewFooter(true)
given(taskbarVisible = false,
navigationMode = GESTURES_NAVIGATION,
insets = windowInsets().withStableBottom())
then(expectedContainerPadding = 0,
- expectedQsPadding = STABLE_INSET_BOTTOM)
+ expectedQsPadding = NOTIFICATIONS_MARGIN - SCRIM_MARGIN)
given(taskbarVisible = false,
navigationMode = BUTTONS_NAVIGATION,
insets = windowInsets().withStableBottom())
then(expectedContainerPadding = 0, // qs goes full height as it's not obscuring nav buttons
expectedNotificationsMargin = STABLE_INSET_BOTTOM + NOTIFICATIONS_MARGIN,
- expectedQsPadding = STABLE_INSET_BOTTOM)
+ expectedQsPadding = STABLE_INSET_BOTTOM + NOTIFICATIONS_MARGIN - SCRIM_MARGIN)
}
@Test
fun testTaskbarNotVisibleInSplitShadeWithCutout() {
- notificationsQSContainerController.splitShadeEnabled = true
+ enableSplitShade()
useNewFooter(false)
given(taskbarVisible = false,
@@ -182,25 +206,26 @@ class NotificationQSContainerControllerTest : SysuiTestCase() {
@Test
fun testTaskbarNotVisibleInSplitShadeWithCutout_newFooter() {
- notificationsQSContainerController.splitShadeEnabled = true
+ enableSplitShade()
useNewFooter(true)
given(taskbarVisible = false,
navigationMode = GESTURES_NAVIGATION,
insets = windowInsets().withCutout())
- then(expectedContainerPadding = CUTOUT_HEIGHT)
+ then(expectedContainerPadding = CUTOUT_HEIGHT,
+ expectedQsPadding = NOTIFICATIONS_MARGIN - SCRIM_MARGIN)
given(taskbarVisible = false,
navigationMode = BUTTONS_NAVIGATION,
insets = windowInsets().withCutout().withStableBottom())
then(expectedContainerPadding = 0,
expectedNotificationsMargin = STABLE_INSET_BOTTOM + NOTIFICATIONS_MARGIN,
- expectedQsPadding = STABLE_INSET_BOTTOM)
+ expectedQsPadding = STABLE_INSET_BOTTOM + NOTIFICATIONS_MARGIN - SCRIM_MARGIN)
}
@Test
fun testTaskbarVisibleInSinglePaneShade() {
- notificationsQSContainerController.splitShadeEnabled = false
+ disableSplitShade()
useNewFooter(false)
given(taskbarVisible = true,
@@ -216,7 +241,7 @@ class NotificationQSContainerControllerTest : SysuiTestCase() {
@Test
fun testTaskbarVisibleInSinglePaneShade_newFooter() {
- notificationsQSContainerController.splitShadeEnabled = false
+ disableSplitShade()
useNewFooter(true)
given(taskbarVisible = true,
@@ -234,7 +259,7 @@ class NotificationQSContainerControllerTest : SysuiTestCase() {
@Test
fun testTaskbarNotVisibleInSinglePaneShade() {
- notificationsQSContainerController.splitShadeEnabled = false
+ disableSplitShade()
useNewFooter(false)
given(taskbarVisible = false,
@@ -255,7 +280,7 @@ class NotificationQSContainerControllerTest : SysuiTestCase() {
@Test
fun testTaskbarNotVisibleInSinglePaneShade_newFooter() {
- notificationsQSContainerController.splitShadeEnabled = false
+ disableSplitShade()
useNewFooter(true)
given(taskbarVisible = false,
@@ -276,8 +301,8 @@ class NotificationQSContainerControllerTest : SysuiTestCase() {
@Test
fun testCustomizingInSinglePaneShade() {
- notificationsQSContainerController.splitShadeEnabled = false
- notificationsQSContainerController.setCustomizerShowing(true)
+ disableSplitShade()
+ controller.setCustomizerShowing(true)
useNewFooter(false)
// always sets spacings to 0
@@ -296,8 +321,8 @@ class NotificationQSContainerControllerTest : SysuiTestCase() {
@Test
fun testCustomizingInSinglePaneShade_newFooter() {
- notificationsQSContainerController.splitShadeEnabled = false
- notificationsQSContainerController.setCustomizerShowing(true)
+ disableSplitShade()
+ controller.setCustomizerShowing(true)
useNewFooter(true)
// always sets spacings to 0
@@ -316,8 +341,8 @@ class NotificationQSContainerControllerTest : SysuiTestCase() {
@Test
fun testDetailShowingInSinglePaneShade() {
- notificationsQSContainerController.splitShadeEnabled = false
- notificationsQSContainerController.setDetailShowing(true)
+ disableSplitShade()
+ controller.setDetailShowing(true)
useNewFooter(false)
// always sets spacings to 0
@@ -336,8 +361,8 @@ class NotificationQSContainerControllerTest : SysuiTestCase() {
@Test
fun testDetailShowingInSinglePaneShade_newFooter() {
- notificationsQSContainerController.splitShadeEnabled = false
- notificationsQSContainerController.setDetailShowing(true)
+ disableSplitShade()
+ controller.setDetailShowing(true)
useNewFooter(true)
// always sets spacings to 0
@@ -356,8 +381,8 @@ class NotificationQSContainerControllerTest : SysuiTestCase() {
@Test
fun testDetailShowingInSplitShade() {
- notificationsQSContainerController.splitShadeEnabled = true
- notificationsQSContainerController.setDetailShowing(true)
+ enableSplitShade()
+ controller.setDetailShowing(true)
useNewFooter(false)
given(taskbarVisible = false,
@@ -374,8 +399,8 @@ class NotificationQSContainerControllerTest : SysuiTestCase() {
@Test
fun testDetailShowingInSplitShade_newFooter() {
- notificationsQSContainerController.splitShadeEnabled = true
- notificationsQSContainerController.setDetailShowing(true)
+ enableSplitShade()
+ controller.setDetailShowing(true)
useNewFooter(true)
given(taskbarVisible = false,
@@ -392,25 +417,140 @@ class NotificationQSContainerControllerTest : SysuiTestCase() {
@Test
fun testNotificationsMarginBottomIsUpdated() {
- notificationsQSContainerController.splitShadeEnabled = true
+ Mockito.clearInvocations(notificationsQSContainer)
+ enableSplitShade()
verify(notificationsQSContainer).setNotificationsMarginBottom(NOTIFICATIONS_MARGIN)
- whenever(notificationsQSContainer.defaultNotificationsMarginBottom).thenReturn(100)
- notificationsQSContainerController.updateMargins()
- notificationsQSContainerController.splitShadeEnabled = false
-
+ overrideResource(R.dimen.notification_panel_margin_bottom, 100)
+ disableSplitShade()
verify(notificationsQSContainer).setNotificationsMarginBottom(100)
}
+ @Test
+ fun testSplitShadeLayout_isAlignedToGuideline() {
+ enableSplitShade()
+ controller.updateResources()
+ assertThat(getConstraintSetLayout(R.id.qs_frame).endToEnd)
+ .isEqualTo(R.id.qs_edge_guideline)
+ assertThat(getConstraintSetLayout(R.id.notification_stack_scroller).startToStart)
+ .isEqualTo(R.id.qs_edge_guideline)
+ }
+
+ @Test
+ fun testSinglePaneLayout_childrenHaveEqualMargins() {
+ disableSplitShade()
+ controller.updateResources()
+ val qsStartMargin = getConstraintSetLayout(R.id.qs_frame).startMargin
+ val qsEndMargin = getConstraintSetLayout(R.id.qs_frame).endMargin
+ val notifStartMargin = getConstraintSetLayout(R.id.notification_stack_scroller).startMargin
+ val notifEndMargin = getConstraintSetLayout(R.id.notification_stack_scroller).endMargin
+ assertThat(qsStartMargin == qsEndMargin &&
+ notifStartMargin == notifEndMargin &&
+ qsStartMargin == notifStartMargin
+ ).isTrue()
+ }
+
+ @Test
+ fun testSplitShadeLayout_childrenHaveInsideMarginsOfZero() {
+ enableSplitShade()
+ controller.updateResources()
+ assertThat(getConstraintSetLayout(R.id.qs_frame).endMargin).isEqualTo(0)
+ assertThat(getConstraintSetLayout(R.id.notification_stack_scroller).startMargin)
+ .isEqualTo(0)
+ }
+
+ @Test
+ fun testSplitShadeLayout_qsFrameHasHorizontalMarginsOfZero() {
+ enableSplitShade()
+ controller.updateResources()
+ assertThat(getConstraintSetLayout(R.id.qs_frame).endMargin).isEqualTo(0)
+ assertThat(getConstraintSetLayout(R.id.qs_frame).startMargin).isEqualTo(0)
+ }
+
+ @Test
+ fun testSinglePaneShadeLayout_qsFrameHasHorizontalMarginsSetToCorrectValue() {
+ disableSplitShade()
+ controller.updateResources()
+ val notificationPanelMarginHorizontal = context.resources
+ .getDimensionPixelSize(R.dimen.notification_panel_margin_horizontal)
+ assertThat(getConstraintSetLayout(R.id.qs_frame).endMargin)
+ .isEqualTo(notificationPanelMarginHorizontal)
+ assertThat(getConstraintSetLayout(R.id.qs_frame).startMargin)
+ .isEqualTo(notificationPanelMarginHorizontal)
+ }
+
+ @Test
+ fun testSinglePaneShadeLayout_isAlignedToParent() {
+ disableSplitShade()
+ controller.updateResources()
+ assertThat(getConstraintSetLayout(R.id.qs_frame).endToEnd)
+ .isEqualTo(ConstraintSet.PARENT_ID)
+ assertThat(getConstraintSetLayout(R.id.notification_stack_scroller).startToStart)
+ .isEqualTo(ConstraintSet.PARENT_ID)
+ }
+
+ @Test
+ fun testAllChildrenOfNotificationContainer_haveIds() {
+ // set dimen to 0 to avoid triggering updating bottom spacing
+ overrideResource(R.dimen.split_shade_notifications_scrim_margin_bottom, 0)
+ val container = NotificationsQuickSettingsContainer(context, null)
+ container.removeAllViews()
+ container.addView(newViewWithId(1))
+ container.addView(newViewWithId(View.NO_ID))
+ val controller = NotificationsQSContainerController(container, navigationModeController,
+ overviewProxyService, featureFlags, delayableExecutor)
+ controller.updateResources()
+
+ assertThat(container.getChildAt(0).id).isEqualTo(1)
+ assertThat(container.getChildAt(1).id).isNotEqualTo(View.NO_ID)
+ }
+
+ @Test
+ fun testWindowInsetDebounce() {
+ disableSplitShade()
+ useNewFooter(true)
+
+ given(taskbarVisible = false,
+ navigationMode = GESTURES_NAVIGATION,
+ insets = emptyInsets(),
+ applyImmediately = false)
+ fakeSystemClock.advanceTime(INSET_DEBOUNCE_MILLIS / 2)
+ windowInsetsCallback.accept(windowInsets().withStableBottom())
+
+ delayableExecutor.advanceClockToLast()
+ delayableExecutor.runAllReady()
+
+ verify(notificationsQSContainer, never()).setQSContainerPaddingBottom(0)
+ verify(notificationsQSContainer).setQSContainerPaddingBottom(STABLE_INSET_BOTTOM)
+ }
+
+ private fun disableSplitShade() {
+ setSplitShadeEnabled(false)
+ }
+
+ private fun enableSplitShade() {
+ setSplitShadeEnabled(true)
+ }
+
+ private fun setSplitShadeEnabled(enabled: Boolean) {
+ overrideResource(R.bool.config_use_split_notification_shade, enabled)
+ controller.updateResources()
+ }
+
private fun given(
taskbarVisible: Boolean,
navigationMode: Int,
- insets: WindowInsets
+ insets: WindowInsets,
+ applyImmediately: Boolean = true
) {
Mockito.clearInvocations(notificationsQSContainer)
taskbarVisibilityCallback.onTaskbarStatusUpdated(taskbarVisible, false)
navigationModeCallback.onNavigationModeChanged(navigationMode)
windowInsetsCallback.accept(insets)
+ if (applyImmediately) {
+ delayableExecutor.advanceClockToLast()
+ delayableExecutor.runAllReady()
+ }
}
fun then(
@@ -448,4 +588,18 @@ class NotificationQSContainerControllerTest : SysuiTestCase() {
private fun useNewFooter(useNewFooter: Boolean) {
whenever(featureFlags.isEnabled(Flags.NEW_FOOTER)).thenReturn(useNewFooter)
}
-} \ No newline at end of file
+
+ private fun getConstraintSetLayout(@IdRes id: Int): ConstraintSet.Layout {
+ return constraintSetCaptor.value.getConstraint(id).layout
+ }
+
+ private fun newViewWithId(id: Int): View {
+ val view = View(mContext)
+ view.id = id
+ val layoutParams = ConstraintLayout.LayoutParams(
+ ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)
+ // required as cloning ConstraintSet fails if view doesn't have layout params
+ view.layoutParams = layoutParams
+ return view
+ }
+}
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 10f4435d3f97..786a8586ea39 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
@@ -16,7 +16,6 @@
package com.android.systemui.statusbar.phone;
-import static com.android.systemui.statusbar.phone.ScrimController.KEYGUARD_SCRIM_ALPHA;
import static com.android.systemui.statusbar.phone.ScrimController.OPAQUE;
import static com.android.systemui.statusbar.phone.ScrimController.SEMI_TRANSPARENT;
import static com.android.systemui.statusbar.phone.ScrimController.TRANSPARENT;
@@ -1234,10 +1233,8 @@ public class ScrimControllerTest extends SysuiTestCase {
mScrimController.transitionTo(ScrimState.KEYGUARD);
mScrimController.setUnocclusionAnimationRunning(true);
- assertAlphaAfterExpansion(mNotificationsScrim, /* alpha */ KEYGUARD_SCRIM_ALPHA,
- /* expansion */ 0.0f);
- assertAlphaAfterExpansion(mNotificationsScrim, /* alpha */ KEYGUARD_SCRIM_ALPHA,
- /* expansion */ 1.0f);
+ assertAlphaAfterExpansion(mNotificationsScrim, /* alpha */ 0f, /* expansion */ 0f);
+ assertAlphaAfterExpansion(mNotificationsScrim, /* alpha */ 0f, /* expansion */ 1.0f);
// Verify normal behavior after
mScrimController.setUnocclusionAnimationRunning(false);
@@ -1265,19 +1262,36 @@ public class ScrimControllerTest extends SysuiTestCase {
mScrimController.setClipsQsScrim(true);
float progress = 0.5f;
- mScrimController.setTransitionToFullShadeProgress(progress);
+ float lsNotifProgress = 0.3f;
+ mScrimController.setTransitionToFullShadeProgress(progress, lsNotifProgress);
assertEquals(MathUtils.lerp(keyguardAlpha, shadeLockedAlpha, progress),
mNotificationsScrim.getViewAlpha(), 0.2);
progress = 0.0f;
- mScrimController.setTransitionToFullShadeProgress(progress);
+ mScrimController.setTransitionToFullShadeProgress(progress, lsNotifProgress);
assertEquals(MathUtils.lerp(keyguardAlpha, shadeLockedAlpha, progress),
mNotificationsScrim.getViewAlpha(), 0.2);
progress = 1.0f;
- mScrimController.setTransitionToFullShadeProgress(progress);
+ mScrimController.setTransitionToFullShadeProgress(progress, lsNotifProgress);
assertEquals(MathUtils.lerp(keyguardAlpha, shadeLockedAlpha, progress),
mNotificationsScrim.getViewAlpha(), 0.2);
}
+ @Test
+ public void notificationTransparency_followsNotificationScrimProgress() {
+ mScrimController.transitionTo(ScrimState.SHADE_LOCKED);
+ mScrimController.setRawPanelExpansionFraction(1.0f);
+ finishAnimationsImmediately();
+ mScrimController.transitionTo(ScrimState.KEYGUARD);
+ mScrimController.setRawPanelExpansionFraction(1.0f);
+ finishAnimationsImmediately();
+
+ float progress = 0.5f;
+ float notifProgress = 0.3f;
+ mScrimController.setTransitionToFullShadeProgress(progress, notifProgress);
+
+ assertThat(mNotificationsScrim.getViewAlpha()).isEqualTo(notifProgress);
+ }
+
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 f4f55ccefd09..29488f1ba8a3 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
@@ -95,6 +95,8 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
@Mock
private KeyguardMessageAreaController.Factory mKeyguardMessageAreaFactory;
@Mock
+ private KeyguardMessageAreaController mKeyguardMessageAreaController;
+ @Mock
private KeyguardBouncer mBouncer;
@Mock
private StatusBarKeyguardViewManager.AlternateAuthInterceptor mAlternateAuthInterceptor;
@@ -120,6 +122,8 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
.thenReturn(mBouncer);
when(mCentralSurfaces.getBouncerContainer()).thenReturn(mContainer);
when(mContainer.findViewById(anyInt())).thenReturn(mKeyguardMessageArea);
+ when(mKeyguardMessageAreaFactory.create(any(KeyguardMessageArea.class)))
+ .thenReturn(mKeyguardMessageAreaController);
mStatusBarKeyguardViewManager = new StatusBarKeyguardViewManager(
getContext(),
mViewMediatorCallback,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
index ace7415f2c17..fa867e2796f7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
@@ -57,6 +57,7 @@ import com.android.systemui.SysuiTestCase;
import com.android.systemui.animation.ActivityLaunchAnimator;
import com.android.systemui.assist.AssistManager;
import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.NotificationClickNotifier;
@@ -84,6 +85,7 @@ import com.android.systemui.wmshell.BubblesManager;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.Mockito;
@@ -130,7 +132,6 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase {
private NotifPipeline mNotifPipeline;
@Mock
private NotificationVisibilityProvider mVisibilityProvider;
-
@Mock
private ActivityIntentHelper mActivityIntentHelper;
@Mock
@@ -145,14 +146,14 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase {
private ActivityLaunchAnimator mActivityLaunchAnimator;
@Mock
private InteractionJankMonitor mJankMonitor;
+ private StatusBarNotificationActivityStarter.LaunchEventsEmitter mLaunchEventsEmitter;
private FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock());
-
private NotificationTestHelper mNotificationTestHelper;
private ExpandableNotificationRow mNotificationRow;
private ExpandableNotificationRow mBubbleNotificationRow;
private final Answer<Void> mCallOnDismiss = answerVoid(
- (ActivityStarter.OnDismissAction dismissAction, Runnable cancel,
+ (OnDismissAction dismissAction, Runnable cancel,
Boolean afterKeyguardGone) -> dismissAction.onDismiss());
private ArrayList<NotificationEntry> mActiveNotifications;
@@ -188,10 +189,11 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase {
when(mNotifPipelineFlags.isNewPipelineEnabled()).thenReturn(false);
when(mOnUserInteractionCallback.getGroupSummaryToDismiss(mNotificationRow.getEntry()))
.thenReturn(null);
- when(mVisibilityProvider.obtain(anyString(), anyBoolean())).thenAnswer(
- invocation-> NotificationVisibility.obtain(invocation.getArgument(0), 0, 1, false));
- when(mVisibilityProvider.obtain(any(NotificationEntry.class), anyBoolean())).thenAnswer(
- invocation-> NotificationVisibility.obtain(
+ when(mVisibilityProvider.obtain(anyString(), anyBoolean()))
+ .thenAnswer(invocation -> NotificationVisibility.obtain(
+ invocation.getArgument(0), 0, 1, false));
+ when(mVisibilityProvider.obtain(any(NotificationEntry.class), anyBoolean()))
+ .thenAnswer(invocation -> NotificationVisibility.obtain(
invocation.<NotificationEntry>getArgument(0).getKey(), 0, 1, false));
HeadsUpManagerPhone headsUpManager = mock(HeadsUpManagerPhone.class);
@@ -201,7 +203,7 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase {
NotificationListContainer.class),
headsUpManager,
mJankMonitor);
-
+ mLaunchEventsEmitter = new StatusBarNotificationActivityStarter.LaunchEventsEmitter();
mNotificationActivityStarter =
new StatusBarNotificationActivityStarter(
getContext(),
@@ -237,12 +239,13 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase {
mock(NotificationPresenter.class),
mock(NotificationPanelViewController.class),
mActivityLaunchAnimator,
- notificationAnimationProvider
+ notificationAnimationProvider,
+ mLaunchEventsEmitter
);
// set up dismissKeyguardThenExecute to synchronously invoke the OnDismissAction arg
doAnswer(mCallOnDismiss).when(mActivityStarter).dismissKeyguardThenExecute(
- any(ActivityStarter.OnDismissAction.class), any(), anyBoolean());
+ any(OnDismissAction.class), any(), anyBoolean());
// set up addAfterKeyguardGoneRunnable to synchronously invoke the Runnable arg
doAnswer(answerVoid(Runnable::run))
@@ -402,4 +405,57 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase {
// THEN display should try wake up for the full screen intent
verify(mCentralSurfaces).wakeUpForFullScreenIntent();
}
+
+ @Test
+ public void testNotifActivityStarterEventSourceStartEvent_onNotificationClicked() {
+ NotifActivityLaunchEvents.Listener listener =
+ mock(NotifActivityLaunchEvents.Listener.class);
+ mLaunchEventsEmitter.registerListener(listener);
+ mNotificationActivityStarter
+ .onNotificationClicked(mNotificationRow.getEntry().getSbn(), mNotificationRow);
+ verify(listener).onStartLaunchNotifActivity(mNotificationRow.getEntry());
+ }
+
+ @Test
+ public void testNotifActivityStarterEventSourceFinishEvent_dismissKeyguardCancelled() {
+ NotifActivityLaunchEvents.Listener listener =
+ mock(NotifActivityLaunchEvents.Listener.class);
+ mLaunchEventsEmitter.registerListener(listener);
+ // set up dismissKeyguardThenExecute to synchronously invoke the cancel runnable arg
+ doAnswer(answerVoid(
+ (OnDismissAction dismissAction, Runnable cancel, Boolean afterKeyguardGone) ->
+ cancel.run()))
+ .when(mActivityStarter)
+ .dismissKeyguardThenExecute(any(OnDismissAction.class), any(), anyBoolean());
+ mNotificationActivityStarter
+ .onNotificationClicked(mNotificationRow.getEntry().getSbn(), mNotificationRow);
+ verify(listener).onFinishLaunchNotifActivity(mNotificationRow.getEntry());
+ }
+
+ @Test
+ public void testNotifActivityStarterEventSourceFinishEvent_postPanelCollapse()
+ throws Exception {
+ NotifActivityLaunchEvents.Listener listener =
+ mock(NotifActivityLaunchEvents.Listener.class);
+ mLaunchEventsEmitter.registerListener(listener);
+ mNotificationActivityStarter
+ .onNotificationClicked(mNotificationRow.getEntry().getSbn(), mNotificationRow);
+ ArgumentCaptor<ActivityLaunchAnimator.Controller> controllerCaptor =
+ ArgumentCaptor.forClass(ActivityLaunchAnimator.Controller.class);
+ verify(mActivityLaunchAnimator).startPendingIntentWithAnimation(
+ controllerCaptor.capture(), anyBoolean(), any(), any());
+ controllerCaptor.getValue().onIntentStarted(false);
+ verify(listener).onFinishLaunchNotifActivity(mNotificationRow.getEntry());
+ }
+
+ @Test
+ public void testNotifActivityStarterEventSourceFinishEvent_postPanelCollapse_noAnimate() {
+ NotifActivityLaunchEvents.Listener listener =
+ mock(NotifActivityLaunchEvents.Listener.class);
+ mLaunchEventsEmitter.registerListener(listener);
+ when(mCentralSurfaces.shouldAnimateLaunch(anyBoolean())).thenReturn(false);
+ mNotificationActivityStarter
+ .onNotificationClicked(mNotificationRow.getEntry().getSbn(), mNotificationRow);
+ verify(listener).onFinishLaunchNotifActivity(mNotificationRow.getEntry());
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchControllerTest.kt
index 4a579cb3fc4d..f58403d3651a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchControllerTest.kt
@@ -26,7 +26,6 @@ import androidx.test.filters.SmallTest
import com.android.internal.logging.UiEventLogger
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
-import com.android.systemui.communal.CommunalStateController
import com.android.systemui.keyguard.ScreenLifecycle
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.qs.user.UserSwitchDialogController
@@ -55,9 +54,6 @@ class KeyguardQsUserSwitchControllerTest : SysuiTestCase() {
private lateinit var userSwitcherController: UserSwitcherController
@Mock
- private lateinit var communalStateController: CommunalStateController
-
- @Mock
private lateinit var keyguardStateController: KeyguardStateController
@Mock
@@ -99,7 +95,6 @@ class KeyguardQsUserSwitchControllerTest : SysuiTestCase() {
context.resources,
screenLifecycle,
userSwitcherController,
- communalStateController,
keyguardStateController,
falsingManager,
configurationController,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java
index 20a3fdaa99a5..3a0a7c9d80fc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java
@@ -114,15 +114,13 @@ public class RemoteInputViewTest extends SysuiTestCase {
mContext.unregisterReceiver(mReceiver);
}
- private void setTestPendingIntent(RemoteInputView view, RemoteInputViewController controller) {
+ private void setTestPendingIntent(RemoteInputViewController controller) {
PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0,
new Intent(TEST_ACTION), PendingIntent.FLAG_MUTABLE);
RemoteInput input = new RemoteInput.Builder(TEST_RESULT_KEY).build();
RemoteInput[] inputs = {input};
- view.setPendingIntent(pendingIntent);
controller.setPendingIntent(pendingIntent);
- view.setRemoteInput(inputs, input, null /* editedSuggestionInfo */);
controller.setRemoteInput(input);
controller.setRemoteInputs(inputs);
}
@@ -137,7 +135,7 @@ public class RemoteInputViewTest extends SysuiTestCase {
RemoteInputView view = RemoteInputView.inflate(mContext, null, row.getEntry(), mController);
RemoteInputViewController controller = bindController(view, row.getEntry());
- setTestPendingIntent(view, controller);
+ setTestPendingIntent(controller);
view.focus();
@@ -177,7 +175,7 @@ public class RemoteInputViewTest extends SysuiTestCase {
RemoteInputView view = RemoteInputView.inflate(mContext, null, row.getEntry(), mController);
RemoteInputViewController controller = bindController(view, row.getEntry());
- setTestPendingIntent(view, controller);
+ setTestPendingIntent(controller);
view.focus();
@@ -235,7 +233,7 @@ public class RemoteInputViewTest extends SysuiTestCase {
RemoteInputView view = RemoteInputView.inflate(mContext, null, row.getEntry(), mController);
RemoteInputViewController controller = bindController(view, row.getEntry());
- setTestPendingIntent(view, controller);
+ setTestPendingIntent(controller);
// Open view, send a reply
view.focus();
@@ -265,7 +263,7 @@ public class RemoteInputViewTest extends SysuiTestCase {
RemoteInputView view = RemoteInputView.inflate(mContext, null, row.getEntry(), mController);
RemoteInputViewController controller = bindController(view, row.getEntry());
- setTestPendingIntent(view, controller);
+ setTestPendingIntent(controller);
// Open view, attach an image
view.focus();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerTest.kt
index 91c347fc4685..1caacb89ba10 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerTest.kt
@@ -41,6 +41,7 @@ import com.android.systemui.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.animation.DialogLaunchAnimator
import com.android.systemui.broadcast.BroadcastDispatcher
+import com.android.systemui.broadcast.BroadcastSender
import com.android.systemui.dump.DumpManager
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.plugins.FalsingManager
@@ -83,6 +84,7 @@ class UserSwitcherControllerTest : SysuiTestCase() {
@Mock private lateinit var userManager: UserManager
@Mock private lateinit var activityStarter: ActivityStarter
@Mock private lateinit var broadcastDispatcher: BroadcastDispatcher
+ @Mock private lateinit var broadcastSender: BroadcastSender
@Mock private lateinit var telephonyListenerManager: TelephonyListenerManager
@Mock private lateinit var secureSettings: SecureSettings
@Mock private lateinit var falsingManager: FalsingManager
@@ -159,6 +161,7 @@ class UserSwitcherControllerTest : SysuiTestCase() {
handler,
activityStarter,
broadcastDispatcher,
+ broadcastSender,
uiEventLogger,
falsingManager,
telephonyListenerManager,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/animation/AnimationUtilTest.kt b/packages/SystemUI/tests/src/com/android/systemui/util/animation/AnimationUtilTest.kt
new file mode 100644
index 000000000000..92afb038b321
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/animation/AnimationUtilTest.kt
@@ -0,0 +1,51 @@
+/*
+ * 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.util.animation
+
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import java.lang.IllegalArgumentException
+
+@SmallTest
+class AnimationUtilTest : SysuiTestCase() {
+ @Test
+ fun getMsForFrames_5frames_returns83() {
+ assertThat(AnimationUtil.getMsForFrames(5)).isEqualTo(83L)
+ }
+
+ @Test
+ fun getMsForFrames_7frames_returns117() {
+ assertThat(AnimationUtil.getMsForFrames(7)).isEqualTo(117L)
+ }
+
+ @Test
+ fun getMsForFrames_30frames_returns500() {
+ assertThat(AnimationUtil.getMsForFrames(30)).isEqualTo(500L)
+ }
+
+ @Test
+ fun getMsForFrames_60frames_returns1000() {
+ assertThat(AnimationUtil.getMsForFrames(60)).isEqualTo(1000L)
+ }
+
+ @Test(expected = IllegalArgumentException::class)
+ fun getMsForFrames_negativeFrames_throwsException() {
+ AnimationUtil.getMsForFrames(-1)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/mockito/KotlinMockitoHelpers.kt b/packages/SystemUI/tests/src/com/android/systemui/util/mockito/KotlinMockitoHelpers.kt
index 0f1b65cb7f04..309acdf13a5d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/mockito/KotlinMockitoHelpers.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/mockito/KotlinMockitoHelpers.kt
@@ -24,6 +24,7 @@ package com.android.systemui.util.mockito
*/
import org.mockito.ArgumentCaptor
+import org.mockito.ArgumentMatcher
import org.mockito.Mockito
/**
@@ -44,6 +45,14 @@ fun <T> any(type: Class<T>): T = Mockito.any<T>(type)
inline fun <reified T> any(): T = any(T::class.java)
/**
+ * Returns Mockito.argThat() as nullable type to avoid java.lang.IllegalStateException when
+ * null is returned.
+ *
+ * Generic T is nullable because implicitly bounded by Any?.
+ */
+fun <T> argThat(matcher: ArgumentMatcher<T>): T = Mockito.argThat(matcher)
+
+/**
* Kotlin type-inferred version of Mockito.nullable()
*/
inline fun <reified T> nullable(): T? = Mockito.nullable(T::class.java)
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 82880febc7f0..78ee9e8921ea 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
@@ -98,6 +98,7 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntryB
import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection;
import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider;
+import com.android.systemui.statusbar.notification.interruption.KeyguardNotificationVisibilityProvider;
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptLogger;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.NotificationTestHelper;
@@ -343,7 +344,9 @@ public class BubblesTest extends SysuiTestCase {
mock(BatteryController.class),
mock(HeadsUpManager.class),
mock(NotificationInterruptLogger.class),
- mock(Handler.class)
+ mock(Handler.class),
+ mock(NotifPipelineFlags.class),
+ mock(KeyguardNotificationVisibilityProvider.class)
);
when(mNotifPipelineFlags.isNewPipelineEnabled()).thenReturn(false);
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 cc848bc34217..fafe4b3fdb5f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java
@@ -85,6 +85,7 @@ import com.android.systemui.statusbar.notification.collection.legacy.Notificatio
import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider;
+import com.android.systemui.statusbar.notification.interruption.KeyguardNotificationVisibilityProvider;
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptLogger;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.NotificationTestHelper;
@@ -309,7 +310,9 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase {
mock(BatteryController.class),
mock(HeadsUpManager.class),
mock(NotificationInterruptLogger.class),
- mock(Handler.class)
+ mock(Handler.class),
+ mock(NotifPipelineFlags.class),
+ mock(KeyguardNotificationVisibilityProvider.class)
);
when(mNotifPipelineFlags.isNewPipelineEnabled()).thenReturn(true);
when(mShellTaskOrganizer.getExecutor()).thenReturn(syncExecutor);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableNotificationInterruptStateProviderImpl.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableNotificationInterruptStateProviderImpl.java
index e698f1e7c4ce..a7f0dc22e849 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableNotificationInterruptStateProviderImpl.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableNotificationInterruptStateProviderImpl.java
@@ -23,7 +23,9 @@ import android.os.PowerManager;
import android.service.dreams.IDreamManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.notification.NotifPipelineFlags;
import com.android.systemui.statusbar.notification.NotificationFilter;
+import com.android.systemui.statusbar.notification.interruption.KeyguardNotificationVisibilityProvider;
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptLogger;
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderImpl;
import com.android.systemui.statusbar.policy.BatteryController;
@@ -42,7 +44,9 @@ public class TestableNotificationInterruptStateProviderImpl
BatteryController batteryController,
HeadsUpManager headsUpManager,
NotificationInterruptLogger logger,
- Handler mainHandler) {
+ Handler mainHandler,
+ NotifPipelineFlags flags,
+ KeyguardNotificationVisibilityProvider keyguardNotificationVisibilityProvider) {
super(contentResolver,
powerManager,
dreamManager,
@@ -52,7 +56,9 @@ public class TestableNotificationInterruptStateProviderImpl
statusBarStateController,
headsUpManager,
logger,
- mainHandler);
+ mainHandler,
+ flags,
+ keyguardNotificationVisibilityProvider);
mUseHeadsUp = true;
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java
index 7726938db3b0..185942e6fbc8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java
@@ -32,6 +32,7 @@ import com.android.systemui.model.SysUiState;
import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.UserInfoController;
import com.android.systemui.tracing.ProtoTracer;
import com.android.wm.shell.ShellCommandHandler;
@@ -66,6 +67,7 @@ public class WMShellTest extends SysuiTestCase {
@Mock CommandQueue mCommandQueue;
@Mock ConfigurationController mConfigurationController;
+ @Mock KeyguardStateController mKeyguardStateController;
@Mock KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@Mock NavigationModeController mNavigationModeController;
@Mock ScreenLifecycle mScreenLifecycle;
@@ -90,9 +92,9 @@ public class WMShellTest extends SysuiTestCase {
Optional.of(mSplitScreen), Optional.of(mOneHanded), Optional.of(mHideDisplayCutout),
Optional.of(mShellCommandHandler), Optional.of(mCompatUI),
Optional.of(mDragAndDrop),
- mCommandQueue, mConfigurationController, mKeyguardUpdateMonitor,
- mNavigationModeController, mScreenLifecycle, mSysUiState, mProtoTracer,
- mWakefulnessLifecycle, mUserInfoController, mSysUiMainExecutor);
+ mCommandQueue, mConfigurationController, mKeyguardStateController,
+ mKeyguardUpdateMonitor, mNavigationModeController, mScreenLifecycle, mSysUiState,
+ mProtoTracer, mWakefulnessLifecycle, mUserInfoController, mSysUiMainExecutor);
}
@Test
@@ -132,6 +134,6 @@ public class WMShellTest extends SysuiTestCase {
public void initCompatUI_registersCallbacks() {
mWMShell.initCompatUi(mCompatUI);
- verify(mKeyguardUpdateMonitor).registerCallback(any(KeyguardUpdateMonitorCallback.class));
+ verify(mKeyguardStateController).addCallback(any(KeyguardStateController.Callback.class));
}
}
diff --git a/proto/src/camera.proto b/proto/src/camera.proto
index 40821185b61a..38d74e4a73ce 100644
--- a/proto/src/camera.proto
+++ b/proto/src/camera.proto
@@ -66,5 +66,5 @@ message CameraStreamProto {
// The dynamic range profile of the stream
optional int64 dynamic_range_profile = 14;
// The stream use case
- optional int32 stream_use_case = 15;
+ optional int64 stream_use_case = 15;
}
diff --git a/proto/src/metrics_constants/metrics_constants.proto b/proto/src/metrics_constants/metrics_constants.proto
index 3f712dd1492f..3801c2473c11 100644
--- a/proto/src/metrics_constants/metrics_constants.proto
+++ b/proto/src/metrics_constants/metrics_constants.proto
@@ -2260,10 +2260,12 @@ message MetricsEvent {
ACCOUNTS_WORK_PROFILE_SETTINGS = 401;
// Settings -> Dev options -> Convert to file encryption
- CONVERT_FBE = 402;
+ // DEPRECATED: this setting was removed in Android T.
+ CONVERT_FBE = 402 [deprecated=true];
// Settings -> Dev options -> Convert to file encryption -> WIPE AND CONVERT...
- CONVERT_FBE_CONFIRM = 403;
+ // DEPRECATED: this setting was removed in Android T.
+ CONVERT_FBE_CONFIRM = 403 [deprecated=true];
// Settings -> Dev options -> Running services
RUNNING_SERVICES = 404;
diff --git a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
index 7f103144b7fb..5ef1008afad5 100644
--- a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
@@ -281,9 +281,9 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
void onDoubleTapAndHold(int displayId);
- void requestImeLocked(AccessibilityServiceConnection connection);
+ void requestImeLocked(AbstractAccessibilityServiceConnection connection);
- void unbindImeLocked(AccessibilityServiceConnection connection);
+ void unbindImeLocked(AbstractAccessibilityServiceConnection connection);
}
public AbstractAccessibilityServiceConnection(Context context, ComponentName componentName,
@@ -387,7 +387,6 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
& AccessibilityServiceInfo.FLAG_REQUEST_FINGERPRINT_GESTURES) != 0;
mRequestAccessibilityButton = (info.flags
& AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON) != 0;
- // TODO(b/218193835): request ime when ime flag is set and clean up when ime flag is unset
mRequestImeApis = (info.flags
& AccessibilityServiceInfo.FLAG_INPUT_METHOD_EDITOR) != 0;
}
@@ -439,6 +438,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
// If the XML manifest had data to configure the service its info
// should be already set. In such a case update only the dynamically
// configurable properties.
+ boolean oldRequestIme = mRequestImeApis;
AccessibilityServiceInfo oldInfo = mAccessibilityServiceInfo;
if (oldInfo != null) {
oldInfo.updateDynamicallyConfigurableProperties(mIPlatformCompat, info);
@@ -447,6 +447,11 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
setDynamicallyConfigurableProperties(info);
}
mSystemSupport.onClientChangeLocked(true);
+ if (!oldRequestIme && mRequestImeApis) {
+ mSystemSupport.requestImeLocked(this);
+ } else if (oldRequestIme && !mRequestImeApis) {
+ mSystemSupport.unbindImeLocked(this);
+ }
}
} finally {
Binder.restoreCallingIdentity(identity);
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 0ea087d6de0f..61e3da8aae51 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -322,28 +322,28 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
@Override
public void setImeSessionEnabled(SparseArray<IInputMethodSession> sessions,
boolean enabled) {
- mService.setImeSessionEnabled(sessions, enabled);
+ mService.scheduleSetImeSessionEnabled(sessions, enabled);
}
@Override
public void unbindInput() {
- mService.unbindInput();
+ mService.scheduleUnbindInput();
}
@Override
public void bindInput(InputBinding binding) {
- mService.bindInput(binding);
+ mService.scheduleBindInput(binding);
}
@Override
public void createImeSession(ArraySet<Integer> ignoreSet) {
- mService.createImeSession(ignoreSet);
+ mService.scheduleCreateImeSession(ignoreSet);
}
@Override
public void startInput(IBinder startInputToken, IInputContext inputContext,
EditorInfo editorInfo, boolean restarting) {
- mService.startInput(startInputToken, inputContext, editorInfo, restarting);
+ mService.scheduleStartInput(startInputToken, inputContext, editorInfo, restarting);
}
}
@@ -4305,7 +4305,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
}
@Override
- public void requestImeLocked(AccessibilityServiceConnection connection) {
+ public void requestImeLocked(AbstractAccessibilityServiceConnection connection) {
mMainHandler.sendMessage(obtainMessage(
AccessibilityManagerService::createSessionForConnection, this, connection));
mMainHandler.sendMessage(obtainMessage(
@@ -4313,12 +4313,12 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
}
@Override
- public void unbindImeLocked(AccessibilityServiceConnection connection) {
+ public void unbindImeLocked(AbstractAccessibilityServiceConnection connection) {
mMainHandler.sendMessage(obtainMessage(
AccessibilityManagerService::unbindInputForConnection, this, connection));
}
- private void createSessionForConnection(AccessibilityServiceConnection connection) {
+ private void createSessionForConnection(AbstractAccessibilityServiceConnection connection) {
synchronized (mLock) {
if (mInputSessionRequested) {
connection.createImeSessionLocked();
@@ -4326,7 +4326,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
}
}
- private void bindAndStartInputForConnection(AccessibilityServiceConnection connection) {
+ private void bindAndStartInputForConnection(AbstractAccessibilityServiceConnection connection) {
synchronized (mLock) {
if (mInputBinding != null) {
connection.bindInputLocked(mInputBinding);
@@ -4336,7 +4336,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
}
}
- private void unbindInputForConnection(AccessibilityServiceConnection connection) {
+ private void unbindInputForConnection(AbstractAccessibilityServiceConnection connection) {
InputMethodManagerInternal.get().unbindAccessibilityFromCurrentClient(connection.mId);
synchronized (mLock) {
connection.unbindInputLocked();
@@ -4377,12 +4377,16 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
*
* @param binding Information given to an accessibility service about a client connecting to it.
*/
- public void bindInput(InputBinding binding) {
- AccessibilityUserState userState;
+ public void scheduleBindInput(InputBinding binding) {
+ mMainHandler.sendMessage(obtainMessage(AccessibilityManagerService::bindInput, this,
+ binding));
+ }
+
+ private void bindInput(InputBinding binding) {
synchronized (mLock) {
// Keep records of these in case new Accessibility Services are enabled.
mInputBinding = binding;
- userState = getCurrentUserStateLocked();
+ AccessibilityUserState userState = getCurrentUserStateLocked();
for (int i = userState.mBoundServices.size() - 1; i >= 0; i--) {
final AccessibilityServiceConnection service = userState.mBoundServices.get(i);
if (service.requestImeApis()) {
@@ -4395,11 +4399,13 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
/**
* Unbind input for accessibility services which request ime capabilities.
*/
- public void unbindInput() {
- AccessibilityUserState userState;
- // TODO(b/218182733): Resolve the Imf lock and mLock possible deadlock
+ public void scheduleUnbindInput() {
+ mMainHandler.sendMessage(obtainMessage(AccessibilityManagerService::unbindInput, this));
+ }
+
+ private void unbindInput() {
synchronized (mLock) {
- userState = getCurrentUserStateLocked();
+ AccessibilityUserState userState = getCurrentUserStateLocked();
for (int i = userState.mBoundServices.size() - 1; i >= 0; i--) {
final AccessibilityServiceConnection service = userState.mBoundServices.get(i);
if (service.requestImeApis()) {
@@ -4412,16 +4418,21 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
/**
* Start input for accessibility services which request ime capabilities.
*/
- public void startInput(IBinder startInputToken, IInputContext inputContext,
+ public void scheduleStartInput(IBinder startInputToken, IInputContext inputContext,
+ EditorInfo editorInfo, boolean restarting) {
+ mMainHandler.sendMessage(obtainMessage(AccessibilityManagerService::startInput, this,
+ startInputToken, inputContext, editorInfo, restarting));
+ }
+
+ private void startInput(IBinder startInputToken, IInputContext inputContext,
EditorInfo editorInfo, boolean restarting) {
- AccessibilityUserState userState;
synchronized (mLock) {
// Keep records of these in case new Accessibility Services are enabled.
mStartInputToken = startInputToken;
mInputContext = inputContext;
mEditorInfo = editorInfo;
mRestarting = restarting;
- userState = getCurrentUserStateLocked();
+ AccessibilityUserState userState = getCurrentUserStateLocked();
for (int i = userState.mBoundServices.size() - 1; i >= 0; i--) {
final AccessibilityServiceConnection service = userState.mBoundServices.get(i);
if (service.requestImeApis()) {
@@ -4435,11 +4446,15 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
* Request input sessions from all accessibility services which request ime capabilities and
* whose id is not in the ignoreSet
*/
- public void createImeSession(ArraySet<Integer> ignoreSet) {
- AccessibilityUserState userState;
+ public void scheduleCreateImeSession(ArraySet<Integer> ignoreSet) {
+ mMainHandler.sendMessage(obtainMessage(AccessibilityManagerService::createImeSession,
+ this, ignoreSet));
+ }
+
+ private void createImeSession(ArraySet<Integer> ignoreSet) {
synchronized (mLock) {
mInputSessionRequested = true;
- userState = getCurrentUserStateLocked();
+ AccessibilityUserState userState = getCurrentUserStateLocked();
for (int i = userState.mBoundServices.size() - 1; i >= 0; i--) {
final AccessibilityServiceConnection service = userState.mBoundServices.get(i);
if ((!ignoreSet.contains(service.mId)) && service.requestImeApis()) {
@@ -4455,10 +4470,15 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
* @param sessions Sessions to enable or disable.
* @param enabled True if enable the sessions or false if disable the sessions.
*/
- public void setImeSessionEnabled(SparseArray<IInputMethodSession> sessions, boolean enabled) {
- AccessibilityUserState userState;
+ public void scheduleSetImeSessionEnabled(SparseArray<IInputMethodSession> sessions,
+ boolean enabled) {
+ mMainHandler.sendMessage(obtainMessage(AccessibilityManagerService::setImeSessionEnabled,
+ this, sessions, enabled));
+ }
+
+ private void setImeSessionEnabled(SparseArray<IInputMethodSession> sessions, boolean enabled) {
synchronized (mLock) {
- userState = getCurrentUserStateLocked();
+ AccessibilityUserState userState = getCurrentUserStateLocked();
for (int i = userState.mBoundServices.size() - 1; i >= 0; i--) {
final AccessibilityServiceConnection service = userState.mBoundServices.get(i);
if (sessions.contains(service.mId) && service.requestImeApis()) {
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
index 86777a2f62fd..e20b15a3e807 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
@@ -1327,14 +1327,13 @@ public class TouchExplorer extends BaseEventStreamTransformation
if (mState.isServiceDetectingGestures() && mState.isTouchInteracting()) {
// Cancel without deleting events.
mHandler.removeCallbacks(mSendHoverEnterAndMoveDelayed);
- mSendHoverEnterAndMoveDelayed.run();
- mSendHoverEnterAndMoveDelayed.clear();
- final MotionEvent prototype = mState.getLastReceivedEvent();
- final MotionEvent rawEvent = mState.getLastReceivedRawEvent();
final int pointerId = mReceivedPointerTracker.getPrimaryPointerId();
final int pointerIdBits = (1 << pointerId);
final int policyFlags = mState.getLastReceivedPolicyFlags();
- mSendHoverExitDelayed.post(prototype, rawEvent, pointerIdBits, policyFlags);
+ mSendHoverEnterAndMoveDelayed.setPointerIdBits(pointerIdBits);
+ mSendHoverEnterAndMoveDelayed.setPolicyFlags(policyFlags);
+ mSendHoverEnterAndMoveDelayed.run();
+ mSendHoverEnterAndMoveDelayed.clear();
}
}
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java
index fa32452f389e..ecc45eb743c6 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java
@@ -18,6 +18,7 @@ package com.android.server.accessibility.magnification;
import static android.accessibilityservice.AccessibilityTrace.FLAGS_WINDOW_MANAGER_INTERNAL;
import static android.accessibilityservice.MagnificationConfig.MAGNIFICATION_MODE_FULLSCREEN;
+import static android.util.TypedValue.COMPLEX_UNIT_DIP;
import static android.view.accessibility.MagnificationAnimationCallback.STUB_ANIMATION_CALLBACK;
import static com.android.server.accessibility.AccessibilityManagerService.INVALID_SERVICE_ID;
@@ -31,15 +32,20 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.res.CompatibilityInfo;
import android.graphics.Rect;
import android.graphics.Region;
+import android.hardware.display.DisplayManagerInternal;
import android.os.Handler;
import android.os.Message;
import android.text.TextUtils;
+import android.util.DisplayMetrics;
import android.util.MathUtils;
import android.util.Slog;
import android.util.SparseArray;
+import android.util.TypedValue;
import android.view.Display;
+import android.view.DisplayInfo;
import android.view.MagnificationSpec;
import android.view.View;
import android.view.accessibility.MagnificationAnimationCallback;
@@ -93,6 +99,8 @@ public class FullScreenMagnificationController implements
// Whether the following typing focus feature for magnification is enabled.
private boolean mMagnificationFollowTypingEnabled = true;
+ private final DisplayManagerInternal mDisplayManagerInternal;
+
/**
* This class implements {@link WindowManagerInternal.MagnificationCallbacks} and holds
* magnification information per display.
@@ -395,6 +403,18 @@ public class FullScreenMagnificationController implements
outRegion.set(mMagnificationRegion);
}
+ private DisplayMetrics getDisplayMetricsForId() {
+ final DisplayMetrics outMetrics = new DisplayMetrics();
+ final DisplayInfo displayInfo = mDisplayManagerInternal.getDisplayInfo(mDisplayId);
+ if (displayInfo != null) {
+ displayInfo.getLogicalMetrics(outMetrics,
+ CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
+ } else {
+ outMetrics.setToDefaults();
+ }
+ return outMetrics;
+ }
+
void requestRectangleOnScreen(int left, int top, int right, int bottom) {
synchronized (mLock) {
final Rect magnifiedFrame = mTempRect;
@@ -408,6 +428,12 @@ public class FullScreenMagnificationController implements
final float scrollX;
final float scrollY;
+ // We offset an additional distance for a user to know the surrounding context.
+ DisplayMetrics metrics = getDisplayMetricsForId();
+ final float offsetViewportX = (float) magnifFrameInScreenCoords.width() / 4;
+ final float offsetViewportY =
+ TypedValue.applyDimension(COMPLEX_UNIT_DIP, 10, metrics);
+
if (right - left > magnifFrameInScreenCoords.width()) {
final int direction = TextUtils
.getLayoutDirectionFromLocale(Locale.getDefault());
@@ -417,9 +443,9 @@ public class FullScreenMagnificationController implements
scrollX = right - magnifFrameInScreenCoords.right;
}
} else if (left < magnifFrameInScreenCoords.left) {
- scrollX = left - magnifFrameInScreenCoords.left;
+ scrollX = left - magnifFrameInScreenCoords.left - offsetViewportX;
} else if (right > magnifFrameInScreenCoords.right) {
- scrollX = right - magnifFrameInScreenCoords.right;
+ scrollX = right - magnifFrameInScreenCoords.right + offsetViewportX;
} else {
scrollX = 0;
}
@@ -427,9 +453,9 @@ public class FullScreenMagnificationController implements
if (bottom - top > magnifFrameInScreenCoords.height()) {
scrollY = top - magnifFrameInScreenCoords.top;
} else if (top < magnifFrameInScreenCoords.top) {
- scrollY = top - magnifFrameInScreenCoords.top;
+ scrollY = top - magnifFrameInScreenCoords.top - offsetViewportY;
} else if (bottom > magnifFrameInScreenCoords.bottom) {
- scrollY = bottom - magnifFrameInScreenCoords.bottom;
+ scrollY = bottom - magnifFrameInScreenCoords.bottom + offsetViewportY;
} else {
scrollY = 0;
}
@@ -687,6 +713,7 @@ public class FullScreenMagnificationController implements
mScreenStateObserver = new ScreenStateObserver(mControllerCtx.getContext(), this);
mMagnificationInfoChangedCallback = magnificationInfoChangedCallback;
mScaleProvider = scaleProvider;
+ mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
}
/**
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/GesturesObserver.java b/services/accessibility/java/com/android/server/accessibility/magnification/GesturesObserver.java
index 3d8f5173d25a..a5c8837dd8f5 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/GesturesObserver.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/GesturesObserver.java
@@ -114,7 +114,7 @@ public final class GesturesObserver implements GestureMatcher.StateChangeListene
* Clears all states to default.
*/
@MainThread
- public void clear() {
+ private void clear() {
for (GestureMatcher matcher : mGestureMatchers) {
matcher.clear();
}
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationGesturesObserver.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationGesturesObserver.java
index 085c343ff631..23cded771cae 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationGesturesObserver.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationGesturesObserver.java
@@ -133,7 +133,7 @@ class MagnificationGesturesObserver implements GesturesObserver.Listener {
mDelayedEventQueue = null;
mCallback.onGestureCompleted(gestureId, mLastDownEventTime, delayEventQueue,
event);
- recycleLastEvent();
+ clear();
}
@Override
@@ -149,19 +149,18 @@ class MagnificationGesturesObserver implements GesturesObserver.Listener {
mDelayedEventQueue = null;
mCallback.onGestureCancelled(mLastDownEventTime, delayEventQueue,
mLastEvent);
- recycleLastEvent();
+ clear();
}
/**
* Resets all state to default.
*/
- void clear() {
+ private void clear() {
if (DBG) {
Slog.d(LOG_TAG, "clear:" + mDelayedEventQueue);
}
recycleLastEvent();
mLastDownEventTime = 0;
- mGesturesObserver.clear();
if (mDelayedEventQueue != null) {
for (MotionEventInfo eventInfo2: mDelayedEventQueue) {
eventInfo2.recycle();
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java
index 820be28387ae..9ff51eecba1d 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java
@@ -440,21 +440,11 @@ public class WindowMagnificationGestureHandler extends MagnificationGestureHandl
}
@Override
- public void onExit() {
- clear();
- }
-
- @Override
public void onMotionEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
mGesturesObserver.onMotionEvent(event, rawEvent, policyFlags);
}
@Override
- public void clear() {
- mGesturesObserver.clear();
- }
-
- @Override
public String toString() {
return "DetectingState{"
+ ", mGestureTimeoutObserver =" + mGesturesObserver
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java
index aeb1112ede5f..ca116e35eb56 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java
@@ -108,6 +108,17 @@ public class WindowMagnificationManager implements
private @interface ConnectionState {
}
+ private static String connectionStateToString(@ConnectionState int state) {
+ switch (state) {
+ case CONNECTING: return "CONNECTING";
+ case CONNECTED: return "CONNECTED";
+ case DISCONNECTING: return "DISCONNECTING";
+ case DISCONNECTED: return "DISCONNECTED";
+ default:
+ return "UNKNOWN:" + state;
+ }
+ }
+
@ConnectionState
private int mConnectionState = DISCONNECTED;
@@ -205,7 +216,8 @@ public class WindowMagnificationManager implements
*/
public void setConnection(@Nullable IWindowMagnificationConnection connection) {
if (DBG) {
- Slog.d(TAG, "setConnection :" + connection + " ,mConnectionState=" + mConnectionState);
+ Slog.d(TAG, "setConnection :" + connection + ", mConnectionState="
+ + connectionStateToString(mConnectionState));
}
synchronized (mLock) {
// Reset connectionWrapper.
@@ -275,9 +287,8 @@ public class WindowMagnificationManager implements
if ((connect && (mConnectionState == CONNECTED || mConnectionState == CONNECTING))
|| (!connect && (mConnectionState == DISCONNECTED
|| mConnectionState == DISCONNECTING))) {
- Slog.w(TAG,
- "requestConnection duplicated request: connect=" + connect
- + " ,mConnectionState=" + mConnectionState);
+ Slog.w(TAG, "requestConnection duplicated request: connect=" + connect
+ + ", mConnectionState=" + connectionStateToString(mConnectionState));
return false;
}
@@ -321,14 +332,14 @@ public class WindowMagnificationManager implements
/**
* Returns window magnification connection state.
*/
- public int getConnectionState() {
- return mConnectionState;
+ public String getConnectionState() {
+ return connectionStateToString(mConnectionState);
}
private void setConnectionState(@ConnectionState int state) {
if (DBG) {
- Slog.d(TAG, "setConnectionState : state=" + state + " ,mConnectionState="
- + mConnectionState);
+ Slog.d(TAG, "setConnectionState : state=" + state + ", mConnectionState="
+ + connectionStateToString(mConnectionState));
}
mConnectionState = state;
}
@@ -1114,7 +1125,7 @@ public class WindowMagnificationManager implements
if (mConnectionWrapper == null) {
Slog.w(TAG,
"enableWindowMagnificationInternal mConnectionWrapper is null. "
- + "mConnectionState=" + mConnectionState);
+ + "mConnectionState=" + connectionStateToString(mConnectionState));
return false;
}
return mConnectionWrapper.enableWindowMagnification(
diff --git a/services/api/current.txt b/services/api/current.txt
index 45c00595841d..780fccfc2e4d 100644
--- a/services/api/current.txt
+++ b/services/api/current.txt
@@ -38,7 +38,7 @@ package com.android.server {
package com.android.server.am {
public interface ActivityManagerLocal {
- method public boolean bindSdkSandboxService(@NonNull android.content.Intent, @NonNull android.content.ServiceConnection, int, @NonNull String, int) throws android.os.RemoteException;
+ method public boolean bindSdkSandboxService(@NonNull android.content.Intent, @NonNull android.content.ServiceConnection, int, @NonNull String, @NonNull String, int) throws android.os.RemoteException;
method public boolean canStartForegroundService(int, int, @NonNull String);
}
@@ -47,6 +47,9 @@ package com.android.server.am {
package com.android.server.pm {
public interface PackageManagerLocal {
+ method public void reconcileSdkData(@Nullable String, @NonNull String, @NonNull java.util.List<java.lang.String>, int, int, int, @NonNull String, int) throws java.io.IOException;
+ field public static final int FLAG_STORAGE_CE = 2; // 0x2
+ field public static final int FLAG_STORAGE_DE = 1; // 0x1
}
}
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 1cff3744687e..8c4db70c301d 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -16,6 +16,8 @@
package com.android.server.autofill;
+import static android.service.autofill.FillEventHistory.Event.NO_SAVE_UI_REASON_NONE;
+import static android.service.autofill.FillEventHistory.Event.UI_TYPE_INLINE;
import static android.service.autofill.FillRequest.FLAG_MANUAL_REQUEST;
import static android.view.autofill.AutofillManager.ACTION_START_SESSION;
import static android.view.autofill.AutofillManager.FLAG_ADD_CLIENT_ENABLED;
@@ -816,12 +818,13 @@ final class AutofillManagerServiceImpl
/**
* Updates the last fill response when a dataset is shown.
*/
- void logDatasetShown(int sessionId, @Nullable Bundle clientState) {
+ void logDatasetShown(int sessionId, @Nullable Bundle clientState, int presentationType) {
synchronized (mLock) {
if (isValidEventLocked("logDatasetShown", sessionId)) {
mEventHistory.addEvent(
new Event(Event.TYPE_DATASETS_SHOWN, null, clientState, null, null, null,
- null, null, null, null, null));
+ null, null, null, null, null, NO_SAVE_UI_REASON_NONE,
+ presentationType));
}
}
}
@@ -858,9 +861,12 @@ final class AutofillManagerServiceImpl
|| mAugmentedAutofillEventHistory.getSessionId() != sessionId) {
return;
}
+ // Augmented Autofill only logs for inline now, so set UI_TYPE_INLINE here.
+ // Ideally should not hardcode here and should also log for menu presentation.
mAugmentedAutofillEventHistory.addEvent(
new Event(Event.TYPE_DATASETS_SHOWN, null, clientState, null, null, null,
- null, null, null, null, null));
+ null, null, null, null, null, NO_SAVE_UI_REASON_NONE,
+ UI_TYPE_INLINE));
}
}
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index e0fa67f64c4c..54183c98204e 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -18,9 +18,12 @@ package com.android.server.autofill;
import static android.service.autofill.AutofillFieldClassificationService.EXTRA_SCORES;
import static android.service.autofill.AutofillService.EXTRA_FILL_RESPONSE;
-import static android.service.autofill.FillRequest.FLAG_ACTIVITY_START;
+import static android.service.autofill.FillEventHistory.Event.UI_TYPE_DIALOG;
+import static android.service.autofill.FillEventHistory.Event.UI_TYPE_INLINE;
+import static android.service.autofill.FillEventHistory.Event.UI_TYPE_MENU;
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;
import static android.service.autofill.FillRequest.FLAG_VIEW_NOT_FOCUSED;
import static android.service.autofill.FillRequest.INVALID_REQUEST_ID;
import static android.view.autofill.AutofillManager.ACTION_RESPONSE_EXPIRED;
@@ -965,7 +968,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
mService.getRemoteInlineSuggestionRenderServiceLocked();
if ((mSessionFlags.mInlineSupportedByService || mSessionFlags.mClientSuggestionsEnabled)
&& remoteRenderService != null
- && (isViewFocusedLocked(flags) || (isRequestFromActivityStarted(flags)))) {
+ && (isViewFocusedLocked(flags) || (isRequestSupportFillDialog(flags)))) {
final Consumer<InlineSuggestionsRequest> inlineSuggestionsRequestConsumer;
if (mSessionFlags.mClientSuggestionsEnabled) {
final int finalRequestId = requestId;
@@ -1011,8 +1014,8 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
requestAssistStructureLocked(requestId, flags);
}
- private boolean isRequestFromActivityStarted(int flags) {
- return (flags & FLAG_ACTIVITY_START) != 0;
+ private boolean isRequestSupportFillDialog(int flags) {
+ return (flags & FLAG_SUPPORTS_FILL_DIALOG) != 0;
}
@GuardedBy("mLock")
@@ -3002,7 +3005,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
// View is triggering autofill.
mCurrentViewId = viewState.id;
viewState.update(value, virtualBounds, flags);
- if (!isRequestFromActivityStarted(flags)) {
+ if (!isRequestSupportFillDialog(flags)) {
mSessionFlags.mFillDialogDisabled = true;
}
requestNewFillResponseLocked(viewState, ViewState.STATE_STARTED_SESSION, flags);
@@ -3290,7 +3293,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
synchronized (mLock) {
final ViewState currentView = mViewStates.get(mCurrentViewId);
currentView.setState(ViewState.STATE_FILL_DIALOG_SHOWN);
- mService.logDatasetShown(id, mClientState);
+ mService.logDatasetShown(id, mClientState, UI_TYPE_DIALOG);
}
return;
}
@@ -3304,7 +3307,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
currentView.setState(ViewState.STATE_INLINE_SHOWN);
//TODO(b/137800469): Fix it to log showed only when IME asks for inflation,
// rather than here where framework sends back the response.
- mService.logDatasetShown(id, mClientState);
+ mService.logDatasetShown(id, mClientState, UI_TYPE_INLINE);
return;
}
}
@@ -3314,7 +3317,9 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
mService.getServicePackageName(), mComponentName,
targetLabel, targetIcon, this, id, mCompatMode);
- mService.logDatasetShown(id, mClientState);
+ synchronized (mLock) {
+ mService.logDatasetShown(id, mClientState, UI_TYPE_MENU);
+ }
synchronized (mLock) {
if (mUiShownTime == 0) {
diff --git a/services/backup/backuplib/java/com/android/server/backup/TransportManager.java b/services/backup/backuplib/java/com/android/server/backup/TransportManager.java
index 21a22f44f3dd..930f49e4d117 100644
--- a/services/backup/backuplib/java/com/android/server/backup/TransportManager.java
+++ b/services/backup/backuplib/java/com/android/server/backup/TransportManager.java
@@ -16,6 +16,9 @@
package com.android.server.backup;
+import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
+import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
+
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.annotation.WorkerThread;
@@ -28,7 +31,6 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
-import android.os.Binder;
import android.os.Bundle;
import android.os.RemoteException;
import android.util.ArrayMap;
@@ -42,8 +44,8 @@ import com.android.internal.util.Preconditions;
import com.android.server.backup.transport.BackupTransportClient;
import com.android.server.backup.transport.OnTransportRegisteredListener;
import com.android.server.backup.transport.TransportConnection;
-import com.android.server.backup.transport.TransportConnectionManager;
import com.android.server.backup.transport.TransportConnectionListener;
+import com.android.server.backup.transport.TransportConnectionManager;
import com.android.server.backup.transport.TransportNotAvailableException;
import com.android.server.backup.transport.TransportNotRegisteredException;
import com.android.server.backup.transport.TransportStats;
@@ -58,6 +60,7 @@ import java.util.function.Predicate;
/** Handles in-memory bookkeeping of all BackupTransport objects. */
public class TransportManager {
private static final String TAG = "BackupTransportManager";
+ private static final boolean MORE_DEBUG = false;
@VisibleForTesting
public static final String SERVICE_ACTION_TRANSPORT_HOST = "android.backup.TRANSPORT_HOST";
@@ -130,14 +133,61 @@ public class TransportManager {
}
}
+ void onPackageEnabled(String packageName) {
+ onPackageAdded(packageName);
+ }
+
+ void onPackageDisabled(String packageName) {
+ onPackageRemoved(packageName);
+ }
+
@WorkerThread
void onPackageChanged(String packageName, String... components) {
+ // Determine if the overall package has changed and not just its
+ // components - see {@link EXTRA_CHANGED_COMPONENT_NAME_LIST}. When we
+ // know a package was enabled/disabled we'll handle that directly and
+ // not continue with onPackageChanged.
+ if (components.length == 1 && components[0].equals(packageName)) {
+ int enabled;
+ try {
+ enabled = mPackageManager.getApplicationEnabledSetting(packageName);
+ } catch (IllegalArgumentException ex) {
+ // packageName doesn't exist: likely due to a race with it being uninstalled.
+ if (MORE_DEBUG) {
+ Slog.d(TAG, "Package " + packageName + " was changed, but no longer exists.");
+ }
+ return;
+ }
+ switch (enabled) {
+ case COMPONENT_ENABLED_STATE_ENABLED: {
+ if (MORE_DEBUG) {
+ Slog.d(TAG, "Package " + packageName + " was enabled.");
+ }
+ onPackageEnabled(packageName);
+ return;
+ }
+ case COMPONENT_ENABLED_STATE_DISABLED: {
+ if (MORE_DEBUG) {
+ Slog.d(TAG, "Package " + packageName + " was disabled.");
+ }
+ onPackageDisabled(packageName);
+ return;
+ }
+ default: {
+ Slog.w(TAG, "Package " + packageName + " enabled setting: " + enabled);
+ return;
+ }
+ }
+ }
// Unfortunately this can't be atomic because we risk a deadlock if
// registerTransportsFromPackage() is put inside the synchronized block
Set<ComponentName> transportComponents = new ArraySet<>(components.length);
for (String componentName : components) {
transportComponents.add(new ComponentName(packageName, componentName));
}
+ if (transportComponents.isEmpty()) {
+ return;
+ }
synchronized (mTransportLock) {
mRegisteredTransportsDescriptionMap.keySet().removeIf(transportComponents::contains);
}
diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerService.java b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
index e10151dbd04b..1af35af9fc17 100644
--- a/services/backup/java/com/android/server/backup/UserBackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
@@ -89,8 +89,6 @@ import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.UserHandle;
import android.os.WorkSource;
-import android.os.storage.IStorageManager;
-import android.os.storage.StorageManager;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.ArraySet;
@@ -325,7 +323,6 @@ public class UserBackupManagerService {
private final ActivityManagerInternal mActivityManagerInternal;
private PowerManager mPowerManager;
private final AlarmManager mAlarmManager;
- private final IStorageManager mStorageManager;
private final BackupManagerConstants mConstants;
private final BackupWakeLock mWakelock;
private final BackupHandler mBackupHandler;
@@ -536,7 +533,6 @@ public class UserBackupManagerService {
mBackupPasswordManager = null;
mPackageManagerBinder = null;
mActivityManager = null;
- mStorageManager = null;
mBackupManagerBinder = null;
mScheduledBackupEligibility = null;
}
@@ -560,7 +556,6 @@ public class UserBackupManagerService {
mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
- mStorageManager = IStorageManager.Stub.asInterface(ServiceManager.getService("mount"));
Objects.requireNonNull(parent, "parent cannot be null");
mBackupManagerBinder = BackupManagerService.asInterface(parent.asBinder());
@@ -2077,26 +2072,6 @@ public class UserBackupManagerService {
}
}
- /** For adb backup/restore. */
- public boolean deviceIsEncrypted() {
- try {
- return mStorageManager.getEncryptionState()
- != StorageManager.ENCRYPTION_STATE_NONE
- && mStorageManager.getPasswordType()
- != StorageManager.CRYPT_TYPE_DEFAULT;
- } catch (Exception e) {
- // If we can't talk to the storagemanager service we have a serious problem; fail
- // "secure" i.e. assuming that the device is encrypted.
- Slog.e(
- TAG,
- addUserIdToLogMessage(
- mUserId,
- "Unable to communicate with storagemanager service: "
- + e.getMessage()));
- return true;
- }
- }
-
// ----- Full-data backup scheduling -----
/**
diff --git a/services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java b/services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java
index 7ee307e30dce..ec58e17148b3 100644
--- a/services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java
+++ b/services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java
@@ -320,12 +320,6 @@ public class PerformAdbBackupTask extends FullBackupTask implements BackupRestor
try {
boolean encrypting = (mEncryptPassword != null && mEncryptPassword.length() > 0);
- // Only allow encrypted backups of encrypted devices
- if (mUserBackupManagerService.deviceIsEncrypted() && !encrypting) {
- Slog.e(TAG, "Unencrypted backup of encrypted device; aborting");
- return;
- }
-
OutputStream finalOutput = ofstream;
// Verify that the given password matches the currently-active
diff --git a/services/cloudsearch/java/com/android/server/cloudsearch/CloudSearchManagerService.java b/services/cloudsearch/java/com/android/server/cloudsearch/CloudSearchManagerService.java
index daead0a5ff9d..ac2d1dd95da1 100644
--- a/services/cloudsearch/java/com/android/server/cloudsearch/CloudSearchManagerService.java
+++ b/services/cloudsearch/java/com/android/server/cloudsearch/CloudSearchManagerService.java
@@ -43,6 +43,8 @@ import com.android.server.infra.FrameworkResourcesServiceNameResolver;
import com.android.server.wm.ActivityTaskManagerInternal;
import java.io.FileDescriptor;
+import java.util.ArrayList;
+import java.util.List;
import java.util.function.Consumer;
/**
@@ -62,7 +64,7 @@ public class CloudSearchManagerService extends
public CloudSearchManagerService(Context context) {
super(context, new FrameworkResourcesServiceNameResolver(context,
- R.string.config_defaultCloudSearchService), null,
+ R.array.config_defaultCloudSearchServices, true), null,
PACKAGE_UPDATE_POLICY_NO_REFRESH | PACKAGE_RESTART_POLICY_NO_REFRESH);
mActivityTaskManagerInternal = LocalServices.getService(ActivityTaskManagerInternal.class);
mContext = context;
@@ -70,7 +72,25 @@ public class CloudSearchManagerService extends
@Override
protected CloudSearchPerUserService newServiceLocked(int resolvedUserId, boolean disabled) {
- return new CloudSearchPerUserService(this, mLock, resolvedUserId);
+ return new CloudSearchPerUserService(this, mLock, resolvedUserId, "");
+ }
+
+ @Override
+ protected List<CloudSearchPerUserService> newServiceListLocked(int resolvedUserId,
+ boolean disabled, String[] serviceNames) {
+ if (serviceNames == null) {
+ return new ArrayList<>();
+ }
+ List<CloudSearchPerUserService> serviceList =
+ new ArrayList<>(serviceNames.length);
+ for (int i = 0; i < serviceNames.length; i++) {
+ if (serviceNames[i] == null) {
+ continue;
+ }
+ serviceList.add(new CloudSearchPerUserService(this, mLock, resolvedUserId,
+ serviceNames[i]));
+ }
+ return serviceList;
}
@Override
@@ -109,21 +129,30 @@ public class CloudSearchManagerService extends
@Override
public void search(@NonNull SearchRequest searchRequest,
@NonNull ICloudSearchManagerCallback callBack) {
- searchRequest.setSource(
+ searchRequest.setCallerPackageName(
mContext.getPackageManager().getNameForUid(Binder.getCallingUid()));
- runForUserLocked("search", searchRequest.getRequestId(), (service) ->
- service.onSearchLocked(searchRequest, callBack));
+ runForUser("search", (service) -> {
+ synchronized (service.mLock) {
+ service.onSearchLocked(searchRequest, callBack);
+ }
+ });
}
@Override
public void returnResults(IBinder token, String requestId, SearchResponse response) {
- runForUserLocked("returnResults", requestId, (service) ->
- service.onReturnResultsLocked(token, requestId, response));
+ runForUser("returnResults", (service) -> {
+ synchronized (service.mLock) {
+ service.onReturnResultsLocked(token, requestId, response);
+ }
+ });
}
public void destroy(@NonNull SearchRequest searchRequest) {
- runForUserLocked("destroyCloudSearchSession", searchRequest.getRequestId(),
- (service) -> service.onDestroyLocked(searchRequest.getRequestId()));
+ runForUser("destroyCloudSearchSession", (service) -> {
+ synchronized (service.mLock) {
+ service.onDestroyLocked(searchRequest.getRequestId());
+ }
+ });
}
public void onShellCommand(@Nullable FileDescriptor in, @Nullable FileDescriptor out,
@@ -134,8 +163,7 @@ public class CloudSearchManagerService extends
.exec(this, in, out, err, args, callback, resultReceiver);
}
- private void runForUserLocked(@NonNull final String func,
- @NonNull final String requestId,
+ private void runForUser(@NonNull final String func,
@NonNull final Consumer<CloudSearchPerUserService> c) {
ActivityManagerInternal am = LocalServices.getService(ActivityManagerInternal.class);
final int userId = am.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
@@ -143,7 +171,7 @@ public class CloudSearchManagerService extends
null, null);
if (DEBUG) {
- Slog.d(TAG, "runForUserLocked:" + func + " from pid=" + Binder.getCallingPid()
+ Slog.d(TAG, "runForUser:" + func + " from pid=" + Binder.getCallingPid()
+ ", uid=" + Binder.getCallingUid());
}
Context ctx = getContext();
@@ -160,8 +188,11 @@ public class CloudSearchManagerService extends
final long origId = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
- final CloudSearchPerUserService service = getServiceForUserLocked(userId);
- c.accept(service);
+ final List<CloudSearchPerUserService> services =
+ getServiceListForUserLocked(userId);
+ for (int i = 0; i < services.size(); i++) {
+ c.accept(services.get(i));
+ }
}
} finally {
Binder.restoreCallingIdentity(origId);
diff --git a/services/cloudsearch/java/com/android/server/cloudsearch/CloudSearchManagerServiceShellCommand.java b/services/cloudsearch/java/com/android/server/cloudsearch/CloudSearchManagerServiceShellCommand.java
index 51f5fd9668cf..c64982d94d6d 100644
--- a/services/cloudsearch/java/com/android/server/cloudsearch/CloudSearchManagerServiceShellCommand.java
+++ b/services/cloudsearch/java/com/android/server/cloudsearch/CloudSearchManagerServiceShellCommand.java
@@ -54,7 +54,12 @@ public class CloudSearchManagerServiceShellCommand extends ShellCommand {
return 0;
}
final int duration = Integer.parseInt(getNextArgRequired());
- mService.setTemporaryService(userId, serviceName, duration);
+ String[] services = serviceName.split(";");
+ if (services.length == 0) {
+ return 0;
+ } else {
+ mService.setTemporaryServices(userId, services, duration);
+ }
pw.println("CloudSearchService temporarily set to " + serviceName
+ " for " + duration + "ms");
break;
diff --git a/services/cloudsearch/java/com/android/server/cloudsearch/CloudSearchPerUserService.java b/services/cloudsearch/java/com/android/server/cloudsearch/CloudSearchPerUserService.java
index 32d66afb33b9..8e0e3959dd0e 100644
--- a/services/cloudsearch/java/com/android/server/cloudsearch/CloudSearchPerUserService.java
+++ b/services/cloudsearch/java/com/android/server/cloudsearch/CloudSearchPerUserService.java
@@ -49,6 +49,8 @@ public class CloudSearchPerUserService extends
@GuardedBy("mLock")
private final CircularQueue<String, CloudSearchCallbackInfo> mCallbackQueue =
new CircularQueue<>(QUEUE_SIZE);
+ private final String mServiceName;
+ private final ComponentName mRemoteComponentName;
@Nullable
@GuardedBy("mLock")
private RemoteCloudSearchService mRemoteService;
@@ -60,8 +62,10 @@ public class CloudSearchPerUserService extends
private boolean mZombie;
protected CloudSearchPerUserService(CloudSearchManagerService master,
- Object lock, int userId) {
+ Object lock, int userId, String serviceName) {
super(master, lock, userId);
+ mServiceName = serviceName;
+ mRemoteComponentName = ComponentName.unflattenFromString(mServiceName);
}
@Override // from PerUserSystemService
@@ -103,12 +107,16 @@ public class CloudSearchPerUserService extends
@GuardedBy("mLock")
public void onSearchLocked(@NonNull SearchRequest searchRequest,
@NonNull ICloudSearchManagerCallback callback) {
+ if (mRemoteComponentName == null) {
+ return;
+ }
+
String filterList = searchRequest.getSearchConstraints().containsKey(
SearchRequest.CONSTRAINT_SEARCH_PROVIDER_FILTER)
? searchRequest.getSearchConstraints().getString(
SearchRequest.CONSTRAINT_SEARCH_PROVIDER_FILTER) : "";
- String remoteServicePackageName = getServiceComponentName().getPackageName();
+ String remoteServicePackageName = mRemoteComponentName.getPackageName();
// By default, all providers are marked as wanted.
boolean wantedProvider = true;
if (filterList.length() > 0) {
@@ -150,11 +158,19 @@ public class CloudSearchPerUserService extends
/**
* Used to return results back to the clients.
*/
+ @GuardedBy("mLock")
public void onReturnResultsLocked(@NonNull IBinder token,
@NonNull String requestId,
@NonNull SearchResponse response) {
+ if (mRemoteService == null) {
+ return;
+ }
+ ICloudSearchService serviceInterface = mRemoteService.getServiceInterface();
+ if (serviceInterface == null || token != serviceInterface.asBinder()) {
+ return;
+ }
if (mCallbackQueue.containsKey(requestId)) {
- response.setSource(mRemoteService.getComponentName().getPackageName());
+ response.setSource(mServiceName);
final CloudSearchCallbackInfo sessionInfo = mCallbackQueue.getElement(requestId);
try {
if (response.getStatusCode() == SearchResponse.SEARCH_STATUS_OK) {
@@ -163,6 +179,10 @@ public class CloudSearchPerUserService extends
sessionInfo.mCallback.onSearchFailed(response);
}
} catch (RemoteException e) {
+ if (mMaster.debug) {
+ Slog.e(TAG, "Exception in posting results");
+ e.printStackTrace();
+ }
onDestroyLocked(requestId);
}
}
@@ -297,7 +317,7 @@ public class CloudSearchPerUserService extends
@Nullable
private RemoteCloudSearchService getRemoteServiceLocked() {
if (mRemoteService == null) {
- final String serviceName = getComponentNameLocked();
+ final String serviceName = getComponentNameForMultipleLocked(mServiceName);
if (serviceName == null) {
if (mMaster.verbose) {
Slog.v(TAG, "getRemoteServiceLocked(): not set");
diff --git a/services/companion/TEST_MAPPING b/services/companion/TEST_MAPPING
index 4a37cb812981..38d937288569 100644
--- a/services/companion/TEST_MAPPING
+++ b/services/companion/TEST_MAPPING
@@ -7,6 +7,9 @@
"name": "CtsCompanionDeviceManagerUiAutomationTestCases"
},
{
+ "name": "CtsCompanionDeviceManagerNoCompanionServicesTestCases"
+ },
+ {
"name": "CtsOsTestCases",
"options": [
{
diff --git a/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java b/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java
index bf8b18ce3157..7a5fa628f645 100644
--- a/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java
+++ b/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java
@@ -51,6 +51,7 @@ import android.os.Parcel;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.UserHandle;
+import android.util.Log;
import android.util.PackageUtils;
import android.util.Slog;
@@ -332,13 +333,28 @@ class AssociationRequestsProcessor {
}
}
- String[] sameOemPackages = mContext.getResources()
+ // Below we check if the requesting package is allowlisted (usually by the OEM) for creating
+ // CDM associations without user confirmation (prompt).
+ // For this we'll check to config arrays:
+ // - com.android.internal.R.array.config_companionDevicePackages
+ // and
+ // - com.android.internal.R.array.config_companionDeviceCerts.
+ // Both arrays are expected to contain similar number of entries.
+ // config_companionDevicePackages contains package names of the allowlisted packages.
+ // config_companionDeviceCerts contains SHA256 digests of the signatures of the
+ // corresponding packages.
+ // If a package may be signed with one of several certificates, its package name would
+ // appear multiple times in the config_companionDevicePackages, with different entries
+ // (one for each of the valid signing certificates) at the corresponding positions in
+ // config_companionDeviceCerts.
+ final String[] allowlistedPackages = mContext.getResources()
.getStringArray(com.android.internal.R.array.config_companionDevicePackages);
- if (!ArrayUtils.contains(sameOemPackages, packageName)) {
- Slog.w(TAG, packageName
- + " can not silently create associations due to no package found."
- + " Packages from OEM: " + Arrays.toString(sameOemPackages)
- );
+ if (!ArrayUtils.contains(allowlistedPackages, packageName)) {
+ if (DEBUG) {
+ Log.d(TAG, packageName + " is not allowlisted for creating associations "
+ + "without user confirmation (prompt)");
+ Log.v(TAG, "Allowlisted packages=" + Arrays.toString(allowlistedPackages));
+ }
return false;
}
@@ -361,44 +377,41 @@ class AssociationRequestsProcessor {
}
}
- String[] sameOemCerts = mContext.getResources()
+ final String[] allowlistedPackagesSignatureDigests = mContext.getResources()
.getStringArray(com.android.internal.R.array.config_companionDeviceCerts);
-
- Signature[] signatures = mPackageManager.getPackage(packageName).getSigningDetails()
- .getSignatures();
- String[] apkCerts = PackageUtils.computeSignaturesSha256Digests(signatures);
-
- Set<String> sameOemPackageCerts =
- getSameOemPackageCerts(packageName, sameOemPackages, sameOemCerts);
-
- for (String cert : apkCerts) {
- if (sameOemPackageCerts.contains(cert)) {
- return true;
+ final Set<String> allowlistedSignatureDigestsForRequestingPackage = new HashSet<>();
+ for (int i = 0; i < allowlistedPackages.length; i++) {
+ if (allowlistedPackages[i].equals(packageName)) {
+ final String digest = allowlistedPackagesSignatureDigests[i].replaceAll(":", "");
+ allowlistedSignatureDigestsForRequestingPackage.add(digest);
}
}
- Slog.w(TAG, packageName
- + " can not silently create associations. " + packageName
- + " has SHA256 certs from APK: " + Arrays.toString(apkCerts)
- + " and from OEM: " + Arrays.toString(sameOemCerts)
- );
+ final Signature[] requestingPackageSignatures = mPackageManager.getPackage(packageName)
+ .getSigningDetails().getSignatures();
+ final String[] requestingPackageSignatureDigests =
+ PackageUtils.computeSignaturesSha256Digests(requestingPackageSignatures);
- return false;
- }
-
- private static Set<String> getSameOemPackageCerts(
- String packageName, String[] oemPackages, String[] sameOemCerts) {
- Set<String> sameOemPackageCerts = new HashSet<>();
+ boolean requestingPackageSignatureAllowlisted = false;
+ for (String signatureDigest : requestingPackageSignatureDigests) {
+ if (allowlistedSignatureDigestsForRequestingPackage.contains(signatureDigest)) {
+ requestingPackageSignatureAllowlisted = true;
+ break;
+ }
+ }
- // Assume OEM may enter same package name in the parallel string array with
- // multiple APK certs corresponding to it
- for (int i = 0; i < oemPackages.length; i++) {
- if (oemPackages[i].equals(packageName)) {
- sameOemPackageCerts.add(sameOemCerts[i].replaceAll(":", ""));
+ if (!requestingPackageSignatureAllowlisted) {
+ Slog.w(TAG, "Certificate mismatch for allowlisted package " + packageName);
+ if (DEBUG) {
+ Log.d(TAG, " > allowlisted signatures for " + packageName + ": ["
+ + String.join(", ", allowlistedSignatureDigestsForRequestingPackage)
+ + "]");
+ Log.d(TAG, " > actual signatures for " + packageName + ": "
+ + Arrays.toString(requestingPackageSignatureDigests));
}
}
- return sameOemPackageCerts;
+ return requestingPackageSignatureAllowlisted;
}
/**
diff --git a/services/companion/java/com/android/server/companion/CompanionApplicationController.java b/services/companion/java/com/android/server/companion/CompanionApplicationController.java
index f32eebc2a31f..2a83a3c431ec 100644
--- a/services/companion/java/com/android/server/companion/CompanionApplicationController.java
+++ b/services/companion/java/com/android/server/companion/CompanionApplicationController.java
@@ -49,7 +49,7 @@ import java.util.Map;
* The following is the list of the APIs provided by {@link CompanionApplicationController} (to be
* utilized by {@link CompanionDeviceManagerService}):
* <ul>
- * <li> {@link #bindCompanionApplication(int, String)}
+ * <li> {@link #bindCompanionApplication(int, String, boolean)}
* <li> {@link #unbindCompanionApplication(int, String)}
* <li> {@link #notifyCompanionApplicationDeviceAppeared(AssociationInfo)}
* <li> {@link #notifyCompanionApplicationDeviceDisappeared(AssociationInfo)}
@@ -103,8 +103,12 @@ class CompanionApplicationController {
mCompanionServicesRegister.invalidate(userId);
}
- void bindCompanionApplication(@UserIdInt int userId, @NonNull String packageName) {
- if (DEBUG) Log.i(TAG, "bind() u" + userId + "/" + packageName);
+ void bindCompanionApplication(@UserIdInt int userId, @NonNull String packageName,
+ boolean bindImportant) {
+ if (DEBUG) {
+ Log.i(TAG, "bind() u" + userId + "/" + packageName
+ + " important=" + bindImportant);
+ }
final List<ComponentName> companionServices =
mCompanionServicesRegister.forPackage(userId, packageName);
@@ -125,7 +129,8 @@ class CompanionApplicationController {
}
serviceConnectors = CollectionUtils.map(companionServices, componentName ->
- new CompanionDeviceServiceConnector(mContext, userId, componentName));
+ CompanionDeviceServiceConnector.newInstance(mContext, userId,
+ componentName, bindImportant));
mBoundCompanionApplications.setValueForPackage(userId, packageName, serviceConnectors);
}
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index eaa99f74e24e..13a5a2829945 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -254,9 +254,12 @@ public class CompanionDeviceManagerService extends SystemService {
final int userId = association.getUserId();
final String packageName = association.getPackageName();
+ // Set bindImportant to true when the association is self-managed to avoid the target
+ // service being killed.
+ final boolean bindImportant = association.isSelfManaged();
if (!mCompanionAppController.isCompanionApplicationBound(userId, packageName)) {
- mCompanionAppController.bindCompanionApplication(userId, packageName);
+ mCompanionAppController.bindCompanionApplication(userId, packageName, bindImportant);
} else if (DEBUG) {
Log.i(TAG, "u" + userId + "\\" + packageName + " is already bound");
}
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceServiceConnector.java b/services/companion/java/com/android/server/companion/CompanionDeviceServiceConnector.java
index f2a58b74a65a..a6bd48056e12 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceServiceConnector.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceServiceConnector.java
@@ -16,6 +16,7 @@
package com.android.server.companion;
+import static android.content.Context.BIND_ALMOST_PERCEPTIBLE;
import static android.content.Context.BIND_IMPORTANT;
import static android.os.Process.THREAD_PRIORITY_DEFAULT;
@@ -44,7 +45,6 @@ import com.android.server.ServiceThread;
class CompanionDeviceServiceConnector extends ServiceConnector.Impl<ICompanionDeviceService> {
private static final String TAG = "CompanionDevice_ServiceConnector";
private static final boolean DEBUG = false;
- private static final int BINDING_FLAGS = BIND_IMPORTANT;
/** Listener for changes to the state of the {@link CompanionDeviceServiceConnector} */
interface Listener {
@@ -53,11 +53,35 @@ class CompanionDeviceServiceConnector extends ServiceConnector.Impl<ICompanionDe
private final @UserIdInt int mUserId;
private final @NonNull ComponentName mComponentName;
+ // IMPORTANT: this can (and will!) be null (at the moment, CompanionApplicationController only
+ // installs a listener to the primary ServiceConnector), hence we should always null-check the
+ // reference before calling on it.
private @Nullable Listener mListener;
- CompanionDeviceServiceConnector(@NonNull Context context, @UserIdInt int userId,
- @NonNull ComponentName componentName) {
- super(context, buildIntent(componentName), BINDING_FLAGS, userId, null);
+ /**
+ * Create a CompanionDeviceServiceConnector instance.
+ *
+ * When bindImportant is false, the binding flag will be BIND_ALMOST_PERCEPTIBLE
+ * (oom_score_adj = PERCEPTIBLE_MEDIUM_APP = 225). The target service will be treated
+ * as important as a perceptible app (IMPORTANCE_VISIBLE = 200), and will be unbound when
+ * the app is removed from task manager.
+ * When bindImportant is true, the binding flag will be BIND_IMPORTANT
+ * (oom_score_adj = PERCEPTIBLE_MEDIUM_APP = -700). The target service will
+ * have the highest priority to avoid being killed (IMPORTANCE_FOREGROUND = 100).
+ *
+ * One time permission's importance level to keep session alive is
+ * IMPORTANCE_FOREGROUND_SERVICE = 125. In order to kill the one time permission session, the
+ * service importance level should be higher than 125.
+ */
+ static CompanionDeviceServiceConnector newInstance(@NonNull Context context,
+ @UserIdInt int userId, @NonNull ComponentName componentName, boolean bindImportant) {
+ final int bindingFlags = bindImportant ? BIND_IMPORTANT : BIND_ALMOST_PERCEPTIBLE;
+ return new CompanionDeviceServiceConnector(context, userId, componentName, bindingFlags);
+ }
+
+ private CompanionDeviceServiceConnector(@NonNull Context context, @UserIdInt int userId,
+ @NonNull ComponentName componentName, int bindingFlags) {
+ super(context, buildIntent(componentName), bindingFlags, userId, null);
mUserId = userId;
mComponentName = componentName;
}
@@ -101,7 +125,9 @@ class CompanionDeviceServiceConnector extends ServiceConnector.Impl<ICompanionDe
if (DEBUG) Log.d(TAG, "onBindingDied() " + mComponentName.toShortString());
- mListener.onBindingDied(mUserId, mComponentName.getPackageName());
+ if (mListener != null) {
+ mListener.onBindingDied(mUserId, mComponentName.getPackageName());
+ }
}
@Override
diff --git a/services/companion/java/com/android/server/companion/presence/BluetoothCompanionDeviceConnectionListener.java b/services/companion/java/com/android/server/companion/presence/BluetoothCompanionDeviceConnectionListener.java
index 1ba198ae26b0..823743da7da6 100644
--- a/services/companion/java/com/android/server/companion/presence/BluetoothCompanionDeviceConnectionListener.java
+++ b/services/companion/java/com/android/server/companion/presence/BluetoothCompanionDeviceConnectionListener.java
@@ -94,7 +94,7 @@ class BluetoothCompanionDeviceConnectionListener
int reason) {
if (DEBUG) {
Log.i(TAG, "onDevice_Disconnected() " + btDeviceToString(device));
- Log.d(TAG, " reason=" + disconnectReasonText(reason));
+ Log.d(TAG, " reason=" + disconnectReasonToString(reason));
}
final MacAddress macAddress = MacAddress.fromString(device.getAddress());
diff --git a/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java b/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java
index b991ba87eef4..3a26c4611629 100644
--- a/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java
+++ b/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java
@@ -22,6 +22,7 @@ import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTE
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.WindowConfiguration;
import android.app.compat.CompatChanges;
import android.companion.virtual.VirtualDeviceManager.ActivityListener;
import android.companion.virtual.VirtualDeviceParams;
@@ -119,6 +120,7 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController
@ActivityPolicy int defaultActivityPolicy,
@NonNull ActivityListener activityListener,
@NonNull Consumer<ActivityInfo> activityBlockedCallback) {
+ super();
mAllowedUsers = allowedUsers;
mAllowedActivities = new ArraySet<>(allowedActivities);
mBlockedActivities = new ArraySet<>(blockedActivities);
@@ -134,7 +136,11 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController
}
@Override
- public boolean canContainActivities(@NonNull List<ActivityInfo> activities) {
+ public boolean canContainActivities(@NonNull List<ActivityInfo> activities,
+ @WindowConfiguration.WindowingMode int windowingMode) {
+ if (!isWindowingModeSupported(windowingMode)) {
+ return false;
+ }
// Can't display all the activities if any of them don't want to be displayed.
final int activityCount = activities.size();
for (int i = 0; i < activityCount; i++) {
diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java
index c9d704084c19..68cd28809fd0 100644
--- a/services/core/java/android/content/pm/PackageManagerInternal.java
+++ b/services/core/java/android/content/pm/PackageManagerInternal.java
@@ -45,9 +45,9 @@ import android.util.SparseArray;
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.pm.PackageList;
import com.android.server.pm.PackageSetting;
+import com.android.server.pm.dex.DynamicCodeLogger;
import com.android.server.pm.parsing.pkg.AndroidPackage;
import com.android.server.pm.pkg.AndroidPackageApi;
-import com.android.server.pm.pkg.PackageState;
import com.android.server.pm.pkg.PackageStateInternal;
import com.android.server.pm.pkg.SharedUserApi;
import com.android.server.pm.pkg.component.ParsedMainComponent;
@@ -68,6 +68,7 @@ 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,
@@ -688,8 +689,6 @@ public abstract class PackageManagerInternal {
@Nullable
public abstract PackageStateInternal getPackageStateInternal(@NonNull String packageName);
- public abstract @Nullable PackageState getPackageState(@NonNull String packageName);
-
@NonNull
public abstract ArrayMap<String, ? extends PackageStateInternal> getPackageStates();
@@ -902,6 +901,11 @@ public abstract class PackageManagerInternal {
public abstract void freeStorage(String volumeUuid, long bytes,
@StorageManager.AllocateFlags int flags) throws IOException;
+ /**
+ * Blocking call to clear all cached app data above quota.
+ */
+ public abstract void freeAllAppCacheAboveQuota(@NonNull String volumeUuid) throws IOException;
+
/** Returns {@code true} if the specified component is enabled and matches the given flags. */
public abstract boolean isEnabledAndMatches(@NonNull ParsedMainComponent component,
@PackageManager.ComponentInfoFlagsBits long flags, int userId);
@@ -1362,4 +1366,8 @@ public abstract class PackageManagerInternal {
*/
@NonNull
public abstract PackageDataSnapshot snapshot();
+
+ public abstract void shutdown();
+
+ public abstract DynamicCodeLogger getDynamicCodeLogger();
}
diff --git a/services/core/java/com/android/server/MasterClearReceiver.java b/services/core/java/com/android/server/MasterClearReceiver.java
index be2b7f72bd4f..7c3a75f256f9 100644
--- a/services/core/java/com/android/server/MasterClearReceiver.java
+++ b/services/core/java/com/android/server/MasterClearReceiver.java
@@ -131,7 +131,7 @@ public class MasterClearReceiver extends BroadcastReceiver {
final UserManager userManager = context.getSystemService(UserManager.class);
final int result = userManager.removeUserWhenPossible(
UserHandle.of(userId), /* overrideDevicePolicy= */ false);
- if (result == UserManager.REMOVE_RESULT_ERROR) {
+ if (!UserManager.isRemoveResultSuccessful(result)) {
Slogf.e(TAG, "Can't remove user %d", userId);
return false;
}
@@ -169,7 +169,7 @@ public class MasterClearReceiver extends BroadcastReceiver {
private String getWorkProfileDeletedTitle(Context context) {
final DevicePolicyManager dpm = context.getSystemService(DevicePolicyManager.class);
- return dpm.getString(WORK_PROFILE_DELETED_TITLE,
+ return dpm.getResources().getString(WORK_PROFILE_DELETED_TITLE,
() -> context.getString(R.string.work_profile_deleted));
}
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index b59cd4c0f212..1a39ffa393b3 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -1166,9 +1166,17 @@ public class NetworkManagementService extends INetworkManagementService.Stub {
final ConnectivityManager cm = mContext.getSystemService(ConnectivityManager.class);
try {
if (allowlist) {
- cm.updateMeteredNetworkAllowList(uid, enable);
+ if (enable) {
+ cm.addUidToMeteredNetworkAllowList(uid);
+ } else {
+ cm.removeUidFromMeteredNetworkAllowList(uid);
+ }
} else {
- cm.updateMeteredNetworkDenyList(uid, enable);
+ if (enable) {
+ cm.addUidToMeteredNetworkDenyList(uid);
+ } else {
+ cm.removeUidFromMeteredNetworkDenyList(uid);
+ }
}
synchronized (mRulesLock) {
if (enable) {
diff --git a/services/core/java/com/android/server/NetworkTimeUpdateService.java b/services/core/java/com/android/server/NetworkTimeUpdateService.java
index 1e534b7c1515..2015dc929a59 100644
--- a/services/core/java/com/android/server/NetworkTimeUpdateService.java
+++ b/services/core/java/com/android/server/NetworkTimeUpdateService.java
@@ -17,6 +17,7 @@
package com.android.server;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.app.timedetector.NetworkTimeSuggestion;
@@ -45,12 +46,12 @@ import android.util.LocalLog;
import android.util.Log;
import android.util.NtpTrustedTime;
import android.util.NtpTrustedTime.TimeResult;
-import android.util.TimeUtils;
import com.android.internal.util.DumpUtils;
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.time.Duration;
/**
* Monitors the network time. If looking up the network time fails for some reason, it tries a few
@@ -191,6 +192,21 @@ public class NetworkTimeUpdateService extends Binder {
return success;
}
+ /**
+ * Overrides the NTP server config for tests. Passing {@code null} to a parameter clears the
+ * test value, i.e. so the normal value will be used next time.
+ */
+ void setServerConfigForTests(
+ @Nullable String hostname, @Nullable Integer port, @Nullable Duration timeout) {
+ mContext.enforceCallingPermission(
+ android.Manifest.permission.SET_TIME, "set NTP server config for tests");
+
+ mLocalLog.log("Setting server config for tests: hostname=" + hostname
+ + ", port=" + port
+ + ", timeout=" + timeout);
+ mTime.setServerConfigForTests(hostname, port, timeout);
+ }
+
private void onPollNetworkTime(int event) {
// If we don't have any default network, don't bother.
if (mDefaultNetwork == null) return;
@@ -349,17 +365,14 @@ public class NetworkTimeUpdateService extends Binder {
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
- pw.print("PollingIntervalMs: ");
- TimeUtils.formatDuration(mPollingIntervalMs, pw);
- pw.print("\nPollingIntervalShorterMs: ");
- TimeUtils.formatDuration(mPollingIntervalShorterMs, pw);
- pw.println("\nTryAgainTimesMax: " + mTryAgainTimesMax);
- pw.println("\nTryAgainCounter: " + mTryAgainCounter);
- NtpTrustedTime.TimeResult ntpResult = mTime.getCachedTimeResult();
- pw.println("NTP cache result: " + ntpResult);
- if (ntpResult != null) {
- pw.println("NTP result age: " + ntpResult.getAgeMillis());
- }
+ pw.println("mPollingIntervalMs=" + Duration.ofMillis(mPollingIntervalMs));
+ pw.println("mPollingIntervalShorterMs=" + Duration.ofMillis(mPollingIntervalShorterMs));
+ pw.println("mTryAgainTimesMax=" + mTryAgainTimesMax);
+ pw.println("mTryAgainCounter=" + mTryAgainCounter);
+ pw.println();
+ pw.println("NtpTrustedTime:");
+ mTime.dump(pw);
+ pw.println();
pw.println("Local logs:");
mLocalLog.dump(fd, pw, args);
pw.println();
diff --git a/services/core/java/com/android/server/NetworkTimeUpdateServiceShellCommand.java b/services/core/java/com/android/server/NetworkTimeUpdateServiceShellCommand.java
index dc93023d82c5..d7504ceb9d4d 100644
--- a/services/core/java/com/android/server/NetworkTimeUpdateServiceShellCommand.java
+++ b/services/core/java/com/android/server/NetworkTimeUpdateServiceShellCommand.java
@@ -20,6 +20,7 @@ import android.annotation.NonNull;
import android.os.ShellCommand;
import java.io.PrintWriter;
+import java.time.Duration;
import java.util.Objects;
/** Implements the shell command interface for {@link NetworkTimeUpdateService}. */
@@ -40,6 +41,14 @@ class NetworkTimeUpdateServiceShellCommand extends ShellCommand {
*/
private static final String SHELL_COMMAND_FORCE_REFRESH = "force_refresh";
+ /**
+ * A shell command that sets the NTP server config for tests. Config is cleared on reboot.
+ */
+ private static final String SHELL_COMMAND_SET_SERVER_CONFIG = "set_server_config";
+ private static final String SET_SERVER_CONFIG_HOSTNAME_ARG = "--hostname";
+ private static final String SET_SERVER_CONFIG_PORT_ARG = "--port";
+ private static final String SET_SERVER_CONFIG_TIMEOUT_ARG = "--timeout_millis";
+
@NonNull
private final NetworkTimeUpdateService mNetworkTimeUpdateService;
@@ -58,6 +67,8 @@ class NetworkTimeUpdateServiceShellCommand extends ShellCommand {
return runClearTime();
case SHELL_COMMAND_FORCE_REFRESH:
return runForceRefresh();
+ case SHELL_COMMAND_SET_SERVER_CONFIG:
+ return runSetServerConfig();
default: {
return handleDefaultCommands(cmd);
}
@@ -75,6 +86,34 @@ class NetworkTimeUpdateServiceShellCommand extends ShellCommand {
return 0;
}
+ private int runSetServerConfig() {
+ String hostname = null;
+ Integer port = null;
+ Duration timeout = null;
+ String opt;
+ while ((opt = getNextArg()) != null) {
+ switch (opt) {
+ case SET_SERVER_CONFIG_HOSTNAME_ARG: {
+ hostname = getNextArgRequired();
+ break;
+ }
+ case SET_SERVER_CONFIG_PORT_ARG: {
+ port = Integer.parseInt(getNextArgRequired());
+ break;
+ }
+ case SET_SERVER_CONFIG_TIMEOUT_ARG: {
+ timeout = Duration.ofMillis(Integer.parseInt(getNextArgRequired()));
+ break;
+ }
+ default: {
+ throw new IllegalArgumentException("Unknown option: " + opt);
+ }
+ }
+ }
+ mNetworkTimeUpdateService.setServerConfigForTests(hostname, port, timeout);
+ return 0;
+ }
+
@Override
public void onHelp() {
final PrintWriter pw = getOutPrintWriter();
@@ -85,6 +124,13 @@ class NetworkTimeUpdateServiceShellCommand extends ShellCommand {
pw.printf(" Clears the latest time.\n");
pw.printf(" %s\n", SHELL_COMMAND_FORCE_REFRESH);
pw.printf(" Refreshes the latest time. Prints whether it was successful.\n");
+ pw.printf(" %s\n", SHELL_COMMAND_SET_SERVER_CONFIG);
+ pw.printf(" Sets the NTP server config for tests. The config is not persisted.\n");
+ pw.printf(" Options: [%s <hostname>] [%s <port>] [%s <millis>]\n",
+ SET_SERVER_CONFIG_HOSTNAME_ARG, SET_SERVER_CONFIG_PORT_ARG,
+ SET_SERVER_CONFIG_TIMEOUT_ARG);
+ pw.printf(" Each key/value is optional and must be specified to override the\n");
+ pw.printf(" normal value, not specifying a key causes it to reset to the original.\n");
pw.println();
}
}
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index d4764a61566e..a2cfe4928249 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -75,7 +75,6 @@ import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.content.pm.ProviderInfo;
import android.content.pm.UserInfo;
-import android.content.res.Configuration;
import android.content.res.ObbInfo;
import android.database.ContentObserver;
import android.net.Uri;
@@ -124,7 +123,6 @@ import android.provider.Downloads;
import android.provider.MediaStore;
import android.provider.Settings;
import android.service.storage.ExternalStorageService;
-import android.sysprop.VoldProperties;
import android.text.TextUtils;
import android.text.format.DateUtils;
import android.util.ArrayMap;
@@ -176,9 +174,6 @@ import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.PrintWriter;
-import java.math.BigInteger;
-import java.security.GeneralSecurityException;
-import java.security.spec.KeySpec;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
@@ -198,10 +193,6 @@ import java.util.concurrent.TimeoutException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-import javax.crypto.SecretKey;
-import javax.crypto.SecretKeyFactory;
-import javax.crypto.spec.PBEKeySpec;
-
/**
* Service responsible for various storage media. Connects to {@code vold} to
* watch for and manage dynamically added storage, such as SD cards and USB mass
@@ -1414,39 +1405,6 @@ class StorageManagerService extends IStorageManager.Stub
private void handleDaemonConnected() {
initIfBootedAndConnected();
resetIfBootedAndConnected();
-
- // On an encrypted device we can't see system properties yet, so pull
- // the system locale out of the mount service.
- if ("".equals(VoldProperties.encrypt_progress().orElse(""))) {
- copyLocaleFromMountService();
- }
- }
-
- private void copyLocaleFromMountService() {
- String systemLocale;
- try {
- systemLocale = getField(StorageManager.SYSTEM_LOCALE_KEY);
- } catch (RemoteException e) {
- return;
- }
- if (TextUtils.isEmpty(systemLocale)) {
- return;
- }
-
- Slog.d(TAG, "Got locale " + systemLocale + " from mount service");
- Locale locale = Locale.forLanguageTag(systemLocale);
- Configuration config = new Configuration();
- config.setLocale(locale);
- try {
- ActivityManager.getService().updatePersistentConfigurationWithAttribution(config,
- mContext.getOpPackageName(), mContext.getAttributionTag());
- } catch (RemoteException e) {
- Slog.e(TAG, "Error setting system locale from mount service", e);
- }
-
- // Temporary workaround for http://b/17945169.
- Slog.d(TAG, "Setting system properties to " + systemLocale + " from mount service");
- SystemProperties.set("persist.sys.locale", locale.toLanguageTag());
}
private final IVoldListener mListener = new IVoldListener.Stub() {
@@ -3130,8 +3088,8 @@ class StorageManagerService extends IStorageManager.Stub
}
@Override
- public void mountObb(String rawPath, String canonicalPath, String key,
- IObbActionListener token, int nonce, ObbInfo obbInfo) {
+ public void mountObb(String rawPath, String canonicalPath, IObbActionListener token,
+ int nonce, ObbInfo obbInfo) {
Objects.requireNonNull(rawPath, "rawPath cannot be null");
Objects.requireNonNull(canonicalPath, "canonicalPath cannot be null");
Objects.requireNonNull(token, "token cannot be null");
@@ -3140,7 +3098,7 @@ class StorageManagerService extends IStorageManager.Stub
final int callingUid = Binder.getCallingUid();
final ObbState obbState = new ObbState(rawPath, canonicalPath,
callingUid, token, nonce, null);
- final ObbAction action = new MountObbAction(obbState, key, callingUid, obbInfo);
+ final ObbAction action = new MountObbAction(obbState, callingUid, obbInfo);
mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action));
if (DEBUG_OBB)
@@ -3171,220 +3129,6 @@ class StorageManagerService extends IStorageManager.Stub
}
}
- @Override
- public int getEncryptionState() {
- mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
- "no permission to access the crypt keeper");
-
- try {
- return mVold.fdeComplete();
- } catch (Exception e) {
- Slog.wtf(TAG, e);
- return StorageManager.ENCRYPTION_STATE_ERROR_UNKNOWN;
- }
- }
-
- @Override
- public int decryptStorage(String password) {
- mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
- "no permission to access the crypt keeper");
-
- if (TextUtils.isEmpty(password)) {
- throw new IllegalArgumentException("password cannot be empty");
- }
-
- if (DEBUG_EVENTS) {
- Slog.i(TAG, "decrypting storage...");
- }
-
- try {
- mVold.fdeCheckPassword(password);
- mHandler.postDelayed(() -> {
- try {
- mVold.fdeRestart();
- } catch (Exception e) {
- Slog.wtf(TAG, e);
- }
- }, DateUtils.SECOND_IN_MILLIS);
- return 0;
- } catch (ServiceSpecificException e) {
- Slog.e(TAG, "fdeCheckPassword failed", e);
- return e.errorCode;
- } catch (Exception e) {
- Slog.wtf(TAG, e);
- return StorageManager.ENCRYPTION_STATE_ERROR_UNKNOWN;
- }
- }
-
- @Override
- public int encryptStorage(int type, String password) {
- mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
- "no permission to access the crypt keeper");
-
- if (type == StorageManager.CRYPT_TYPE_DEFAULT) {
- password = "";
- } else if (TextUtils.isEmpty(password)) {
- throw new IllegalArgumentException("password cannot be empty");
- }
-
- if (DEBUG_EVENTS) {
- Slog.i(TAG, "encrypting storage...");
- }
-
- try {
- mVold.fdeEnable(type, password, 0);
- } catch (Exception e) {
- Slog.wtf(TAG, e);
- return -1;
- }
-
- return 0;
- }
-
- /** Set the password for encrypting the main key.
- * @param type One of the CRYPTO_TYPE_XXX consts defined in StorageManager.
- * @param password The password to set.
- */
- @Override
- public int changeEncryptionPassword(int type, String password) {
- mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
- "no permission to access the crypt keeper");
-
- if (StorageManager.isFileEncryptedNativeOnly()) {
- // Not supported on FBE devices
- return -1;
- }
-
- if (type == StorageManager.CRYPT_TYPE_DEFAULT) {
- password = "";
- } else if (TextUtils.isEmpty(password)) {
- throw new IllegalArgumentException("password cannot be empty");
- }
-
- if (DEBUG_EVENTS) {
- Slog.i(TAG, "changing encryption password...");
- }
-
- try {
- mVold.fdeChangePassword(type, password);
- return 0;
- } catch (Exception e) {
- Slog.wtf(TAG, e);
- return -1;
- }
- }
-
- /**
- * Validate a user-supplied password string with cryptfs
- */
- @Override
- public int verifyEncryptionPassword(String password) throws RemoteException {
- // Only the system process is permitted to validate passwords
- if (Binder.getCallingUid() != android.os.Process.SYSTEM_UID) {
- throw new SecurityException("no permission to access the crypt keeper");
- }
-
- mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
- "no permission to access the crypt keeper");
-
- if (TextUtils.isEmpty(password)) {
- throw new IllegalArgumentException("password cannot be empty");
- }
-
- if (DEBUG_EVENTS) {
- Slog.i(TAG, "validating encryption password...");
- }
-
- try {
- mVold.fdeVerifyPassword(password);
- return 0;
- } catch (Exception e) {
- Slog.wtf(TAG, e);
- return -1;
- }
- }
-
- /**
- * Get the type of encryption used to encrypt the main key.
- * @return The type, one of the CRYPT_TYPE_XXX consts from StorageManager.
- */
- @Override
- public int getPasswordType() {
- mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
- "no permission to access the crypt keeper");
-
- try {
- return mVold.fdeGetPasswordType();
- } catch (Exception e) {
- Slog.wtf(TAG, e);
- return -1;
- }
- }
-
- /**
- * Set a field in the crypto header.
- * @param field field to set
- * @param contents contents to set in field
- */
- @Override
- public void setField(String field, String contents) throws RemoteException {
- mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
- "no permission to access the crypt keeper");
-
- if (!StorageManager.isBlockEncrypted()) {
- // Only supported on FDE devices
- return;
- }
-
- try {
- mVold.fdeSetField(field, contents);
- return;
- } catch (Exception e) {
- Slog.wtf(TAG, e);
- return;
- }
- }
-
- /**
- * Gets a field from the crypto header.
- * @param field field to get
- * @return contents of field
- */
- @Override
- public String getField(String field) throws RemoteException {
- mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
- "no permission to access the crypt keeper");
-
- if (!StorageManager.isBlockEncrypted()) {
- // Only supported on FDE devices
- return null;
- }
-
- try {
- return mVold.fdeGetField(field);
- } catch (Exception e) {
- Slog.wtf(TAG, e);
- return null;
- }
- }
-
- /**
- * Is userdata convertible to file based encryption?
- * @return non zero for convertible
- */
- @Override
- public boolean isConvertibleToFBE() throws RemoteException {
- mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
- "no permission to access the crypt keeper");
-
- try {
- return mVold.isConvertibleToFbe();
- } catch (Exception e) {
- Slog.wtf(TAG, e);
- return false;
- }
- }
-
/**
* Check whether the device supports filesystem checkpointing.
*
@@ -3450,33 +3194,6 @@ class StorageManagerService extends IStorageManager.Stub
}
@Override
- public String getPassword() throws RemoteException {
- mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
- "only keyguard can retrieve password");
-
- try {
- return mVold.fdeGetPassword();
- } catch (Exception e) {
- Slog.wtf(TAG, e);
- return null;
- }
- }
-
- @Override
- public void clearPassword() throws RemoteException {
- mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
- "only keyguard can clear password");
-
- try {
- mVold.fdeClearPassword();
- return;
- } catch (Exception e) {
- Slog.wtf(TAG, e);
- return;
- }
- }
-
- @Override
public void createUserKey(int userId, int serialNumber, boolean ephemeral) {
enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
@@ -3677,11 +3394,20 @@ class StorageManagerService extends IStorageManager.Stub
mInstaller.tryMountDataMirror(volumeUuid);
}
}
- } catch (RemoteException | Installer.InstallerException e) {
+ } catch (Exception e) {
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
// wasn't successfully set up.
+ //
+ // Very unfortunately, these errors need to be ignored for broken
+ // users that already existed on-disk from older Android versions.
+ UserManagerInternal umInternal = LocalServices.getService(UserManagerInternal.class);
+ if (umInternal.shouldIgnorePrepareStorageErrors(userId)) {
+ Slog.wtf(TAG, "ignoring error preparing storage for existing user " + userId
+ + "; device may be insecure!");
+ return;
+ }
throw new RuntimeException(e);
}
}
@@ -4586,13 +4312,11 @@ class StorageManagerService extends IStorageManager.Stub
}
class MountObbAction extends ObbAction {
- private final String mKey;
private final int mCallingUid;
private ObbInfo mObbInfo;
- MountObbAction(ObbState obbState, String key, int callingUid, ObbInfo obbInfo) {
+ MountObbAction(ObbState obbState, int callingUid, ObbInfo obbInfo) {
super(obbState);
- mKey = key;
mCallingUid = callingUid;
mObbInfo = obbInfo;
}
@@ -4615,29 +4339,8 @@ class StorageManagerService extends IStorageManager.Stub
"Attempt to mount OBB which is already mounted: " + mObbInfo.filename);
}
- final String hashedKey;
- final String binderKey;
- if (mKey == null) {
- hashedKey = "none";
- binderKey = "";
- } else {
- try {
- SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
-
- KeySpec ks = new PBEKeySpec(mKey.toCharArray(), mObbInfo.salt,
- PBKDF2_HASH_ROUNDS, CRYPTO_ALGORITHM_KEY_SIZE);
- SecretKey key = factory.generateSecret(ks);
- BigInteger bi = new BigInteger(key.getEncoded());
- hashedKey = bi.toString(16);
- binderKey = hashedKey;
- } catch (GeneralSecurityException e) {
- throw new ObbException(ERROR_INTERNAL, e);
- }
- }
-
try {
- mObbState.volId = mVold.createObb(mObbState.canonicalPath, binderKey,
- mObbState.ownerGid);
+ mObbState.volId = mVold.createObb(mObbState.canonicalPath, mObbState.ownerGid);
mVold.mount(mObbState.volId, 0, -1, null);
if (DEBUG_OBB)
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 40ab0c07d166..839cdc6eaca3 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -91,7 +91,7 @@ import android.util.Pair;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IBatteryStats;
-import com.android.internal.telephony.ICarrierPrivilegesListener;
+import com.android.internal.telephony.ICarrierPrivilegesCallback;
import com.android.internal.telephony.IOnSubscriptionsChangedListener;
import com.android.internal.telephony.IPhoneStateListener;
import com.android.internal.telephony.ITelephonyRegistry;
@@ -153,7 +153,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
IPhoneStateListener callback;
IOnSubscriptionsChangedListener onSubscriptionsChangedListenerCallback;
IOnSubscriptionsChangedListener onOpportunisticSubscriptionsChangedListenerCallback;
- ICarrierPrivilegesListener carrierPrivilegesListener;
+ ICarrierPrivilegesCallback carrierPrivilegesCallback;
int callerUid;
int callerPid;
@@ -178,8 +178,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
return (onOpportunisticSubscriptionsChangedListenerCallback != null);
}
- boolean matchCarrierPrivilegesListener() {
- return carrierPrivilegesListener != null;
+ boolean matchCarrierPrivilegesCallback() {
+ return carrierPrivilegesCallback != null;
}
boolean canReadCallLog() {
@@ -199,7 +199,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
+ onSubscriptionsChangedListenerCallback
+ " onOpportunisticSubscriptionsChangedListenererCallback="
+ onOpportunisticSubscriptionsChangedListenerCallback
- + " carrierPrivilegesListener=" + carrierPrivilegesListener
+ + " carrierPrivilegesCallback=" + carrierPrivilegesCallback
+ " subId=" + subId + " phoneId=" + phoneId + " events=" + eventList + "}";
}
}
@@ -414,7 +414,9 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
mPreciseDataConnectionStates;
/** Per-phoneId snapshot of privileged packages (names + UIDs). */
- private List<Pair<List<String>, int[]>> mCarrierPrivilegeStates;
+ @NonNull private List<Pair<List<String>, int[]>> mCarrierPrivilegeStates;
+ /** Per-phoneId of CarrierService (PackageName, UID) pair. */
+ @NonNull private List<Pair<String, Integer>> mCarrierServiceStates;
/**
* Support backward compatibility for {@link android.telephony.TelephonyDisplayInfo}.
@@ -705,6 +707,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
cutListToSize(mPhysicalChannelConfigs, mNumPhones);
cutListToSize(mLinkCapacityEstimateLists, mNumPhones);
cutListToSize(mCarrierPrivilegeStates, mNumPhones);
+ cutListToSize(mCarrierServiceStates, mNumPhones);
return;
}
@@ -746,6 +749,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
mAllowedNetworkTypeValue[i] = -1;
mLinkCapacityEstimateLists.add(i, INVALID_LCE_LIST);
mCarrierPrivilegeStates.add(i, new Pair<>(Collections.emptyList(), new int[0]));
+ mCarrierServiceStates.add(i, new Pair<>(null, Process.INVALID_UID));
}
}
}
@@ -813,6 +817,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
mDataEnabledReason = new int[numPhones];
mLinkCapacityEstimateLists = new ArrayList<>();
mCarrierPrivilegeStates = new ArrayList<>();
+ mCarrierServiceStates = new ArrayList<>();
for (int i = 0; i < numPhones; i++) {
mCallState[i] = TelephonyManager.CALL_STATE_IDLE;
@@ -851,6 +856,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
mAllowedNetworkTypeValue[i] = -1;
mLinkCapacityEstimateLists.add(i, INVALID_LCE_LIST);
mCarrierPrivilegeStates.add(i, new Pair<>(Collections.emptyList(), new int[0]));
+ mCarrierServiceStates.add(i, new Pair<>(null, Process.INVALID_UID));
}
mAppOps = mContext.getSystemService(AppOpsManager.class);
@@ -2013,10 +2019,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
return;
}
- ApnSetting apnSetting = preciseState.getApnSetting();
-
synchronized (mRecords) {
- if (validatePhoneId(phoneId)) {
+ if (validatePhoneId(phoneId) && preciseState.getApnSetting() != null) {
Pair<Integer, ApnSetting> key = Pair.create(preciseState.getTransportType(),
preciseState.getApnSetting());
PreciseDataConnectionState oldState = mPreciseDataConnectionStates.get(phoneId)
@@ -2786,16 +2790,16 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
@Override
- public void addCarrierPrivilegesListener(
+ public void addCarrierPrivilegesCallback(
int phoneId,
- ICarrierPrivilegesListener callback,
- String callingPackage,
- String callingFeatureId) {
+ @NonNull ICarrierPrivilegesCallback callback,
+ @NonNull String callingPackage,
+ @NonNull String callingFeatureId) {
int callerUserId = UserHandle.getCallingUserId();
mAppOps.checkPackage(Binder.getCallingUid(), callingPackage);
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
- "addCarrierPrivilegesListener");
+ "addCarrierPrivilegesCallback");
if (VDBG) {
log(
"listen carrier privs: E pkg=" + pii(callingPackage) + " phoneId=" + phoneId
@@ -2815,7 +2819,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
if (r == null) return;
r.context = mContext;
- r.carrierPrivilegesListener = callback;
+ r.carrierPrivilegesCallback = callback;
r.callingPackage = callingPackage;
r.callingFeatureId = callingFeatureId;
r.callerUid = Binder.getCallingUid();
@@ -2827,10 +2831,18 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
Pair<List<String>, int[]> state = mCarrierPrivilegeStates.get(phoneId);
+ Pair<String, Integer> carrierServiceState = mCarrierServiceStates.get(phoneId);
try {
- r.carrierPrivilegesListener.onCarrierPrivilegesChanged(
- Collections.unmodifiableList(state.first),
- Arrays.copyOf(state.second, state.second.length));
+ if (r.matchCarrierPrivilegesCallback()) {
+ // Here, two callbacks are triggered in quick succession on the same binder.
+ // In typical case, we expect the callers to care about only one or the other.
+ r.carrierPrivilegesCallback.onCarrierPrivilegesChanged(
+ Collections.unmodifiableList(state.first),
+ Arrays.copyOf(state.second, state.second.length));
+
+ r.carrierPrivilegesCallback.onCarrierServiceChanged(carrierServiceState.first,
+ carrierServiceState.second);
+ }
} catch (RemoteException ex) {
remove(r.binder);
}
@@ -2838,12 +2850,12 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
@Override
- public void removeCarrierPrivilegesListener(
- ICarrierPrivilegesListener callback, String callingPackage) {
+ public void removeCarrierPrivilegesCallback(
+ @NonNull ICarrierPrivilegesCallback callback, @NonNull String callingPackage) {
mAppOps.checkPackage(Binder.getCallingUid(), callingPackage);
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
- "removeCarrierPrivilegesListener");
+ "removeCarrierPrivilegesCallback");
remove(callback.asBinder());
}
@@ -2868,13 +2880,13 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
for (Record r : mRecords) {
// Listeners are per-slot, not per-subscription. This is to provide a stable
// view across SIM profile switches.
- if (!r.matchCarrierPrivilegesListener()
+ if (!r.matchCarrierPrivilegesCallback()
|| !idMatch(r, SubscriptionManager.INVALID_SUBSCRIPTION_ID, phoneId)) {
continue;
}
try {
// Make sure even in-process listeners can't modify the values.
- r.carrierPrivilegesListener.onCarrierPrivilegesChanged(
+ r.carrierPrivilegesCallback.onCarrierPrivilegesChanged(
Collections.unmodifiableList(privilegedPackageNames),
Arrays.copyOf(privilegedUids, privilegedUids.length));
} catch (RemoteException ex) {
@@ -2885,6 +2897,34 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
}
+ @Override
+ public void notifyCarrierServiceChanged(int phoneId, @Nullable String packageName, int uid) {
+ if (!checkNotifyPermission("notifyCarrierServiceChanged")) return;
+ if (!validatePhoneId(phoneId)) return;
+ if (VDBG) {
+ log("notifyCarrierServiceChanged: phoneId=" + phoneId
+ + ", package=" + pii(packageName) + ", uid=" + uid);
+ }
+
+ synchronized (mRecords) {
+ mCarrierServiceStates.set(
+ phoneId, new Pair<>(packageName, uid));
+ for (Record r : mRecords) {
+ // Listeners are per-slot, not per-subscription.
+ if (!r.matchCarrierPrivilegesCallback()
+ || !idMatch(r, SubscriptionManager.INVALID_SUBSCRIPTION_ID, phoneId)) {
+ continue;
+ }
+ try {
+ r.carrierPrivilegesCallback.onCarrierServiceChanged(packageName, uid);
+ } catch (RemoteException ex) {
+ mRemoveList.add(r.binder);
+ }
+ }
+ handleRemoveListLocked();
+ }
+ }
+
@NeverCompile // Avoid size overhead of debugging code.
@Override
public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
@@ -2940,6 +2980,9 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
pw.println(
"mCarrierPrivilegeState=<packages=" + pii(carrierPrivilegeState.first)
+ ", uids=" + Arrays.toString(carrierPrivilegeState.second) + ">");
+ Pair<String, Integer> carrierServiceState = mCarrierServiceStates.get(i);
+ pw.println("mCarrierServiceState=<package=" + pii(carrierServiceState.first)
+ + ", uid=" + carrierServiceState.second + ">");
pw.decreaseIndent();
}
diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java
index 569d4809a541..2dfe94729bb8 100644
--- a/services/core/java/com/android/server/UiModeManagerService.java
+++ b/services/core/java/com/android/server/UiModeManagerService.java
@@ -1302,7 +1302,7 @@ final class UiModeManagerService extends SystemService {
pw.print(" mLastBroadcastState="); pw.println(mLastBroadcastState);
pw.print(" mNightMode="); pw.print(mNightMode); pw.print(" (");
- pw.print(Shell.nightModeToStr(mNightMode)); pw.print(") ");
+ pw.print(Shell.nightModeToStr(mNightMode, mNightModeCustomType)); pw.print(") ");
pw.print(" mOverrideOn/Off="); pw.print(mOverrideNightModeOn);
pw.print("/"); pw.print(mOverrideNightModeOff);
@@ -1917,7 +1917,8 @@ final class UiModeManagerService extends SystemService {
public static final String NIGHT_MODE_STR_YES = "yes";
public static final String NIGHT_MODE_STR_NO = "no";
public static final String NIGHT_MODE_STR_AUTO = "auto";
- public static final String NIGHT_MODE_STR_CUSTOM = "custom";
+ public static final String NIGHT_MODE_STR_CUSTOM_SCHEDULE = "custom_schedule";
+ public static final String NIGHT_MODE_STR_CUSTOM_BEDTIME = "custom_bedtime";
public static final String NIGHT_MODE_STR_UNKNOWN = "unknown";
private final IUiModeManager mInterface;
@@ -1931,7 +1932,7 @@ final class UiModeManagerService extends SystemService {
pw.println("UiModeManager service (uimode) commands:");
pw.println(" help");
pw.println(" Print this help text.");
- pw.println(" night [yes|no|auto|custom]");
+ pw.println(" night [yes|no|auto|custom_schedule|custom_bedtime]");
pw.println(" Set or read night mode.");
pw.println(" car [yes|no]");
pw.println(" Set or read car mode.");
@@ -2001,14 +2002,19 @@ final class UiModeManagerService extends SystemService {
}
final int mode = strToNightMode(modeStr);
+ final int customType = strToNightModeCustomType(modeStr);
if (mode >= 0) {
mInterface.setNightMode(mode);
+ if (mode == UiModeManager.MODE_NIGHT_CUSTOM) {
+ mInterface.setNightModeCustomType(customType);
+ }
printCurrentNightMode();
return 0;
} else {
err.println("Error: mode must be '" + NIGHT_MODE_STR_YES + "', '"
+ NIGHT_MODE_STR_NO + "', or '" + NIGHT_MODE_STR_AUTO
- + "', or '" + NIGHT_MODE_STR_CUSTOM + "'");
+ + "', or '" + NIGHT_MODE_STR_CUSTOM_SCHEDULE + "', or '"
+ + NIGHT_MODE_STR_CUSTOM_BEDTIME + "'");
return -1;
}
}
@@ -2016,11 +2022,12 @@ final class UiModeManagerService extends SystemService {
private void printCurrentNightMode() throws RemoteException {
final PrintWriter pw = getOutPrintWriter();
final int currMode = mInterface.getNightMode();
- final String currModeStr = nightModeToStr(currMode);
+ final int customType = mInterface.getNightModeCustomType();
+ final String currModeStr = nightModeToStr(currMode, customType);
pw.println("Night mode: " + currModeStr);
}
- private static String nightModeToStr(int mode) {
+ private static String nightModeToStr(int mode, int customType) {
switch (mode) {
case UiModeManager.MODE_NIGHT_YES:
return NIGHT_MODE_STR_YES;
@@ -2029,7 +2036,12 @@ final class UiModeManagerService extends SystemService {
case UiModeManager.MODE_NIGHT_AUTO:
return NIGHT_MODE_STR_AUTO;
case MODE_NIGHT_CUSTOM:
- return NIGHT_MODE_STR_CUSTOM;
+ if (customType == UiModeManager.MODE_NIGHT_CUSTOM_TYPE_SCHEDULE) {
+ return NIGHT_MODE_STR_CUSTOM_SCHEDULE;
+ }
+ if (customType == UiModeManager.MODE_NIGHT_CUSTOM_TYPE_BEDTIME) {
+ return NIGHT_MODE_STR_CUSTOM_BEDTIME;
+ }
default:
return NIGHT_MODE_STR_UNKNOWN;
}
@@ -2043,13 +2055,25 @@ final class UiModeManagerService extends SystemService {
return UiModeManager.MODE_NIGHT_NO;
case NIGHT_MODE_STR_AUTO:
return UiModeManager.MODE_NIGHT_AUTO;
- case NIGHT_MODE_STR_CUSTOM:
+ case NIGHT_MODE_STR_CUSTOM_SCHEDULE:
+ case NIGHT_MODE_STR_CUSTOM_BEDTIME:
return UiModeManager.MODE_NIGHT_CUSTOM;
default:
return -1;
}
}
+ private static int strToNightModeCustomType(String customTypeStr) {
+ switch (customTypeStr) {
+ case NIGHT_MODE_STR_CUSTOM_BEDTIME:
+ return UiModeManager.MODE_NIGHT_CUSTOM_TYPE_BEDTIME;
+ case NIGHT_MODE_STR_CUSTOM_SCHEDULE:
+ return UiModeManager.MODE_NIGHT_CUSTOM_TYPE_SCHEDULE;
+ default:
+ return -1;
+ }
+ }
+
private int handleCarMode() throws RemoteException {
final PrintWriter err = getErrPrintWriter();
final String modeStr = getNextArg();
diff --git a/services/core/java/com/android/server/VpnManagerService.java b/services/core/java/com/android/server/VpnManagerService.java
index 7b8cce54c8a7..c1d8e7bf3dc0 100644
--- a/services/core/java/com/android/server/VpnManagerService.java
+++ b/services/core/java/com/android/server/VpnManagerService.java
@@ -37,6 +37,7 @@ import android.net.NetworkStack;
import android.net.UnderlyingNetworkInfo;
import android.net.Uri;
import android.net.VpnManager;
+import android.net.VpnProfileState;
import android.net.VpnService;
import android.net.util.NetdService;
import android.os.Binder;
@@ -374,6 +375,24 @@ public class VpnManagerService extends IVpnManager.Stub {
}
/**
+ * Retrieve the VpnProfileState for the profile provisioned by the given package.
+ *
+ * @return the VpnProfileState with current information, or null if there was no profile
+ * provisioned by the given package.
+ * @hide
+ */
+ @Override
+ @Nullable
+ public VpnProfileState getProvisionedVpnProfileState(@NonNull String packageName) {
+ final int callingUid = Binder.getCallingUid();
+ verifyCallingUidAndPackage(packageName, callingUid);
+ final int user = UserHandle.getUserId(callingUid);
+ synchronized (mVpns) {
+ return mVpns.get(user).getProvisionedVpnProfileState(packageName);
+ }
+ }
+
+ /**
* Start legacy VPN, controlling native daemons as needed. Creates a
* secondary thread to perform connection work, returning quickly.
*
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index d4ad718fbe73..b0ab5390724b 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -2722,7 +2722,7 @@ public final class ActiveServices {
int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
String resolvedType, final IServiceConnection connection, int flags,
String instanceName, boolean isSdkSandboxService, int sdkSandboxClientAppUid,
- String callingPackage, final int userId)
+ String sdkSandboxClientAppPackage, String callingPackage, final int userId)
throws TransactionTooLargeException {
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "bindService: " + service
+ " type=" + resolvedType + " conn=" + connection.asBinder()
@@ -2807,8 +2807,9 @@ public final class ActiveServices {
final boolean allowInstant = (flags & Context.BIND_ALLOW_INSTANT) != 0;
ServiceLookupResult res = retrieveServiceLocked(service, instanceName,
- isSdkSandboxService, sdkSandboxClientAppUid, resolvedType, callingPackage,
- callingPid, callingUid, userId, true, callerFg, isBindExternal, allowInstant);
+ isSdkSandboxService, sdkSandboxClientAppUid, sdkSandboxClientAppPackage,
+ resolvedType, callingPackage, callingPid, callingUid, userId, true, callerFg,
+ isBindExternal, allowInstant);
if (res == null) {
return 0;
}
@@ -3228,14 +3229,14 @@ public final class ActiveServices {
int callingPid, int callingUid, int userId,
boolean createIfNeeded, boolean callingFromFg, boolean isBindExternal,
boolean allowInstant) {
- return retrieveServiceLocked(service, instanceName, false, 0, resolvedType, callingPackage,
- callingPid, callingUid, userId, createIfNeeded, callingFromFg, isBindExternal,
- allowInstant);
+ return retrieveServiceLocked(service, instanceName, false, 0, null, resolvedType,
+ callingPackage, callingPid, callingUid, userId, createIfNeeded, callingFromFg,
+ isBindExternal, allowInstant);
}
private ServiceLookupResult retrieveServiceLocked(Intent service,
String instanceName, boolean isSdkSandboxService, int sdkSandboxClientAppUid,
- String resolvedType,
+ String sdkSandboxClientAppPackage, String resolvedType,
String callingPackage, int callingPid, int callingUid, int userId,
boolean createIfNeeded, boolean callingFromFg, boolean isBindExternal,
boolean allowInstant) {
@@ -3416,7 +3417,8 @@ public final class ActiveServices {
: null;
r = new ServiceRecord(mAm, className, name, definingPackageName,
definingUid, filter, sInfo, callingFromFg, res,
- sdkSandboxProcessName, sdkSandboxClientAppUid);
+ sdkSandboxProcessName, sdkSandboxClientAppUid,
+ sdkSandboxClientAppPackage);
res.setService(r);
smap.mServicesByInstanceName.put(name, r);
smap.mServicesByIntent.put(filter, r);
@@ -3799,6 +3801,18 @@ public final class ActiveServices {
@GuardedBy("mAm")
void performScheduleRestartLocked(ServiceRecord r, @NonNull String scheduling,
@NonNull String reason, @UptimeMillisLong long now) {
+
+ // If the service is waiting to become a foreground service, remove the pending
+ // SERVICE_FOREGROUND_TIMEOUT_MSG msg, and set fgWaiting to false, so next time the service
+ // is brought up, scheduleServiceForegroundTransitionTimeoutLocked() can be called again and
+ // a new SERVICE_FOREGROUND_TIMEOUT_MSG is scheduled in SERVICE_START_FOREGROUND_TIMEOUT
+ // again.
+ if (r.fgRequired && r.fgWaiting) {
+ mAm.mHandler.removeMessages(
+ ActivityManagerService.SERVICE_FOREGROUND_TIMEOUT_MSG, r);
+ r.fgWaiting = false;
+ }
+
mAm.mHandler.removeCallbacks(r.restarter);
mAm.mHandler.postAtTime(r.restarter, r.nextRestartTime);
r.nextRestartTime = now + r.restartDelay;
@@ -4195,7 +4209,7 @@ public final class ActiveServices {
if (r.isSdkSandbox) {
final int uid = Process.toSdkSandboxUid(r.sdkSandboxClientAppUid);
app = mAm.startSdkSandboxProcessLocked(procName, r.appInfo, true, intentFlags,
- hostingRecord, ZYGOTE_POLICY_FLAG_EMPTY, uid);
+ hostingRecord, ZYGOTE_POLICY_FLAG_EMPTY, uid, r.sdkSandboxClientAppPackage);
r.isolationHostProc = app;
} else {
app = mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
@@ -5676,7 +5690,7 @@ public final class ActiveServices {
void serviceForegroundTimeout(ServiceRecord r) {
ProcessRecord app;
synchronized (mAm) {
- if (!r.fgRequired || r.destroying) {
+ if (!r.fgRequired || !r.fgWaiting || r.destroying) {
return;
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
index 5fe87199f1b8..cc8c6fb6c23a 100644
--- a/services/core/java/com/android/server/am/ActivityManagerConstants.java
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -127,7 +127,15 @@ final class ActivityManagerConstants extends ContentObserver {
static final String KEY_KILL_BG_RESTRICTED_CACHED_IDLE = "kill_bg_restricted_cached_idle";
static final String KEY_KILL_BG_RESTRICTED_CACHED_IDLE_SETTLE_TIME =
"kill_bg_restricted_cached_idle_settle_time";
+ /**
+ * Note this key is on {@link DeviceConfig#NAMESPACE_ACTIVITY_MANAGER_COMPONENT_ALIAS}.
+ * @see #mEnableComponentAlias
+ */
static final String KEY_ENABLE_COMPONENT_ALIAS = "enable_experimental_component_alias";
+ /**
+ * Note this key is on {@link DeviceConfig#NAMESPACE_ACTIVITY_MANAGER_COMPONENT_ALIAS}.
+ * @see #mComponentAliasOverrides
+ */
static final String KEY_COMPONENT_ALIAS_OVERRIDES = "component_alias_overrides";
private static final int DEFAULT_MAX_CACHED_PROCESSES = 32;
@@ -650,6 +658,38 @@ final class ActivityManagerConstants extends ContentObserver {
// initialized in the constructor.
public int CUR_MAX_EMPTY_PROCESSES;
+
+ /** @see #mNoKillCachedProcessesUntilBootCompleted */
+ private static final String KEY_NO_KILL_CACHED_PROCESSES_UNTIL_BOOT_COMPLETED =
+ "no_kill_cached_processes_until_boot_completed";
+
+ /** @see #mNoKillCachedProcessesPostBootCompletedDurationMillis */
+ private static final String KEY_NO_KILL_CACHED_PROCESSES_POST_BOOT_COMPLETED_DURATION_MILLIS =
+ "no_kill_cached_processes_post_boot_completed_duration_millis";
+
+ /** @see #mNoKillCachedProcessesUntilBootCompleted */
+ private static final boolean DEFAULT_NO_KILL_CACHED_PROCESSES_UNTIL_BOOT_COMPLETED = true;
+
+ /** @see #mNoKillCachedProcessesPostBootCompletedDurationMillis */
+ private static final long
+ DEFAULT_NO_KILL_CACHED_PROCESSES_POST_BOOT_COMPLETED_DURATION_MILLIS = 600_000;
+
+ /**
+ * If true, do not kill excessive cached processes proactively, until user-0 is unlocked.
+ * @see #mNoKillCachedProcessesPostBootCompletedDurationMillis
+ */
+ volatile boolean mNoKillCachedProcessesUntilBootCompleted =
+ DEFAULT_NO_KILL_CACHED_PROCESSES_UNTIL_BOOT_COMPLETED;
+
+ /**
+ * Do not kill excessive cached processes proactively, for this duration after each user is
+ * unlocked.
+ * Note we don't proactively kill extra cached processes after this. The next oomadjuster pass
+ * will naturally do it.
+ */
+ volatile long mNoKillCachedProcessesPostBootCompletedDurationMillis =
+ DEFAULT_NO_KILL_CACHED_PROCESSES_POST_BOOT_COMPLETED_DURATION_MILLIS;
+
// The number of empty apps at which we don't consider it necessary to do
// memory trimming.
public int CUR_TRIM_EMPTY_PROCESSES = computeEmptyProcessLimit(MAX_CACHED_PROCESSES) / 2;
@@ -659,6 +699,14 @@ final class ActivityManagerConstants extends ContentObserver {
public int CUR_TRIM_CACHED_PROCESSES =
(MAX_CACHED_PROCESSES - computeEmptyProcessLimit(MAX_CACHED_PROCESSES)) / 3;
+ /** @see #mNoKillCachedProcessesUntilBootCompleted */
+ private static final String KEY_MAX_EMPTY_TIME_MILLIS =
+ "max_empty_time_millis";
+
+ private static final long DEFAULT_MAX_EMPTY_TIME_MILLIS = 30 * 60 * 1000;
+
+ volatile long mMaxEmptyTimeMillis = DEFAULT_MAX_EMPTY_TIME_MILLIS;
+
/**
* Packages that can't be killed even if it's requested to be killed on imperceptible.
*/
@@ -859,16 +907,41 @@ final class ActivityManagerConstants extends ContentObserver {
case KEY_ENABLE_EXTRA_SERVICE_RESTART_DELAY_ON_MEM_PRESSURE:
updateEnableExtraServiceRestartDelayOnMemPressure();
break;
- case KEY_ENABLE_COMPONENT_ALIAS:
- case KEY_COMPONENT_ALIAS_OVERRIDES:
- updateComponentAliases();
- break;
case KEY_PROCESS_KILL_TIMEOUT:
updateProcessKillTimeout();
break;
case KEY_DEFER_BOOT_COMPLETED_BROADCAST:
updateDeferBootCompletedBroadcast();
break;
+ case KEY_NO_KILL_CACHED_PROCESSES_UNTIL_BOOT_COMPLETED:
+ updateNoKillCachedProcessesUntilBootCompleted();
+ break;
+ case KEY_NO_KILL_CACHED_PROCESSES_POST_BOOT_COMPLETED_DURATION_MILLIS:
+ updateNoKillCachedProcessesPostBootCompletedDurationMillis();
+ break;
+ case KEY_MAX_EMPTY_TIME_MILLIS:
+ updateMaxEmptyTimeMillis();
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ };
+
+ private final OnPropertiesChangedListener mOnDeviceConfigChangedForComponentAliasListener =
+ new OnPropertiesChangedListener() {
+ @Override
+ public void onPropertiesChanged(Properties properties) {
+ for (String name : properties.getKeyset()) {
+ if (name == null) {
+ return;
+ }
+ switch (name) {
+ case KEY_ENABLE_COMPONENT_ALIAS:
+ case KEY_COMPONENT_ALIAS_OVERRIDES:
+ updateComponentAliases();
+ break;
default:
break;
}
@@ -942,6 +1015,10 @@ final class ActivityManagerConstants extends ContentObserver {
DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
ActivityThread.currentApplication().getMainExecutor(),
mOnDeviceConfigChangedListener);
+ DeviceConfig.addOnPropertiesChangedListener(
+ DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_COMPONENT_ALIAS,
+ ActivityThread.currentApplication().getMainExecutor(),
+ mOnDeviceConfigChangedForComponentAliasListener);
loadDeviceConfigConstants();
// The following read from Settings.
updateActivityStartsLoggingEnabled();
@@ -951,6 +1028,9 @@ final class ActivityManagerConstants extends ContentObserver {
private void loadDeviceConfigConstants() {
mOnDeviceConfigChangedListener.onPropertiesChanged(
DeviceConfig.getProperties(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER));
+ mOnDeviceConfigChangedForComponentAliasListener.onPropertiesChanged(
+ DeviceConfig.getProperties(
+ DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_COMPONENT_ALIAS));
}
public void setOverrideMaxCachedProcesses(int value) {
@@ -1288,6 +1368,27 @@ final class ActivityManagerConstants extends ContentObserver {
DEFAULT_DEFER_BOOT_COMPLETED_BROADCAST);
}
+ private void updateNoKillCachedProcessesUntilBootCompleted() {
+ mNoKillCachedProcessesUntilBootCompleted = DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ KEY_NO_KILL_CACHED_PROCESSES_UNTIL_BOOT_COMPLETED,
+ DEFAULT_NO_KILL_CACHED_PROCESSES_UNTIL_BOOT_COMPLETED);
+ }
+
+ private void updateNoKillCachedProcessesPostBootCompletedDurationMillis() {
+ mNoKillCachedProcessesPostBootCompletedDurationMillis = DeviceConfig.getLong(
+ DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ KEY_NO_KILL_CACHED_PROCESSES_POST_BOOT_COMPLETED_DURATION_MILLIS,
+ DEFAULT_NO_KILL_CACHED_PROCESSES_POST_BOOT_COMPLETED_DURATION_MILLIS);
+ }
+
+ private void updateMaxEmptyTimeMillis() {
+ mMaxEmptyTimeMillis = DeviceConfig.getLong(
+ DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ KEY_MAX_EMPTY_TIME_MILLIS,
+ DEFAULT_MAX_EMPTY_TIME_MILLIS);
+ }
+
private long[] parseLongArray(@NonNull String key, @NonNull long[] def) {
final String val = DeviceConfig.getString(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
key, null);
@@ -1309,11 +1410,11 @@ final class ActivityManagerConstants extends ContentObserver {
private void updateComponentAliases() {
mEnableComponentAlias = DeviceConfig.getBoolean(
- DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_COMPONENT_ALIAS,
KEY_ENABLE_COMPONENT_ALIAS,
DEFAULT_ENABLE_COMPONENT_ALIAS);
mComponentAliasOverrides = DeviceConfig.getString(
- DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_COMPONENT_ALIAS,
KEY_COMPONENT_ALIAS_OVERRIDES,
DEFAULT_COMPONENT_ALIAS_OVERRIDES);
mService.mComponentAliasResolver.update(mEnableComponentAlias, mComponentAliasOverrides);
@@ -1562,6 +1663,12 @@ final class ActivityManagerConstants extends ContentObserver {
pw.print("="); pw.println(mComponentAliasOverrides);
pw.print(" "); pw.print(KEY_DEFER_BOOT_COMPLETED_BROADCAST);
pw.print("="); pw.println(mDeferBootCompletedBroadcast);
+ pw.print(" "); pw.print(KEY_NO_KILL_CACHED_PROCESSES_UNTIL_BOOT_COMPLETED);
+ pw.print("="); pw.println(mNoKillCachedProcessesUntilBootCompleted);
+ pw.print(" "); pw.print(KEY_NO_KILL_CACHED_PROCESSES_POST_BOOT_COMPLETED_DURATION_MILLIS);
+ pw.print("="); pw.println(mNoKillCachedProcessesPostBootCompletedDurationMillis);
+ pw.print(" "); pw.print(KEY_MAX_EMPTY_TIME_MILLIS);
+ pw.print("="); pw.println(mMaxEmptyTimeMillis);
pw.println();
if (mOverrideMaxCachedProcesses >= 0) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerLocal.java b/services/core/java/com/android/server/am/ActivityManagerLocal.java
index 3226a2b58a96..1d2c36b63bda 100644
--- a/services/core/java/com/android/server/am/ActivityManagerLocal.java
+++ b/services/core/java/com/android/server/am/ActivityManagerLocal.java
@@ -74,6 +74,8 @@ public interface ActivityManagerLocal {
* @param conn Receives information as the service is started and stopped.
* This must be a valid ServiceConnection object; it must not be null.
* @param clientAppUid Uid of the app for which the sdk sandbox process needs to be spawned.
+ * @param clientAppPackage Package of the app for which the sdk sandbox process needs to
+ * be spawned. This package must belong to the clientAppUid.
* @param processName Unique identifier for the service instance. Each unique name here will
* result in a different service instance being created. Identifiers must only contain
* ASCII letters, digits, underscores, and periods.
@@ -87,6 +89,7 @@ public interface ActivityManagerLocal {
*/
@SuppressLint("RethrowRemoteException")
boolean bindSdkSandboxService(@NonNull Intent service, @NonNull ServiceConnection conn,
- int clientAppUid, @NonNull String processName, @Context.BindServiceFlags int flags)
+ int clientAppUid, @NonNull String clientAppPackage, @NonNull String processName,
+ @Context.BindServiceFlags int flags)
throws RemoteException;
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 47f9fd535801..36fdb9d40e8e 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -36,6 +36,7 @@ import static android.app.ActivityManager.PROCESS_STATE_TOP;
import static android.app.ActivityManager.StopUserOnSwitch;
import static android.app.ActivityManagerInternal.ALLOW_FULL_ONLY;
import static android.app.ActivityManagerInternal.ALLOW_NON_FULL;
+import static android.app.AppOpsManager.MODE_ALLOWED;
import static android.app.AppOpsManager.OP_NONE;
import static android.content.pm.ApplicationInfo.HIDDEN_API_ENFORCEMENT_DEFAULT;
import static android.content.pm.PackageManager.GET_SHARED_LIBRARY_FILES;
@@ -79,6 +80,7 @@ import static android.os.Process.ZYGOTE_POLICY_FLAG_LATENCY_SENSITIVE;
import static android.os.Process.ZYGOTE_POLICY_FLAG_SYSTEM_PROCESS;
import static android.os.Process.ZYGOTE_PROCESS;
import static android.os.Process.getTotalMemory;
+import static android.os.Process.isSdkSandboxUid;
import static android.os.Process.isThreadInProcess;
import static android.os.Process.killProcess;
import static android.os.Process.killProcessQuiet;
@@ -404,6 +406,7 @@ import com.android.server.pm.permission.PermissionManagerServiceInternal;
import com.android.server.pm.pkg.SELinuxUtil;
import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
import com.android.server.pm.snapshot.PackageDataSnapshot;
+import com.android.server.sdksandbox.SdkSandboxManagerLocal;
import com.android.server.uri.GrantUri;
import com.android.server.uri.NeededUriGrants;
import com.android.server.uri.UriGrantsManagerInternal;
@@ -1894,6 +1897,7 @@ public class ActivityManagerService extends IActivityManager.Stub
0,
false,
0,
+ null,
new HostingRecord("system"));
app.setPersistent(true);
app.setPid(MY_PID);
@@ -2782,7 +2786,8 @@ public class ActivityManagerService extends IActivityManager.Stub
false /* knownToBeDead */, 0 /* intentFlags */,
sNullHostingRecord /* hostingRecord */, ZYGOTE_POLICY_FLAG_EMPTY,
true /* allowWhileBooting */, true /* isolated */,
- uid, false /* supplemental */, 0 /* supplementalUid */,
+ uid, false /* isSdkSandbox */, 0 /* sdkSandboxUid */,
+ null /* sdkSandboxClientAppPackage */,
abiOverride, entryPoint, entryPointArgs, crashHandler);
return proc != null;
}
@@ -2791,11 +2796,12 @@ public class ActivityManagerService extends IActivityManager.Stub
@GuardedBy("this")
final ProcessRecord startSdkSandboxProcessLocked(String processName,
ApplicationInfo info, boolean knownToBeDead, int intentFlags,
- HostingRecord hostingRecord, int zygotePolicyFlags, int sdkSandboxUid) {
+ HostingRecord hostingRecord, int zygotePolicyFlags, int sdkSandboxUid,
+ String sdkSandboxClientAppPackage) {
return mProcessList.startProcessLocked(processName, info, knownToBeDead, intentFlags,
hostingRecord, zygotePolicyFlags, false /* allowWhileBooting */,
false /* isolated */, 0 /* isolatedUid */,
- true /* isSdkSandbox */, sdkSandboxUid,
+ true /* isSdkSandbox */, sdkSandboxUid, sdkSandboxClientAppPackage,
null /* ABI override */, null /* entryPoint */,
null /* entryPointArgs */, null /* crashHandler */);
}
@@ -2807,7 +2813,8 @@ public class ActivityManagerService extends IActivityManager.Stub
boolean isolated) {
return mProcessList.startProcessLocked(processName, info, knownToBeDead, intentFlags,
hostingRecord, zygotePolicyFlags, allowWhileBooting, isolated, 0 /* isolatedUid */,
- false /* isSdkSandbox */, 0 /* sdkSandboxClientdAppUid */,
+ false /* isSdkSandbox */, 0 /* sdkSandboxClientAppUid */,
+ null /* sdkSandboxClientAppPackage */,
null /* ABI override */, null /* entryPoint */,
null /* entryPointArgs */, null /* crashHandler */);
}
@@ -2905,12 +2912,35 @@ public class ActivityManagerService extends IActivityManager.Stub
return mAtmInternal.compatibilityInfoForPackage(ai);
}
+ /**
+ * Enforces that the uid that calls a method is not an
+ * {@link UserHandle#isIsolated(int) isolated} uid.
+ *
+ * @param caller the name of the method being called.
+ * @throws SecurityException if the calling uid is an isolated uid.
+ */
/* package */ void enforceNotIsolatedCaller(String caller) {
if (UserHandle.isIsolated(Binder.getCallingUid())) {
throw new SecurityException("Isolated process not allowed to call " + caller);
}
}
+ /**
+ * Enforces that the uid that calls a method is not an
+ * {@link UserHandle#isIsolated(int) isolated} uid or an
+ * {@link Process#isSdkSandboxUid(int) SDK sandbox} uid.
+ *
+ * @param caller the name of the method being called.
+ * @throws SecurityException if the calling uid is an isolated uid or SDK sandbox uid.
+ */
+ void enforceNotIsolatedOrSdkSandboxCaller(String caller) {
+ enforceNotIsolatedCaller(caller);
+
+ if (Process.isSdkSandboxUid(Binder.getCallingUid())) {
+ throw new SecurityException("SDK sandbox process not allowed to call " + caller);
+ }
+ }
+
@Override
public void setPackageScreenCompatMode(String packageName, int mode) {
mActivityTaskManager.setPackageScreenCompatMode(packageName, mode);
@@ -3779,7 +3809,7 @@ public class ActivityManagerService extends IActivityManager.Stub
synchronized (mProcLock) {
mProcessList.killPackageProcessesLSP(packageName, appId, targetUserId,
ProcessList.SERVICE_ADJ, ApplicationExitInfo.REASON_USER_REQUESTED,
- ApplicationExitInfo.SUBREASON_UNKNOWN, "kill background");
+ ApplicationExitInfo.SUBREASON_KILL_BACKGROUND, "kill background");
}
}
}
@@ -3809,7 +3839,7 @@ public class ActivityManagerService extends IActivityManager.Stub
mProcessList.killPackageProcessesLSP(null /* packageName */, -1 /* appId */,
UserHandle.USER_ALL, ProcessList.CACHED_APP_MIN_ADJ,
ApplicationExitInfo.REASON_USER_REQUESTED,
- ApplicationExitInfo.SUBREASON_UNKNOWN,
+ ApplicationExitInfo.SUBREASON_KILL_BACKGROUND,
"kill all background");
}
@@ -4351,7 +4381,7 @@ public class ActivityManagerService extends IActivityManager.Stub
ProcessList.INVALID_ADJ, true, false, true,
false, true /* setRemoved */, false,
ApplicationExitInfo.REASON_USER_REQUESTED,
- ApplicationExitInfo.SUBREASON_UNKNOWN,
+ ApplicationExitInfo.SUBREASON_STOP_APP,
"fully stop " + packageName + "/" + userId + " by user request");
}
@@ -4403,7 +4433,7 @@ public class ActivityManagerService extends IActivityManager.Stub
evenPersistent, true /* setRemoved */, uninstalling,
packageName == null ? ApplicationExitInfo.REASON_USER_STOPPED
: ApplicationExitInfo.REASON_USER_REQUESTED,
- ApplicationExitInfo.SUBREASON_UNKNOWN,
+ ApplicationExitInfo.SUBREASON_FORCE_STOP,
(packageName == null ? ("stop user " + userId) : ("stop " + packageName))
+ " due to " + reason);
}
@@ -4772,7 +4802,8 @@ public class ActivityManagerService extends IActivityManager.Stub
thread.runIsolatedEntryPoint(
app.getIsolatedEntryPoint(), app.getIsolatedEntryPointArgs());
} else if (instr2 != null) {
- thread.bindApplication(processName, appInfo, providerList,
+ thread.bindApplication(processName, appInfo, app.sdkSandboxClientAppPackage,
+ providerList,
instr2.mClass,
profilerInfo, instr2.mArguments,
instr2.mWatcher,
@@ -4786,8 +4817,8 @@ public class ActivityManagerService extends IActivityManager.Stub
app.getDisabledCompatChanges(), serializedSystemFontMap,
app.getStartElapsedTime(), app.getStartUptime());
} else {
- thread.bindApplication(processName, appInfo, providerList, null, profilerInfo,
- null, null, null, testMode,
+ thread.bindApplication(processName, appInfo, app.sdkSandboxClientAppPackage,
+ providerList, null, profilerInfo, null, null, null, testMode,
mBinderTransactionTrackingEnabled, enableTrackAllocation,
isRestrictedBackupMode || !normalMode, app.isPersistent(),
new Configuration(app.getWindowProcessController().getConfiguration()),
@@ -5748,6 +5779,18 @@ public class ActivityManagerService extends IActivityManager.Stub
owningUid, exported);
}
+ private void enforceDebuggable(ProcessRecord proc) {
+ if (!Build.IS_DEBUGGABLE && !proc.isDebuggable()) {
+ throw new SecurityException("Process not debuggable: " + proc.info.packageName);
+ }
+ }
+
+ private void enforceDebuggable(ApplicationInfo info) {
+ if (!Build.IS_DEBUGGABLE && (info.flags & ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
+ throw new SecurityException("Process not debuggable: " + info.packageName);
+ }
+ }
+
/**
* As the only public entry point for permissions checking, this method
* can enforce the semantic that requesting a check on a null global
@@ -6542,6 +6585,30 @@ public class ActivityManagerService extends IActivityManager.Stub
final ProcessRecord addAppLocked(ApplicationInfo info, String customProcess, boolean isolated,
boolean disableHiddenApiChecks, boolean disableTestApiChecks,
String abiOverride, int zygotePolicyFlags) {
+ return addAppLocked(
+ info,
+ customProcess,
+ isolated,
+ /* isSdkSandbox= */ false,
+ /* sdkSandboxUid= */ 0,
+ /* sdkSandboxClientAppPackage= */ null,
+ disableHiddenApiChecks,
+ disableTestApiChecks,
+ abiOverride,
+ zygotePolicyFlags);
+ }
+
+ final ProcessRecord addAppLocked(
+ ApplicationInfo info,
+ String customProcess,
+ boolean isolated,
+ boolean isSdkSandbox,
+ int sdkSandboxUid,
+ @Nullable String sdkSandboxClientAppPackage,
+ boolean disableHiddenApiChecks,
+ boolean disableTestApiChecks,
+ String abiOverride,
+ int zygotePolicyFlags) {
ProcessRecord app;
if (!isolated) {
app = getProcessRecordLocked(customProcess != null ? customProcess : info.processName,
@@ -6551,10 +6618,16 @@ public class ActivityManagerService extends IActivityManager.Stub
}
if (app == null) {
- app = mProcessList.newProcessRecordLocked(info, customProcess, isolated, 0,
- false, 0,
+ app = mProcessList.newProcessRecordLocked(
+ info,
+ customProcess,
+ isolated,
+ /* isolatedUid= */0,
+ isSdkSandbox,
+ sdkSandboxUid,
+ sdkSandboxClientAppPackage,
new HostingRecord("added application",
- customProcess != null ? customProcess : info.processName));
+ customProcess != null ? customProcess : info.processName));
updateLruProcessLocked(app, false, null);
updateOomAdjLocked(app, OomAdjuster.OOM_ADJ_REASON_PROCESS_BEGIN);
}
@@ -6564,13 +6637,16 @@ public class ActivityManagerService extends IActivityManager.Stub
Event.APP_COMPONENT_USED);
// This package really, really can not be stopped.
- try {
- AppGlobals.getPackageManager().setPackageStoppedState(
- info.packageName, false, UserHandle.getUserId(app.uid));
- } catch (RemoteException e) {
- } catch (IllegalArgumentException e) {
- Slog.w(TAG, "Failed trying to unstop package "
- + info.packageName + ": " + e);
+ // TODO: how set package stopped state should work for sdk sandboxes?
+ if (!isSdkSandbox) {
+ try {
+ AppGlobals.getPackageManager().setPackageStoppedState(
+ info.packageName, false, UserHandle.getUserId(app.uid));
+ } catch (RemoteException e) {
+ } catch (IllegalArgumentException e) {
+ Slog.w(TAG, "Failed trying to unstop package "
+ + info.packageName + ": " + e);
+ }
}
if ((info.flags & PERSISTENT_MASK) == PERSISTENT_MASK) {
@@ -6785,22 +6861,25 @@ public class ActivityManagerService extends IActivityManager.Stub
}
void setTrackAllocationApp(ApplicationInfo app, String processName) {
- if (!Build.IS_DEBUGGABLE) {
- if ((app.flags & ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
- throw new SecurityException("Process not debuggable: " + app.packageName);
- }
- }
+ enforceDebuggable(app);
synchronized (mProcLock) {
mTrackAllocationApp = processName;
}
}
- void setProfileApp(ApplicationInfo app, String processName, ProfilerInfo profilerInfo) {
+ void setProfileApp(ApplicationInfo app, String processName, ProfilerInfo profilerInfo,
+ ApplicationInfo sdkSandboxClientApp) {
synchronized (mAppProfiler.mProfilerLock) {
if (!Build.IS_DEBUGGABLE) {
boolean isAppDebuggable = (app.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
boolean isAppProfileable = app.isProfileableByShell();
+
+ if (sdkSandboxClientApp != null) {
+ isAppDebuggable |=
+ (sdkSandboxClientApp.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
+ isAppProfileable |= sdkSandboxClientApp.isProfileableByShell();
+ }
if (!isAppDebuggable && !isAppProfileable) {
throw new SecurityException("Process not debuggable, "
+ "and not profileable by shell: " + app.packageName);
@@ -6811,11 +6890,7 @@ public class ActivityManagerService extends IActivityManager.Stub
}
void setNativeDebuggingAppLocked(ApplicationInfo app, String processName) {
- if (!Build.IS_DEBUGGABLE) {
- if ((app.flags & ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
- throw new SecurityException("Process not debuggable: " + app.packageName);
- }
- }
+ enforceDebuggable(app);
mNativeDebuggingApp = processName;
}
@@ -8561,6 +8636,9 @@ public class ActivityManagerService extends IActivityManager.Stub
if (process.info.isInstantApp()) {
sb.append("Instant-App: true\n");
}
+ if (isSdkSandboxUid(process.uid)) {
+ sb.append("SdkSandbox: true\n");
+ }
}
}
@@ -9165,6 +9243,10 @@ public class ActivityManagerService extends IActivityManager.Stub
mAppRestrictionController.dump(pw, "");
}
+ void dumpAppRestrictionController(ProtoOutputStream proto, int uid) {
+ mAppRestrictionController.dumpAsProto(proto, uid);
+ }
+
/**
* Wrapper function to print out debug data filtered by specified arguments.
*/
@@ -9277,6 +9359,29 @@ public class ActivityManagerService extends IActivityManager.Stub
mProcessList.writeProcessesToProtoLSP(proto, dumpPackage);
}
}
+ } else if ("app-restrictions".equals(cmd)) {
+ int uid = Process.INVALID_UID;
+ boolean error = false;
+ for (int i = 0; i < args.length; i++) {
+ if ("--uid".equals(args[i])) {
+ if (i + 1 < args.length) {
+ try {
+ uid = Integer.parseInt(args[i + 1]);
+ } catch (NumberFormatException e) {
+ error = true;
+ }
+ } else {
+ error = true;
+ }
+ break;
+ }
+ }
+ if (error) {
+ pw.println("Invalid --uid argument");
+ pw.println("Use -h for help.");
+ } else {
+ dumpAppRestrictionController(proto, uid);
+ }
} else {
// default option, dump everything, output is ActivityManagerServiceProto
synchronized (this) {
@@ -9752,7 +9857,7 @@ public class ActivityManagerService extends IActivityManager.Stub
if (info.deniedPermissions != null) {
for (int j = 0; j < info.deniedPermissions.size(); j++) {
pw.print(" deny: ");
- pw.println(info.deniedPermissions.valueAt(i));
+ pw.println(info.deniedPermissions.valueAt(j));
}
}
}
@@ -12391,13 +12496,13 @@ public class ActivityManagerService extends IActivityManager.Stub
String resolvedType, IServiceConnection connection, int flags, String instanceName,
String callingPackage, int userId) throws TransactionTooLargeException {
return bindServiceInstance(caller, token, service, resolvedType, connection, flags,
- instanceName, false, 0, callingPackage, userId);
+ instanceName, false, 0, null, callingPackage, userId);
}
private int bindServiceInstance(IApplicationThread caller, IBinder token, Intent service,
String resolvedType, IServiceConnection connection, int flags, String instanceName,
- boolean isSdkSandboxService, int sdkSandboxClientdAppUid, String callingPackage,
- int userId)
+ boolean isSdkSandboxService, int sdkSandboxClientAppUid,
+ String sdkSandboxClientAppPackage, String callingPackage, int userId)
throws TransactionTooLargeException {
enforceNotIsolatedCaller("bindService");
@@ -12434,8 +12539,8 @@ public class ActivityManagerService extends IActivityManager.Stub
}
synchronized (this) {
return mServices.bindServiceLocked(caller, token, service, resolvedType, connection,
- flags, instanceName, isSdkSandboxService, sdkSandboxClientdAppUid,
- callingPackage, userId);
+ flags, instanceName, isSdkSandboxService, sdkSandboxClientAppUid,
+ sdkSandboxClientAppPackage, callingPackage, userId);
}
} finally {
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
@@ -12822,7 +12927,7 @@ public class ActivityManagerService extends IActivityManager.Stub
public Intent registerReceiverWithFeature(IApplicationThread caller, String callerPackage,
String callerFeatureId, String receiverId, IIntentReceiver receiver,
IntentFilter filter, String permission, int userId, int flags) {
- enforceNotIsolatedCaller("registerReceiver");
+ enforceNotIsolatedOrSdkSandboxCaller("registerReceiver");
ArrayList<Intent> stickyIntents = null;
ProcessRecord callerApp = null;
final boolean visibleToInstantApps
@@ -13434,8 +13539,13 @@ public class ActivityManagerService extends IActivityManager.Stub
}
if (brOptions.getIdForResponseEvent() > 0) {
- enforceUsageStatsPermission(callerPackage, callingUid, callingPid,
- "recordResponseEventWhileInBackground()");
+ // STOPSHIP (206518114): Temporarily check for PACKAGE_USAGE_STATS permission as
+ // well until the clients switch to using the new permission.
+ if (checkPermission(android.Manifest.permission.ACCESS_BROADCAST_RESPONSE_STATS,
+ callingPid, callingUid) != PERMISSION_GRANTED) {
+ enforceUsageStatsPermission(callerPackage, callingUid, callingPid,
+ "recordResponseEventWhileInBackground()");
+ }
}
}
@@ -13632,7 +13742,7 @@ public class ActivityManagerService extends IActivityManager.Stub
UserHandle.getAppId(extraUid),
userId, ProcessList.INVALID_ADJ,
ApplicationExitInfo.REASON_USER_REQUESTED,
- ApplicationExitInfo.SUBREASON_UNKNOWN,
+ ApplicationExitInfo.SUBREASON_PACKAGE_UPDATE,
"change " + ssp);
}
}
@@ -14366,6 +14476,32 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
+ boolean disableHiddenApiChecks = ai.usesNonSdkApi()
+ || (flags & INSTR_FLAG_DISABLE_HIDDEN_API_CHECKS) != 0;
+ boolean disableTestApiChecks = disableHiddenApiChecks
+ || (flags & INSTR_FLAG_DISABLE_TEST_API_CHECKS) != 0;
+
+ if (disableHiddenApiChecks || disableTestApiChecks) {
+ enforceCallingPermission(android.Manifest.permission.DISABLE_HIDDEN_API_CHECKS,
+ "disable hidden API checks");
+ }
+
+ if ((flags & ActivityManager.INSTR_FLAG_INSTRUMENT_SDK_SANDBOX) != 0) {
+ return startInstrumentationOfSdkSandbox(
+ className,
+ profileFile,
+ arguments,
+ watcher,
+ uiAutomationConnection,
+ userId,
+ abiOverride,
+ ii,
+ ai,
+ noRestart,
+ disableHiddenApiChecks,
+ disableTestApiChecks);
+ }
+
ActiveInstrumentation activeInstr = new ActiveInstrumentation(this);
activeInstr.mClass = className;
String defProcess = ai.processName;;
@@ -14390,15 +14526,6 @@ public class ActivityManagerService extends IActivityManager.Stub
START_FOREGROUND_SERVICES_FROM_BACKGROUND, callingPid, callingUid)
== PackageManager.PERMISSION_GRANTED;
activeInstr.mNoRestart = noRestart;
- boolean disableHiddenApiChecks = ai.usesNonSdkApi()
- || (flags & INSTR_FLAG_DISABLE_HIDDEN_API_CHECKS) != 0;
- boolean disableTestApiChecks = disableHiddenApiChecks
- || (flags & INSTR_FLAG_DISABLE_TEST_API_CHECKS) != 0;
-
- if (disableHiddenApiChecks || disableTestApiChecks) {
- enforceCallingPermission(android.Manifest.permission.DISABLE_HIDDEN_API_CHECKS,
- "disable hidden API checks");
- }
final long origId = Binder.clearCallingIdentity();
@@ -14444,6 +14571,111 @@ public class ActivityManagerService extends IActivityManager.Stub
return true;
}
+ @GuardedBy("this")
+ private boolean startInstrumentationOfSdkSandbox(
+ ComponentName className,
+ String profileFile,
+ Bundle arguments,
+ IInstrumentationWatcher watcher,
+ IUiAutomationConnection uiAutomationConnection,
+ int userId,
+ String abiOverride,
+ InstrumentationInfo instrumentationInfo,
+ ApplicationInfo sdkSandboxClientAppInfo,
+ boolean noRestart,
+ boolean disableHiddenApiChecks,
+ boolean disableTestApiChecks) {
+
+ if (noRestart) {
+ reportStartInstrumentationFailureLocked(
+ watcher,
+ className,
+ "Instrumenting sdk sandbox with --no-restart flag is not supported");
+ return false;
+ }
+
+ final ApplicationInfo sdkSandboxInfo;
+ try {
+ final PackageManager pm = mContext.getPackageManager();
+ sdkSandboxInfo = pm.getApplicationInfoAsUser(pm.getSdkSandboxPackageName(), 0, userId);
+ } catch (NameNotFoundException e) {
+ reportStartInstrumentationFailureLocked(
+ watcher, className, "Can't find SdkSandbox package");
+ return false;
+ }
+
+ final SdkSandboxManagerLocal sandboxManagerLocal =
+ LocalManagerRegistry.getManager(SdkSandboxManagerLocal.class);
+ if (sandboxManagerLocal == null) {
+ reportStartInstrumentationFailureLocked(
+ watcher, className, "Can't locate SdkSandboxManagerLocal");
+ return false;
+ }
+
+ final String processName = sandboxManagerLocal.getSdkSandboxProcessNameForInstrumentation(
+ sdkSandboxClientAppInfo);
+
+ ActiveInstrumentation activeInstr = new ActiveInstrumentation(this);
+ activeInstr.mClass = className;
+ activeInstr.mTargetProcesses = new String[]{processName};
+ activeInstr.mTargetInfo = sdkSandboxInfo;
+ activeInstr.mProfileFile = profileFile;
+ activeInstr.mArguments = arguments;
+ activeInstr.mWatcher = watcher;
+ activeInstr.mUiAutomationConnection = uiAutomationConnection;
+ activeInstr.mResultClass = className;
+ activeInstr.mHasBackgroundActivityStartsPermission = false;
+ activeInstr.mHasBackgroundForegroundServiceStartsPermission = false;
+ // Instrumenting sdk sandbox without a restart is not supported
+ activeInstr.mNoRestart = false;
+
+ final int callingUid = Binder.getCallingUid();
+ final long token = Binder.clearCallingIdentity();
+ try {
+ sandboxManagerLocal.notifyInstrumentationStarted(
+ sdkSandboxClientAppInfo.packageName, sdkSandboxClientAppInfo.uid);
+ synchronized (mProcLock) {
+ int sdkSandboxUid = Process.toSdkSandboxUid(sdkSandboxClientAppInfo.uid);
+ // Kill the package sdk sandbox process belong to. At this point sdk sandbox is
+ // already killed.
+ forceStopPackageLocked(
+ instrumentationInfo.targetPackage,
+ /* appId= */ -1,
+ /* callerWillRestart= */ true,
+ /* purgeCache= */ false,
+ /* doIt= */ true,
+ /* evenPersistent= */ true,
+ /* uninstalling= */ false,
+ userId,
+ "start instr");
+
+ ProcessRecord app = addAppLocked(
+ sdkSandboxInfo,
+ processName,
+ /* isolated= */ false,
+ /* isSdkSandbox= */ true,
+ sdkSandboxUid,
+ sdkSandboxClientAppInfo.packageName,
+ disableHiddenApiChecks,
+ disableTestApiChecks,
+ abiOverride,
+ ZYGOTE_POLICY_FLAG_EMPTY);
+
+ app.setActiveInstrumentation(activeInstr);
+ activeInstr.mFinished = false;
+ activeInstr.mSourceUid = callingUid;
+ activeInstr.mRunningProcesses.add(app);
+ if (!mActiveInstrumentation.contains(activeInstr)) {
+ mActiveInstrumentation.add(activeInstr);
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+
+ return true;
+ }
+
private void instrumentWithoutRestart(ActiveInstrumentation activeInstr,
ApplicationInfo targetInfo) {
ProcessRecord pr;
@@ -14566,7 +14798,17 @@ public class ActivityManagerService extends IActivityManager.Stub
app.setActiveInstrumentation(null);
}
- if (!instr.mNoRestart) {
+ if (app.isSdkSandbox) {
+ // For sharedUid apps this will kill all sdk sandbox processes, which is not ideal.
+ // TODO(b/209061624): should we call ProcessList.removeProcessLocked instead?
+ killUid(UserHandle.getAppId(app.uid), UserHandle.getUserId(app.uid), "finished instr");
+ final SdkSandboxManagerLocal sandboxManagerLocal =
+ LocalManagerRegistry.getManager(SdkSandboxManagerLocal.class);
+ if (sandboxManagerLocal != null) {
+ sandboxManagerLocal.notifyInstrumentationFinished(
+ app.sdkSandboxClientAppPackage, Process.getAppUidForSdkSandboxUid(app.uid));
+ }
+ } else if (!instr.mNoRestart) {
forceStopPackageLocked(app.info.packageName, -1, false, false, true, true, false,
app.userId,
"finished inst");
@@ -15558,12 +15800,7 @@ public class ActivityManagerService extends IActivityManager.Stub
throw new IllegalArgumentException("Unknown process: " + process);
}
- boolean isDebuggable = Build.IS_DEBUGGABLE;
- if (!isDebuggable) {
- if ((proc.info.flags&ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
- throw new SecurityException("Process not debuggable: " + proc);
- }
- }
+ enforceDebuggable(proc);
mOomAdjuster.mCachedAppOptimizer.enableFreezer(false);
@@ -15666,10 +15903,7 @@ public class ActivityManagerService extends IActivityManager.Stub
throw new SecurityException("No process found for calling pid "
+ Binder.getCallingPid());
}
- if (!Build.IS_DEBUGGABLE
- && (proc.info.flags&ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
- throw new SecurityException("Not running a debuggable build");
- }
+ enforceDebuggable(proc);
processName = proc.processName;
uid = proc.uid;
if (reportPackage != null && !proc.getPkgList().containsKey(reportPackage)) {
@@ -15880,13 +16114,7 @@ public class ActivityManagerService extends IActivityManager.Stub
return false;
}
- if (!Build.IS_DEBUGGABLE) {
- if ((process.info.flags&ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
- return false;
- }
- }
-
- return true;
+ return Build.IS_DEBUGGABLE || process.isDebuggable();
}
public boolean startBinderTracking() throws RemoteException {
@@ -16018,22 +16246,29 @@ public class ActivityManagerService extends IActivityManager.Stub
@Override
public boolean bindSdkSandboxService(Intent service, ServiceConnection conn,
- int userAppUid, String processName, int flags) throws RemoteException {
+ int clientAppUid, String clientAppPackage, String processName, int flags)
+ throws RemoteException {
if (service == null) {
throw new IllegalArgumentException("intent is null");
}
if (conn == null) {
throw new IllegalArgumentException("connection is null");
}
+ if (clientAppPackage == null) {
+ throw new IllegalArgumentException("clientAppPackage is null");
+ }
if (processName == null) {
throw new IllegalArgumentException("processName is null");
}
if (service.getComponent() == null) {
throw new IllegalArgumentException("service must specify explicit component");
}
- if (!UserHandle.isApp(userAppUid)) {
+ if (!UserHandle.isApp(clientAppUid)) {
throw new IllegalArgumentException("uid is not within application range");
}
+ if (mAppOpsService.checkPackage(clientAppUid, clientAppPackage) != MODE_ALLOWED) {
+ throw new IllegalArgumentException("uid does not belong to provided package");
+ }
Handler handler = mContext.getMainThreadHandler();
@@ -16042,8 +16277,8 @@ public class ActivityManagerService extends IActivityManager.Stub
return ActivityManagerService.this.bindServiceInstance(
mContext.getIApplicationThread(), mContext.getActivityToken(), service,
service.resolveTypeIfNeeded(mContext.getContentResolver()), sd, flags,
- processName, /*isSupplementalProcessService*/ true, userAppUid,
- mContext.getOpPackageName(), UserHandle.getUserId(userAppUid)) != 0;
+ processName, /*isSdkSandboxService*/ true, clientAppUid, clientAppPackage,
+ mContext.getOpPackageName(), UserHandle.getUserId(clientAppUid)) != 0;
}
@Override
@@ -16361,7 +16596,7 @@ public class ActivityManagerService extends IActivityManager.Stub
if (pr.mState.getSetSchedGroup() == ProcessList.SCHED_GROUP_BACKGROUND
&& pr.mReceivers.numberOfCurReceivers() == 0) {
pr.killLocked("remove task", ApplicationExitInfo.REASON_USER_REQUESTED,
- ApplicationExitInfo.SUBREASON_UNKNOWN, true);
+ ApplicationExitInfo.SUBREASON_REMOVE_TASK, true);
} else {
// We delay killing processes that are not in the background or running a
// receiver.
@@ -16833,7 +17068,7 @@ public class ActivityManagerService extends IActivityManager.Stub
}
if (profilerInfo != null) {
- setProfileApp(aInfo.applicationInfo, aInfo.processName, profilerInfo);
+ setProfileApp(aInfo.applicationInfo, aInfo.processName, profilerInfo, null);
}
wmLock.notify();
}
@@ -16998,7 +17233,17 @@ public class ActivityManagerService extends IActivityManager.Stub
@Override
public void addPendingTopUid(int uid, int pid) {
- mPendingStartActivityUids.add(uid, pid);
+ final boolean isNewPending = mPendingStartActivityUids.add(uid, pid);
+ // If the next top activity is in cached and frozen mode, WM should raise its priority
+ // to unfreeze it. This is done by calling AMS.updateOomAdj that will lower its oom adj.
+ // However, WM cannot hold the AMS clock here so the updateOomAdj operation is performed
+ // in a separate thread asynchronously. Therefore WM can't guarantee AMS will unfreeze
+ // next top activity on time. This race will fail the following binder transactions WM
+ // sends to the activity. After this race issue between WM/ATMS and AMS is solved, this
+ // workaround can be removed. (b/213288355)
+ if (isNewPending && mOomAdjuster != null) { // It can be null in unit test.
+ mOomAdjuster.mCachedAppOptimizer.unfreezeProcess(pid);
+ }
}
@Override
@@ -17611,11 +17856,7 @@ public class ActivityManagerService extends IActivityManager.Stub
throw new IllegalArgumentException("Unknown process: " + process);
}
- if (!Build.IS_DEBUGGABLE) {
- if ((proc.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
- throw new SecurityException("Process not debuggable: " + proc);
- }
- }
+ enforceDebuggable(proc);
thread.attachAgent(path);
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 28b807c5d30b..2b61e7fd2752 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -343,6 +343,8 @@ final class ActivityManagerShellCommand extends ShellCommand {
return runSetStopUserOnSwitch(pw);
case "set-bg-abusive-uids":
return runSetBgAbusiveUids(pw);
+ case "list-bg-exemptions-config":
+ return runListBgExemptionsConfig(pw);
default:
return handleDefaultCommands(cmd);
}
@@ -3292,6 +3294,19 @@ final class ActivityManagerShellCommand extends ShellCommand {
return 0;
}
+ private int runListBgExemptionsConfig(PrintWriter pw) throws RemoteException {
+ final ArraySet<String> sysConfigs = mInternal.mAppRestrictionController
+ .mBgRestrictionExemptioFromSysConfig;
+ if (sysConfigs != null) {
+ for (int i = 0, size = sysConfigs.size(); i < size; i++) {
+ pw.print(sysConfigs.valueAt(i));
+ pw.print(' ');
+ }
+ pw.println();
+ }
+ return 0;
+ }
+
private Resources getResources(PrintWriter pw) throws RemoteException {
// system resources does not contain all the device configuration, construct it manually.
Configuration config = mInterface.getConfiguration();
diff --git a/services/core/java/com/android/server/am/AppBatteryExemptionTracker.java b/services/core/java/com/android/server/am/AppBatteryExemptionTracker.java
index d1cf0049d146..6f11b0001c7a 100644
--- a/services/core/java/com/android/server/am/AppBatteryExemptionTracker.java
+++ b/services/core/java/com/android/server/am/AppBatteryExemptionTracker.java
@@ -26,10 +26,13 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.os.SystemClock;
+import android.util.ArrayMap;
import android.util.Pair;
import android.util.Slog;
+import android.util.SparseArray;
import com.android.internal.R;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.am.AppBatteryExemptionTracker.AppBatteryExemptionPolicy;
import com.android.server.am.AppBatteryExemptionTracker.UidBatteryStates;
@@ -65,6 +68,11 @@ final class AppBatteryExemptionTracker
// As it's a UID-based tracker, anywhere which requires a package name, use this default name.
static final String DEFAULT_NAME = "";
+ // As it's a UID-based tracker, while the state change event it receives could be
+ // in the combination of UID + package name, we'd have to leverage each package's state.
+ @GuardedBy("mLock")
+ private UidProcessMap<Integer> mUidPackageStates = new UidProcessMap<>();
+
AppBatteryExemptionTracker(Context context, AppRestrictionController controller) {
this(context, controller, null, null);
}
@@ -103,12 +111,75 @@ final class AppBatteryExemptionTracker
.getUidBatteryUsage(uid);
final int stateTypeIndex = stateTypeToIndex(stateType);
synchronized (mLock) {
- UidBatteryStates pkg = mPkgEvents.get(uid, DEFAULT_NAME);
- if (pkg == null) {
- pkg = createAppStateEvents(uid, DEFAULT_NAME);
- mPkgEvents.put(uid, DEFAULT_NAME, pkg);
+ final SparseArray<ArrayMap<String, Integer>> map = mUidPackageStates.getMap();
+ ArrayMap<String, Integer> pkgsStates = map.get(uid);
+ if (pkgsStates == null) {
+ pkgsStates = new ArrayMap<>();
+ map.put(uid, pkgsStates);
+ }
+ int states = 0;
+ int indexOfPkg = pkgsStates.indexOfKey(packageName);
+ if (indexOfPkg >= 0) {
+ states = pkgsStates.valueAt(indexOfPkg);
+ } else {
+ pkgsStates.put(packageName, 0);
+ indexOfPkg = pkgsStates.indexOfKey(packageName);
+ }
+ boolean addEvent = false;
+ if (start) {
+ // Check if there is another package within this UID with this type of event start.
+ boolean alreadyStarted = false;
+ for (int i = pkgsStates.size() - 1; i >= 0; i--) {
+ final int s = pkgsStates.valueAt(i);
+ if ((s & stateType) != 0) {
+ alreadyStarted = true;
+ break;
+ }
+ }
+ pkgsStates.setValueAt(indexOfPkg, states | stateType);
+ if (!alreadyStarted) {
+ // This is the first package within this UID with this type of event start.
+ addEvent = true;
+ }
+ } else {
+ states &= ~stateType;
+ pkgsStates.setValueAt(indexOfPkg, states);
+ boolean allStopped = true;
+ for (int i = pkgsStates.size() - 1; i >= 0; i--) {
+ final int s = pkgsStates.valueAt(i);
+ if ((s & stateType) != 0) {
+ allStopped = false;
+ break;
+ }
+ }
+ if (allStopped) {
+ // None of the packages in this UID has an active event of this type.
+ addEvent = true;
+ }
+ if (states == 0) { // None of the states of this package are active, prune it.
+ pkgsStates.removeAt(indexOfPkg);
+ if (pkgsStates.size() == 0) {
+ map.remove(uid);
+ }
+ }
+ }
+ if (addEvent) {
+ UidBatteryStates pkg = mPkgEvents.get(uid, DEFAULT_NAME);
+ if (pkg == null) {
+ pkg = createAppStateEvents(uid, DEFAULT_NAME);
+ mPkgEvents.put(uid, DEFAULT_NAME, pkg);
+ }
+ pkg.addEvent(start, now, batteryUsage, stateTypeIndex);
}
- pkg.addEvent(start, now, batteryUsage, stateTypeIndex);
+ }
+ }
+
+ @VisibleForTesting
+ @Override
+ void reset() {
+ super.reset();
+ synchronized (mLock) {
+ mUidPackageStates.clear();
}
}
@@ -116,6 +187,7 @@ final class AppBatteryExemptionTracker
if (!enabled) {
synchronized (mLock) {
mPkgEvents.clear();
+ mUidPackageStates.clear();
}
}
}
diff --git a/services/core/java/com/android/server/am/AppBatteryTracker.java b/services/core/java/com/android/server/am/AppBatteryTracker.java
index 7579d2bc78fd..690051f47326 100644
--- a/services/core/java/com/android/server/am/AppBatteryTracker.java
+++ b/services/core/java/com/android/server/am/AppBatteryTracker.java
@@ -28,6 +28,7 @@ import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_USER_INTERACT
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.BatteryConsumer.POWER_COMPONENT_ANY;
import static android.os.BatteryConsumer.PROCESS_STATE_BACKGROUND;
+import static android.os.BatteryConsumer.PROCESS_STATE_CACHED;
import static android.os.BatteryConsumer.PROCESS_STATE_COUNT;
import static android.os.BatteryConsumer.PROCESS_STATE_FOREGROUND;
import static android.os.BatteryConsumer.PROCESS_STATE_FOREGROUND_SERVICE;
@@ -38,7 +39,6 @@ import static android.util.TimeUtils.formatTime;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.am.AppRestrictionController.DEVICE_CONFIG_SUBNAMESPACE_PREFIX;
-import static com.android.server.am.BaseAppStateTracker.ONE_MINUTE;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -48,6 +48,7 @@ import android.content.Context;
import android.content.pm.ServiceInfo;
import android.content.res.Resources;
import android.content.res.TypedArray;
+import android.os.AppBatteryStatsProto;
import android.os.BatteryConsumer;
import android.os.BatteryConsumer.Dimensions;
import android.os.BatteryStatsInternal;
@@ -64,6 +65,7 @@ import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
import android.util.TimeUtils;
+import android.util.proto.ProtoOutputStream;
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
@@ -71,7 +73,6 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
import com.android.server.am.AppBatteryTracker.AppBatteryPolicy;
import com.android.server.am.AppRestrictionController.UidBatteryUsageProvider;
-import com.android.server.am.BaseAppStateTracker.Injector;
import com.android.server.pm.UserManagerInternal;
import java.io.PrintWriter;
@@ -679,11 +680,69 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
super.dump(pw, prefix);
}
+ @Override
+ void dumpAsProto(ProtoOutputStream proto, int uid) {
+ synchronized (mLock) {
+ final SparseArray<ImmutableBatteryUsage> uidConsumers = mUidBatteryUsageInWindow;
+ if (uid != android.os.Process.INVALID_UID) {
+ final BatteryUsage usage = uidConsumers.get(uid);
+ if (usage != null) {
+ dumpUidStats(proto, uid, usage);
+ }
+ } else {
+ for (int i = 0, size = uidConsumers.size(); i < size; i++) {
+ final int aUid = uidConsumers.keyAt(i);
+ final BatteryUsage usage = uidConsumers.valueAt(i);
+ dumpUidStats(proto, aUid, usage);
+ }
+ }
+ }
+ }
+
+ private void dumpUidStats(ProtoOutputStream proto, int uid, BatteryUsage usage) {
+ if (usage.mUsage == null) {
+ return;
+ }
+
+ final double foregroundUsage = usage.getUsagePowerMah(PROCESS_STATE_FOREGROUND);
+ final double backgroundUsage = usage.getUsagePowerMah(PROCESS_STATE_BACKGROUND);
+ final double fgsUsage = usage.getUsagePowerMah(PROCESS_STATE_FOREGROUND_SERVICE);
+
+ if (foregroundUsage == 0 && backgroundUsage == 0 && fgsUsage == 0) {
+ return;
+ }
+
+ final long token = proto.start(AppBatteryStatsProto.UID_STATS);
+ proto.write(AppBatteryStatsProto.UidStats.UID, uid);
+ dumpProcessStateStats(proto,
+ AppBatteryStatsProto.UidStats.ProcessStateStats.FOREGROUND,
+ foregroundUsage);
+ dumpProcessStateStats(proto,
+ AppBatteryStatsProto.UidStats.ProcessStateStats.BACKGROUND,
+ backgroundUsage);
+ dumpProcessStateStats(proto,
+ AppBatteryStatsProto.UidStats.ProcessStateStats.FOREGROUND_SERVICE,
+ fgsUsage);
+ proto.end(token);
+ }
+
+ private void dumpProcessStateStats(ProtoOutputStream proto, int processState, double powerMah) {
+ if (powerMah == 0) {
+ return;
+ }
+
+ final long token = proto.start(AppBatteryStatsProto.UidStats.PROCESS_STATE_STATS);
+ proto.write(AppBatteryStatsProto.UidStats.ProcessStateStats.PROCESS_STATE, processState);
+ proto.write(AppBatteryStatsProto.UidStats.ProcessStateStats.POWER_MAH, powerMah);
+ proto.end(token);
+ }
+
static class BatteryUsage {
static final int BATTERY_USAGE_INDEX_UNSPECIFIED = PROCESS_STATE_UNSPECIFIED;
static final int BATTERY_USAGE_INDEX_FOREGROUND = PROCESS_STATE_FOREGROUND;
static final int BATTERY_USAGE_INDEX_BACKGROUND = PROCESS_STATE_BACKGROUND;
static final int BATTERY_USAGE_INDEX_FOREGROUND_SERVICE = PROCESS_STATE_FOREGROUND_SERVICE;
+ static final int BATTERY_USAGE_INDEX_CACHED = PROCESS_STATE_CACHED;
static final int BATTERY_USAGE_COUNT = PROCESS_STATE_COUNT;
static final Dimensions[] BATT_DIMENS = new Dimensions[] {
@@ -695,17 +754,20 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
PROCESS_STATE_BACKGROUND),
new Dimensions(AppBatteryPolicy.DEFAULT_BG_CURRENT_DRAIN_POWER_COMPONENTS,
PROCESS_STATE_FOREGROUND_SERVICE),
+ new Dimensions(AppBatteryPolicy.DEFAULT_BG_CURRENT_DRAIN_POWER_COMPONENTS,
+ PROCESS_STATE_CACHED),
};
@NonNull double[] mUsage;
@Nullable double[] mPercentage;
BatteryUsage() {
- this(0.0d, 0.0d, 0.0d, 0.0d);
+ this(0.0d, 0.0d, 0.0d, 0.0d, 0.0d);
}
- BatteryUsage(double unspecifiedUsage, double fgUsage, double bgUsage, double fgsUsage) {
- mUsage = new double[] {unspecifiedUsage, fgUsage, bgUsage, fgsUsage};
+ BatteryUsage(double unspecifiedUsage, double fgUsage, double bgUsage, double fgsUsage,
+ double cachedUsage) {
+ mUsage = new double[] {unspecifiedUsage, fgUsage, bgUsage, fgsUsage, cachedUsage};
}
BatteryUsage(@NonNull double[] usage) {
@@ -728,7 +790,8 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
getConsumedPowerNoThrow(consumer, dims[BATTERY_USAGE_INDEX_UNSPECIFIED]),
getConsumedPowerNoThrow(consumer, dims[BATTERY_USAGE_INDEX_FOREGROUND]),
getConsumedPowerNoThrow(consumer, dims[BATTERY_USAGE_INDEX_BACKGROUND]),
- getConsumedPowerNoThrow(consumer, dims[BATTERY_USAGE_INDEX_FOREGROUND_SERVICE])
+ getConsumedPowerNoThrow(consumer, dims[BATTERY_USAGE_INDEX_FOREGROUND_SERVICE]),
+ getConsumedPowerNoThrow(consumer, dims[BATTERY_USAGE_INDEX_CACHED]),
};
}
@@ -798,6 +861,15 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
return formatBatteryUsage(mUsage);
}
+ double getUsagePowerMah(@BatteryConsumer.ProcessState int processState) {
+ switch (processState) {
+ case PROCESS_STATE_FOREGROUND: return mUsage[1];
+ case PROCESS_STATE_BACKGROUND: return mUsage[2];
+ case PROCESS_STATE_FOREGROUND_SERVICE: return mUsage[3];
+ }
+ return 0;
+ }
+
boolean isValid() {
for (int i = 0; i < mUsage.length; i++) {
if (mUsage[i] < 0.0d) {
@@ -840,19 +912,21 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
}
private static String formatBatteryUsage(double[] usage) {
- return String.format("%.3f %.3f %.3f %.3f mAh",
+ return String.format("%.3f %.3f %.3f %.3f %.3f mAh",
usage[BATTERY_USAGE_INDEX_UNSPECIFIED],
usage[BATTERY_USAGE_INDEX_FOREGROUND],
usage[BATTERY_USAGE_INDEX_BACKGROUND],
- usage[BATTERY_USAGE_INDEX_FOREGROUND_SERVICE]);
+ usage[BATTERY_USAGE_INDEX_FOREGROUND_SERVICE],
+ usage[BATTERY_USAGE_INDEX_CACHED]);
}
static String formatBatteryUsagePercentage(double[] percentage) {
- return String.format("%4.2f%% %4.2f%% %4.2f%% %4.2f%%",
+ return String.format("%4.2f%% %4.2f%% %4.2f%% %4.2f%% %4.2f%%",
percentage[BATTERY_USAGE_INDEX_UNSPECIFIED],
percentage[BATTERY_USAGE_INDEX_FOREGROUND],
percentage[BATTERY_USAGE_INDEX_BACKGROUND],
- percentage[BATTERY_USAGE_INDEX_FOREGROUND_SERVICE]);
+ percentage[BATTERY_USAGE_INDEX_FOREGROUND_SERVICE],
+ percentage[BATTERY_USAGE_INDEX_CACHED]);
}
private static double getConsumedPowerNoThrow(final UidBatteryConsumer uidConsumer,
@@ -871,8 +945,8 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
}
ImmutableBatteryUsage(double unspecifiedUsage, double fgUsage, double bgUsage,
- double fgsUsage) {
- super(unspecifiedUsage, fgUsage, bgUsage, fgsUsage);
+ double fgsUsage, double cachedUsage) {
+ super(unspecifiedUsage, fgUsage, bgUsage, fgsUsage, cachedUsage);
}
ImmutableBatteryUsage(@NonNull double[] usage) {
@@ -932,6 +1006,7 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
static final int BATTERY_USAGE_TYPE_FOREGROUND = 1 << 1;
static final int BATTERY_USAGE_TYPE_BACKGROUND = 1 << 2;
static final int BATTERY_USAGE_TYPE_FOREGROUND_SERVICE = 1 << 3;
+ static final int BATTERY_USAGE_TYPE_CACHED = 1 << 4;
/**
* Whether or not we should enable the monitoring on background current drains.
@@ -1007,8 +1082,8 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
/**
* The types of battery drain we're checking on each app; if the sum of the battery drain
* exceeds the threshold, it'll be moved to restricted standby bucket; the type here
- * must be one of, or combination of {@link #BATTERY_USAGE_TYPE_BACKGROUND} and
- * {@link #BATTERY_USAGE_TYPE_FOREGROUND_SERVICE}.
+ * must be one of, or combination of {@link #BATTERY_USAGE_TYPE_BACKGROUND},
+ * {@link #BATTERY_USAGE_TYPE_FOREGROUND_SERVICE} and {@link #BATTERY_USAGE_TYPE_CACHED}.
*/
static final String KEY_BG_CURRENT_DRAIN_TYPES_TO_RESTRICTED_BUCKET =
DEVICE_CONFIG_SUBNAMESPACE_PREFIX + "current_drain_types_to_restricted_bucket";
@@ -1016,8 +1091,8 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
/**
* The types of battery drain we're checking on each app; if the sum of the battery drain
* exceeds the threshold, it'll be moved to background restricted level; the type here
- * must be one of, or combination of {@link #BATTERY_USAGE_TYPE_BACKGROUND} and
- * {@link #BATTERY_USAGE_TYPE_FOREGROUND_SERVICE}.
+ * must be one of, or combination of {@link #BATTERY_USAGE_TYPE_BACKGROUND},
+ * {@link #BATTERY_USAGE_TYPE_FOREGROUND_SERVICE} and {@link #BATTERY_USAGE_TYPE_CACHED}.
*/
static final String KEY_BG_CURRENT_DRAIN_TYPES_TO_BG_RESTRICTED =
DEVICE_CONFIG_SUBNAMESPACE_PREFIX + "current_drain_types_to_bg_restricted";
@@ -1217,7 +1292,7 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
mDefaultBgCurrentDrainBgRestrictedThreshold =
isLowRamDeviceStatic() ? val[1] : val[0];
mDefaultBgCurrentDrainWindowMs = resources.getInteger(
- R.integer.config_bg_current_drain_window);
+ R.integer.config_bg_current_drain_window) * 1_000;
val = getFloatArray(resources.obtainTypedArray(
R.array.config_bg_current_drain_high_threshold_to_restricted_bucket));
mDefaultBgCurrentDrainRestrictedBucketHighThreshold =
@@ -1227,9 +1302,9 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
mDefaultBgCurrentDrainBgRestrictedHighThreshold =
isLowRamDeviceStatic() ? val[1] : val[0];
mDefaultBgCurrentDrainMediaPlaybackMinDuration = resources.getInteger(
- R.integer.config_bg_current_drain_media_playback_min_duration);
+ R.integer.config_bg_current_drain_media_playback_min_duration) * 1_000;
mDefaultBgCurrentDrainLocationMinDuration = resources.getInteger(
- R.integer.config_bg_current_drain_location_min_duration);
+ R.integer.config_bg_current_drain_location_min_duration) * 1_000;
mDefaultBgCurrentDrainEventDurationBasedThresholdEnabled = resources.getBoolean(
R.bool.config_bg_current_drain_event_duration_based_threshold_enabled);
mDefaultCurrentDrainTypesToRestrictedBucket = resources.getInteger(
@@ -1461,6 +1536,9 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
case BATTERY_USAGE_TYPE_FOREGROUND_SERVICE:
sb.append("FOREGROUND_SERVICE");
break;
+ case BATTERY_USAGE_TYPE_CACHED:
+ sb.append("CACHED");
+ break;
default:
return "[UNKNOWN(" + Integer.toHexString(types) + ")]";
}
diff --git a/services/core/java/com/android/server/am/AppExitInfoTracker.java b/services/core/java/com/android/server/am/AppExitInfoTracker.java
index fc29982dc7f0..d84c1fcd54fb 100644
--- a/services/core/java/com/android/server/am/AppExitInfoTracker.java
+++ b/services/core/java/com/android/server/am/AppExitInfoTracker.java
@@ -1002,6 +1002,7 @@ public final class AppExitInfoTracker {
info.setPackageName(app.info.packageName);
info.setPackageList(app.getPackageList());
info.setReason(ApplicationExitInfo.REASON_UNKNOWN);
+ info.setSubReason(ApplicationExitInfo.SUBREASON_UNKNOWN);
info.setStatus(0);
info.setImportance(procStateToImportance(app.mState.getReportedProcState()));
info.setPss(app.mProfile.getLastPss());
diff --git a/services/core/java/com/android/server/am/AppFGSTracker.java b/services/core/java/com/android/server/am/AppFGSTracker.java
index 075402f10882..246725e03ba6 100644
--- a/services/core/java/com/android/server/am/AppFGSTracker.java
+++ b/services/core/java/com/android/server/am/AppFGSTracker.java
@@ -32,18 +32,22 @@ import static com.android.server.am.BaseAppStateTracker.ONE_HOUR;
import android.annotation.NonNull;
import android.app.ActivityManagerInternal.ForegroundServiceStateListener;
import android.app.IProcessObserver;
+import android.content.ComponentName;
import android.content.Context;
import android.content.pm.ServiceInfo.ForegroundServiceType;
import android.os.Handler;
import android.os.Message;
import android.os.PowerExemptionManager.ReasonCode;
+import android.os.RemoteException;
import android.os.SystemClock;
import android.os.UserHandle;
import android.provider.DeviceConfig;
+import android.service.notification.NotificationListenerService;
+import android.service.notification.StatusBarNotification;
import android.util.ArrayMap;
-import android.util.ArraySet;
import android.util.Slog;
import android.util.SparseArray;
+import android.util.SparseBooleanArray;
import android.util.TimeUtils;
import com.android.internal.annotations.GuardedBy;
@@ -53,7 +57,6 @@ import com.android.server.am.AppFGSTracker.PackageDurations;
import com.android.server.am.BaseAppStateEventsTracker.BaseAppStateEventsPolicy;
import com.android.server.am.BaseAppStateTimeEvents.BaseTimeEvent;
import com.android.server.am.BaseAppStateTracker.Injector;
-import com.android.server.notification.NotificationManagerInternal;
import java.io.PrintWriter;
import java.lang.reflect.Constructor;
@@ -72,11 +75,14 @@ final class AppFGSTracker extends BaseAppStateDurationsTracker<AppFGSPolicy, Pac
private final MyHandler mHandler;
@GuardedBy("mLock")
- private final UidProcessMap<ArraySet<Integer>> mFGSNotificationIDs = new UidProcessMap<>();
+ private final UidProcessMap<SparseBooleanArray> mFGSNotificationIDs = new UidProcessMap<>();
// Unlocked since it's only accessed in single thread.
private final ArrayMap<PackageDurations, Long> mTmpPkgDurations = new ArrayMap<>();
+ @VisibleForTesting
+ final NotificationListener mNotificationListener = new NotificationListener();
+
final IProcessObserver.Stub mProcessObserver = new IProcessObserver.Stub() {
@Override
public void onForegroundActivitiesChanged(int pid, int uid, boolean fg) {
@@ -116,6 +122,8 @@ final class AppFGSTracker extends BaseAppStateDurationsTracker<AppFGSPolicy, Pac
static final int MSG_FOREGROUND_SERVICES_CHANGED = 2;
static final int MSG_FOREGROUND_SERVICES_NOTIFICATION_UPDATED = 3;
static final int MSG_CHECK_LONG_RUNNING_FGS = 4;
+ static final int MSG_NOTIFICATION_POSTED = 5;
+ static final int MSG_NOTIFICATION_REMOVED = 6;
private final AppFGSTracker mTracker;
@@ -146,6 +154,12 @@ final class AppFGSTracker extends BaseAppStateDurationsTracker<AppFGSPolicy, Pac
case MSG_CHECK_LONG_RUNNING_FGS:
mTracker.checkLongRunningFgs();
break;
+ case MSG_NOTIFICATION_POSTED:
+ mTracker.handleNotificationPosted((String) msg.obj, msg.arg1, msg.arg2);
+ break;
+ case MSG_NOTIFICATION_REMOVED:
+ mTracker.handleNotificationRemoved((String) msg.obj, msg.arg1, msg.arg2);
+ break;
}
}
}
@@ -223,19 +237,36 @@ final class AppFGSTracker extends BaseAppStateDurationsTracker<AppFGSPolicy, Pac
private void handleForegroundServiceNotificationUpdated(String packageName, int uid,
int notificationId) {
synchronized (mLock) {
+ SparseBooleanArray notificationIDs = mFGSNotificationIDs.get(uid, packageName);
if (notificationId > 0) {
- ArraySet<Integer> notificationIDs = mFGSNotificationIDs.get(uid, packageName);
if (notificationIDs == null) {
- notificationIDs = new ArraySet<>();
+ notificationIDs = new SparseBooleanArray();
mFGSNotificationIDs.put(uid, packageName, notificationIDs);
}
- notificationIDs.add(notificationId);
+ notificationIDs.put(notificationId, false);
} else if (notificationId < 0) {
- final ArraySet<Integer> notificationIDs = mFGSNotificationIDs.get(uid, packageName);
if (notificationIDs != null) {
- notificationIDs.remove(-notificationId);
- if (notificationIDs.isEmpty()) {
- mFGSNotificationIDs.remove(uid, packageName);
+ final int indexOfKey = notificationIDs.indexOfKey(-notificationId);
+ if (indexOfKey >= 0) {
+ final boolean wasVisible = notificationIDs.valueAt(indexOfKey);
+ notificationIDs.removeAt(indexOfKey);
+ if (notificationIDs.size() == 0) {
+ mFGSNotificationIDs.remove(uid, packageName);
+ }
+ // Walk through the list of FGS notification IDs and see if there are any
+ // visible ones.
+ for (int i = notificationIDs.size() - 1; i >= 0; i--) {
+ if (notificationIDs.valueAt(i)) {
+ // Still visible, nothing to do.
+ return;
+ }
+ }
+ if (wasVisible) {
+ // That was the last visible notification, notify the listeners.
+ notifyListenersOnStateChange(uid, packageName, false,
+ SystemClock.elapsedRealtime(),
+ STATE_TYPE_FGS_WITH_NOTIFICATION);
+ }
}
}
}
@@ -244,20 +275,74 @@ final class AppFGSTracker extends BaseAppStateDurationsTracker<AppFGSPolicy, Pac
@GuardedBy("mLock")
private boolean hasForegroundServiceNotificationsLocked(String packageName, int uid) {
- final ArraySet<Integer> notificationIDs = mFGSNotificationIDs.get(uid, packageName);
- if (notificationIDs == null || notificationIDs.isEmpty()) {
+ final SparseBooleanArray notificationIDs = mFGSNotificationIDs.get(uid, packageName);
+ if (notificationIDs == null || notificationIDs.size() == 0) {
return false;
}
- final NotificationManagerInternal nm = mInjector.getNotificationManagerInternal();
- final int userId = UserHandle.getUserId(uid);
for (int i = notificationIDs.size() - 1; i >= 0; i--) {
- if (nm.isNotificationShown(packageName, null, notificationIDs.valueAt(i), userId)) {
+ if (notificationIDs.valueAt(i)) {
return true;
}
}
return false;
}
+ private void handleNotificationPosted(String pkgName, int uid, int notificationId) {
+ synchronized (mLock) {
+ final SparseBooleanArray notificationIDs = mFGSNotificationIDs.get(uid, pkgName);
+ final int indexOfKey;
+ if (notificationIDs == null
+ || (indexOfKey = notificationIDs.indexOfKey(notificationId)) < 0) {
+ return;
+ }
+ if (notificationIDs.valueAt(indexOfKey)) {
+ // It's already visible.
+ return;
+ }
+ boolean anyVisible = false;
+ // Walk through the list of FGS notification IDs and see if there are any visible ones.
+ for (int i = notificationIDs.size() - 1; i >= 0; i--) {
+ if (notificationIDs.valueAt(i)) {
+ anyVisible = true;
+ break;
+ }
+ }
+ notificationIDs.setValueAt(indexOfKey, true);
+ if (!anyVisible) {
+ // We didn't have any visible FGS notifications but now we have one,
+ // let the listeners know.
+ notifyListenersOnStateChange(uid, pkgName, true, SystemClock.elapsedRealtime(),
+ STATE_TYPE_FGS_WITH_NOTIFICATION);
+ }
+ }
+ }
+
+ private void handleNotificationRemoved(String pkgName, int uid, int notificationId) {
+ synchronized (mLock) {
+ final SparseBooleanArray notificationIDs = mFGSNotificationIDs.get(uid, pkgName);
+ final int indexOfKey;
+ if (notificationIDs == null
+ || (indexOfKey = notificationIDs.indexOfKey(notificationId)) < 0) {
+ return;
+ }
+ if (!notificationIDs.valueAt(indexOfKey)) {
+ // It's already invisible.
+ return;
+ }
+ notificationIDs.setValueAt(indexOfKey, false);
+ // Walk through the list of FGS notification IDs and see if there are any visible ones.
+ for (int i = notificationIDs.size() - 1; i >= 0; i--) {
+ if (notificationIDs.valueAt(i)) {
+ // Still visible, nothing to do.
+ return;
+ }
+ }
+ // Nothing is visible now, let the listeners know.
+ notifyListenersOnStateChange(uid, pkgName, false, SystemClock.elapsedRealtime(),
+ STATE_TYPE_FGS_WITH_NOTIFICATION);
+ }
+ }
+
@GuardedBy("mLock")
private void scheduleDurationCheckLocked(long now) {
// Look for the active FGS with longest running time till now.
@@ -374,7 +459,19 @@ final class AppFGSTracker extends BaseAppStateDurationsTracker<AppFGSPolicy, Pac
synchronized (mLock) {
scheduleDurationCheckLocked(SystemClock.elapsedRealtime());
}
+ try {
+ mNotificationListener.registerAsSystemService(mContext,
+ new ComponentName(mContext, NotificationListener.class),
+ UserHandle.USER_ALL);
+ } catch (RemoteException e) {
+ // Intra-process call, should never happen.
+ }
} else {
+ try {
+ mNotificationListener.unregisterAsSystemService();
+ } catch (RemoteException e) {
+ // Intra-process call, should never happen.
+ }
mHandler.removeMessages(MyHandler.MSG_CHECK_LONG_RUNNING_FGS);
synchronized (mLock) {
mPkgEvents.clear();
@@ -436,9 +533,9 @@ final class AppFGSTracker extends BaseAppStateDurationsTracker<AppFGSPolicy, Pac
boolean hasForegroundServiceNotifications(int uid) {
synchronized (mLock) {
- final SparseArray<ArrayMap<String, ArraySet<Integer>>> map =
+ final SparseArray<ArrayMap<String, SparseBooleanArray>> map =
mFGSNotificationIDs.getMap();
- final ArrayMap<String, ArraySet<Integer>> pkgs = map.get(uid);
+ final ArrayMap<String, SparseBooleanArray> pkgs = map.get(uid);
if (pkgs != null) {
for (int i = pkgs.size() - 1; i >= 0; i--) {
if (hasForegroundServiceNotificationsLocked(pkgs.keyAt(i), uid)) {
@@ -463,7 +560,7 @@ final class AppFGSTracker extends BaseAppStateDurationsTracker<AppFGSPolicy, Pac
pw.println("APPS WITH ACTIVE FOREGROUND SERVICES:");
prefix = " " + prefix;
synchronized (mLock) {
- final SparseArray<ArrayMap<String, ArraySet<Integer>>> map =
+ final SparseArray<ArrayMap<String, SparseBooleanArray>> map =
mFGSNotificationIDs.getMap();
if (map.size() == 0) {
pw.print(prefix);
@@ -472,7 +569,7 @@ final class AppFGSTracker extends BaseAppStateDurationsTracker<AppFGSPolicy, Pac
for (int i = 0, size = map.size(); i < size; i++) {
final int uid = map.keyAt(i);
final String uidString = UserHandle.formatUid(uid);
- final ArrayMap<String, ArraySet<Integer>> pkgs = map.valueAt(i);
+ final ArrayMap<String, SparseBooleanArray> pkgs = map.valueAt(i);
for (int j = 0, numOfPkgs = pkgs.size(); j < numOfPkgs; j++) {
final String pkgName = pkgs.keyAt(j);
pw.print(prefix);
@@ -622,6 +719,28 @@ final class AppFGSTracker extends BaseAppStateDurationsTracker<AppFGSPolicy, Pac
}
}
+ @VisibleForTesting
+ class NotificationListener extends NotificationListenerService {
+ @Override
+ public void onNotificationPosted(StatusBarNotification sbn, RankingMap map) {
+ if (DEBUG_BACKGROUND_FGS_TRACKER) {
+ Slog.i(TAG, "Notification posted: " + sbn);
+ }
+ mHandler.obtainMessage(MyHandler.MSG_NOTIFICATION_POSTED,
+ sbn.getUid(), sbn.getId(), sbn.getPackageName()).sendToTarget();
+ }
+
+ @Override
+ public void onNotificationRemoved(StatusBarNotification sbn, RankingMap rankingMap,
+ int reason) {
+ if (DEBUG_BACKGROUND_FGS_TRACKER) {
+ Slog.i(TAG, "Notification removed: " + sbn);
+ }
+ mHandler.obtainMessage(MyHandler.MSG_NOTIFICATION_REMOVED,
+ sbn.getUid(), sbn.getId(), sbn.getPackageName()).sendToTarget();
+ }
+ }
+
static final class AppFGSPolicy extends BaseAppStateEventsPolicy<AppFGSTracker> {
/**
* Whether or not we should enable the monitoring on abusive FGS.
diff --git a/services/core/java/com/android/server/am/AppPermissionTracker.java b/services/core/java/com/android/server/am/AppPermissionTracker.java
index 69f70ca0d0e0..622d7465d4bf 100644
--- a/services/core/java/com/android/server/am/AppPermissionTracker.java
+++ b/services/core/java/com/android/server/am/AppPermissionTracker.java
@@ -17,6 +17,14 @@
package com.android.server.am;
import static android.Manifest.permission.ACCESS_FINE_LOCATION;
+import static android.Manifest.permission.CAMERA;
+import static android.Manifest.permission.RECORD_AUDIO;
+import static android.app.AppOpsManager.OPSTR_CAMERA;
+import static android.app.AppOpsManager.OPSTR_FINE_LOCATION;
+import static android.app.AppOpsManager.OPSTR_RECORD_AUDIO;
+import static android.app.AppOpsManager.OP_NONE;
+import static android.app.AppOpsManager.opToPublicName;
+import static android.app.AppOpsManager.strOpToOp;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.Process.SYSTEM_UID;
@@ -27,28 +35,37 @@ import static com.android.server.am.AppRestrictionController.DEVICE_CONFIG_SUBNA
import static com.android.server.am.BaseAppStateTracker.STATE_TYPE_PERMISSION;
import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.AppOpsManager;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager.OnPermissionsChangedListener;
import android.content.pm.PackageManagerInternal;
import android.os.Handler;
import android.os.Message;
+import android.os.RemoteException;
import android.os.SystemClock;
import android.os.UserHandle;
import android.permission.PermissionManager;
import android.provider.DeviceConfig;
+import android.text.TextUtils;
import android.util.ArraySet;
+import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.app.IAppOpsCallback;
+import com.android.internal.app.IAppOpsService;
import com.android.server.am.AppPermissionTracker.AppPermissionPolicy;
import com.android.server.pm.permission.PermissionManagerServiceInternal;
import java.io.PrintWriter;
import java.lang.reflect.Constructor;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import java.util.Objects;
/**
* The tracker for monitoring selected permission state of apps.
@@ -61,8 +78,17 @@ final class AppPermissionTracker extends BaseAppStateTracker<AppPermissionPolicy
private final MyHandler mHandler;
+ /**
+ * Keep a new instance of callback for each appop we're monitoring,
+ * as the AppOpsService doesn't support monitoring multiple appops with single callback
+ * instance (except the ALL_OPS case).
+ */
+ @GuardedBy("mAppOpsCallbacks")
+ private final SparseArray<MyAppOpsCallback> mAppOpsCallbacks = new SparseArray<>();
+
@GuardedBy("mLock")
- private SparseArray<ArraySet<String>> mUidGrantedPermissionsInMonitor = new SparseArray<>();
+ private SparseArray<ArraySet<UidGrantedPermissionState>> mUidGrantedPermissionsInMonitor =
+ new SparseArray<>();
private volatile boolean mLockedBootCompleted = false;
@@ -82,12 +108,25 @@ final class AppPermissionTracker extends BaseAppStateTracker<AppPermissionPolicy
mHandler.obtainMessage(MyHandler.MSG_PERMISSIONS_CHANGED, uid, 0).sendToTarget();
}
+ private void handleAppOpsInit() {
+ final ArrayList<Integer> ops = new ArrayList<>();
+ final Pair[] permissions = mInjector.getPolicy().getBgPermissionsInMonitor();
+ for (int i = 0; i < permissions.length; i++) {
+ final Pair<String, Integer> pair = permissions[i];
+ if (pair.second != OP_NONE) {
+ ops.add(pair.second);
+ }
+ }
+ startWatchingMode(ops.toArray(new Integer[ops.size()]));
+ }
+
private void handlePermissionsInit() {
final int[] allUsers = mInjector.getUserManagerInternal().getUserIds();
final PackageManagerInternal pmi = mInjector.getPackageManagerInternal();
final PermissionManagerServiceInternal pm = mInjector.getPermissionManagerServiceInternal();
- final String[] permissions = mInjector.getPolicy().getBgPermissionsInMonitor();
- final SparseArray<ArraySet<String>> uidPerms = mUidGrantedPermissionsInMonitor;
+ final Pair[] permissions = mInjector.getPolicy().getBgPermissionsInMonitor();
+ final SparseArray<ArraySet<UidGrantedPermissionState>> uidPerms =
+ mUidGrantedPermissionsInMonitor;
for (int userId : allUsers) {
final List<ApplicationInfo> apps = pmi.getInstalledApplications(0, userId, SYSTEM_UID);
if (apps == null) {
@@ -96,33 +135,44 @@ final class AppPermissionTracker extends BaseAppStateTracker<AppPermissionPolicy
final long now = SystemClock.elapsedRealtime();
for (int i = 0, size = apps.size(); i < size; i++) {
final ApplicationInfo ai = apps.get(i);
- for (String permission : permissions) {
- if (pm.checkUidPermission(ai.uid, permission) != PERMISSION_GRANTED) {
+ for (Pair<String, Integer> permission : permissions) {
+ final UidGrantedPermissionState state = new UidGrantedPermissionState(
+ ai.uid, permission.first, permission.second);
+ if (!state.isGranted()) {
+ // No need to track it.
continue;
}
synchronized (mLock) {
- ArraySet<String> grantedPermissions = uidPerms.get(ai.uid);
+ ArraySet<UidGrantedPermissionState> grantedPermissions =
+ uidPerms.get(ai.uid);
if (grantedPermissions == null) {
- grantedPermissions = new ArraySet<String>();
+ grantedPermissions = new ArraySet<UidGrantedPermissionState>();
uidPerms.put(ai.uid, grantedPermissions);
+ // This UID has at least one active permission-in-interest now,
+ // let the listeners know.
+ notifyListenersOnStateChange(ai.uid, DEFAULT_NAME, true, now,
+ STATE_TYPE_PERMISSION);
}
- grantedPermissions.add(permission);
- notifyListenersOnStateChange(ai.uid, DEFAULT_NAME, true, now,
- STATE_TYPE_PERMISSION);
+ grantedPermissions.add(state);
}
}
}
}
}
+ private void handleAppOpsDestroy() {
+ stopWatchingMode();
+ }
+
private void handlePermissionsDestroy() {
synchronized (mLock) {
- final SparseArray<ArraySet<String>> uidPerms = mUidGrantedPermissionsInMonitor;
+ final SparseArray<ArraySet<UidGrantedPermissionState>> uidPerms =
+ mUidGrantedPermissionsInMonitor;
final long now = SystemClock.elapsedRealtime();
for (int i = 0, size = uidPerms.size(); i < size; i++) {
final int uid = uidPerms.keyAt(i);
- final ArraySet<String> grantedPermissions = uidPerms.valueAt(i);
- for (int j = 0, numOfPerms = grantedPermissions.size(); j < numOfPerms; j++) {
+ final ArraySet<UidGrantedPermissionState> grantedPermissions = uidPerms.valueAt(i);
+ if (grantedPermissions.size() > 0) {
notifyListenersOnStateChange(uid, DEFAULT_NAME, false, now,
STATE_TYPE_PERMISSION);
}
@@ -131,44 +181,78 @@ final class AppPermissionTracker extends BaseAppStateTracker<AppPermissionPolicy
}
}
+ private void handleOpChanged(int op, int uid, String packageName) {
+ if (DEBUG_PERMISSION_TRACKER) {
+ final IAppOpsService appOpsService = mInjector.getIAppOpsService();
+ try {
+ final int mode = appOpsService.checkOperation(op, uid, packageName);
+ Slog.i(TAG, "onOpChanged: " + opToPublicName(op)
+ + " " + UserHandle.formatUid(uid)
+ + " " + packageName + " " + mode);
+ } catch (RemoteException e) {
+ // Intra-process call, should never happen.
+ }
+ }
+ final Pair[] permissions = mInjector.getPolicy().getBgPermissionsInMonitor();
+ if (permissions != null && permissions.length > 0) {
+ for (int i = 0; i < permissions.length; i++) {
+ final Pair<String, Integer> pair = permissions[i];
+ if (pair.second != op) {
+ continue;
+ }
+ final UidGrantedPermissionState state =
+ new UidGrantedPermissionState(uid, pair.first, op);
+ synchronized (mLock) {
+ handlePermissionsChangedLocked(uid, new UidGrantedPermissionState[] {state});
+ }
+ break;
+ }
+ }
+ }
+
private void handlePermissionsChanged(int uid) {
- final String[] permissions = mInjector.getPolicy().getBgPermissionsInMonitor();
+ if (DEBUG_PERMISSION_TRACKER) {
+ Slog.i(TAG, "handlePermissionsChanged " + UserHandle.formatUid(uid));
+ }
+ final Pair[] permissions = mInjector.getPolicy().getBgPermissionsInMonitor();
if (permissions != null && permissions.length > 0) {
final PermissionManagerServiceInternal pm =
mInjector.getPermissionManagerServiceInternal();
- final boolean[] states = new boolean[permissions.length];
+ final UidGrantedPermissionState[] states =
+ new UidGrantedPermissionState[permissions.length];
for (int i = 0; i < permissions.length; i++) {
- states[i] = pm.checkUidPermission(uid, permissions[i]) == PERMISSION_GRANTED;
+ final Pair<String, Integer> pair = permissions[i];
+ states[i] = new UidGrantedPermissionState(uid, pair.first, pair.second);
if (DEBUG_PERMISSION_TRACKER) {
- Slog.i(TAG, UserHandle.formatUid(uid) + " " + permissions[i] + "=" + states[i]);
+ Slog.i(TAG, states[i].toString());
}
}
synchronized (mLock) {
- handlePermissionsChangedLocked(uid, permissions, states);
+ handlePermissionsChangedLocked(uid, states);
}
}
}
@GuardedBy("mLock")
- private void handlePermissionsChangedLocked(int uid, String[] permissions, boolean[] states) {
+ private void handlePermissionsChangedLocked(int uid, UidGrantedPermissionState[] states) {
final int index = mUidGrantedPermissionsInMonitor.indexOfKey(uid);
- ArraySet<String> grantedPermissions = index >= 0
+ ArraySet<UidGrantedPermissionState> grantedPermissions = index >= 0
? mUidGrantedPermissionsInMonitor.valueAt(index) : null;
final long now = SystemClock.elapsedRealtime();
- for (int i = 0; i < permissions.length; i++) {
- final String permission = permissions[i];
- final boolean granted = states[i];
+ for (int i = 0; i < states.length; i++) {
+ final boolean granted = states[i].isGranted();
boolean changed = false;
if (granted) {
if (grantedPermissions == null) {
grantedPermissions = new ArraySet<>();
mUidGrantedPermissionsInMonitor.put(uid, grantedPermissions);
+ changed = true;
}
- changed = grantedPermissions.add(permission);
- } else if (grantedPermissions != null) {
- changed = grantedPermissions.remove(permission);
- if (grantedPermissions.isEmpty()) {
+ grantedPermissions.add(states[i]);
+ } else if (grantedPermissions != null && !grantedPermissions.isEmpty()) {
+ if (grantedPermissions.remove(states[i]) && grantedPermissions.isEmpty()) {
mUidGrantedPermissionsInMonitor.removeAt(index);
+ changed = true;
}
}
if (changed) {
@@ -178,10 +262,141 @@ final class AppPermissionTracker extends BaseAppStateTracker<AppPermissionPolicy
}
}
+ /**
+ * Represents the grant state of a permission + appop of the given UID.
+ */
+ private class UidGrantedPermissionState {
+ final int mUid;
+ final @Nullable String mPermission;
+ final int mAppOp;
+
+ private boolean mPermissionGranted;
+ private boolean mAppOpAllowed;
+
+ UidGrantedPermissionState(int uid, @Nullable String permission, int appOp) {
+ mUid = uid;
+ mPermission = permission;
+ mAppOp = appOp;
+ updatePermissionState();
+ updateAppOps();
+ }
+
+ void updatePermissionState() {
+ if (TextUtils.isEmpty(mPermission)) {
+ mPermissionGranted = true;
+ return;
+ }
+ mPermissionGranted = mInjector.getPermissionManagerServiceInternal()
+ .checkUidPermission(mUid, mPermission) == PERMISSION_GRANTED;
+ }
+
+ void updateAppOps() {
+ if (mAppOp == OP_NONE) {
+ mAppOpAllowed = true;
+ return;
+ }
+ final String[] packages = mInjector.getPackageManager().getPackagesForUid(mUid);
+ if (packages != null) {
+ final IAppOpsService appOpsService = mInjector.getIAppOpsService();
+ for (String pkg : packages) {
+ try {
+ final int mode = appOpsService.checkOperation(mAppOp, mUid, pkg);
+ if (mode == AppOpsManager.MODE_ALLOWED) {
+ mAppOpAllowed = true;
+ return;
+ }
+ } catch (RemoteException e) {
+ // Intra-process call, should never happen.
+ }
+ }
+ }
+ mAppOpAllowed = false;
+ }
+
+ boolean isGranted() {
+ return mPermissionGranted && mAppOpAllowed;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == null || !(other instanceof UidGrantedPermissionState)) {
+ return false;
+ }
+ final UidGrantedPermissionState otherState = (UidGrantedPermissionState) other;
+ return mUid == otherState.mUid && mAppOp == otherState.mAppOp
+ && Objects.equals(mPermission, otherState.mPermission);
+ }
+
+ @Override
+ public int hashCode() {
+ return (Integer.hashCode(mUid) * 31 + Integer.hashCode(mAppOp)) * 31
+ + (mPermission == null ? 0 : mPermission.hashCode());
+ }
+
+ @Override
+ public String toString() {
+ String s = "UidGrantedPermissionState{"
+ + System.identityHashCode(this) + " "
+ + UserHandle.formatUid(mUid) + ": ";
+ final boolean emptyPermissionName = TextUtils.isEmpty(mPermission);
+ if (!emptyPermissionName) {
+ s += mPermission + "=" + mPermissionGranted;
+ }
+ if (mAppOp != OP_NONE) {
+ if (!emptyPermissionName) {
+ s += ",";
+ }
+ s += opToPublicName(mAppOp) + "=" + mAppOpAllowed;
+ }
+ s += "}";
+ return s;
+ }
+ }
+
+ private void startWatchingMode(@NonNull Integer[] ops) {
+ synchronized (mAppOpsCallbacks) {
+ stopWatchingMode();
+ final IAppOpsService appOpsService = mInjector.getIAppOpsService();
+ try {
+ for (int op: ops) {
+ final MyAppOpsCallback cb = new MyAppOpsCallback();
+ mAppOpsCallbacks.put(op, cb);
+ appOpsService.startWatchingModeWithFlags(op, null,
+ AppOpsManager.WATCH_FOREGROUND_CHANGES, cb);
+ }
+ } catch (RemoteException e) {
+ // Intra-process call, should never happen.
+ }
+ }
+ }
+
+ private void stopWatchingMode() {
+ synchronized (mAppOpsCallbacks) {
+ final IAppOpsService appOpsService = mInjector.getIAppOpsService();
+ for (int i = mAppOpsCallbacks.size() - 1; i >= 0; i--) {
+ try {
+ appOpsService.stopWatchingMode(mAppOpsCallbacks.valueAt(i));
+ } catch (RemoteException e) {
+ // Intra-process call, should never happen.
+ }
+ }
+ mAppOpsCallbacks.clear();
+ }
+ }
+
+ private class MyAppOpsCallback extends IAppOpsCallback.Stub {
+ @Override
+ public void opChanged(int op, int uid, String packageName) {
+ mHandler.obtainMessage(MyHandler.MSG_APPOPS_CHANGED, op, uid, packageName)
+ .sendToTarget();
+ }
+ }
+
private static class MyHandler extends Handler {
static final int MSG_PERMISSIONS_INIT = 0;
static final int MSG_PERMISSIONS_DESTROY = 1;
static final int MSG_PERMISSIONS_CHANGED = 2;
+ static final int MSG_APPOPS_CHANGED = 3;
private @NonNull AppPermissionTracker mTracker;
@@ -194,14 +409,19 @@ final class AppPermissionTracker extends BaseAppStateTracker<AppPermissionPolicy
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_PERMISSIONS_INIT:
+ mTracker.handleAppOpsInit();
mTracker.handlePermissionsInit();
break;
case MSG_PERMISSIONS_DESTROY:
mTracker.handlePermissionsDestroy();
+ mTracker.handleAppOpsDestroy();
break;
case MSG_PERMISSIONS_CHANGED:
mTracker.handlePermissionsChanged(msg.arg1);
break;
+ case MSG_APPOPS_CHANGED:
+ mTracker.handleOpChanged(msg.arg1, msg.arg2, (String) msg.obj);
+ break;
}
}
}
@@ -231,25 +451,41 @@ final class AppPermissionTracker extends BaseAppStateTracker<AppPermissionPolicy
void dump(PrintWriter pw, String prefix) {
pw.print(prefix);
pw.println("APP PERMISSIONS TRACKER:");
- final String[] permissions = mInjector.getPolicy().getBgPermissionsInMonitor();
+ final Pair[] permissions = mInjector.getPolicy().getBgPermissionsInMonitor();
final String prefixMore = " " + prefix;
final String prefixMoreMore = " " + prefixMore;
- for (String permission : permissions) {
+ for (Pair<String, Integer> permission : permissions) {
pw.print(prefixMore);
- pw.print(permission);
+ final boolean emptyPermissionName = TextUtils.isEmpty(permission.first);
+ if (!emptyPermissionName) {
+ pw.print(permission.first);
+ }
+ if (permission.second != OP_NONE) {
+ if (!emptyPermissionName) {
+ pw.print('+');
+ }
+ pw.print(opToPublicName(permission.second));
+ }
pw.println(':');
synchronized (mLock) {
- final SparseArray<ArraySet<String>> uidPerms = mUidGrantedPermissionsInMonitor;
+ final SparseArray<ArraySet<UidGrantedPermissionState>> uidPerms =
+ mUidGrantedPermissionsInMonitor;
pw.print(prefixMoreMore);
pw.print('[');
boolean needDelimiter = false;
for (int i = 0, size = uidPerms.size(); i < size; i++) {
- if (uidPerms.valueAt(i).contains(permission)) {
- if (needDelimiter) {
- pw.print(',');
+ final ArraySet<UidGrantedPermissionState> uidPerm = uidPerms.valueAt(i);
+ for (int j = uidPerm.size() - 1; j >= 0; j--) {
+ final UidGrantedPermissionState state = uidPerm.valueAt(j);
+ if (state.mAppOp == permission.second
+ && TextUtils.equals(state.mPermission, permission.first)) {
+ if (needDelimiter) {
+ pw.print(',');
+ }
+ needDelimiter = true;
+ pw.print(UserHandle.formatUid(state.mUid));
+ break;
}
- needDelimiter = true;
- pw.print(UserHandle.formatUid(uidPerms.keyAt(i)));
}
}
pw.println(']');
@@ -277,20 +513,25 @@ final class AppPermissionTracker extends BaseAppStateTracker<AppPermissionPolicy
static final boolean DEFAULT_BG_PERMISSION_MONITOR_ENABLED = true;
/**
- * Default value to {@link #mBgPermissionsInMonitor}.
+ * Default value to {@link #mBgPermissionsInMonitor}, it comes in pair;
+ * the first string strings in the pair is the permission name, and the second string
+ * is the appops name, if they are associated.
*/
static final String[] DEFAULT_BG_PERMISSIONS_IN_MONITOR = new String[] {
- ACCESS_FINE_LOCATION,
+ ACCESS_FINE_LOCATION, OPSTR_FINE_LOCATION,
+ CAMERA, OPSTR_CAMERA,
+ RECORD_AUDIO, OPSTR_RECORD_AUDIO,
};
/**
* @see #KEY_BG_PERMISSIONS_IN_MONITOR.
*/
- volatile String[] mBgPermissionsInMonitor = DEFAULT_BG_PERMISSIONS_IN_MONITOR;
+ volatile @NonNull Pair[] mBgPermissionsInMonitor;
AppPermissionPolicy(@NonNull Injector injector, @NonNull AppPermissionTracker tracker) {
super(injector, tracker, KEY_BG_PERMISSION_MONITOR_ENABLED,
DEFAULT_BG_PERMISSION_MONITOR_ENABLED);
+ mBgPermissionsInMonitor = parsePermissionConfig(DEFAULT_BG_PERMISSIONS_IN_MONITOR);
}
@Override
@@ -311,17 +552,38 @@ final class AppPermissionTracker extends BaseAppStateTracker<AppPermissionPolicy
}
}
- String[] getBgPermissionsInMonitor() {
+ Pair[] getBgPermissionsInMonitor() {
return mBgPermissionsInMonitor;
}
+ private @NonNull Pair[] parsePermissionConfig(@NonNull String[] perms) {
+ final Pair[] result = new Pair[perms.length / 2];
+ for (int i = 0, j = 0; i < perms.length; i += 2, j++) {
+ try {
+ result[j] = Pair.create(TextUtils.isEmpty(perms[i]) ? null : perms[i],
+ TextUtils.isEmpty(perms[i + 1]) ? OP_NONE : strOpToOp(perms[i + 1]));
+ } catch (Exception e) {
+ // Ignore.
+ }
+ }
+ return result;
+ }
+
private void updateBgPermissionsInMonitor() {
final String config = DeviceConfig.getString(
DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
KEY_BG_PERMISSIONS_IN_MONITOR,
null);
- mBgPermissionsInMonitor = config != null
- ? config.split(",") : DEFAULT_BG_PERMISSIONS_IN_MONITOR;
+ final Pair[] newPermsInMonitor = parsePermissionConfig(
+ config != null ? config.split(",") : DEFAULT_BG_PERMISSIONS_IN_MONITOR);
+ if (!Arrays.equals(mBgPermissionsInMonitor, newPermsInMonitor)) {
+ mBgPermissionsInMonitor = newPermsInMonitor;
+ if (isEnabled()) {
+ // Trigger a reload.
+ onTrackerEnabled(false);
+ onTrackerEnabled(true);
+ }
+ }
}
@Override
@@ -338,7 +600,21 @@ final class AppPermissionTracker extends BaseAppStateTracker<AppPermissionPolicy
pw.print(prefix);
pw.print(KEY_BG_PERMISSIONS_IN_MONITOR);
pw.print('=');
- pw.println(Arrays.toString(mBgPermissionsInMonitor));
+ pw.print('[');
+ for (int i = 0; i < mBgPermissionsInMonitor.length; i++) {
+ if (i > 0) {
+ pw.print(',');
+ }
+ final Pair<String, Integer> pair = mBgPermissionsInMonitor[i];
+ if (pair.first != null) {
+ pw.print(pair.first);
+ }
+ pw.print(',');
+ if (pair.second != OP_NONE) {
+ pw.print(opToPublicName(pair.second));
+ }
+ }
+ pw.println(']');
}
}
}
diff --git a/services/core/java/com/android/server/am/AppProfiler.java b/services/core/java/com/android/server/am/AppProfiler.java
index d6a4cf650cba..16a728386bd6 100644
--- a/services/core/java/com/android/server/am/AppProfiler.java
+++ b/services/core/java/com/android/server/am/AppProfiler.java
@@ -58,7 +58,6 @@ import android.content.ComponentCallbacks2;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
-import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.net.Uri;
import android.os.Binder;
@@ -608,13 +607,7 @@ public class AppProfiler {
if (check != null) {
if ((pss * 1024) >= check && profile.getThread() != null
&& mMemWatchDumpProcName == null) {
- boolean isDebuggable = Build.IS_DEBUGGABLE;
- if (!isDebuggable) {
- if ((proc.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
- isDebuggable = true;
- }
- }
- if (isDebuggable) {
+ if (Build.IS_DEBUGGABLE || proc.isDebuggable()) {
Slog.w(TAG, "Process " + proc + " exceeded pss limit " + check + "; reporting");
startHeapDumpLPf(profile, false);
} else {
@@ -1702,7 +1695,8 @@ public class AppProfiler {
try {
if (start) {
stopProfilerLPf(null, 0);
- mService.setProfileApp(proc.info, proc.processName, profilerInfo);
+ mService.setProfileApp(proc.info, proc.processName, profilerInfo,
+ proc.isSdkSandbox ? proc.getClientInfoForSdkSandbox() : null);
mProfileData.setProfileProc(proc);
mProfileType = profileType;
ParcelFileDescriptor fd = profilerInfo.profileFd;
@@ -1886,8 +1880,7 @@ public class AppProfiler {
BatteryStatsImpl.Uid.Proc ps = st.batteryStats;
if (ps == null || !ps.isActive()) {
st.batteryStats = ps = bstats.getProcessStatsLocked(
- bstats.mapUid(st.uid), st.name,
- elapsedRealtime, uptime);
+ st.uid, st.name, elapsedRealtime, uptime);
}
ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
}
@@ -2076,7 +2069,7 @@ public class AppProfiler {
if (mAppAgentMap != null && mAppAgentMap.containsKey(processName)) {
// We need to do a debuggable check here. See setAgentApp for why the check is
// postponed to here.
- if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
+ if (app.isDebuggable()) {
String agent = mAppAgentMap.get(processName);
// Do not overwrite already requested agent.
if (profilerInfo == null) {
@@ -2133,7 +2126,7 @@ public class AppProfiler {
if (preBindAgent != null) {
thread.attachAgent(preBindAgent);
}
- if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
+ if (app.isDebuggable()) {
thread.attachStartupAgents(app.info.dataDir);
}
return profilerInfo;
diff --git a/services/core/java/com/android/server/am/AppRestrictionController.java b/services/core/java/com/android/server/am/AppRestrictionController.java
index 6e6cb879ae4f..41ff08309d89 100644
--- a/services/core/java/com/android/server/am/AppRestrictionController.java
+++ b/services/core/java/com/android/server/am/AppRestrictionController.java
@@ -135,6 +135,7 @@ import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseArrayMap;
import android.util.TimeUtils;
+import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
@@ -182,7 +183,7 @@ public final class AppRestrictionController {
/**
* Whether or not to show the foreground service manager on tapping notifications.
*/
- private static final boolean ENABLE_SHOW_FOREGROUND_SERVICE_MANAGER = false;
+ private static final boolean ENABLE_SHOW_FOREGROUND_SERVICE_MANAGER = true;
private final Context mContext;
private final HandlerThread mBgHandlerThread;
@@ -241,7 +242,7 @@ public final class AppRestrictionController {
/**
* The pre-config packages that are exempted from the background restrictions.
*/
- private ArraySet<String> mBgRestrictionExemptioFromSysConfig;
+ ArraySet<String> mBgRestrictionExemptioFromSysConfig;
/**
* Lock specifically for bookkeeping around the carrier-privileged app set.
@@ -1369,6 +1370,12 @@ public final class AppRestrictionController {
}
}
+ void dumpAsProto(ProtoOutputStream proto, int uid) {
+ for (int i = 0, size = mAppStateTrackers.size(); i < size; i++) {
+ mAppStateTrackers.get(i).dumpAsProto(proto, uid);
+ }
+ }
+
private void applyRestrictionLevel(String pkgName, int uid, @RestrictionLevel int level,
int curBucket, boolean allowUpdateBucket, int reason, int subReason) {
int curLevel;
@@ -1595,8 +1602,8 @@ public final class AppRestrictionController {
cancelRequestBgRestrictedIfNecessary(packageName, uid);
final Intent newIntent = new Intent(ACTION_SHOW_FOREGROUND_SERVICE_MANAGER);
newIntent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
- mContext.sendBroadcastAsUser(newIntent,
- UserHandle.of(UserHandle.getUserId(uid)));
+ // Task manager runs in SystemUI, which is SYSTEM user only.
+ mContext.sendBroadcastAsUser(newIntent, UserHandle.SYSTEM);
break;
}
}
@@ -1670,9 +1677,10 @@ public final class AppRestrictionController {
if (ENABLE_SHOW_FOREGROUND_SERVICE_MANAGER) {
final Intent intent = new Intent(ACTION_SHOW_FOREGROUND_SERVICE_MANAGER);
intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
+ // Task manager runs in SystemUI, which is SYSTEM user only.
pendingIntent = PendingIntent.getBroadcastAsUser(mContext, 0,
intent, PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE,
- UserHandle.of(UserHandle.getUserId(uid)));
+ UserHandle.SYSTEM);
} else {
final Intent intent = new Intent(Settings.ACTION_VIEW_ADVANCED_POWER_USAGE_DETAIL);
intent.setData(Uri.fromParts(PACKAGE_SCHEME, packageName, null));
@@ -1750,7 +1758,7 @@ public final class AppRestrictionController {
SYSTEM_UID, UserHandle.getUserId(uid));
final String title = mContext.getString(titleRes);
final String message = mContext.getString(messageRes,
- ai != null ? pm.getText(packageName, ai.labelRes, ai) : packageName);
+ ai != null ? ai.loadLabel(pm) : packageName);
final Icon icon = ai != null ? Icon.createWithResource(packageName, ai.icon) : null;
postNotification(notificationId, packageName, uid, title, message, icon, pendingIntent,
@@ -1833,6 +1841,9 @@ public final class AppRestrictionController {
}
void handleUidInactive(int uid, boolean disabled) {
+ if (!mConstantsObserver.mBgAutoRestrictedBucket) {
+ return;
+ }
final ArrayList<Runnable> pendingTasks = mTmpRunnables;
synchronized (mSettingsLock) {
final int index = mActiveUids.indexOfKey(uid);
@@ -1855,6 +1866,9 @@ public final class AppRestrictionController {
}
void handleUidActive(int uid) {
+ if (!mConstantsObserver.mBgAutoRestrictedBucket) {
+ return;
+ }
synchronized (mSettingsLock) {
final AppStandbyInternal appStandbyInternal = mInjector.getAppStandbyInternal();
final int userId = UserHandle.getUserId(uid);
diff --git a/services/core/java/com/android/server/am/BaseAppStateTracker.java b/services/core/java/com/android/server/am/BaseAppStateTracker.java
index 0fada53d622e..2f76e2497834 100644
--- a/services/core/java/com/android/server/am/BaseAppStateTracker.java
+++ b/services/core/java/com/android/server/am/BaseAppStateTracker.java
@@ -33,9 +33,12 @@ import android.media.session.MediaSessionManager;
import android.os.BatteryManagerInternal;
import android.os.BatteryStatsInternal;
import android.os.Handler;
+import android.os.ServiceManager;
import android.permission.PermissionManager;
import android.util.Slog;
+import android.util.proto.ProtoOutputStream;
+import com.android.internal.app.IAppOpsService;
import com.android.server.DeviceIdleInternal;
import com.android.server.LocalServices;
import com.android.server.notification.NotificationManagerInternal;
@@ -61,13 +64,15 @@ public abstract class BaseAppStateTracker<T extends BaseAppStatePolicy> {
static final int STATE_TYPE_MEDIA_SESSION = 1;
static final int STATE_TYPE_FGS_MEDIA_PLAYBACK = 1 << 1;
static final int STATE_TYPE_FGS_LOCATION = 1 << 2;
- static final int STATE_TYPE_PERMISSION = 1 << 3;
- static final int STATE_TYPE_NUM = 4;
+ static final int STATE_TYPE_FGS_WITH_NOTIFICATION = 1 << 3;
+ static final int STATE_TYPE_PERMISSION = 1 << 4;
+ static final int STATE_TYPE_NUM = 5;
static final int STATE_TYPE_INDEX_MEDIA_SESSION = 0;
static final int STATE_TYPE_INDEX_FGS_MEDIA_PLAYBACK = 1;
static final int STATE_TYPE_INDEX_FGS_LOCATION = 2;
- static final int STATE_TYPE_INDEX_PERMISSION = 3;
+ static final int STATE_TYPE_INDEX_FGS_WITH_NOTIFICATION = 3;
+ static final int STATE_TYPE_INDEX_PERMISSION = 4;
protected final AppRestrictionController mAppRestrictionController;
protected final Injector<T> mInjector;
@@ -126,6 +131,9 @@ public abstract class BaseAppStateTracker<T extends BaseAppStatePolicy> {
case STATE_TYPE_FGS_LOCATION:
sb.append("FGS_LOCATION");
break;
+ case STATE_TYPE_FGS_WITH_NOTIFICATION:
+ sb.append("FGS_NOTIFICATION");
+ break;
case STATE_TYPE_PERMISSION:
sb.append("PERMISSION");
break;
@@ -250,6 +258,9 @@ public abstract class BaseAppStateTracker<T extends BaseAppStatePolicy> {
mInjector.getPolicy().dump(pw, " " + prefix);
}
+ void dumpAsProto(ProtoOutputStream proto, int uid) {
+ }
+
static class Injector<T extends BaseAppStatePolicy> {
T mAppStatePolicy;
@@ -266,6 +277,7 @@ public abstract class BaseAppStateTracker<T extends BaseAppStatePolicy> {
MediaSessionManager mMediaSessionManager;
RoleManager mRoleManager;
NotificationManagerInternal mNotificationManagerInternal;
+ IAppOpsService mIAppOpsService;
void setPolicy(T policy) {
mAppStatePolicy = policy;
@@ -288,6 +300,8 @@ public abstract class BaseAppStateTracker<T extends BaseAppStatePolicy> {
mRoleManager = context.getSystemService(RoleManager.class);
mNotificationManagerInternal = LocalServices.getService(
NotificationManagerInternal.class);
+ mIAppOpsService = IAppOpsService.Stub.asInterface(
+ ServiceManager.getService(Context.APP_OPS_SERVICE));
getPolicy().onSystemReady();
}
@@ -358,5 +372,9 @@ public abstract class BaseAppStateTracker<T extends BaseAppStatePolicy> {
NotificationManagerInternal getNotificationManagerInternal() {
return mNotificationManagerInternal;
}
+
+ IAppOpsService getIAppOpsService() {
+ return mIAppOpsService;
+ }
}
}
diff --git a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
index 1131fa8a32b8..4fdc88d3fd64 100644
--- a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
+++ b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
@@ -561,8 +561,18 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync {
// We were asked to fetch Bluetooth data.
final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
if (adapter != null) {
- bluetoothReceiver = new SynchronousResultReceiver("bluetooth");
- adapter.requestControllerActivityEnergyInfo(bluetoothReceiver);
+ SynchronousResultReceiver resultReceiver =
+ new SynchronousResultReceiver("bluetooth");
+ adapter.requestControllerActivityEnergyInfo(
+ Runnable::run,
+ info -> {
+ Bundle bundle = new Bundle();
+ bundle.putParcelable(BatteryStats.RESULT_RECEIVER_CONTROLLER_KEY,
+ info);
+ resultReceiver.send(0, bundle);
+ }
+ );
+ bluetoothReceiver = resultReceiver;
}
}
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 91822ac353ab..eb7897b2c678 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -799,6 +799,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub
final BatteryUsageStatsQuery querySinceReset =
new BatteryUsageStatsQuery.Builder()
.includeProcessStateData()
+ .includeVirtualUids()
.build();
bus = getBatteryUsageStats(List.of(querySinceReset)).get(0);
break;
@@ -806,6 +807,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub
final BatteryUsageStatsQuery queryPowerProfile =
new BatteryUsageStatsQuery.Builder()
.includeProcessStateData()
+ .includeVirtualUids()
.powerProfileModeledOnly()
.build();
bus = getBatteryUsageStats(List.of(queryPowerProfile)).get(0);
@@ -821,6 +823,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub
final BatteryUsageStatsQuery queryBeforeReset =
new BatteryUsageStatsQuery.Builder()
.includeProcessStateData()
+ .includeVirtualUids()
.aggregateSnapshots(sessionStart, sessionEnd)
.build();
bus = getBatteryUsageStats(List.of(queryBeforeReset)).get(0);
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index ea63c080cf68..ade44eac4583 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -21,6 +21,9 @@ import static android.os.Process.ZYGOTE_POLICY_FLAG_EMPTY;
import static android.os.Process.ZYGOTE_POLICY_FLAG_LATENCY_SENSITIVE;
import static android.text.TextUtils.formatSimple;
+import static com.android.internal.util.FrameworkStatsLog.BOOT_COMPLETED_BROADCAST_COMPLETION_LATENCY_REPORTED;
+import static com.android.internal.util.FrameworkStatsLog.BOOT_COMPLETED_BROADCAST_COMPLETION_LATENCY_REPORTED__EVENT__BOOT_COMPLETED;
+import static com.android.internal.util.FrameworkStatsLog.BOOT_COMPLETED_BROADCAST_COMPLETION_LATENCY_REPORTED__EVENT__LOCKED_BOOT_COMPLETED;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BROADCAST;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BROADCAST_DEFERRAL;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BROADCAST_LIGHT;
@@ -29,6 +32,7 @@ import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PERMISSIONS
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_BROADCAST;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_MU;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
@@ -51,6 +55,7 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PermissionInfo;
import android.content.pm.ResolveInfo;
+import android.content.pm.UserInfo;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
@@ -64,6 +69,7 @@ import android.os.RemoteException;
import android.os.SystemClock;
import android.os.Trace;
import android.os.UserHandle;
+import android.os.UserManager;
import android.permission.IPermissionManager;
import android.text.TextUtils;
import android.util.EventLog;
@@ -75,6 +81,7 @@ import android.util.proto.ProtoOutputStream;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FrameworkStatsLog;
import com.android.server.LocalServices;
+import com.android.server.pm.UserManagerInternal;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -250,12 +257,16 @@ public final class BroadcastQueue {
public void enqueueParallelBroadcastLocked(BroadcastRecord r) {
r.enqueueClockTime = System.currentTimeMillis();
+ r.enqueueTime = SystemClock.uptimeMillis();
+ r.enqueueRealTime = SystemClock.elapsedRealtime();
mParallelBroadcasts.add(r);
enqueueBroadcastHelper(r);
}
public void enqueueOrderedBroadcastLocked(BroadcastRecord r) {
r.enqueueClockTime = System.currentTimeMillis();
+ r.enqueueTime = SystemClock.uptimeMillis();
+ r.enqueueRealTime = SystemClock.elapsedRealtime();
mDispatcher.enqueueOrderedBroadcastLocked(r);
enqueueBroadcastHelper(r);
}
@@ -1121,6 +1132,7 @@ public final class BroadcastQueue {
while (mParallelBroadcasts.size() > 0) {
r = mParallelBroadcasts.remove(0);
r.dispatchTime = SystemClock.uptimeMillis();
+ r.dispatchRealTime = SystemClock.elapsedRealtime();
r.dispatchClockTime = System.currentTimeMillis();
if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
@@ -1292,6 +1304,7 @@ public final class BroadcastQueue {
performReceiveLocked(r.callerApp, r.resultTo,
new Intent(r.intent), r.resultCode,
r.resultData, r.resultExtras, false, false, r.userId);
+ logBootCompletedBroadcastCompletionLatencyIfPossible(r);
// Set this to null so that the reference
// (local and remote) isn't kept in the mBroadcastHistory.
r.resultTo = null;
@@ -1408,6 +1421,7 @@ public final class BroadcastQueue {
r.receiverTime = SystemClock.uptimeMillis();
if (recIdx == 0) {
r.dispatchTime = r.receiverTime;
+ r.dispatchRealTime = SystemClock.elapsedRealtime();
r.dispatchClockTime = System.currentTimeMillis();
if (mLogLatencyMetrics) {
@@ -1866,6 +1880,59 @@ public final class BroadcastQueue {
return null;
}
+ private void logBootCompletedBroadcastCompletionLatencyIfPossible(BroadcastRecord r) {
+ // Only log after last receiver.
+ // In case of split BOOT_COMPLETED broadcast, make sure only call this method on the
+ // last BroadcastRecord of the split broadcast which has non-null resultTo.
+ final int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
+ if (r.nextReceiver < numReceivers) {
+ return;
+ }
+ final String action = r.intent.getAction();
+ int event = 0;
+ if (Intent.ACTION_LOCKED_BOOT_COMPLETED.equals(action)) {
+ event = BOOT_COMPLETED_BROADCAST_COMPLETION_LATENCY_REPORTED__EVENT__LOCKED_BOOT_COMPLETED;
+ } else if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
+ event = BOOT_COMPLETED_BROADCAST_COMPLETION_LATENCY_REPORTED__EVENT__BOOT_COMPLETED;
+ }
+ if (event != 0) {
+ final int dispatchLatency = (int)(r.dispatchTime - r.enqueueTime);
+ final int completeLatency = (int)
+ (SystemClock.uptimeMillis() - r.enqueueTime);
+ final int dispatchRealLatency = (int)(r.dispatchRealTime - r.enqueueRealTime);
+ final int completeRealLatency = (int)
+ (SystemClock.elapsedRealtime() - r.enqueueRealTime);
+ int userType = FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__USER_TYPE__TYPE_UNKNOWN;
+ // This method is called very infrequently, no performance issue we call
+ // LocalServices.getService() here.
+ final UserManagerInternal umInternal = LocalServices.getService(
+ UserManagerInternal.class);
+ final UserInfo userInfo = umInternal.getUserInfo(r.userId);
+ if (userInfo != null) {
+ userType = UserManager.getUserTypeForStatsd(userInfo.userType);
+ }
+ Slog.i(TAG_BROADCAST,
+ "BOOT_COMPLETED_BROADCAST_COMPLETION_LATENCY_REPORTED action:"
+ + action
+ + " dispatchLatency:" + dispatchLatency
+ + " completeLatency:" + completeLatency
+ + " dispatchRealLatency:" + dispatchRealLatency
+ + " completeRealLatency:" + completeRealLatency
+ + " receiversSize:" + r.receivers.size()
+ + " userId:" + r.userId
+ + " userType:" + (userInfo != null? userInfo.userType : null));
+ FrameworkStatsLog.write(
+ BOOT_COMPLETED_BROADCAST_COMPLETION_LATENCY_REPORTED,
+ event,
+ dispatchLatency,
+ completeLatency,
+ dispatchRealLatency,
+ completeRealLatency,
+ r.userId,
+ userType);
+ }
+ }
+
private void maybeReportBroadcastDispatchedEventLocked(BroadcastRecord r, int targetUid) {
// STOPSHIP (217251579): Temporarily use temp-allowlist reason to identify
// push messages and record response events.
diff --git a/services/core/java/com/android/server/am/BroadcastRecord.java b/services/core/java/com/android/server/am/BroadcastRecord.java
index 8b1e829ad836..2ee32b6abe96 100644
--- a/services/core/java/com/android/server/am/BroadcastRecord.java
+++ b/services/core/java/com/android/server/am/BroadcastRecord.java
@@ -84,11 +84,14 @@ final class BroadcastRecord extends Binder {
boolean deferred;
int splitCount; // refcount for result callback, when split
int splitToken; // identifier for cross-BroadcastRecord refcount
+ long enqueueTime; // uptimeMillis when the broadcast was enqueued
+ long enqueueRealTime; // elapsedRealtime when the broadcast was enqueued
long enqueueClockTime; // the clock time the broadcast was enqueued
long dispatchTime; // when dispatch started on this set of receivers
+ long dispatchRealTime; // elapsedRealtime when the broadcast was dispatched
long dispatchClockTime; // the clock time the dispatch started
long receiverTime; // when current receiver started for timeouts.
- long finishTime; // when we finished the broadcast.
+ long finishTime; // when we finished the current receiver.
boolean timeoutExempt; // true if this broadcast is not subject to receiver timeouts
int resultCode; // current result code value.
String resultData; // current result data value.
@@ -169,7 +172,7 @@ final class BroadcastRecord extends Binder {
pw.print(prefix); pw.print("dispatchTime=");
TimeUtils.formatDuration(dispatchTime, now, pw);
pw.print(" (");
- TimeUtils.formatDuration(dispatchClockTime-enqueueClockTime, pw);
+ TimeUtils.formatDuration(dispatchTime - enqueueTime, pw);
pw.print(" since enq)");
if (finishTime != 0) {
pw.print(" finishTime="); TimeUtils.formatDuration(finishTime, now, pw);
@@ -324,8 +327,11 @@ final class BroadcastRecord extends Binder {
delivery = from.delivery;
duration = from.duration;
resultTo = from.resultTo;
+ enqueueTime = from.enqueueTime;
+ enqueueRealTime = from.enqueueRealTime;
enqueueClockTime = from.enqueueClockTime;
dispatchTime = from.dispatchTime;
+ dispatchRealTime = from.dispatchRealTime;
dispatchClockTime = from.dispatchClockTime;
receiverTime = from.receiverTime;
finishTime = from.finishTime;
@@ -378,7 +384,9 @@ final class BroadcastRecord extends Binder {
requiredPermissions, excludedPermissions, appOp, options, splitReceivers, resultTo,
resultCode, resultData, resultExtras, ordered, sticky, initialSticky, userId,
allowBackgroundActivityStarts, mBackgroundActivityStartsToken, timeoutExempt);
-
+ split.enqueueTime = this.enqueueTime;
+ split.enqueueRealTime = this.enqueueRealTime;
+ split.enqueueClockTime = this.enqueueClockTime;
split.splitToken = this.splitToken;
return split;
}
@@ -448,9 +456,11 @@ final class BroadcastRecord extends Binder {
final BroadcastRecord br = new BroadcastRecord(queue, intent, callerApp, callerPackage,
callerFeatureId, callingPid, callingUid, callerInstantApp, resolvedType,
requiredPermissions, excludedPermissions, appOp, options,
- uid2receiverList.valueAt(i), resultTo,
+ uid2receiverList.valueAt(i), null /* _resultTo */,
resultCode, resultData, resultExtras, ordered, sticky, initialSticky, userId,
allowBackgroundActivityStarts, mBackgroundActivityStartsToken, timeoutExempt);
+ br.enqueueTime = this.enqueueTime;
+ br.enqueueRealTime = this.enqueueRealTime;
br.enqueueClockTime = this.enqueueClockTime;
ret.put(uid2receiverList.keyAt(i), br);
}
diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java
index b18d390476f0..ff569a681a4e 100644
--- a/services/core/java/com/android/server/am/CachedAppOptimizer.java
+++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java
@@ -183,6 +183,8 @@ public final class CachedAppOptimizer {
private final ActivityManagerGlobalLock mProcLock;
+ private final Object mFreezerLock = new Object();
+
private final OnPropertiesChangedListener mOnFlagsChangedListener =
new OnPropertiesChangedListener() {
@Override
@@ -949,8 +951,8 @@ public final class CachedAppOptimizer {
}
}
- @GuardedBy({"mAm", "mProcLock"})
- void unfreezeAppLSP(ProcessRecord app) {
+ @GuardedBy({"mAm", "mProcLock", "mFreezerLock"})
+ void unfreezeAppInternalLSP(ProcessRecord app) {
final int pid = app.getPid();
final ProcessCachedOptimizerRecord opt = app.mOptRecord;
if (opt.isPendingFreeze()) {
@@ -1035,6 +1037,42 @@ public final class CachedAppOptimizer {
}
}
+ @GuardedBy({"mAm", "mProcLock"})
+ void unfreezeAppLSP(ProcessRecord app) {
+ synchronized (mFreezerLock) {
+ unfreezeAppInternalLSP(app);
+ }
+ }
+
+ /**
+ * This quick function works around the race condition between WM/ATMS and AMS, allowing
+ * the former to directly unfreeze a frozen process before the latter runs updateOomAdj.
+ * After the race issue is solved, this workaround can be removed. (b/213288355)
+ * The caller of this function should still trigger updateOomAdj for AMS to unfreeze the app.
+ * @param pid pid of the process to be unfrozen
+ */
+ void unfreezeProcess(int pid) {
+ synchronized (mFreezerLock) {
+ ProcessRecord app = mFrozenProcesses.get(pid);
+ if (app == null) {
+ return;
+ }
+ Slog.d(TAG_AM, "quick sync unfreeze " + pid);
+ try {
+ freezeBinder(pid, false);
+ } catch (RuntimeException e) {
+ Slog.e(TAG_AM, "Unable to quick unfreeze binder for " + pid);
+ return;
+ }
+
+ try {
+ Process.setProcessFrozen(pid, app.uid, false);
+ } catch (Exception e) {
+ Slog.e(TAG_AM, "Unable to quick unfreeze " + pid);
+ }
+ }
+ }
+
/**
* To be called when the given app is killed.
*/
@@ -1464,8 +1502,6 @@ public final class CachedAppOptimizer {
return;
}
- Slog.d(TAG_AM, "froze " + pid + " " + name);
-
EventLog.writeEvent(EventLogTags.AM_FREEZE, pid, name);
// See above for why we're not taking mPhenotypeFlagLock here
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index 6a211d31aa49..9626bbe0b4b2 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -407,7 +407,6 @@ public class OomAdjuster {
uids.clear();
uids.put(uidRec.getUid(), uidRec);
updateUidsLSP(uids, SystemClock.elapsedRealtime());
- mProcessList.incrementProcStateSeqAndNotifyAppsLOSP(uids);
}
}
@@ -750,7 +749,7 @@ public class OomAdjuster {
}
final long now = SystemClock.uptimeMillis();
final long nowElapsed = SystemClock.elapsedRealtime();
- final long oldTime = now - ProcessList.MAX_EMPTY_TIME;
+ final long oldTime = now - mConstants.mMaxEmptyTimeMillis;
final boolean fullUpdate = processes == null;
ActiveUids activeUids = uids;
ArrayList<ProcessRecord> activeProcesses = fullUpdate ? mProcessList.getLruProcessesLOSP()
@@ -1031,15 +1030,25 @@ public class OomAdjuster {
}
}
+ private long mNextNoKillDebugMessageTime;
+
@GuardedBy({"mService", "mProcLock"})
private boolean updateAndTrimProcessLSP(final long now, final long nowElapsed,
final long oldTime, final ActiveUids activeUids) {
ArrayList<ProcessRecord> lruList = mProcessList.getLruProcessesLOSP();
final int numLru = lruList.size();
- final int emptyProcessLimit = mConstants.CUR_MAX_EMPTY_PROCESSES;
- final int cachedProcessLimit = mConstants.CUR_MAX_CACHED_PROCESSES
- - emptyProcessLimit;
+ final boolean doKillExcessiveProcesses = shouldKillExcessiveProcesses(now);
+ if (!doKillExcessiveProcesses) {
+ if (mNextNoKillDebugMessageTime < now) {
+ Slog.d(TAG, "Not killing cached processes"); // STOPSHIP Remove it b/222365734
+ mNextNoKillDebugMessageTime = now + 5000; // Every 5 seconds
+ }
+ }
+ final int emptyProcessLimit = doKillExcessiveProcesses
+ ? mConstants.CUR_MAX_EMPTY_PROCESSES : Integer.MAX_VALUE;
+ final int cachedProcessLimit = doKillExcessiveProcesses
+ ? (mConstants.CUR_MAX_CACHED_PROCESSES - emptyProcessLimit) : Integer.MAX_VALUE;
int lastCachedGroup = 0;
int lastCachedGroupUid = 0;
int numCached = 0;
@@ -1089,7 +1098,7 @@ public class OomAdjuster {
case PROCESS_STATE_CACHED_EMPTY:
if (numEmpty > mConstants.CUR_TRIM_EMPTY_PROCESSES
&& app.getLastActivityTime() < oldTime) {
- app.killLocked("empty for " + ((oldTime + ProcessList.MAX_EMPTY_TIME
+ app.killLocked("empty for " + ((now
- app.getLastActivityTime()) / 1000) + "s",
"empty for too long",
ApplicationExitInfo.REASON_OTHER,
@@ -1134,8 +1143,6 @@ public class OomAdjuster {
}
}
- mProcessList.incrementProcStateSeqAndNotifyAppsLOSP(activeUids);
-
return mService.mAppProfiler.updateLowMemStateLSP(numCached, numEmpty, numTrimming);
}
@@ -1170,6 +1177,11 @@ public class OomAdjuster {
@GuardedBy({"mService", "mProcLock"})
private void updateUidsLSP(ActiveUids activeUids, final long nowElapsed) {
+ // This compares previously set procstate to the current procstate in regards to whether
+ // or not the app's network access will be blocked. So, this needs to be called before
+ // we update the UidRecord's procstate by calling {@link UidRecord#setSetProcState}.
+ mProcessList.incrementProcStateSeqAndNotifyAppsLOSP(activeUids);
+
ArrayList<UidRecord> becameIdle = mTmpBecameIdle;
becameIdle.clear();
@@ -1258,6 +1270,25 @@ public class OomAdjuster {
}
}
+ /**
+ * Return true if we should kill excessive cached/empty processes.
+ */
+ private boolean shouldKillExcessiveProcesses(long nowUptime) {
+ final long lastUserUnlockingUptime = mService.mUserController.getLastUserUnlockingUptime();
+
+ if (lastUserUnlockingUptime == 0) {
+ // No users have been unlocked.
+ return !mConstants.mNoKillCachedProcessesUntilBootCompleted;
+ }
+ final long noKillCachedProcessesPostBootCompletedDurationMillis =
+ mConstants.mNoKillCachedProcessesPostBootCompletedDurationMillis;
+ if ((lastUserUnlockingUptime + noKillCachedProcessesPostBootCompletedDurationMillis)
+ > nowUptime) {
+ return false;
+ }
+ return true;
+ }
+
private final ComputeOomAdjWindowCallback mTmpComputeOomAdjWindowCallback =
new ComputeOomAdjWindowCallback();
@@ -2532,7 +2563,7 @@ public class OomAdjuster {
if (app.getWaitingToKill() != null && app.mReceivers.numberOfCurReceivers() == 0
&& state.getSetSchedGroup() == ProcessList.SCHED_GROUP_BACKGROUND) {
app.killLocked(app.getWaitingToKill(), ApplicationExitInfo.REASON_USER_REQUESTED,
- ApplicationExitInfo.SUBREASON_UNKNOWN, true);
+ ApplicationExitInfo.SUBREASON_REMOVE_TASK, true);
success = false;
} else {
int processGroup;
diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java
index b1c91ba4a79d..81a8680cdbf0 100644
--- a/services/core/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/core/java/com/android/server/am/PendingIntentRecord.java
@@ -368,8 +368,7 @@ public final class PendingIntentRecord extends IIntentSender.Stub {
// Apply any launch flags from the ActivityOptions. This is to ensure that the caller
// can specify a consistent launch mode even if the PendingIntent is immutable
- final ActivityOptions opts = options != null ? ActivityOptions.fromBundle(options)
- : null;
+ final ActivityOptions opts = ActivityOptions.fromBundle(options);
if (opts != null) {
finalIntent.addFlags(opts.getPendingIntentLaunchFlags());
}
diff --git a/services/core/java/com/android/server/am/PendingStartActivityUids.java b/services/core/java/com/android/server/am/PendingStartActivityUids.java
index 802ea001e28c..455c75b88218 100644
--- a/services/core/java/com/android/server/am/PendingStartActivityUids.java
+++ b/services/core/java/com/android/server/am/PendingStartActivityUids.java
@@ -46,10 +46,13 @@ final class PendingStartActivityUids {
mContext = context;
}
- synchronized void add(int uid, int pid) {
+ /** Returns {@code true} if the uid is put to the pending array. Otherwise it existed. */
+ synchronized boolean add(int uid, int pid) {
if (mPendingUids.get(uid) == null) {
mPendingUids.put(uid, new Pair<>(pid, SystemClock.elapsedRealtime()));
+ return true;
}
+ return false;
}
synchronized void delete(int uid) {
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 636b7f2abe50..253686c2602d 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -293,9 +293,6 @@ public final class ProcessList {
// without empty apps being able to push them out of memory.
static final int MIN_CACHED_APPS = 2;
- // We allow empty processes to stick around for at most 30 minutes.
- static final long MAX_EMPTY_TIME = 30 * 60 * 1000;
-
// Threshold of number of cached+empty where we consider memory critical.
static final int TRIM_CRITICAL_THRESHOLD = 3;
@@ -1721,8 +1718,16 @@ public final class ProcessList {
int runtimeFlags = 0;
boolean debuggableFlag = (app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
- if (!debuggableFlag && app.isSdkSandbox) {
- debuggableFlag = isAppForSdkSandboxDebuggable(app);
+ boolean isProfileableByShell = app.info.isProfileableByShell();
+ boolean isProfileable = app.info.isProfileable();
+
+ if (app.isSdkSandbox) {
+ ApplicationInfo clientInfo = app.getClientInfoForSdkSandbox();
+ if (clientInfo != null) {
+ debuggableFlag |= (clientInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
+ isProfileableByShell |= clientInfo.isProfileableByShell();
+ isProfileable |= clientInfo.isProfileable();
+ }
}
if (debuggableFlag) {
@@ -1744,10 +1749,10 @@ public final class ProcessList {
if ((app.info.flags & ApplicationInfo.FLAG_VM_SAFE_MODE) != 0 || mService.mSafeMode) {
runtimeFlags |= Zygote.DEBUG_ENABLE_SAFEMODE;
}
- if ((app.info.privateFlags & ApplicationInfo.PRIVATE_FLAG_PROFILEABLE_BY_SHELL) != 0) {
+ if (isProfileableByShell) {
runtimeFlags |= Zygote.PROFILE_FROM_SHELL;
}
- if (app.info.isProfileable()) {
+ if (isProfileable) {
runtimeFlags |= Zygote.PROFILEABLE;
}
if ("1".equals(SystemProperties.get("debug.checkjni"))) {
@@ -1815,7 +1820,7 @@ public final class ProcessList {
}
String invokeWith = null;
- if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
+ if (debuggableFlag) {
// Debuggable apps may include a wrapper script with their library directory.
String wrapperFileName = app.info.nativeLibraryDir + "/wrap.sh";
StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
@@ -1890,24 +1895,6 @@ public final class ProcessList {
}
}
- /** Return true if the client app for the SDK sandbox process is debuggable. */
- private boolean isAppForSdkSandboxDebuggable(ProcessRecord sandboxProcess) {
- // TODO (b/221004701) use client app process name
- final int appUid = Process.sdkSandboxToAppUid(sandboxProcess.uid);
- IPackageManager pm = mService.getPackageManager();
- try {
- String[] packages = pm.getPackagesForUid(appUid);
- for (String aPackage : packages) {
- ApplicationInfo i = pm.getApplicationInfo(aPackage, 0, sandboxProcess.userId);
- if ((i.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
- return true;
- }
- }
- } catch (RemoteException e) {
- // shouldn't happen
- }
- return false;
- }
@GuardedBy("mService")
boolean startProcessLocked(HostingRecord hostingRecord, String entryPoint, ProcessRecord app,
@@ -2368,7 +2355,7 @@ public final class ProcessList {
ProcessRecord startProcessLocked(String processName, ApplicationInfo info,
boolean knownToBeDead, int intentFlags, HostingRecord hostingRecord,
int zygotePolicyFlags, boolean allowWhileBooting, boolean isolated, int isolatedUid,
- boolean isSdkSandbox, int sdkSandboxUid,
+ boolean isSdkSandbox, int sdkSandboxUid, String sdkSandboxClientAppPackage,
String abiOverride, String entryPoint, String[] entryPointArgs, Runnable crashHandler) {
long startTime = SystemClock.uptimeMillis();
ProcessRecord app;
@@ -2463,7 +2450,7 @@ public final class ProcessList {
if (app == null) {
checkSlow(startTime, "startProcess: creating new process record");
app = newProcessRecordLocked(info, processName, isolated, isolatedUid, isSdkSandbox,
- sdkSandboxUid, hostingRecord);
+ sdkSandboxUid, sdkSandboxClientAppPackage, hostingRecord);
if (app == null) {
Slog.w(TAG, "Failed making new process record for "
+ processName + "/" + info.uid + " isolated=" + isolated);
@@ -2959,7 +2946,7 @@ public final class ProcessList {
@GuardedBy("mService")
ProcessRecord newProcessRecordLocked(ApplicationInfo info, String customProcess,
boolean isolated, int isolatedUid, boolean isSdkSandbox, int sdkSandboxUid,
- HostingRecord hostingRecord) {
+ String sdkSandboxClientAppPackage, HostingRecord hostingRecord) {
String proc = customProcess != null ? customProcess : info.processName;
final int userId = UserHandle.getUserId(info.uid);
int uid = info.uid;
@@ -2995,6 +2982,7 @@ public final class ProcessList {
FrameworkStatsLog.ISOLATED_UID_CHANGED__EVENT__CREATED);
}
final ProcessRecord r = new ProcessRecord(mService, info, proc, uid,
+ sdkSandboxClientAppPackage,
hostingRecord.getDefiningUid(), hostingRecord.getDefiningProcessName());
final ProcessStateRecord state = r.mState;
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index f7cc3d780f89..b4ff8709a32f 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -27,6 +27,7 @@ import android.app.ApplicationExitInfo.Reason;
import android.app.ApplicationExitInfo.SubReason;
import android.app.IApplicationThread;
import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManagerInternal;
import android.content.pm.ProcessInfo;
import android.content.pm.VersionedPackage;
import android.content.res.CompatibilityInfo;
@@ -84,6 +85,8 @@ class ProcessRecord implements WindowProcessListener {
final int uid; // uid of process; may be different from 'info' if isolated
final int userId; // user of process.
final String processName; // name of the process
+ final String sdkSandboxClientAppPackage; // if this is an sdk sandbox process, name of the
+ // app package for which it is running
/**
* Overall state of process's uid.
@@ -493,11 +496,12 @@ class ProcessRecord implements WindowProcessListener {
ProcessRecord(ActivityManagerService _service, ApplicationInfo _info, String _processName,
int _uid) {
- this(_service, _info, _processName, _uid, -1, null);
+ this(_service, _info, _processName, _uid, null, -1, null);
}
ProcessRecord(ActivityManagerService _service, ApplicationInfo _info, String _processName,
- int _uid, int _definingUid, String _definingProcessName) {
+ int _uid, String _sdkSandboxClientAppPackage, int _definingUid,
+ String _definingProcessName) {
mService = _service;
mProcLock = _service.mProcLock;
info = _info;
@@ -530,6 +534,7 @@ class ProcessRecord implements WindowProcessListener {
uid = _uid;
userId = UserHandle.getUserId(_uid);
processName = _processName;
+ sdkSandboxClientAppPackage = _sdkSandboxClientAppPackage;
mPersistent = false;
mRemoved = false;
mProfile = new ProcessProfileRecord(this);
@@ -861,6 +866,29 @@ class ProcessRecord implements WindowProcessListener {
return mDebugging;
}
+ @Nullable
+ public ApplicationInfo getClientInfoForSdkSandbox() {
+ if (!isSdkSandbox || sdkSandboxClientAppPackage == null) {
+ throw new IllegalStateException(
+ "getClientInfoForSdkSandbox called for non-sandbox process"
+ );
+ }
+ PackageManagerInternal pm = mService.getPackageManagerInternal();
+ return pm.getApplicationInfo(
+ sdkSandboxClientAppPackage, /* flags */0, Process.SYSTEM_UID, userId);
+ }
+
+ public boolean isDebuggable() {
+ if ((info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
+ return true;
+ }
+ if (isSdkSandbox) {
+ ApplicationInfo clientInfo = getClientInfoForSdkSandbox();
+ return clientInfo != null && (clientInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
+ }
+ return false;
+ }
+
@GuardedBy("mService")
void setDebugging(boolean debugging) {
mDebugging = debugging;
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index c53d4d6b5015..795311f019a4 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -96,6 +96,8 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN
final long createRealTime; // when this service was created
final boolean isSdkSandbox; // whether this is a sdk sandbox service
final int sdkSandboxClientAppUid; // the app uid for which this sdk sandbox service is running
+ final String sdkSandboxClientAppPackage; // the app package for which this sdk sandbox service
+ // is running
final ArrayMap<Intent.FilterComparison, IntentBindRecord> bindings
= new ArrayMap<Intent.FilterComparison, IntentBindRecord>();
// All active bindings to the service.
@@ -573,13 +575,14 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN
Intent.FilterComparison intent, ServiceInfo sInfo, boolean callerIsFg,
Runnable restarter) {
this(ams, name, instanceName, definingPackageName, definingUid, intent, sInfo, callerIsFg,
- restarter, null, 0);
+ restarter, null, 0, null);
}
ServiceRecord(ActivityManagerService ams, ComponentName name,
ComponentName instanceName, String definingPackageName, int definingUid,
Intent.FilterComparison intent, ServiceInfo sInfo, boolean callerIsFg,
- Runnable restarter, String sdkSandboxProcessName, int sdkSandboxClientAppUid) {
+ Runnable restarter, String sdkSandboxProcessName, int sdkSandboxClientAppUid,
+ String sdkSandboxClientAppPackage) {
this.ams = ams;
this.name = name;
this.instanceName = instanceName;
@@ -590,8 +593,9 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN
serviceInfo = sInfo;
appInfo = sInfo.applicationInfo;
packageName = sInfo.applicationInfo.packageName;
- isSdkSandbox = sdkSandboxProcessName != null;
+ this.isSdkSandbox = sdkSandboxProcessName != null;
this.sdkSandboxClientAppUid = sdkSandboxClientAppUid;
+ this.sdkSandboxClientAppPackage = sdkSandboxClientAppPackage;
if ((sInfo.flags & ServiceInfo.FLAG_ISOLATED_PROCESS) != 0) {
processName = sInfo.processName + ":" + instanceName.getClassName();
} else if (sdkSandboxProcessName != null) {
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 1095cf0a0d30..879534778800 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -399,6 +399,9 @@ class UserController implements Handler.Callback {
@GuardedBy("mLock")
private @StopUserOnSwitch int mStopUserOnSwitch = STOP_USER_ON_SWITCH_DEFAULT;
+ /** @see #getLastUserUnlockingUptime */
+ private volatile long mLastUserUnlockingUptime = 0;
+
UserController(ActivityManagerService service) {
this(new Injector(service));
}
@@ -661,6 +664,8 @@ class UserController implements Handler.Callback {
uss.mUnlockProgress.setProgress(20);
+ mLastUserUnlockingUptime = SystemClock.uptimeMillis();
+
// Dispatch unlocked to system services; when fully dispatched,
// that calls through to the next "unlocked" phase
mHandler.obtainMessage(USER_UNLOCK_MSG, userId, 0, uss).sendToTarget();
@@ -2613,7 +2618,7 @@ class UserController implements Handler.Callback {
if (getStartedUserState(userId) == null) {
return false;
}
- if (!mInjector.getUserManager().isCredentialSharedWithParent(userId)) {
+ if (!mInjector.getUserManager().isCredentialSharableWithParent(userId)) {
return false;
}
if (mLockPatternUtils.isSeparateProfileChallengeEnabled(userId)) {
@@ -2753,6 +2758,7 @@ class UserController implements Handler.Callback {
if (mSwitchingToSystemUserMessage != null) {
pw.println(" mSwitchingToSystemUserMessage: " + mSwitchingToSystemUserMessage);
}
+ pw.println(" mLastUserUnlockingUptime:" + mLastUserUnlockingUptime);
}
}
@@ -3078,6 +3084,14 @@ class UserController implements Handler.Callback {
}
/**
+ * Uptime when any user was being unlocked most recently. 0 if no users have been unlocked
+ * yet. To avoid lock contention (since it's used by OomAdjuster), it's volatile internally.
+ */
+ public long getLastUserUnlockingUptime() {
+ return mLastUserUnlockingUptime;
+ }
+
+ /**
* Helper class to store user journey and session id.
*
* <p> User journey tracks a chain of user lifecycle events occurring during different user
diff --git a/services/core/java/com/android/server/ambientcontext/AmbientContextManagerPerUserService.java b/services/core/java/com/android/server/ambientcontext/AmbientContextManagerPerUserService.java
index b73cf5b20ec0..42a7423725a3 100644
--- a/services/core/java/com/android/server/ambientcontext/AmbientContextManagerPerUserService.java
+++ b/services/core/java/com/android/server/ambientcontext/AmbientContextManagerPerUserService.java
@@ -171,16 +171,15 @@ final class AmbientContextManagerPerUserService extends
return;
}
- // Remove any existing intent and unregister for this package before adding a new one.
+ // Remove any existing PendingIntent for this package.
String callingPackage = pendingIntent.getCreatorPackage();
PendingIntent duplicatePendingIntent = findExistingRequestByPackage(callingPackage);
if (duplicatePendingIntent != null) {
- Slog.d(TAG, "Unregister duplicate request from " + callingPackage);
- onUnregisterObserver(callingPackage);
+ Slog.d(TAG, "Replace duplicate request from " + callingPackage);
mExistingPendingIntents.remove(duplicatePendingIntent);
}
- // Register new package and add request to mExistingRequests
+ // Register package and add pendingIntent to mExistingPendingIntents
startDetection(request, callingPackage, createDetectionResultRemoteCallback(),
getServerStatusCallback(clientStatusCallback));
mExistingPendingIntents.add(pendingIntent);
diff --git a/services/core/java/com/android/server/ambientcontext/AmbientContextShellCommand.java b/services/core/java/com/android/server/ambientcontext/AmbientContextShellCommand.java
index 010bf1b4cfb8..e2b22dc1bd3d 100644
--- a/services/core/java/com/android/server/ambientcontext/AmbientContextShellCommand.java
+++ b/services/core/java/com/android/server/ambientcontext/AmbientContextShellCommand.java
@@ -110,6 +110,8 @@ final class AmbientContextShellCommand extends ShellCommand {
return runStopDetection();
case "get-last-status-code":
return getLastStatusCode();
+ case "get-last-package-name":
+ return getLastPackageName();
case "query-service-status":
return runQueryServiceStatus();
case "get-bound-package":
@@ -157,6 +159,13 @@ final class AmbientContextShellCommand extends ShellCommand {
return lastResponse.getStatusCode();
}
+ private int getLastPackageName() {
+ AmbientContextDetectionServiceStatus lastResponse =
+ sTestableCallbackInternal.getLastStatus();
+ out.println(lastResponse == null ? "" : lastResponse.getPackageName());
+ return 0;
+ }
+
@Override
public void onHelp() {
PrintWriter pw = getOutPrintWriter();
@@ -167,6 +176,7 @@ final class AmbientContextShellCommand extends ShellCommand {
pw.println(" start-detection USER_ID PACKAGE_NAME: Starts AmbientContextEvent detection.");
pw.println(" stop-detection USER_ID: Stops AmbientContextEvent detection.");
pw.println(" get-last-status-code: Prints the latest request status code.");
+ pw.println(" get-last-package-name: Prints the latest request package name.");
pw.println(" query-event-status USER_ID PACKAGE_NAME: Prints the event status code.");
pw.println(" get-bound-package USER_ID:"
+ " Print the bound package that implements the service.");
diff --git a/services/core/java/com/android/server/ambientcontext/RemoteAmbientContextDetectionService.java b/services/core/java/com/android/server/ambientcontext/RemoteAmbientContextDetectionService.java
index f42080d550b7..8aec75226958 100644
--- a/services/core/java/com/android/server/ambientcontext/RemoteAmbientContextDetectionService.java
+++ b/services/core/java/com/android/server/ambientcontext/RemoteAmbientContextDetectionService.java
@@ -49,6 +49,12 @@ final class RemoteAmbientContextDetectionService
connect();
}
+ @Override
+ protected long getAutoDisconnectTimeoutMs() {
+ // Disable automatic unbinding.
+ return -1;
+ }
+
/**
* Asks the implementation to start detection.
*
diff --git a/services/core/java/com/android/server/app/GameManagerService.java b/services/core/java/com/android/server/app/GameManagerService.java
index 3efd8ad0581b..4fa1ba1c8158 100644
--- a/services/core/java/com/android/server/app/GameManagerService.java
+++ b/services/core/java/com/android/server/app/GameManagerService.java
@@ -359,6 +359,7 @@ public final class GameManagerService extends IGameManagerService.Stub {
public enum FrameRate {
FPS_DEFAULT(0),
FPS_30(30),
+ FPS_40(40),
FPS_45(45),
FPS_60(60),
FPS_90(90),
@@ -378,6 +379,8 @@ public final class GameManagerService extends IGameManagerService.Stub {
switch (raw) {
case "30":
return FrameRate.FPS_30.fps;
+ case "40":
+ return FrameRate.FPS_40.fps;
case "45":
return FrameRate.FPS_45.fps;
case "60":
diff --git a/services/core/java/com/android/server/app/GameServiceProviderInstanceFactoryImpl.java b/services/core/java/com/android/server/app/GameServiceProviderInstanceFactoryImpl.java
index 0abab6aafe73..a76eb8f1e55d 100644
--- a/services/core/java/com/android/server/app/GameServiceProviderInstanceFactoryImpl.java
+++ b/services/core/java/com/android/server/app/GameServiceProviderInstanceFactoryImpl.java
@@ -18,6 +18,7 @@ package com.android.server.app;
import android.annotation.NonNull;
import android.app.ActivityManager;
+import android.app.ActivityManagerInternal;
import android.app.ActivityTaskManager;
import android.content.Context;
import android.content.Intent;
@@ -29,6 +30,7 @@ import android.service.games.IGameSessionService;
import com.android.internal.infra.ServiceConnector;
import com.android.internal.os.BackgroundThread;
+import com.android.internal.util.ScreenshotHelper;
import com.android.server.LocalServices;
import com.android.server.app.GameServiceConfiguration.GameServiceComponentConfiguration;
import com.android.server.wm.WindowManagerInternal;
@@ -51,11 +53,13 @@ final class GameServiceProviderInstanceFactoryImpl implements GameServiceProvide
mContext,
new GameClassifierImpl(mContext.getPackageManager()),
ActivityManager.getService(),
+ LocalServices.getService(ActivityManagerInternal.class),
ActivityTaskManager.getService(),
(WindowManagerService) ServiceManager.getService(Context.WINDOW_SERVICE),
LocalServices.getService(WindowManagerInternal.class),
new GameServiceConnector(mContext, configuration),
- new GameSessionServiceConnector(mContext, configuration));
+ new GameSessionServiceConnector(mContext, configuration),
+ new ScreenshotHelper(mContext));
}
private static final class GameServiceConnector extends ServiceConnector.Impl<IGameService> {
diff --git a/services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java b/services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java
index e4edf4e0f5f9..b38195aed250 100644
--- a/services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java
+++ b/services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java
@@ -21,15 +21,20 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.app.ActivityManager.RunningTaskInfo;
+import android.app.ActivityManagerInternal;
import android.app.ActivityTaskManager;
import android.app.IActivityManager;
import android.app.IActivityTaskManager;
+import android.app.IProcessObserver;
import android.app.TaskStackListener;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
+import android.graphics.Insets;
import android.graphics.Rect;
+import android.net.Uri;
+import android.os.Bundle;
import android.os.RemoteException;
import android.os.UserHandle;
import android.service.games.CreateGameSessionRequest;
@@ -42,15 +47,19 @@ import android.service.games.IGameServiceController;
import android.service.games.IGameSession;
import android.service.games.IGameSessionController;
import android.service.games.IGameSessionService;
+import android.text.TextUtils;
import android.util.Slog;
import android.view.SurfaceControl;
import android.view.SurfaceControlViewHost.SurfacePackage;
+import android.view.WindowManager;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.infra.AndroidFuture;
import com.android.internal.infra.ServiceConnector;
import com.android.internal.infra.ServiceConnector.ServiceLifecycleCallbacks;
+import com.android.internal.os.BackgroundThread;
+import com.android.internal.util.ScreenshotHelper;
import com.android.server.wm.WindowManagerInternal;
import com.android.server.wm.WindowManagerInternal.TaskSystemBarsListener;
import com.android.server.wm.WindowManagerService;
@@ -59,6 +68,7 @@ import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
+import java.util.function.Consumer;
final class GameServiceProviderInstanceImpl implements GameServiceProviderInstance {
private static final String TAG = "GameServiceProviderInstance";
@@ -75,15 +85,6 @@ final class GameServiceProviderInstanceImpl implements GameServiceProviderInstan
Slog.w(TAG, "Failed to send connected event", ex);
}
}
-
- @Override
- public void onDisconnected(@NonNull IGameService service) {
- try {
- service.disconnected();
- } catch (RemoteException ex) {
- Slog.w(TAG, "Failed to send disconnected event", ex);
- }
- }
};
private final ServiceLifecycleCallbacks<IGameSessionService>
@@ -136,12 +137,43 @@ final class GameServiceProviderInstanceImpl implements GameServiceProviderInstan
GameServiceProviderInstanceImpl.this.onTaskFocusChanged(taskId, focused);
});
}
+ };
+
+ /**
+ * The TaskStackListener declared above gives us good visibility into game task lifecycle.
+ * However, it is possible for the Android system to kill all the processes associated with a
+ * game task (e.g., when the system is under memory pressure or reaches a background process
+ * limit). When this happens, the game task remains (and no TaskStackListener callbacks are
+ * invoked), but we would nonetheless want to destroy a game session associated with the task
+ * if this were to happen.
+ *
+ * This process observer gives us visibility into process lifecycles and lets us track all the
+ * processes associated with each package so that any game sessions associated with the package
+ * are destroyed if the process count for a given package reaches zero (most packages will
+ * have at most one task). If processes for a given package are started up again, the destroyed
+ * game sessions will be re-created.
+ */
+ private final IProcessObserver mProcessObserver = new IProcessObserver.Stub() {
+ @Override
+ public void onForegroundActivitiesChanged(int pid, int uid, boolean fg) {
+ // This callback is used to track how many processes are running for a given package.
+ // Then, when a process dies, we will know if it was the only process running for that
+ // package and the associated game sessions should be destroyed.
+ mBackgroundExecutor.execute(() -> {
+ GameServiceProviderInstanceImpl.this.onForegroundActivitiesChanged(pid);
+ });
+ }
- // TODO(b/204503192): Limit the lifespan of the game session in the Game Service provider
- // to only when the associated task is running. Right now it is possible for a task to
- // move into the background and for all associated processes to die and for the Game Session
- // provider's GameSessionService to continue to be running. Ideally we could unbind the
- // service when this happens.
+ @Override
+ public void onProcessDied(int pid, int uid) {
+ mBackgroundExecutor.execute(() -> {
+ GameServiceProviderInstanceImpl.this.onProcessDied(pid);
+ });
+ }
+
+ @Override
+ public void onForegroundServicesChanged(int pid, int uid, int serviceTypes) {
+ }
};
private final IGameServiceController mGameServiceController =
@@ -160,8 +192,11 @@ final class GameServiceProviderInstanceImpl implements GameServiceProviderInstan
private final IGameSessionController mGameSessionController =
new IGameSessionController.Stub() {
@Override
+ @RequiresPermission(android.Manifest.permission.MANAGE_GAME_ACTIVITY)
public void takeScreenshot(int taskId,
@NonNull AndroidFuture gameScreenshotResultFuture) {
+ mContext.enforceCallingPermission(Manifest.permission.MANAGE_GAME_ACTIVITY,
+ "takeScreenshot()");
mBackgroundExecutor.execute(() -> {
GameServiceProviderInstanceImpl.this.takeScreenshot(taskId,
gameScreenshotResultFuture);
@@ -185,9 +220,11 @@ final class GameServiceProviderInstanceImpl implements GameServiceProviderInstan
private final Context mContext;
private final GameClassifier mGameClassifier;
private final IActivityManager mActivityManager;
+ private final ActivityManagerInternal mActivityManagerInternal;
private final IActivityTaskManager mActivityTaskManager;
private final WindowManagerService mWindowManagerService;
private final WindowManagerInternal mWindowManagerInternal;
+ private final ScreenshotHelper mScreenshotHelper;
private final ServiceConnector<IGameService> mGameServiceConnector;
private final ServiceConnector<IGameSessionService> mGameSessionServiceConnector;
@@ -195,6 +232,12 @@ final class GameServiceProviderInstanceImpl implements GameServiceProviderInstan
private final ConcurrentHashMap<Integer, GameSessionRecord> mGameSessions =
new ConcurrentHashMap<>();
@GuardedBy("mLock")
+ private final ConcurrentHashMap<Integer, String> mPidToPackageMap = new ConcurrentHashMap<>();
+ @GuardedBy("mLock")
+ private final ConcurrentHashMap<String, Integer> mPackageNameToProcessCountMap =
+ new ConcurrentHashMap<>();
+
+ @GuardedBy("mLock")
private volatile boolean mIsRunning;
GameServiceProviderInstanceImpl(
@@ -203,21 +246,25 @@ final class GameServiceProviderInstanceImpl implements GameServiceProviderInstan
@NonNull Context context,
@NonNull GameClassifier gameClassifier,
@NonNull IActivityManager activityManager,
+ @NonNull ActivityManagerInternal activityManagerInternal,
@NonNull IActivityTaskManager activityTaskManager,
@NonNull WindowManagerService windowManagerService,
@NonNull WindowManagerInternal windowManagerInternal,
@NonNull ServiceConnector<IGameService> gameServiceConnector,
- @NonNull ServiceConnector<IGameSessionService> gameSessionServiceConnector) {
+ @NonNull ServiceConnector<IGameSessionService> gameSessionServiceConnector,
+ @NonNull ScreenshotHelper screenshotHelper) {
mUserHandle = userHandle;
mBackgroundExecutor = backgroundExecutor;
mContext = context;
mGameClassifier = gameClassifier;
mActivityManager = activityManager;
+ mActivityManagerInternal = activityManagerInternal;
mActivityTaskManager = activityTaskManager;
mWindowManagerService = windowManagerService;
mWindowManagerInternal = windowManagerInternal;
mGameServiceConnector = gameServiceConnector;
mGameSessionServiceConnector = gameSessionServiceConnector;
+ mScreenshotHelper = screenshotHelper;
}
@Override
@@ -253,6 +300,12 @@ final class GameServiceProviderInstanceImpl implements GameServiceProviderInstan
Slog.w(TAG, "Failed to register task stack listener", e);
}
+ try {
+ mActivityManager.registerProcessObserver(mProcessObserver);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed to register process observer", e);
+ }
+
mWindowManagerInternal.registerTaskSystemBarsListener(mTaskSystemBarsVisibilityListener);
}
@@ -264,6 +317,12 @@ final class GameServiceProviderInstanceImpl implements GameServiceProviderInstan
mIsRunning = false;
try {
+ mActivityManager.unregisterProcessObserver(mProcessObserver);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed to unregister process observer", e);
+ }
+
+ try {
mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener);
} catch (RemoteException e) {
Slog.w(TAG, "Failed to unregister task stack listener", e);
@@ -274,7 +333,9 @@ final class GameServiceProviderInstanceImpl implements GameServiceProviderInstan
destroyAndClearAllGameSessionsLocked();
- mGameServiceConnector.unbind();
+ mGameServiceConnector.post(IGameService::disconnected).whenComplete((result, t) -> {
+ mGameServiceConnector.unbind();
+ });
mGameSessionServiceConnector.unbind();
mGameServiceConnector.setServiceLifecycleCallbacks(null);
@@ -586,6 +647,126 @@ final class GameServiceProviderInstanceImpl implements GameServiceProviderInstan
}
}
+ private void onForegroundActivitiesChanged(int pid) {
+ synchronized (mLock) {
+ onForegroundActivitiesChangedLocked(pid);
+ }
+ }
+
+ @GuardedBy("mLock")
+ private void onForegroundActivitiesChangedLocked(int pid) {
+ if (mPidToPackageMap.containsKey(pid)) {
+ // We are already tracking this pid, nothing to do.
+ return;
+ }
+
+ final String packageName = mActivityManagerInternal.getPackageNameByPid(pid);
+ if (TextUtils.isEmpty(packageName)) {
+ // Game processes should always have a package name.
+ return;
+ }
+
+ if (!gameSessionExistsForPackageNameLocked(packageName)) {
+ // We only need to track processes for tasks with game session records.
+ return;
+ }
+
+ mPidToPackageMap.put(pid, packageName);
+ final int processCountForPackage = mPackageNameToProcessCountMap.getOrDefault(packageName,
+ 0) + 1;
+ mPackageNameToProcessCountMap.put(packageName, processCountForPackage);
+
+ if (DEBUG) {
+ Slog.d(TAG, "onForegroundActivitiesChangedLocked: tracking pid " + pid + ", for "
+ + packageName + ". Process count for package: " + processCountForPackage);
+ }
+
+ // If there are processes for the package, we may need to re-create game sessions
+ // that are associated with the package
+ if (processCountForPackage > 0) {
+ recreateEndedGameSessionsLocked(packageName);
+ }
+ }
+
+ @GuardedBy("mLock")
+ private void recreateEndedGameSessionsLocked(String packageName) {
+ for (GameSessionRecord gameSessionRecord : mGameSessions.values()) {
+ if (gameSessionRecord.isGameSessionEndedForProcessDeath() && packageName.equals(
+ gameSessionRecord.getComponentName().getPackageName())) {
+ if (DEBUG) {
+ Slog.d(TAG,
+ "recreateGameSessionsLocked(): re-creating game session for: "
+ + packageName + " with taskId: "
+ + gameSessionRecord.getTaskId());
+ }
+
+ final int taskId = gameSessionRecord.getTaskId();
+ mGameSessions.put(taskId, GameSessionRecord.awaitingGameSessionRequest(taskId,
+ gameSessionRecord.getComponentName()));
+ createGameSessionLocked(gameSessionRecord.getTaskId());
+ }
+ }
+ }
+
+ private void onProcessDied(int pid) {
+ synchronized (mLock) {
+ onProcessDiedLocked(pid);
+ }
+ }
+
+ @GuardedBy("mLock")
+ private void onProcessDiedLocked(int pid) {
+ final String packageName = mPidToPackageMap.remove(pid);
+ if (packageName == null) {
+ // We weren't tracking this process.
+ return;
+ }
+
+ final Integer oldProcessCountForPackage = mPackageNameToProcessCountMap.get(packageName);
+ if (oldProcessCountForPackage == null) {
+ // This should never happen; we should have a process count for all tracked packages.
+ Slog.w(TAG, "onProcessDiedLocked(): Missing process count for package");
+ return;
+ }
+
+ final int processCountForPackage = oldProcessCountForPackage - 1;
+ mPackageNameToProcessCountMap.put(packageName, processCountForPackage);
+
+ // If there are no more processes for the game, then we will terminate any game sessions
+ // running for the package.
+ if (processCountForPackage <= 0) {
+ endGameSessionsForPackageLocked(packageName);
+ }
+ }
+
+ @GuardedBy("mLock")
+ private void endGameSessionsForPackageLocked(String packageName) {
+ for (GameSessionRecord gameSessionRecord : mGameSessions.values()) {
+ if (gameSessionRecord.getGameSession() != null && packageName.equals(
+ gameSessionRecord.getComponentName().getPackageName())) {
+ if (DEBUG) {
+ Slog.d(TAG, "endGameSessionsForPackageLocked(): No more processes for "
+ + packageName + ", ending game session with taskId: "
+ + gameSessionRecord.getTaskId());
+ }
+ mGameSessions.put(gameSessionRecord.getTaskId(),
+ gameSessionRecord.withGameSessionEndedOnProcessDeath());
+ destroyGameSessionFromRecordLocked(gameSessionRecord);
+ }
+ }
+ }
+
+ @GuardedBy("mLock")
+ private boolean gameSessionExistsForPackageNameLocked(String packageName) {
+ for (GameSessionRecord gameSessionRecord : mGameSessions.values()) {
+ if (packageName.equals(gameSessionRecord.getComponentName().getPackageName())) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
@Nullable
private GameSessionViewHostConfiguration createViewHostConfigurationForTask(int taskId) {
RunningTaskInfo runningTaskInfo = getRunningTaskInfoForTask(taskId);
@@ -651,7 +832,26 @@ final class GameServiceProviderInstanceImpl implements GameServiceProviderInstan
Slog.w(TAG, "Could not get bitmap for id: " + taskId);
callback.complete(GameScreenshotResult.createInternalErrorResult());
} else {
- callback.complete(GameScreenshotResult.createSuccessResult(bitmap));
+ final Bundle bundle = ScreenshotHelper.HardwareBitmapBundler.hardwareBitmapToBundle(
+ bitmap);
+ final RunningTaskInfo runningTaskInfo = getRunningTaskInfoForTask(taskId);
+ if (runningTaskInfo == null) {
+ Slog.w(TAG, "Could not get running task info for id: " + taskId);
+ callback.complete(GameScreenshotResult.createInternalErrorResult());
+ }
+ final Rect crop = runningTaskInfo.configuration.windowConfiguration.getBounds();
+ final Consumer<Uri> completionConsumer = (uri) -> {
+ if (uri == null) {
+ callback.complete(GameScreenshotResult.createInternalErrorResult());
+ } else {
+ callback.complete(GameScreenshotResult.createSuccessResult());
+ }
+ };
+ mScreenshotHelper.provideScreenshot(bundle, crop, Insets.NONE, taskId,
+ mUserHandle.getIdentifier(), gameSessionRecord.getComponentName(),
+ WindowManager.ScreenshotSource.SCREENSHOT_OTHER,
+ BackgroundThread.getHandler(),
+ completionConsumer);
}
});
}
diff --git a/services/core/java/com/android/server/app/GameSessionRecord.java b/services/core/java/com/android/server/app/GameSessionRecord.java
index a241812f7868..74e538ef5011 100644
--- a/services/core/java/com/android/server/app/GameSessionRecord.java
+++ b/services/core/java/com/android/server/app/GameSessionRecord.java
@@ -35,6 +35,10 @@ final class GameSessionRecord {
// A Game Session is created and attached.
// GameSessionRecord.getGameSession() != null.
GAME_SESSION_ATTACHED,
+ // A Game Session did exist for a given game task but was destroyed because the last process
+ // for the game died.
+ // GameSessionRecord.getGameSession() == null.
+ GAME_SESSION_ENDED_PROCESS_DEATH,
}
private final int mTaskId;
@@ -99,6 +103,20 @@ final class GameSessionRecord {
}
@NonNull
+ public GameSessionRecord withGameSessionEndedOnProcessDeath() {
+ return new GameSessionRecord(
+ mTaskId,
+ State.GAME_SESSION_ENDED_PROCESS_DEATH,
+ mRootComponentName,
+ /* gameSession=*/ null,
+ /* surfacePackage=*/ null);
+ }
+
+ public boolean isGameSessionEndedForProcessDeath() {
+ return mState == State.GAME_SESSION_ENDED_PROCESS_DEATH;
+ }
+
+ @NonNull
public int getTaskId() {
return mTaskId;
}
diff --git a/services/core/java/com/android/server/attention/AttentionManagerService.java b/services/core/java/com/android/server/attention/AttentionManagerService.java
index 567d1aef3272..d16fe1240d0c 100644
--- a/services/core/java/com/android/server/attention/AttentionManagerService.java
+++ b/services/core/java/com/android/server/attention/AttentionManagerService.java
@@ -74,6 +74,8 @@ import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.Objects;
import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
/**
* An attention service implementation that runs in System Server process.
@@ -87,6 +89,9 @@ public class AttentionManagerService extends SystemService {
/** Service will unbind if connection is not used for that amount of time. */
private static final long CONNECTION_TTL_MILLIS = 60_000;
+ /** How long AttentionManagerService will wait for service binding after lazy binding. */
+ private static final long SERVICE_BINDING_WAIT_MILLIS = 1000;
+
/** DeviceConfig flag name, if {@code true}, enables AttentionManagerService features. */
@VisibleForTesting
static final String KEY_SERVICE_ENABLED = "service_enabled";
@@ -129,6 +134,7 @@ public class AttentionManagerService extends SystemService {
@GuardedBy("mLock")
private boolean mBinding;
private AttentionHandler mAttentionHandler;
+ private CountDownLatch mServiceBindingLatch;
@VisibleForTesting
ComponentName mComponentName;
@@ -161,6 +167,7 @@ public class AttentionManagerService extends SystemService {
mLock = lock;
mAttentionHandler = handler;
mPrivacyManager = SensorPrivacyManager.getInstance(context);
+ mServiceBindingLatch = new CountDownLatch(1);
}
@Override
@@ -275,13 +282,16 @@ public class AttentionManagerService extends SystemService {
}
synchronized (mLock) {
- final long now = SystemClock.uptimeMillis();
// schedule shutting down the connection if no one resets this timer
freeIfInactiveLocked();
// lazily start the service, which should be very lightweight to start
bindLocked();
-
+ }
+ final long now = SystemClock.uptimeMillis();
+ // Proceed when the service binding is complete.
+ awaitServiceBinding(Math.min(SERVICE_BINDING_WAIT_MILLIS, timeout));
+ synchronized (mLock) {
// throttle frequent requests
final AttentionCheckCache cache = mAttentionCheckCacheBuffer == null ? null
: mAttentionCheckCacheBuffer.getLast();
@@ -361,7 +371,10 @@ public class AttentionManagerService extends SystemService {
// lazily start the service, which should be very lightweight to start
bindLocked();
-
+ }
+ // Proceed when the service binding is complete.
+ awaitServiceBinding(SERVICE_BINDING_WAIT_MILLIS);
+ synchronized (mLock) {
/*
Prevent spamming with multiple requests, only one at a time is allowed.
If there are use-cases for keeping track of multiple requests, we
@@ -419,6 +432,14 @@ public class AttentionManagerService extends SystemService {
return context.getPackageManager().getAttentionServicePackageName();
}
+ private void awaitServiceBinding(long millis) {
+ try {
+ mServiceBindingLatch.await(millis, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ Slog.e(LOG_TAG, "Interrupted while waiting to bind Attention Service.", e);
+ }
+ }
+
/**
* Provides attention service component name at runtime, making sure it's provided by the
* system.
@@ -711,6 +732,7 @@ public class AttentionManagerService extends SystemService {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
init(IAttentionService.Stub.asInterface(service));
+ mServiceBindingLatch.countDown();
}
@Override
@@ -730,6 +752,7 @@ public class AttentionManagerService extends SystemService {
void cleanupService() {
init(null);
+ mServiceBindingLatch = new CountDownLatch(1);
}
private void init(@Nullable IAttentionService service) {
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 82476d8d1df8..309a4ff16753 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -102,6 +102,7 @@ import android.media.IRecordingConfigDispatcher;
import android.media.IRingtonePlayer;
import android.media.ISpatializerCallback;
import android.media.ISpatializerHeadToSoundStagePoseCallback;
+import android.media.ISpatializerHeadTrackerAvailableCallback;
import android.media.ISpatializerHeadTrackingModeCallback;
import android.media.ISpatializerOutputCallback;
import android.media.IStrategyPreferredDevicesDispatcher;
@@ -127,6 +128,7 @@ import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
+import android.os.HwBinder;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
@@ -8722,6 +8724,11 @@ public class AudioService extends IAudioService.Stub
return mSpatializerHelper.isHeadTrackerEnabled(Objects.requireNonNull(device));
}
+ /** @see Spatializer#isHeadTrackerAvailable() */
+ public boolean isHeadTrackerAvailable() {
+ return mSpatializerHelper.isHeadTrackerAvailable();
+ }
+
/** @see Spatializer#setSpatializerEnabled(boolean) */
public void setSpatializerEnabled(boolean enabled) {
enforceModifyDefaultAudioEffectsPermission();
@@ -8766,6 +8773,13 @@ public class AudioService extends IAudioService.Stub
mSpatializerHelper.unregisterHeadTrackingModeCallback(cb);
}
+ /** @see Spatializer.SpatializerHeadTrackerAvailableDispatcherStub */
+ public void registerSpatializerHeadTrackerAvailableCallback(
+ @NonNull ISpatializerHeadTrackerAvailableCallback cb, boolean register) {
+ Objects.requireNonNull(cb);
+ mSpatializerHelper.registerHeadTrackerAvailableCallback(cb, register);
+ }
+
/** @see Spatializer#setOnHeadToSoundstagePoseUpdatedListener */
public void registerHeadToSoundstagePoseCallback(
@NonNull ISpatializerHeadToSoundStagePoseCallback cb) {
@@ -10471,6 +10485,25 @@ 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"};
+
+ /** @see AudioManager#getHalVersion */
+ public @Nullable String getHalVersion() {
+ for (String version : HAL_VERSIONS) {
+ try {
+ HwBinder.getService(
+ String.format("android.hardware.audio@%s::IDevicesFactory", version),
+ "default");
+ return version;
+ } catch (NoSuchElementException e) {
+ // Ignore, the specified HAL interface is not found.
+ } catch (RemoteException re) {
+ Log.e(TAG, "Remote exception when getting hardware audio service:", re);
+ }
+ }
+ return null;
+ }
+
/** see AudioManager.hasRegisteredDynamicPolicy */
public boolean hasRegisteredDynamicPolicy() {
synchronized (mAudioPolicies) {
diff --git a/services/core/java/com/android/server/audio/SpatializerHelper.java b/services/core/java/com/android/server/audio/SpatializerHelper.java
index 193cc5f679af..f0f04e27b7de 100644
--- a/services/core/java/com/android/server/audio/SpatializerHelper.java
+++ b/services/core/java/com/android/server/audio/SpatializerHelper.java
@@ -30,6 +30,7 @@ import android.media.INativeSpatializerCallback;
import android.media.ISpatializer;
import android.media.ISpatializerCallback;
import android.media.ISpatializerHeadToSoundStagePoseCallback;
+import android.media.ISpatializerHeadTrackerAvailableCallback;
import android.media.ISpatializerHeadTrackingCallback;
import android.media.ISpatializerHeadTrackingModeCallback;
import android.media.ISpatializerOutputCallback;
@@ -126,6 +127,7 @@ public class SpatializerHelper {
private boolean mBinauralSupported = false;
private int mActualHeadTrackingMode = Spatializer.HEAD_TRACKING_MODE_UNSUPPORTED;
private int mDesiredHeadTrackingMode = Spatializer.HEAD_TRACKING_MODE_RELATIVE_WORLD;
+ private boolean mHeadTrackerAvailable = false;
/**
* The desired head tracking mode when enabling head tracking, tracks mDesiredHeadTrackingMode,
* except when head tracking gets disabled through setting the desired mode to
@@ -137,6 +139,7 @@ public class SpatializerHelper {
private @Nullable SpatializerCallback mSpatCallback;
private @Nullable SpatializerHeadTrackingCallback mSpatHeadTrackingCallback;
private @Nullable HelperDynamicSensorCallback mDynSensorCallback;
+ private boolean mIsHeadTrackingSupported = false;
// default attributes and format that determine basic availability of spatialization
private static final AudioAttributes DEFAULT_ATTRIBUTES = new AudioAttributes.Builder()
@@ -275,6 +278,7 @@ public class SpatializerHelper {
*/
synchronized void reset(boolean featureEnabled) {
Log.i(TAG, "Resetting");
+ releaseSpat();
mState = STATE_UNINITIALIZED;
mSpatLevel = Spatializer.SPATIALIZER_IMMERSIVE_LEVEL_NONE;
mCapableSpatLevel = Spatializer.SPATIALIZER_IMMERSIVE_LEVEL_NONE;
@@ -810,8 +814,9 @@ public class SpatializerHelper {
mSpat = AudioSystem.getSpatializer(mSpatCallback);
try {
mSpat.setLevel((byte) Spatializer.SPATIALIZER_IMMERSIVE_LEVEL_MULTICHANNEL);
+ mIsHeadTrackingSupported = mSpat.isHeadTrackingSupported();
//TODO: register heatracking callback only when sensors are registered
- if (mSpat.isHeadTrackingSupported()) {
+ if (mIsHeadTrackingSupported) {
mSpat.registerHeadTrackingCallback(mSpatHeadTrackingCallback);
}
} catch (RemoteException e) {
@@ -829,12 +834,16 @@ public class SpatializerHelper {
if (mSpat != null) {
mSpatCallback = null;
try {
- mSpat.registerHeadTrackingCallback(null);
+ if (mIsHeadTrackingSupported) {
+ mSpat.registerHeadTrackingCallback(null);
+ }
+ mHeadTrackerAvailable = false;
mSpat.release();
- mSpat = null;
} catch (RemoteException e) {
Log.e(TAG, "Can't set release spatializer cleanly", e);
}
+ mIsHeadTrackingSupported = false;
+ mSpat = null;
}
}
@@ -889,6 +898,18 @@ public class SpatializerHelper {
mHeadTrackingModeCallbacks.unregister(callback);
}
+ final RemoteCallbackList<ISpatializerHeadTrackerAvailableCallback> mHeadTrackerCallbacks =
+ new RemoteCallbackList<>();
+
+ synchronized void registerHeadTrackerAvailableCallback(
+ @NonNull ISpatializerHeadTrackerAvailableCallback cb, boolean register) {
+ if (register) {
+ mHeadTrackerCallbacks.register(cb);
+ } else {
+ mHeadTrackerCallbacks.unregister(cb);
+ }
+ }
+
synchronized int[] getSupportedHeadTrackingModes() {
switch (mState) {
case STATE_UNINITIALIZED:
@@ -1089,6 +1110,10 @@ public class SpatializerHelper {
return false;
}
+ synchronized boolean isHeadTrackerAvailable() {
+ return mHeadTrackerAvailable;
+ }
+
private boolean checkSpatForHeadTracking(String funcName) {
switch (mState) {
case STATE_UNINITIALIZED:
@@ -1104,7 +1129,7 @@ public class SpatializerHelper {
}
break;
}
- return true;
+ return mIsHeadTrackingSupported;
}
private void dispatchActualHeadTrackingMode(int newMode) {
@@ -1114,7 +1139,8 @@ public class SpatializerHelper {
mHeadTrackingModeCallbacks.getBroadcastItem(i)
.dispatchSpatializerActualHeadTrackingModeChanged(newMode);
} catch (RemoteException e) {
- Log.e(TAG, "Error in dispatchSpatializerActualHeadTrackingModeChanged", e);
+ Log.e(TAG, "Error in dispatchSpatializerActualHeadTrackingModeChanged("
+ + newMode + ")", e);
}
}
mHeadTrackingModeCallbacks.finishBroadcast();
@@ -1127,12 +1153,27 @@ public class SpatializerHelper {
mHeadTrackingModeCallbacks.getBroadcastItem(i)
.dispatchSpatializerDesiredHeadTrackingModeChanged(newMode);
} catch (RemoteException e) {
- Log.e(TAG, "Error in dispatchSpatializerDesiredHeadTrackingModeChanged", e);
+ Log.e(TAG, "Error in dispatchSpatializerDesiredHeadTrackingModeChanged("
+ + newMode + ")", e);
}
}
mHeadTrackingModeCallbacks.finishBroadcast();
}
+ private void dispatchHeadTrackerAvailable(boolean available) {
+ final int nbCallbacks = mHeadTrackerCallbacks.beginBroadcast();
+ for (int i = 0; i < nbCallbacks; i++) {
+ try {
+ mHeadTrackerCallbacks.getBroadcastItem(i)
+ .dispatchSpatializerHeadTrackerAvailable(available);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error in dispatchSpatializerHeadTrackerAvailable("
+ + available + ")", e);
+ }
+ }
+ mHeadTrackerCallbacks.finishBroadcast();
+ }
+
//------------------------------------------------------
// head pose
final RemoteCallbackList<ISpatializerHeadToSoundStagePoseCallback> mHeadPoseCallbacks =
@@ -1278,13 +1319,8 @@ public class SpatializerHelper {
Log.e(TAG, "not " + action + " sensors, null spatializer");
return;
}
- try {
- if (!mSpat.isHeadTrackingSupported()) {
- Log.e(TAG, "not " + action + " sensors, spatializer doesn't support headtracking");
- return;
- }
- } catch (RemoteException e) {
- Log.e(TAG, "not " + action + " sensors, error querying headtracking", e);
+ if (!mIsHeadTrackingSupported) {
+ Log.e(TAG, "not " + action + " sensors, spatializer doesn't support headtracking");
return;
}
int headHandle = -1;
@@ -1347,6 +1383,10 @@ public class SpatializerHelper {
try {
Log.i(TAG, "setHeadSensor:" + headHandle);
mSpat.setHeadSensor(headHandle);
+ if (mHeadTrackerAvailable != (headHandle != -1)) {
+ mHeadTrackerAvailable = (headHandle != -1);
+ dispatchHeadTrackerAvailable(mHeadTrackerAvailable);
+ }
} catch (Exception e) {
Log.e(TAG, "Error calling setHeadSensor:" + headHandle, e);
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/BaseClientMonitor.java b/services/core/java/com/android/server/biometrics/sensors/BaseClientMonitor.java
index 1b2e606117e7..1370fd83f6a8 100644
--- a/services/core/java/com/android/server/biometrics/sensors/BaseClientMonitor.java
+++ b/services/core/java/com/android/server/biometrics/sensors/BaseClientMonitor.java
@@ -38,7 +38,7 @@ import java.util.NoSuchElementException;
*/
public abstract class BaseClientMonitor implements IBinder.DeathRecipient {
- private static final String TAG = "Biometrics/ClientMonitor";
+ private static final String TAG = "BaseClientMonitor";
protected static final boolean DEBUG = true;
// Counter used to distinguish between ClientMonitor instances to help debugging.
@@ -120,8 +120,18 @@ public abstract class BaseClientMonitor implements IBinder.DeathRecipient {
}
/**
+ * Sets the lifecycle callback before the operation is started via
+ * {@link #start(ClientMonitorCallback)} when the client must wait for a cookie before starting.
+ *
+ * @param callback lifecycle callback (typically same callback used for starting the operation)
+ */
+ public void waitForCookie(@NonNull ClientMonitorCallback callback) {
+ mCallback = callback;
+ }
+
+ /**
* Starts the ClientMonitor's lifecycle.
- * @param callback invoked when the operation is complete (succeeds, fails, etc)
+ * @param callback invoked when the operation is complete (succeeds, fails, etc.)
*/
public void start(@NonNull ClientMonitorCallback callback) {
mCallback = wrapCallbackForStart(callback);
@@ -246,12 +256,12 @@ public abstract class BaseClientMonitor implements IBinder.DeathRecipient {
}
/** Unique request id. */
- public final long getRequestId() {
+ public long getRequestId() {
return mRequestId;
}
/** If a unique id has been set via {@link #setRequestId(long)} */
- public final boolean hasRequestId() {
+ public boolean hasRequestId() {
return mRequestId > 0;
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java b/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
index d0ec4470d3e6..19a93f30937f 100644
--- a/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
+++ b/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
@@ -285,7 +285,7 @@ public class BiometricScheduler {
// Not all operations start immediately. BiometricPrompt waits for its operation
// to arrive at the head of the queue, before pinging it to start.
- final int cookie = mCurrentOperation.isReadyToStart();
+ final int cookie = mCurrentOperation.isReadyToStart(mInternalCallback);
if (cookie == 0) {
if (!mCurrentOperation.start(mInternalCallback)) {
// Note down current length of queue
@@ -463,6 +463,18 @@ public class BiometricScheduler {
return mCurrentOperation != null ? mCurrentOperation.getClientMonitor() : null;
}
+ /** The current operation if the requestId is set and matches. */
+ @Deprecated
+ @Nullable
+ public BaseClientMonitor getCurrentClientIfMatches(long requestId) {
+ if (mCurrentOperation != null) {
+ if (mCurrentOperation.isMatchingRequestId(requestId)) {
+ return mCurrentOperation.getClientMonitor();
+ }
+ }
+ return null;
+ }
+
public int getCurrentPendingCount() {
return mPendingOperations.size();
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/BiometricSchedulerOperation.java b/services/core/java/com/android/server/biometrics/sensors/BiometricSchedulerOperation.java
index 15f0cadced99..968146a166ed 100644
--- a/services/core/java/com/android/server/biometrics/sensors/BiometricSchedulerOperation.java
+++ b/services/core/java/com/android/server/biometrics/sensors/BiometricSchedulerOperation.java
@@ -123,11 +123,12 @@ public class BiometricSchedulerOperation {
*
* @return cookie or 0 if ready/started
*/
- public int isReadyToStart() {
+ public int isReadyToStart(@NonNull ClientMonitorCallback callback) {
if (mState == STATE_WAITING_FOR_COOKIE || mState == STATE_WAITING_IN_QUEUE) {
final int cookie = mClientMonitor.getCookie();
if (cookie != 0) {
mState = STATE_WAITING_FOR_COOKIE;
+ mClientMonitor.waitForCookie(getWrappedCallback(callback));
}
return cookie;
}
@@ -137,7 +138,7 @@ public class BiometricSchedulerOperation {
/**
* Start this operation without waiting for a cookie
- * (i.e. {@link #isReadyToStart() returns zero}
+ * (i.e. {@link #isReadyToStart(ClientMonitorCallback)} returns zero}
*
* @param callback lifecycle callback
* @return if this operation started
diff --git a/services/core/java/com/android/server/biometrics/sensors/SensorOverlays.java b/services/core/java/com/android/server/biometrics/sensors/SensorOverlays.java
index 008717899aba..aeb6b6e2a907 100644
--- a/services/core/java/com/android/server/biometrics/sensors/SensorOverlays.java
+++ b/services/core/java/com/android/server/biometrics/sensors/SensorOverlays.java
@@ -84,7 +84,8 @@ public final class SensorOverlays {
};
try {
- mUdfpsOverlayController.get().showUdfpsOverlay(sensorId, reason, callback);
+ mUdfpsOverlayController.get().showUdfpsOverlay(
+ client.getRequestId(), sensorId, reason, callback);
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception when showing the UDFPS overlay", e);
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/UserAwareBiometricScheduler.java b/services/core/java/com/android/server/biometrics/sensors/UserAwareBiometricScheduler.java
index 4f900208841e..a0999771a1be 100644
--- a/services/core/java/com/android/server/biometrics/sensors/UserAwareBiometricScheduler.java
+++ b/services/core/java/com/android/server/biometrics/sensors/UserAwareBiometricScheduler.java
@@ -57,30 +57,25 @@ public class UserAwareBiometricScheduler extends BiometricScheduler {
@Nullable private StopUserClient<?> mStopUserClient;
private class ClientFinishedCallback implements ClientMonitorCallback {
- private final BaseClientMonitor mOwner;
+ @NonNull private final BaseClientMonitor mOwner;
- ClientFinishedCallback(BaseClientMonitor owner) {
+ ClientFinishedCallback(@NonNull BaseClientMonitor owner) {
mOwner = owner;
}
@Override
public void onClientFinished(@NonNull BaseClientMonitor clientMonitor, boolean success) {
mHandler.post(() -> {
- if (mOwner != clientMonitor) {
- Slog.e(getTag(), "[Wrong client finished], actual: "
- + clientMonitor + ", expected: " + mOwner);
- return;
- }
-
Slog.d(getTag(), "[Client finished] " + clientMonitor + ", success: " + success);
if (mCurrentOperation != null && mCurrentOperation.isFor(mOwner)) {
mCurrentOperation = null;
- startNextOperationIfIdle();
} else {
- // can usually be ignored (hal died, etc.)
- Slog.d(getTag(), "operation is already null or different (reset?): "
+ // can happen if the hal dies and is usually okay
+ // do not unset the current operation that may be newer
+ Slog.w(getTag(), "operation is already null or different (reset?): "
+ mCurrentOperation);
}
+ startNextOperationIfIdle();
});
}
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java
index 7765ab3b8e53..9ae6750dbcbf 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java
@@ -136,8 +136,8 @@ class FaceAuthenticationClient extends AuthenticationClient<AidlSession>
try {
if (mSensorPrivacyManager != null
&& mSensorPrivacyManager
- .isSensorPrivacyEnabled(SensorPrivacyManager.Sensors.CAMERA,
- getTargetUserId())) {
+ .isSensorPrivacyEnabled(SensorPrivacyManager.TOGGLE_TYPE_SOFTWARE,
+ SensorPrivacyManager.Sensors.CAMERA)) {
onError(BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE,
0 /* vendorCode */);
mCallback.onClientFinished(this, false /* success */);
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceDetectClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceDetectClient.java
index efedcf815228..ded18100e458 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceDetectClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceDetectClient.java
@@ -96,7 +96,8 @@ public class FaceDetectClient extends AcquisitionClient<AidlSession> implements
protected void startHalOperation() {
if (mSensorPrivacyManager != null
&& mSensorPrivacyManager
- .isSensorPrivacyEnabled(SensorPrivacyManager.Sensors.CAMERA, getTargetUserId())) {
+ .isSensorPrivacyEnabled(SensorPrivacyManager.TOGGLE_TYPE_SOFTWARE,
+ SensorPrivacyManager.Sensors.CAMERA)) {
onError(BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */);
mCallback.onClientFinished(this, false /* success */);
return;
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java
index 8d76e9f031f7..1935a5b135d7 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java
@@ -109,7 +109,8 @@ class FaceAuthenticationClient extends AuthenticationClient<IBiometricsFace> {
if (mSensorPrivacyManager != null
&& mSensorPrivacyManager
- .isSensorPrivacyEnabled(SensorPrivacyManager.Sensors.CAMERA, getTargetUserId())) {
+ .isSensorPrivacyEnabled(SensorPrivacyManager.TOGGLE_TYPE_SOFTWARE,
+ SensorPrivacyManager.Sensors.CAMERA)) {
onError(BiometricFaceConstants.FACE_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */);
mCallback.onClientFinished(this, false /* success */);
return;
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 b4befd23671f..e8d8fb828542 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
@@ -928,7 +928,8 @@ public class FingerprintService extends SystemService {
}
@Override
- public void onPointerDown(int sensorId, int x, int y, float minor, float major) {
+ public void onPointerDown(long requestId, int sensorId, int x, int y,
+ float minor, float major) {
Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
final ServiceProvider provider = getProviderForSensor(sensorId);
@@ -936,11 +937,11 @@ public class FingerprintService extends SystemService {
Slog.w(TAG, "No matching provider for onFingerDown, sensorId: " + sensorId);
return;
}
- provider.onPointerDown(sensorId, x, y, minor, major);
+ provider.onPointerDown(requestId, sensorId, x, y, minor, major);
}
@Override
- public void onPointerUp(int sensorId) {
+ public void onPointerUp(long requestId, int sensorId) {
Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
final ServiceProvider provider = getProviderForSensor(sensorId);
@@ -948,11 +949,11 @@ public class FingerprintService extends SystemService {
Slog.w(TAG, "No matching provider for onFingerUp, sensorId: " + sensorId);
return;
}
- provider.onPointerUp(sensorId);
+ provider.onPointerUp(requestId, sensorId);
}
@Override
- public void onUiReady(int sensorId) {
+ public void onUiReady(long requestId, int sensorId) {
Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
final ServiceProvider provider = getProviderForSensor(sensorId);
@@ -960,7 +961,7 @@ public class FingerprintService extends SystemService {
Slog.w(TAG, "No matching provider for onUiReady, sensorId: " + sensorId);
return;
}
- provider.onUiReady(sensorId);
+ provider.onUiReady(requestId, sensorId);
}
@Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java
index 0bdc4ebad66e..9cdbdc9158fb 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java
@@ -142,11 +142,11 @@ public interface ServiceProvider {
long getAuthenticatorId(int sensorId, int userId);
- void onPointerDown(int sensorId, int x, int y, float minor, float major);
+ void onPointerDown(long requestId, int sensorId, int x, int y, float minor, float major);
- void onPointerUp(int sensorId);
+ void onPointerUp(long requestId, int sensorId);
- void onUiReady(int sensorId);
+ void onUiReady(long requestId, int sensorId);
void setUdfpsOverlayController(@NonNull IUdfpsOverlayController controller);
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
index 653776b3ca65..79e3bf53acd3 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
@@ -140,12 +140,9 @@ class FingerprintAuthenticationClient extends AuthenticationClient<AidlSession>
@Override
public void onAcquired(@FingerprintAcquired int acquiredInfo, int vendorCode) {
- // For UDFPS, notify SysUI that the illumination can be turned off.
- // See AcquiredInfo#GOOD and AcquiredInfo#RETRYING_CAPTURE
- if (acquiredInfo == BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_GOOD) {
- mSensorOverlays.ifUdfps(controller -> controller.onAcquiredGood(getSensorId()));
- }
-
+ // For UDFPS, notify SysUI with acquiredInfo, so that the illumination can be turned off
+ // for most ACQUIRED messages. See BiometricFingerprintConstants#FingerprintAcquired
+ mSensorOverlays.ifUdfps(controller -> controller.onAcquired(getSensorId(), acquiredInfo));
super.onAcquired(acquiredInfo, vendorCode);
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java
index c92d599d68e6..bb1fed0bfecc 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java
@@ -114,12 +114,16 @@ class FingerprintEnrollClient extends EnrollClient<AidlSession> implements Udfps
@Override
public void onAcquired(@FingerprintAcquired int acquiredInfo, int vendorCode) {
+ boolean acquiredGood =
+ acquiredInfo == BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_GOOD;
// For UDFPS, notify SysUI that the illumination can be turned off.
// See AcquiredInfo#GOOD and AcquiredInfo#RETRYING_CAPTURE
- if (acquiredInfo == BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_GOOD
- && mSensorProps.isAnyUdfpsType()) {
- vibrateSuccess();
- mSensorOverlays.ifUdfps(controller -> controller.onAcquiredGood(getSensorId()));
+ if (mSensorProps.isAnyUdfpsType()) {
+ if (acquiredGood) {
+ vibrateSuccess();
+ }
+ mSensorOverlays.ifUdfps(
+ controller -> controller.onAcquired(getSensorId(), acquiredInfo));
}
mSensorOverlays.ifUdfps(controller -> {
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
index f810bca9707d..1fac8a8ce5c9 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
@@ -580,39 +580,37 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
}
@Override
- public void onPointerDown(int sensorId, int x, int y, float minor, float major) {
+ public void onPointerDown(long requestId, int sensorId, int x, int y,
+ float minor, float major) {
final BaseClientMonitor client =
- mSensors.get(sensorId).getScheduler().getCurrentClient();
+ mSensors.get(sensorId).getScheduler().getCurrentClientIfMatches(requestId);
if (!(client instanceof Udfps)) {
Slog.e(getTag(), "onPointerDown received during client: " + client);
return;
}
- final Udfps udfps = (Udfps) client;
- udfps.onPointerDown(x, y, minor, major);
+ ((Udfps) client).onPointerDown(x, y, minor, major);
}
@Override
- public void onPointerUp(int sensorId) {
+ public void onPointerUp(long requestId, int sensorId) {
final BaseClientMonitor client =
- mSensors.get(sensorId).getScheduler().getCurrentClient();
+ mSensors.get(sensorId).getScheduler().getCurrentClientIfMatches(requestId);
if (!(client instanceof Udfps)) {
Slog.e(getTag(), "onPointerUp received during client: " + client);
return;
}
- final Udfps udfps = (Udfps) client;
- udfps.onPointerUp();
+ ((Udfps) client).onPointerUp();
}
@Override
- public void onUiReady(int sensorId) {
+ public void onUiReady(long requestId, int sensorId) {
final BaseClientMonitor client =
- mSensors.get(sensorId).getScheduler().getCurrentClient();
+ mSensors.get(sensorId).getScheduler().getCurrentClientIfMatches(requestId);
if (!(client instanceof Udfps)) {
Slog.e(getTag(), "onUiReady received during client: " + client);
return;
}
- final Udfps udfps = (Udfps) client;
- udfps.onUiReady();
+ ((Udfps) client).onUiReady();
}
@Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
index 9d60859a4a21..1d2a3655021c 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
@@ -792,36 +792,34 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
}
@Override
- public void onPointerDown(int sensorId, int x, int y, float minor, float major) {
- final BaseClientMonitor client = mScheduler.getCurrentClient();
+ public void onPointerDown(long requestId, int sensorId, int x, int y,
+ float minor, float major) {
+ final BaseClientMonitor client = mScheduler.getCurrentClientIfMatches(requestId);
if (!(client instanceof Udfps)) {
Slog.w(TAG, "onFingerDown received during client: " + client);
return;
}
- final Udfps udfps = (Udfps) client;
- udfps.onPointerDown(x, y, minor, major);
+ ((Udfps) client).onPointerDown(x, y, minor, major);
}
@Override
- public void onPointerUp(int sensorId) {
- final BaseClientMonitor client = mScheduler.getCurrentClient();
+ public void onPointerUp(long requestId, int sensorId) {
+ final BaseClientMonitor client = mScheduler.getCurrentClientIfMatches(requestId);
if (!(client instanceof Udfps)) {
Slog.w(TAG, "onFingerDown received during client: " + client);
return;
}
- final Udfps udfps = (Udfps) client;
- udfps.onPointerUp();
+ ((Udfps) client).onPointerUp();
}
@Override
- public void onUiReady(int sensorId) {
- final BaseClientMonitor client = mScheduler.getCurrentClient();
+ public void onUiReady(long requestId, int sensorId) {
+ final BaseClientMonitor client = mScheduler.getCurrentClientIfMatches(requestId);
if (!(client instanceof Udfps)) {
Slog.w(TAG, "onUiReady received during client: " + client);
return;
}
- final Udfps udfps = (Udfps) client;
- udfps.onUiReady();
+ ((Udfps) client).onUiReady();
}
@Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java
index 149526f21fdb..a4e343e786c1 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java
@@ -441,7 +441,8 @@ public class Fingerprint21UdfpsMock extends Fingerprint21 implements TrustManage
}
@Override
- public void onPointerDown(int sensorId, int x, int y, float minor, float major) {
+ public void onPointerDown(long requestId, int sensorId, int x, int y, float minor,
+ float major) {
mHandler.post(() -> {
Slog.d(TAG, "onFingerDown");
final AuthenticationConsumer lastAuthenticatedConsumer =
@@ -488,7 +489,7 @@ public class Fingerprint21UdfpsMock extends Fingerprint21 implements TrustManage
}
@Override
- public void onPointerUp(int sensorId) {
+ public void onPointerUp(long requestId, int sensorId) {
mHandler.post(() -> {
Slog.d(TAG, "onFingerUp");
diff --git a/services/core/java/com/android/server/camera/CameraServiceProxy.java b/services/core/java/com/android/server/camera/CameraServiceProxy.java
index e0b768d7c592..7db99f1da130 100644
--- a/services/core/java/com/android/server/camera/CameraServiceProxy.java
+++ b/services/core/java/com/android/server/camera/CameraServiceProxy.java
@@ -184,6 +184,9 @@ public class CameraServiceProxy extends SystemService
// Must be equal to number of CameraStreamProto in CameraActionEvent
private static final int MAX_STREAM_STATISTICS = 5;
+ private static final float MIN_PREVIEW_FPS = 30.0f;
+ private static final float MAX_PREVIEW_FPS = 60.0f;
+
private final Context mContext;
private final ServiceThread mHandlerThread;
private final Handler mHandler;
@@ -467,7 +470,8 @@ public class CameraServiceProxy extends SystemService
ParceledListSlice<ActivityManager.RecentTaskInfo> recentTasks = null;
try {
- recentTasks = ActivityTaskManager.getService().getRecentTasks(/*maxNum*/1,
+ // Get 2 recent tasks in case we are running in split mode
+ recentTasks = ActivityTaskManager.getService().getRecentTasks(/*maxNum*/2,
/*flags*/ 0, userId);
} catch (RemoteException e) {
Log.e(TAG, "Failed to query recent tasks!");
@@ -475,23 +479,27 @@ public class CameraServiceProxy extends SystemService
}
if ((recentTasks != null) && (!recentTasks.getList().isEmpty())) {
- ActivityManager.RecentTaskInfo task = recentTasks.getList().get(0);
- if (packageName.equals(task.topActivityInfo.packageName)) {
- taskInfo = new TaskInfo();
- taskInfo.frontTaskId = task.taskId;
- taskInfo.isResizeable =
- (task.topActivityInfo.resizeMode != RESIZE_MODE_UNRESIZEABLE);
- taskInfo.displayId = task.displayId;
- taskInfo.userId = task.userId;
- taskInfo.isFixedOrientationLandscape =
- ActivityInfo.isFixedOrientationLandscape(
- task.topActivityInfo.screenOrientation);
- taskInfo.isFixedOrientationPortrait =
- ActivityInfo.isFixedOrientationPortrait(
- task.topActivityInfo.screenOrientation);
- } else {
- Log.e(TAG, "Recent task package name: " + task.topActivityInfo.packageName
- + " doesn't match with camera client package name: " + packageName);
+ for (ActivityManager.RecentTaskInfo task : recentTasks.getList()) {
+ if (packageName.equals(task.topActivityInfo.packageName)) {
+ taskInfo = new TaskInfo();
+ taskInfo.frontTaskId = task.taskId;
+ taskInfo.isResizeable =
+ (task.topActivityInfo.resizeMode != RESIZE_MODE_UNRESIZEABLE);
+ taskInfo.displayId = task.displayId;
+ taskInfo.userId = task.userId;
+ taskInfo.isFixedOrientationLandscape =
+ ActivityInfo.isFixedOrientationLandscape(
+ task.topActivityInfo.screenOrientation);
+ taskInfo.isFixedOrientationPortrait =
+ ActivityInfo.isFixedOrientationPortrait(
+ task.topActivityInfo.screenOrientation);
+ break;
+ }
+ }
+
+ if (taskInfo == null) {
+ Log.e(TAG, "Recent tasks don't include camera client package name: " +
+ packageName);
return CaptureRequest.SCALER_ROTATE_AND_CROP_NONE;
}
} else {
@@ -816,6 +824,7 @@ public class CameraServiceProxy extends SystemService
Slog.v(TAG, "Stream " + i + ": width " + streamProtos[i].width
+ ", height " + streamProtos[i].height
+ ", format " + streamProtos[i].format
+ + ", maxPreviewFps " + streamStats.getMaxPreviewFps()
+ ", dataSpace " + streamProtos[i].dataSpace
+ ", usage " + streamProtos[i].usage
+ ", requestCount " + streamProtos[i].requestCount
@@ -1010,6 +1019,11 @@ public class CameraServiceProxy extends SystemService
return false;
}
+ private float getMinFps(CameraSessionStats cameraState) {
+ float maxFps = cameraState.getMaxPreviewFps();
+ return Math.max(Math.min(maxFps, MAX_PREVIEW_FPS), MIN_PREVIEW_FPS);
+ }
+
private void updateActivityCount(CameraSessionStats cameraState) {
String cameraId = cameraState.getCameraId();
int newCameraState = cameraState.getNewCameraState();
@@ -1063,7 +1077,9 @@ public class CameraServiceProxy extends SystemService
if (!alreadyActivePackage) {
WindowManagerInternal wmi =
LocalServices.getService(WindowManagerInternal.class);
- wmi.addNonHighRefreshRatePackage(clientName);
+ float minFps = getMinFps(cameraState);
+ wmi.addRefreshRateRangeForPackage(clientName,
+ minFps, MAX_PREVIEW_FPS);
}
// Update activity events
@@ -1102,7 +1118,7 @@ public class CameraServiceProxy extends SystemService
if (!stillActivePackage) {
WindowManagerInternal wmi =
LocalServices.getService(WindowManagerInternal.class);
- wmi.removeNonHighRefreshRatePackage(clientName);
+ wmi.removeRefreshRateRangeForPackage(clientName);
}
}
diff --git a/services/core/java/com/android/server/clipboard/EmulatorClipboardMonitor.java b/services/core/java/com/android/server/clipboard/EmulatorClipboardMonitor.java
index 62b701aff398..28c7cad3b184 100644
--- a/services/core/java/com/android/server/clipboard/EmulatorClipboardMonitor.java
+++ b/services/core/java/com/android/server/clipboard/EmulatorClipboardMonitor.java
@@ -18,6 +18,7 @@ package com.android.server.clipboard;
import android.annotation.Nullable;
import android.content.ClipData;
+import android.os.SystemProperties;
import android.system.ErrnoException;
import android.system.Os;
import android.system.OsConstants;
@@ -39,6 +40,8 @@ class EmulatorClipboardMonitor implements Consumer<ClipData> {
private static final String PIPE_NAME = "pipe:clipboard";
private static final int HOST_PORT = 5000;
private final Thread mHostMonitorThread;
+ private static final boolean LOG_CLIBOARD_ACCESS =
+ SystemProperties.getBoolean("ro.boot.qemu.log_clipboard_access", false);
private FileDescriptor mPipe = null;
private static byte[] createOpenHandshake() {
@@ -51,8 +54,8 @@ class EmulatorClipboardMonitor implements Consumer<ClipData> {
return bits;
}
- private boolean isPipeOpened() {
- return mPipe != null;
+ private synchronized FileDescriptor getPipeFD() {
+ return mPipe;
}
private synchronized boolean openPipe() {
@@ -104,14 +107,16 @@ class EmulatorClipboardMonitor implements Consumer<ClipData> {
return msg;
}
- private void sendMessage(final byte[] msg) throws ErrnoException, InterruptedIOException {
+ private static void sendMessage(
+ final FileDescriptor fd,
+ final byte[] msg) throws ErrnoException, InterruptedIOException {
final byte[] lengthBits = new byte[4];
final ByteBuffer bb = ByteBuffer.wrap(lengthBits);
bb.order(ByteOrder.LITTLE_ENDIAN);
bb.putInt(msg.length);
- Os.write(mPipe, lengthBits, 0, lengthBits.length);
- Os.write(mPipe, msg, 0, msg.length);
+ Os.write(fd, lengthBits, 0, lengthBits.length);
+ Os.write(fd, msg, 0, msg.length);
}
EmulatorClipboardMonitor(final Consumer<ClipData> setAndroidClipboard) {
@@ -132,6 +137,9 @@ class EmulatorClipboardMonitor implements Consumer<ClipData> {
new String[]{"text/plain"},
new ClipData.Item(str));
+ if (LOG_CLIBOARD_ACCESS) {
+ Slog.i(TAG, "Setting the guest clipboard to '" + str + "'");
+ }
setAndroidClipboard.accept(clip);
} catch (ErrnoException | InterruptedIOException e) {
closePipe();
@@ -156,13 +164,22 @@ class EmulatorClipboardMonitor implements Consumer<ClipData> {
}
private void setHostClipboardImpl(final String value) {
- try {
- if (isPipeOpened()) {
- sendMessage(value.getBytes());
- }
- } catch (ErrnoException | InterruptedIOException e) {
- Slog.e(TAG, "Failed to set host clipboard " + e.getMessage());
- } catch (IllegalArgumentException e) {
+ final FileDescriptor pipeFD = getPipeFD();
+
+ if (pipeFD != null) {
+ Thread t = new Thread(() -> {
+ if (LOG_CLIBOARD_ACCESS) {
+ Slog.i(TAG, "Setting the host clipboard to '" + value + "'");
+ }
+
+ try {
+ sendMessage(pipeFD, value.getBytes());
+ } catch (ErrnoException | InterruptedIOException e) {
+ Slog.e(TAG, "Failed to set host clipboard " + e.getMessage());
+ } catch (IllegalArgumentException e) {
+ }
+ });
+ t.start();
}
}
}
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 682f0dfe067c..a6da4a6a4260 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -75,6 +75,7 @@ import android.net.RouteInfo;
import android.net.UidRangeParcel;
import android.net.UnderlyingNetworkInfo;
import android.net.VpnManager;
+import android.net.VpnProfileState;
import android.net.VpnService;
import android.net.VpnTransportInfo;
import android.net.ipsec.ike.ChildSessionCallback;
@@ -1320,6 +1321,7 @@ public class Vpn {
.setLegacyTypeName("VPN")
.setBypassableVpn(mConfig.allowBypass && !mLockdown)
.setVpnRequiresValidation(mConfig.requiresInternetValidation)
+ .setLocalRoutesExcludedForVpn(mConfig.excludeLocalRoutes)
.build();
capsBuilder.setOwnerUid(mOwnerUID);
@@ -3386,6 +3388,7 @@ public class Vpn {
mConfig.startTime = SystemClock.elapsedRealtime();
mConfig.proxyInfo = profile.proxy;
mConfig.requiresInternetValidation = profile.requiresInternetValidation;
+ mConfig.excludeLocalRoutes = profile.excludeLocalRoutes;
switch (profile.type) {
case VpnProfile.TYPE_IKEV2_IPSEC_USER_PASS:
@@ -3436,6 +3439,45 @@ public class Vpn {
}
}
+ private @VpnProfileState.State int getStateFromLegacyState(int legacyState) {
+ switch (legacyState) {
+ case LegacyVpnInfo.STATE_CONNECTING:
+ return VpnProfileState.STATE_CONNECTING;
+ case LegacyVpnInfo.STATE_CONNECTED:
+ return VpnProfileState.STATE_CONNECTED;
+ case LegacyVpnInfo.STATE_DISCONNECTED:
+ return VpnProfileState.STATE_DISCONNECTED;
+ case LegacyVpnInfo.STATE_FAILED:
+ return VpnProfileState.STATE_FAILED;
+ default:
+ Log.wtf(TAG, "Unhandled state " + legacyState
+ + ", treat it as STATE_DISCONNECTED");
+ return VpnProfileState.STATE_DISCONNECTED;
+ }
+ }
+
+ private VpnProfileState makeVpnProfileState() {
+ // TODO: mSessionKey will be moved to Ikev2VpnRunner once aosp/2007077 is merged, so after
+ // merging aosp/2007077, here should check Ikev2VpnRunner is null or not. Session key will
+ // be null if Ikev2VpnRunner is null.
+ return new VpnProfileState(getStateFromLegacyState(mLegacyState), mSessionKey, mAlwaysOn,
+ mLockdown);
+ }
+
+ /**
+ * Retrieve the VpnProfileState for the profile provisioned by the given package.
+ *
+ * @return the VpnProfileState with current information, or null if there was no profile
+ * provisioned by the given package.
+ */
+ @Nullable
+ public synchronized VpnProfileState getProvisionedVpnProfileState(
+ @NonNull String packageName) {
+ requireNonNull(packageName, "No package name provided");
+ enforceNotRestrictedUser();
+ return isCurrentIkev2VpnLocked(packageName) ? makeVpnProfileState() : null;
+ }
+
/**
* Proxy to allow testing
*
diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java
index fadcce9ee9b3..954b9307a3ef 100644
--- a/services/core/java/com/android/server/content/ContentService.java
+++ b/services/core/java/com/android/server/content/ContentService.java
@@ -20,6 +20,7 @@ import static android.content.PermissionChecker.PERMISSION_GRANTED;
import android.Manifest;
import android.accounts.Account;
+import android.accounts.AccountManagerInternal;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
@@ -28,7 +29,10 @@ import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
import android.app.AppGlobals;
import android.app.AppOpsManager;
+import android.app.compat.CompatChanges;
import android.app.job.JobInfo;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledAfter;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
@@ -106,6 +110,13 @@ public final class ContentService extends IContentService.Stub {
*/
private static final long BACKGROUND_OBSERVER_DELAY = 10 * DateUtils.SECOND_IN_MILLIS;
+ /**
+ * Enables checking for account access for the calling uid on all sync-related APIs.
+ */
+ @ChangeId
+ @EnabledAfter(targetSdkVersion = android.os.Build.VERSION_CODES.S_V2)
+ public static final long ACCOUNT_ACCESS_CHECK_CHANGE_ID = 201794303L;
+
public static class Lifecycle extends SystemService {
private ContentService mService;
@@ -157,6 +168,8 @@ public final class ContentService extends IContentService.Stub {
private SyncManager mSyncManager = null;
private final Object mSyncManagerLock = new Object();
+ private final AccountManagerInternal mAccountManagerInternal;
+
private static final BinderDeathDispatcher<IContentObserver> sObserverDeathDispatcher =
new BinderDeathDispatcher<>();
@@ -317,6 +330,8 @@ public final class ContentService extends IContentService.Stub {
localeFilter.addAction(Intent.ACTION_LOCALE_CHANGED);
mContext.registerReceiverAsUser(mCacheReceiver, UserHandle.ALL,
localeFilter, null, null);
+
+ mAccountManagerInternal = LocalServices.getService(AccountManagerInternal.class);
}
void onBootPhase(int phase) {
@@ -593,6 +608,10 @@ public final class ContentService extends IContentService.Stub {
final int callingUid = Binder.getCallingUid();
final int callingPid = Binder.getCallingPid();
+ if (!hasAccountAccess(true, account, callingUid)) {
+ return;
+ }
+
validateExtras(callingUid, extras);
final int syncExemption = getSyncExemptionAndCleanUpExtrasForCaller(callingUid, extras);
@@ -642,11 +661,14 @@ public final class ContentService extends IContentService.Stub {
@Override
public void syncAsUser(SyncRequest request, int userId, String callingPackage) {
enforceCrossUserPermission(userId, "no permission to request sync as user: " + userId);
+
final int callingUid = Binder.getCallingUid();
final int callingPid = Binder.getCallingPid();
+ if (!hasAccountAccess(true, request.getAccount(), callingUid)) {
+ return;
+ }
final Bundle extras = request.getBundle();
-
validateExtras(callingUid, extras);
final int syncExemption = getSyncExemptionAndCleanUpExtrasForCaller(callingUid, extras);
@@ -853,6 +875,9 @@ public final class ContentService extends IContentService.Stub {
"no permission to read the sync settings for user " + userId);
mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS,
"no permission to read the sync settings");
+ if (!hasAccountAccess(true, account, Binder.getCallingUid())) {
+ return false;
+ }
final long identityToken = clearCallingIdentity();
try {
@@ -882,8 +907,13 @@ public final class ContentService extends IContentService.Stub {
"no permission to write the sync settings");
enforceCrossUserPermission(userId,
"no permission to modify the sync settings for user " + userId);
+
final int callingUid = Binder.getCallingUid();
final int callingPid = Binder.getCallingPid();
+ if (!hasAccountAccess(true, account, callingUid)) {
+ return;
+ }
+
final int syncExemptionFlag = getSyncExemptionForCaller(callingUid);
final long identityToken = clearCallingIdentity();
@@ -912,7 +942,11 @@ public final class ContentService extends IContentService.Stub {
mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
"no permission to write the sync settings");
- validateExtras(Binder.getCallingUid(), extras);
+ final int callingUid = Binder.getCallingUid();
+ if (!hasAccountAccess(true, account, callingUid)) {
+ return;
+ }
+ validateExtras(callingUid, extras);
int userId = UserHandle.getCallingUserId();
@@ -942,9 +976,11 @@ public final class ContentService extends IContentService.Stub {
mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
"no permission to write the sync settings");
- validateExtras(Binder.getCallingUid(), extras);
-
final int callingUid = Binder.getCallingUid();
+ if (!hasAccountAccess(true, account, callingUid)) {
+ return;
+ }
+ validateExtras(callingUid, extras);
int userId = UserHandle.getCallingUserId();
final long identityToken = clearCallingIdentity();
@@ -969,6 +1005,9 @@ public final class ContentService extends IContentService.Stub {
}
mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS,
"no permission to read the sync settings");
+ if (!hasAccountAccess(true, account, Binder.getCallingUid())) {
+ return new ArrayList<>(); // return a new empty list for consistent behavior
+ }
int userId = UserHandle.getCallingUserId();
final long identityToken = clearCallingIdentity();
@@ -995,6 +1034,9 @@ public final class ContentService extends IContentService.Stub {
"no permission to read the sync settings for user " + userId);
mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS,
"no permission to read the sync settings");
+ if (!hasAccountAccess(true, account, Binder.getCallingUid())) {
+ return SyncStorageEngine.AuthorityInfo.NOT_SYNCABLE; // to keep behavior consistent
+ }
final long identityToken = clearCallingIdentity();
try {
@@ -1031,6 +1073,9 @@ public final class ContentService extends IContentService.Stub {
syncable = normalizeSyncable(syncable);
final int callingUid = Binder.getCallingUid();
final int callingPid = Binder.getCallingPid();
+ if (!hasAccountAccess(true, account, callingUid)) {
+ return;
+ }
final long identityToken = clearCallingIdentity();
try {
@@ -1103,6 +1148,10 @@ public final class ContentService extends IContentService.Stub {
public boolean isSyncActive(Account account, String authority, ComponentName cname) {
mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS,
"no permission to read the sync stats");
+ if (!hasAccountAccess(true, account, Binder.getCallingUid())) {
+ return false;
+ }
+
int userId = UserHandle.getCallingUserId();
final long identityToken = clearCallingIdentity();
try {
@@ -1165,6 +1214,9 @@ public final class ContentService extends IContentService.Stub {
"no permission to read the sync stats for user " + userId);
mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS,
"no permission to read the sync stats");
+ if (!hasAccountAccess(true, account, Binder.getCallingUid())) {
+ return null;
+ }
final long identityToken = clearCallingIdentity();
try {
@@ -1196,6 +1248,10 @@ public final class ContentService extends IContentService.Stub {
"no permission to read the sync stats");
enforceCrossUserPermission(userId,
"no permission to retrieve the sync settings for user " + userId);
+ if (!hasAccountAccess(true, account, Binder.getCallingUid())) {
+ return false;
+ }
+
final long identityToken = clearCallingIdentity();
SyncManager syncManager = getSyncManager();
if (syncManager == null) return false;
@@ -1405,6 +1461,32 @@ public final class ContentService extends IContentService.Stub {
Manifest.permission.INTERACT_ACROSS_USERS_FULL, message);
}
+ /**
+ * Checks to see if the given account is accessible by the provided uid.
+ *
+ * @param checkCompatFlag whether to check if the ACCOUNT_ACCESS_CHECK_CHANGE_ID flag is enabled
+ * @param account the account trying to be accessed
+ * @param uid the uid trying to access the account
+ * @return {@code true} if the account is accessible by the given uid, {@code false} otherwise
+ */
+ private boolean hasAccountAccess(boolean checkCompatFlag, Account account, int uid) {
+ if (account == null) {
+ // If the account is null, it means to check for all accounts hence skip the check here.
+ return true;
+ }
+ if (checkCompatFlag
+ && !CompatChanges.isChangeEnabled(ACCOUNT_ACCESS_CHECK_CHANGE_ID, uid)) {
+ return true;
+ }
+
+ final long identityToken = clearCallingIdentity();
+ try {
+ return mAccountManagerInternal.hasAccountAccess(account, uid);
+ } finally {
+ restoreCallingIdentity(identityToken);
+ }
+ }
+
private static int normalizeSyncable(int syncable) {
if (syncable > 0) {
return SyncStorageEngine.AuthorityInfo.SYNCABLE;
diff --git a/services/core/java/com/android/server/display/ColorFade.java b/services/core/java/com/android/server/display/ColorFade.java
index 7cb29215b5bf..cb04ddfd636d 100644
--- a/services/core/java/com/android/server/display/ColorFade.java
+++ b/services/core/java/com/android/server/display/ColorFade.java
@@ -156,9 +156,15 @@ final class ColorFade {
mMode = mode;
+ DisplayInfo displayInfo = mDisplayManagerInternal.getDisplayInfo(mDisplayId);
+ if (displayInfo == null) {
+ // displayInfo can be null if the associated display has been removed. There
+ // is a delay between the display being removed and ColorFade being dismissed.
+ return false;
+ }
+
// Get the display size and layer stack.
// This is not expected to change while the color fade surface is showing.
- DisplayInfo displayInfo = mDisplayManagerInternal.getDisplayInfo(mDisplayId);
mDisplayLayerStack = displayInfo.layerStack;
mDisplayWidth = displayInfo.getNaturalWidth();
mDisplayHeight = displayInfo.getNaturalHeight();
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 9067f2e25152..f819e56e6856 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -129,7 +129,8 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
private static final int MSG_STOP = 9;
private static final int MSG_UPDATE_BRIGHTNESS = 10;
private static final int MSG_UPDATE_RBC = 11;
- private static final int MSG_STATSD_HBM_BRIGHTNESS = 12;
+ private static final int MSG_BRIGHTNESS_RAMP_DONE = 12;
+ private static final int MSG_STATSD_HBM_BRIGHTNESS = 13;
private static final int PROXIMITY_UNKNOWN = -1;
private static final int PROXIMITY_NEGATIVE = 0;
@@ -1050,9 +1051,8 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
@Override
public void onAnimationEnd() {
sendUpdatePowerState();
-
- final float brightness = mPowerState.getScreenBrightness();
- reportStats(brightness);
+ Message msg = mHandler.obtainMessage(MSG_BRIGHTNESS_RAMP_DONE);
+ mHandler.sendMessage(msg);
}
};
@@ -1066,6 +1066,12 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
mCallbacks.releaseSuspendBlocker();
mUnfinishedBusiness = false;
}
+
+ final float brightness = mPowerState != null
+ ? mPowerState.getScreenBrightness()
+ : PowerManager.BRIGHTNESS_MIN;
+ reportStats(brightness);
+
if (mPowerState != null) {
mPowerState.stop();
mPowerState = null;
@@ -2580,6 +2586,10 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
}
private void reportStats(float brightness) {
+ if (mLastStatsBrightness == brightness) {
+ return;
+ }
+
float hbmTransitionPoint = PowerManager.BRIGHTNESS_MAX;
synchronized(mCachedBrightnessInfo) {
if (mCachedBrightnessInfo.hbmTransitionPoint == null) {
@@ -2680,6 +2690,13 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
handleRbcChanged(strengthChanged == 1, justActivated == 1);
break;
+ case MSG_BRIGHTNESS_RAMP_DONE:
+ if (mPowerState != null) {
+ final float brightness = mPowerState.getScreenBrightness();
+ reportStats(brightness);
+ }
+ break;
+
case MSG_STATSD_HBM_BRIGHTNESS:
logHbmBrightnessStats(Float.intBitsToFloat(msg.arg1), msg.arg2);
break;
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index 7a0cf4b592e7..540ae8165dbd 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -73,6 +73,8 @@ final class LocalDisplayAdapter extends DisplayAdapter {
private final SurfaceControlProxy mSurfaceControlProxy;
+ private final boolean mIsBootDisplayModeSupported;
+
// Called with SyncRoot lock held.
public LocalDisplayAdapter(DisplayManagerService.SyncRoot syncRoot,
Context context, Handler handler, Listener listener) {
@@ -85,6 +87,7 @@ final class LocalDisplayAdapter extends DisplayAdapter {
super(syncRoot, context, handler, listener, TAG);
mInjector = injector;
mSurfaceControlProxy = mInjector.getSurfaceControlProxy();
+ mIsBootDisplayModeSupported = mSurfaceControlProxy.getBootDisplayModeSupport();
}
@Override
@@ -349,8 +352,7 @@ final class LocalDisplayAdapter extends DisplayAdapter {
if (preferredRecord != null) {
int preferredModeId = preferredRecord.mMode.getModeId();
- if (mSurfaceControlProxy.getBootDisplayModeSupport()
- && mSystemPreferredModeId != preferredModeId) {
+ if (mIsBootDisplayModeSupported && mSystemPreferredModeId != preferredModeId) {
mSystemPreferredModeId = preferredModeId;
preferredModeChanged = true;
}
@@ -900,7 +902,7 @@ final class LocalDisplayAdapter extends DisplayAdapter {
}
updateDeviceInfoLocked();
- if (!mSurfaceControlProxy.getBootDisplayModeSupport()) {
+ if (!mIsBootDisplayModeSupported) {
return;
}
if (mUserPreferredModeId == INVALID_MODE_ID) {
diff --git a/services/core/java/com/android/server/dreams/DreamManagerService.java b/services/core/java/com/android/server/dreams/DreamManagerService.java
index 22d32a665611..50f5536d9f4b 100644
--- a/services/core/java/com/android/server/dreams/DreamManagerService.java
+++ b/services/core/java/com/android/server/dreams/DreamManagerService.java
@@ -467,7 +467,9 @@ public final class DreamManagerService extends SystemService {
}
mCurrentDreamDozeScreenState = Display.STATE_UNKNOWN;
mCurrentDreamDozeScreenBrightness = PowerManager.BRIGHTNESS_DEFAULT;
- mAtmInternal.notifyDreamStateChanged(false);
+ mHandler.post(() -> {
+ mAtmInternal.notifyDreamStateChanged(false);
+ });
}
private void checkPermission(String permission) {
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index c0950bf13a1c..d249d578cf67 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -654,14 +654,17 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
protected int handleTextViewOn(HdmiCecMessage message) {
assertRunOnServiceThread();
- // Note that <Text View On> (and <Image View On>) command won't be handled here in
- // most cases. A dedicated microcontroller should be in charge while Android system
- // is in sleep mode, and the command need not be passed up to this service.
- // The only situation where the command reaches this handler is that sleep mode is
- // implemented in such a way that Android system is not really put to standby mode
- // but only the display is set to blank. Then the command leads to the effect of
+ // Note that if the device is in sleep mode, the <Text View On> (and <Image View On>)
+ // command won't be handled here in most cases. A dedicated microcontroller should be in
+ // charge while the Android system is in sleep mode, and the command doesn't need to be
+ // passed up to this service.
+ // The only situations where the command reaches this handler are
+ // 1. if sleep mode is implemented in such a way that Android system is not really put to
+ // standby mode but only the display is set to blank. Then the command leads to
// turning on the display by the invocation of PowerManager.wakeUp().
- if (mService.isPowerStandbyOrTransient() && getAutoWakeup()) {
+ // 2. if the device is in dream mode, not sleep mode. Then this command leads to
+ // waking up the device from dream mode by the invocation of PowerManager.wakeUp().
+ if (getAutoWakeup()) {
mService.wakeUp();
}
return Constants.HANDLED;
diff --git a/services/core/java/com/android/server/infra/AbstractMasterSystemService.java b/services/core/java/com/android/server/infra/AbstractMasterSystemService.java
index 9e00f95c9c6f..34e3ce1ab641 100644
--- a/services/core/java/com/android/server/infra/AbstractMasterSystemService.java
+++ b/services/core/java/com/android/server/infra/AbstractMasterSystemService.java
@@ -48,6 +48,7 @@ import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import java.util.Objects;
@@ -168,10 +169,10 @@ public abstract class AbstractMasterSystemService<M extends AbstractMasterSystem
private final SparseBooleanArray mDisabledByUserRestriction;
/**
- * Cache of services per user id.
+ * Cache of service list per user id.
*/
@GuardedBy("mLock")
- private final SparseArray<S> mServicesCache = new SparseArray<>();
+ private final SparseArray<List<S>> mServicesCacheList = new SparseArray<>();
/**
* Value that determines whether the per-user service should be removed from the cache when its
@@ -252,8 +253,7 @@ public abstract class AbstractMasterSystemService<M extends AbstractMasterSystem
mServiceNameResolver = serviceNameResolver;
if (mServiceNameResolver != null) {
mServiceNameResolver.setOnTemporaryServiceNameChangedCallback(
- (u, s, t) -> onServiceNameChanged(u, s, t));
-
+ this::onServiceNameChanged);
}
if (disallowProperty == null) {
mDisabledByUserRestriction = null;
@@ -308,7 +308,7 @@ public abstract class AbstractMasterSystemService<M extends AbstractMasterSystem
@Override // from SystemService
public void onUserStopped(@NonNull TargetUser user) {
synchronized (mLock) {
- removeCachedServiceLocked(user.getUserIdentifier());
+ removeCachedServiceListLocked(user.getUserIdentifier());
}
}
@@ -386,21 +386,58 @@ public abstract class AbstractMasterSystemService<M extends AbstractMasterSystem
synchronized (mLock) {
final S oldService = peekServiceForUserLocked(userId);
if (oldService != null) {
- oldService.removeSelfFromCacheLocked();
+ oldService.removeSelfFromCache();
}
mServiceNameResolver.setTemporaryService(userId, componentName, durationMs);
}
}
/**
+ * Temporarily sets the service implementation.
+ *
+ * <p>Typically used by Shell command and/or CTS tests.
+ *
+ * @param componentNames list of the names of the new component
+ * @param durationMs how long the change will be valid (the service will be automatically
+ * reset
+ * to the default component after this timeout expires).
+ * @throws SecurityException if caller is not allowed to manage this service's settings.
+ * @throws IllegalArgumentException if value of {@code durationMs} is higher than
+ * {@link #getMaximumTemporaryServiceDurationMs()}.
+ */
+ public final void setTemporaryServices(@UserIdInt int userId, @NonNull String[] componentNames,
+ int durationMs) {
+ Slog.i(mTag, "setTemporaryService(" + userId + ") to " + Arrays.toString(componentNames)
+ + " for " + durationMs + "ms");
+ if (mServiceNameResolver == null) {
+ return;
+ }
+ enforceCallingPermissionForManagement();
+
+ Objects.requireNonNull(componentNames);
+ final int maxDurationMs = getMaximumTemporaryServiceDurationMs();
+ if (durationMs > maxDurationMs) {
+ throw new IllegalArgumentException(
+ "Max duration is " + maxDurationMs + " (called with " + durationMs + ")");
+ }
+
+ synchronized (mLock) {
+ final S oldService = peekServiceForUserLocked(userId);
+ if (oldService != null) {
+ oldService.removeSelfFromCache();
+ }
+ mServiceNameResolver.setTemporaryServices(userId, componentNames, durationMs);
+ }
+ }
+
+ /**
* Sets whether the default service should be used.
*
* <p>Typically used during CTS tests to make sure only the default service doesn't interfere
* with the test results.
*
- * @throws SecurityException if caller is not allowed to manage this service's settings.
- *
* @return whether the enabled state changed.
+ * @throws SecurityException if caller is not allowed to manage this service's settings.
*/
public final boolean setDefaultServiceEnabled(@UserIdInt int userId, boolean enabled) {
Slog.i(mTag, "setDefaultServiceEnabled() for userId " + userId + ": " + enabled);
@@ -420,7 +457,7 @@ public abstract class AbstractMasterSystemService<M extends AbstractMasterSystem
final S oldService = peekServiceForUserLocked(userId);
if (oldService != null) {
- oldService.removeSelfFromCacheLocked();
+ oldService.removeSelfFromCache();
}
// Must update the service on cache so its initialization code is triggered
@@ -501,6 +538,21 @@ public abstract class AbstractMasterSystemService<M extends AbstractMasterSystem
protected abstract S newServiceLocked(@UserIdInt int resolvedUserId, boolean disabled);
/**
+ * Creates a new service list that will be added to the cache.
+ *
+ * @param resolvedUserId the resolved user id for the service.
+ * @param disabled whether the service is currently disabled (due to {@link UserManager}
+ * restrictions).
+ * @return a new instance.
+ */
+ @Nullable
+ @GuardedBy("mLock")
+ protected List<S> newServiceListLocked(@UserIdInt int resolvedUserId, boolean disabled,
+ String[] serviceNames) {
+ throw new UnsupportedOperationException("newServiceListLocked not implemented. ");
+ }
+
+ /**
* Register the service for extra Settings changes (i.e., other than
* {@link android.provider.Settings.Secure#USER_SETUP_COMPLETE} or
* {@link #getServiceSettingsProperty()}, which are automatically handled).
@@ -516,7 +568,6 @@ public abstract class AbstractMasterSystemService<M extends AbstractMasterSystem
* <p><b>NOTE: </p>it doesn't need to register for
* {@link android.provider.Settings.Secure#USER_SETUP_COMPLETE} or
* {@link #getServiceSettingsProperty()}.
- *
*/
@SuppressWarnings("unused")
protected void registerForExtraSettingsChanges(@NonNull ContentResolver resolver,
@@ -527,7 +578,7 @@ public abstract class AbstractMasterSystemService<M extends AbstractMasterSystem
* Callback for Settings changes that were registered though
* {@link #registerForExtraSettingsChanges(ContentResolver, ContentObserver)}.
*
- * @param userId user associated with the change
+ * @param userId user associated with the change
* @param property Settings property changed.
*/
protected void onSettingsChanged(@UserIdInt int userId, @NonNull String property) {
@@ -539,18 +590,35 @@ public abstract class AbstractMasterSystemService<M extends AbstractMasterSystem
@GuardedBy("mLock")
@NonNull
protected S getServiceForUserLocked(@UserIdInt int userId) {
+ List<S> services = getServiceListForUserLocked(userId);
+ return services == null || services.size() == 0 ? null : services.get(0);
+ }
+
+ /**
+ * Gets the service instance list for a user, creating instances if not present in the cache.
+ */
+ @GuardedBy("mLock")
+ protected List<S> getServiceListForUserLocked(@UserIdInt int userId) {
final int resolvedUserId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
Binder.getCallingUid(), userId, false, false, null, null);
- S service = mServicesCache.get(resolvedUserId);
- if (service == null) {
+ List<S> services = mServicesCacheList.get(resolvedUserId);
+ if (services == null || services.size() == 0) {
final boolean disabled = isDisabledLocked(userId);
- service = newServiceLocked(resolvedUserId, disabled);
+ if (mServiceNameResolver != null && mServiceNameResolver.isConfiguredInMultipleMode()) {
+ services = newServiceListLocked(resolvedUserId, disabled,
+ mServiceNameResolver.getServiceNameList(userId));
+ } else {
+ services = new ArrayList<>();
+ services.add(newServiceLocked(resolvedUserId, disabled));
+ }
if (!disabled) {
- onServiceEnabledLocked(service, resolvedUserId);
+ for (int i = 0; i < services.size(); i++) {
+ onServiceEnabledLocked(services.get(i), resolvedUserId);
+ }
}
- mServicesCache.put(userId, service);
+ mServicesCacheList.put(userId, services);
}
- return service;
+ return services;
}
/**
@@ -560,9 +628,20 @@ public abstract class AbstractMasterSystemService<M extends AbstractMasterSystem
@GuardedBy("mLock")
@Nullable
protected S peekServiceForUserLocked(@UserIdInt int userId) {
+ List<S> serviceList = peekServiceListForUserLocked(userId);
+ return serviceList == null || serviceList.size() == 0 ? null : serviceList.get(0);
+ }
+
+ /**
+ * Gets the <b>existing</b> service instance for a user, returning {@code null} if not already
+ * present in the cache.
+ */
+ @GuardedBy("mLock")
+ @Nullable
+ protected List<S> peekServiceListForUserLocked(@UserIdInt int userId) {
final int resolvedUserId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
Binder.getCallingUid(), userId, false, false, null, null);
- return mServicesCache.get(resolvedUserId);
+ return mServicesCacheList.get(resolvedUserId);
}
/**
@@ -570,36 +649,59 @@ public abstract class AbstractMasterSystemService<M extends AbstractMasterSystem
*/
@GuardedBy("mLock")
protected void updateCachedServiceLocked(@UserIdInt int userId) {
- updateCachedServiceLocked(userId, isDisabledLocked(userId));
+ updateCachedServiceListLocked(userId, isDisabledLocked(userId));
}
/**
* Checks whether the service is disabled (through {@link UserManager} restrictions) for the
* given user.
*/
+ @GuardedBy("mLock")
protected boolean isDisabledLocked(@UserIdInt int userId) {
- return mDisabledByUserRestriction == null ? false : mDisabledByUserRestriction.get(userId);
+ return mDisabledByUserRestriction != null && mDisabledByUserRestriction.get(userId);
}
/**
* Updates a cached service for a given user.
*
- * @param userId user handle.
+ * @param userId user handle.
* @param disabled whether the user is disabled.
* @return service for the user.
*/
@GuardedBy("mLock")
protected S updateCachedServiceLocked(@UserIdInt int userId, boolean disabled) {
final S service = getServiceForUserLocked(userId);
- if (service != null) {
- service.updateLocked(disabled);
- if (!service.isEnabledLocked()) {
- removeCachedServiceLocked(userId);
- } else {
- onServiceEnabledLocked(service, userId);
+ updateCachedServiceListLocked(userId, disabled);
+ return service;
+ }
+
+ /**
+ * Updates a cached service for a given user.
+ *
+ * @param userId user handle.
+ * @param disabled whether the user is disabled.
+ * @return service for the user.
+ */
+ @GuardedBy("mLock")
+ protected List<S> updateCachedServiceListLocked(@UserIdInt int userId, boolean disabled) {
+ final List<S> services = getServiceListForUserLocked(userId);
+ if (services == null) {
+ return null;
+ }
+ for (int i = 0; i < services.size(); i++) {
+ S service = services.get(i);
+ if (service != null) {
+ synchronized (service.mLock) {
+ service.updateLocked(disabled);
+ if (!service.isEnabledLocked()) {
+ removeCachedServiceListLocked(userId);
+ } else {
+ onServiceEnabledLocked(services.get(i), userId);
+ }
+ }
}
}
- return service;
+ return services;
}
/**
@@ -619,28 +721,32 @@ public abstract class AbstractMasterSystemService<M extends AbstractMasterSystem
* <p>By default doesn't do anything, but can be overridden by subclasses.
*/
@SuppressWarnings("unused")
+ @GuardedBy("mLock")
protected void onServiceEnabledLocked(@NonNull S service, @UserIdInt int userId) {
}
/**
- * Removes a cached service for a given user.
+ * Removes a cached service list for a given user.
*
* @return the removed service.
*/
@GuardedBy("mLock")
@NonNull
- protected final S removeCachedServiceLocked(@UserIdInt int userId) {
- final S service = peekServiceForUserLocked(userId);
- if (service != null) {
- mServicesCache.delete(userId);
- onServiceRemoved(service, userId);
+ protected final List<S> removeCachedServiceListLocked(@UserIdInt int userId) {
+ final List<S> services = peekServiceListForUserLocked(userId);
+ if (services != null) {
+ mServicesCacheList.delete(userId);
+ for (int i = 0; i < services.size(); i++) {
+ onServiceRemoved(services.get(i), userId);
+ }
}
- return service;
+ return services;
}
/**
* Called before the package that provides the service for the given user is being updated.
*/
+ @GuardedBy("mLock")
protected void onServicePackageUpdatingLocked(@UserIdInt int userId) {
if (verbose) Slog.v(mTag, "onServicePackageUpdatingLocked(" + userId + ")");
}
@@ -648,6 +754,7 @@ public abstract class AbstractMasterSystemService<M extends AbstractMasterSystem
/**
* Called after the package that provides the service for the given user is being updated.
*/
+ @GuardedBy("mLock")
protected void onServicePackageUpdatedLocked(@UserIdInt int userId) {
if (verbose) Slog.v(mTag, "onServicePackageUpdated(" + userId + ")");
}
@@ -655,6 +762,7 @@ public abstract class AbstractMasterSystemService<M extends AbstractMasterSystem
/**
* Called after the package data that provides the service for the given user is cleared.
*/
+ @GuardedBy("mLock")
protected void onServicePackageDataClearedLocked(@UserIdInt int userId) {
if (verbose) Slog.v(mTag, "onServicePackageDataCleared(" + userId + ")");
}
@@ -662,6 +770,7 @@ public abstract class AbstractMasterSystemService<M extends AbstractMasterSystem
/**
* Called after the package that provides the service for the given user is restarted.
*/
+ @GuardedBy("mLock")
protected void onServicePackageRestartedLocked(@UserIdInt int userId) {
if (verbose) Slog.v(mTag, "onServicePackageRestarted(" + userId + ")");
}
@@ -679,14 +788,31 @@ public abstract class AbstractMasterSystemService<M extends AbstractMasterSystem
* <p>By default, it calls {@link #updateCachedServiceLocked(int)}; subclasses must either call
* that same method, or {@code super.onServiceNameChanged()}.
*
- * @param userId user handle.
+ * @param userId user handle.
* @param serviceName the new service name.
* @param isTemporary whether the new service is temporary.
*/
protected void onServiceNameChanged(@UserIdInt int userId, @Nullable String serviceName,
boolean isTemporary) {
synchronized (mLock) {
- updateCachedServiceLocked(userId);
+ updateCachedServiceListLocked(userId, isDisabledLocked(userId));
+ }
+ }
+
+ /**
+ * Called when the service name list has changed (typically when using temporary services).
+ *
+ * <p>By default, it calls {@link #updateCachedServiceLocked(int)}; subclasses must either call
+ * that same method, or {@code super.onServiceNameChanged()}.
+ *
+ * @param userId user handle.
+ * @param serviceNames the new service name list.
+ * @param isTemporary whether the new service is temporary.
+ */
+ protected void onServiceNameListChanged(@UserIdInt int userId, @Nullable String[] serviceNames,
+ boolean isTemporary) {
+ synchronized (mLock) {
+ updateCachedServiceListLocked(userId, isDisabledLocked(userId));
}
}
@@ -695,9 +821,12 @@ public abstract class AbstractMasterSystemService<M extends AbstractMasterSystem
*/
@GuardedBy("mLock")
protected void visitServicesLocked(@NonNull Visitor<S> visitor) {
- final int size = mServicesCache.size();
+ final int size = mServicesCacheList.size();
for (int i = 0; i < size; i++) {
- visitor.visit(mServicesCache.valueAt(i));
+ List<S> services = mServicesCacheList.valueAt(i);
+ for (int j = 0; j < services.size(); j++) {
+ visitor.visit(services.get(j));
+ }
}
}
@@ -706,7 +835,7 @@ public abstract class AbstractMasterSystemService<M extends AbstractMasterSystem
*/
@GuardedBy("mLock")
protected void clearCacheLocked() {
- mServicesCache.clear();
+ mServicesCacheList.clear();
}
/**
@@ -757,6 +886,7 @@ public abstract class AbstractMasterSystemService<M extends AbstractMasterSystem
}
// TODO(b/117779333): support proto
+ @GuardedBy("mLock")
protected void dumpLocked(@NonNull String prefix, @NonNull PrintWriter pw) {
boolean realDebug = debug;
boolean realVerbose = verbose;
@@ -765,40 +895,64 @@ public abstract class AbstractMasterSystemService<M extends AbstractMasterSystem
try {
// Temporarily turn on full logging;
debug = verbose = true;
- final int size = mServicesCache.size();
- pw.print(prefix); pw.print("Debug: "); pw.print(realDebug);
- pw.print(" Verbose: "); pw.println(realVerbose);
- pw.print("Package policy flags: "); pw.println(mServicePackagePolicyFlags);
+ final int size = mServicesCacheList.size();
+ pw.print(prefix);
+ pw.print("Debug: ");
+ pw.print(realDebug);
+ pw.print(" Verbose: ");
+ pw.println(realVerbose);
+ pw.print("Package policy flags: ");
+ pw.println(mServicePackagePolicyFlags);
if (mUpdatingPackageNames != null) {
- pw.print("Packages being updated: "); pw.println(mUpdatingPackageNames);
+ pw.print("Packages being updated: ");
+ pw.println(mUpdatingPackageNames);
}
dumpSupportedUsers(pw, prefix);
if (mServiceNameResolver != null) {
- pw.print(prefix); pw.print("Name resolver: ");
- mServiceNameResolver.dumpShort(pw); pw.println();
+ pw.print(prefix);
+ pw.print("Name resolver: ");
+ mServiceNameResolver.dumpShort(pw);
+ pw.println();
final List<UserInfo> users = getSupportedUsers();
for (int i = 0; i < users.size(); i++) {
final int userId = users.get(i).id;
- pw.print(prefix2); pw.print(userId); pw.print(": ");
- mServiceNameResolver.dumpShort(pw, userId); pw.println();
+ pw.print(prefix2);
+ pw.print(userId);
+ pw.print(": ");
+ mServiceNameResolver.dumpShort(pw, userId);
+ pw.println();
}
}
- pw.print(prefix); pw.print("Users disabled by restriction: ");
+ pw.print(prefix);
+ pw.print("Users disabled by restriction: ");
pw.println(mDisabledByUserRestriction);
- pw.print(prefix); pw.print("Allow instant service: "); pw.println(mAllowInstantService);
+ pw.print(prefix);
+ pw.print("Allow instant service: ");
+ pw.println(mAllowInstantService);
final String settingsProperty = getServiceSettingsProperty();
if (settingsProperty != null) {
- pw.print(prefix); pw.print("Settings property: "); pw.println(settingsProperty);
+ pw.print(prefix);
+ pw.print("Settings property: ");
+ pw.println(settingsProperty);
}
- pw.print(prefix); pw.print("Cached services: ");
+ pw.print(prefix);
+ pw.print("Cached services: ");
if (size == 0) {
pw.println("none");
} else {
pw.println(size);
for (int i = 0; i < size; i++) {
- pw.print(prefix); pw.print("Service at "); pw.print(i); pw.println(": ");
- final S service = mServicesCache.valueAt(i);
- service.dumpLocked(prefix2, pw);
+ pw.print(prefix);
+ pw.print("Service at ");
+ pw.print(i);
+ pw.println(": ");
+ final List<S> services = mServicesCacheList.valueAt(i);
+ for (int j = 0; j < services.size(); j++) {
+ S service = services.get(i);
+ synchronized (service.mLock) {
+ service.dumpLocked(prefix2, pw);
+ }
+ }
pw.println();
}
}
@@ -820,7 +974,7 @@ public abstract class AbstractMasterSystemService<M extends AbstractMasterSystem
final int userId = getChangingUserId();
synchronized (mLock) {
if (mUpdatingPackageNames == null) {
- mUpdatingPackageNames = new SparseArray<String>(mServicesCache.size());
+ mUpdatingPackageNames = new SparseArray<String>(mServicesCacheList.size());
}
mUpdatingPackageNames.put(userId, packageName);
onServicePackageUpdatingLocked(userId);
@@ -835,7 +989,7 @@ public abstract class AbstractMasterSystemService<M extends AbstractMasterSystem
+ " because package " + activePackageName
+ " is being updated");
}
- removeCachedServiceLocked(userId);
+ removeCachedServiceListLocked(userId);
if ((mServicePackagePolicyFlags & PACKAGE_UPDATE_POLICY_REFRESH_EAGER)
!= 0) {
@@ -901,7 +1055,7 @@ public abstract class AbstractMasterSystemService<M extends AbstractMasterSystem
if (Intent.ACTION_PACKAGE_RESTARTED.equals(action)) {
handleActiveServiceRestartedLocked(activePackageName, userId);
} else {
- removeCachedServiceLocked(userId);
+ removeCachedServiceListLocked(userId);
}
} else {
handlePackageUpdateLocked(pkg);
@@ -930,7 +1084,7 @@ public abstract class AbstractMasterSystemService<M extends AbstractMasterSystem
private void handleActiveServiceRemoved(@UserIdInt int userId) {
synchronized (mLock) {
- removeCachedServiceLocked(userId);
+ removeCachedServiceListLocked(userId);
}
final String serviceSettingsProperty = getServiceSettingsProperty();
if (serviceSettingsProperty != null) {
@@ -939,6 +1093,7 @@ public abstract class AbstractMasterSystemService<M extends AbstractMasterSystem
}
}
+ @GuardedBy("mLock")
private void handleActiveServiceRestartedLocked(String activePackageName,
@UserIdInt int userId) {
if ((mServicePackagePolicyFlags & PACKAGE_RESTART_POLICY_NO_REFRESH) != 0) {
@@ -952,7 +1107,7 @@ public abstract class AbstractMasterSystemService<M extends AbstractMasterSystem
+ " because package " + activePackageName
+ " is being restarted");
}
- removeCachedServiceLocked(userId);
+ removeCachedServiceListLocked(userId);
if ((mServicePackagePolicyFlags & PACKAGE_RESTART_POLICY_REFRESH_EAGER) != 0) {
if (debug) {
@@ -966,14 +1121,27 @@ public abstract class AbstractMasterSystemService<M extends AbstractMasterSystem
@Override
public void onPackageModified(String packageName) {
- if (verbose) Slog.v(mTag, "onPackageModified(): " + packageName);
+ synchronized (mLock) {
+ if (verbose) Slog.v(mTag, "onPackageModified(): " + packageName);
- if (mServiceNameResolver == null) {
- return;
+ if (mServiceNameResolver == null) {
+ return;
+ }
+
+ final int userId = getChangingUserId();
+ final String[] serviceNames = mServiceNameResolver.getDefaultServiceNameList(
+ userId);
+ if (serviceNames != null) {
+ for (int i = 0; i < serviceNames.length; i++) {
+ peekAndUpdateCachedServiceLocked(packageName, userId, serviceNames[i]);
+ }
+ }
}
+ }
- final int userId = getChangingUserId();
- final String serviceName = mServiceNameResolver.getDefaultServiceName(userId);
+ @GuardedBy("mLock")
+ private void peekAndUpdateCachedServiceLocked(String packageName, int userId,
+ String serviceName) {
if (serviceName == null) {
return;
}
@@ -997,6 +1165,7 @@ public abstract class AbstractMasterSystemService<M extends AbstractMasterSystem
}
}
+ @GuardedBy("mLock")
private String getActiveServicePackageNameLocked() {
final int userId = getChangingUserId();
final S service = peekServiceForUserLocked(userId);
@@ -1017,7 +1186,7 @@ public abstract class AbstractMasterSystemService<M extends AbstractMasterSystem
};
// package changes
- monitor.register(getContext(), null, UserHandle.ALL, true);
+ monitor.register(getContext(), null, UserHandle.ALL, true);
}
/**
diff --git a/services/core/java/com/android/server/infra/AbstractPerUserSystemService.java b/services/core/java/com/android/server/infra/AbstractPerUserSystemService.java
index 757a5cca0817..b8f1db402a55 100644
--- a/services/core/java/com/android/server/infra/AbstractPerUserSystemService.java
+++ b/services/core/java/com/android/server/infra/AbstractPerUserSystemService.java
@@ -43,14 +43,13 @@ import java.io.PrintWriter;
*
* @param <M> "main" service class.
* @param <S> "real" service class.
- *
* @hide
*/
public abstract class AbstractPerUserSystemService<S extends AbstractPerUserSystemService<S, M>,
M extends AbstractMasterSystemService<M, S>> {
- protected final @UserIdInt int mUserId;
- protected final Object mLock;
+ @UserIdInt protected final int mUserId;
+ public final Object mLock;
protected final String mTag = getClass().getSimpleName();
protected final M mMaster;
@@ -91,14 +90,14 @@ public abstract class AbstractPerUserSystemService<S extends AbstractPerUserSyst
* <p><b>MUST</b> be overridden by subclasses that bind to an
* {@link com.android.internal.infra.AbstractRemoteService}.
*
- * @throws NameNotFoundException if the service does not exist.
- * @throws SecurityException if the service does not have the proper permissions to be bound to.
- * @throws UnsupportedOperationException if subclass binds to a remote service but does not
- * overrides it.
- *
* @return new {@link ServiceInfo},
+ * @throws NameNotFoundException if the service does not exist.
+ * @throws SecurityException if the service does not have the proper permissions to
+ * be bound to.
+ * @throws UnsupportedOperationException if subclass binds to a remote service but does not
+ * overrides it.
*/
- protected @NonNull ServiceInfo newServiceInfoLocked(
+ @NonNull protected ServiceInfo newServiceInfoLocked(
@SuppressWarnings("unused") @NonNull ComponentName serviceComponent)
throws NameNotFoundException {
throw new UnsupportedOperationException("not overridden");
@@ -137,7 +136,6 @@ public abstract class AbstractPerUserSystemService<S extends AbstractPerUserSyst
* previous state.
*
* @param disabled whether the service is disabled (due to {@link UserManager} restrictions).
- *
* @return whether the disabled state changed.
*/
@GuardedBy("mLock")
@@ -154,18 +152,49 @@ public abstract class AbstractPerUserSystemService<S extends AbstractPerUserSyst
updateIsSetupComplete(mUserId);
mDisabled = disabled;
- updateServiceInfoLocked();
+ if (mMaster.mServiceNameResolver != null
+ && mMaster.mServiceNameResolver.isConfiguredInMultipleMode()) {
+ updateServiceInfoListLocked();
+ } else {
+ updateServiceInfoLocked();
+ }
return wasEnabled != isEnabledLocked();
}
/**
* Updates the internal reference to the service info, and returns the service's component.
*/
+ @GuardedBy("mLock")
protected final ComponentName updateServiceInfoLocked() {
- ComponentName serviceComponent = null;
- if (mMaster.mServiceNameResolver != null) {
- ServiceInfo serviceInfo = null;
+ ComponentName[] componentNames = updateServiceInfoListLocked();
+ return componentNames == null || componentNames.length == 0 ? null : componentNames[0];
+ }
+
+ /**
+ * Updates the internal reference to the service info, and returns the service's component.
+ */
+ @GuardedBy("mLock")
+ protected final ComponentName[] updateServiceInfoListLocked() {
+ if (mMaster.mServiceNameResolver == null) {
+ return null;
+ }
+ if (!mMaster.mServiceNameResolver.isConfiguredInMultipleMode()) {
final String componentName = getComponentNameLocked();
+ return new ComponentName[] { getServiceComponent(componentName) };
+ }
+ final String[] componentNames = mMaster.mServiceNameResolver.getServiceNameList(
+ mUserId);
+ ComponentName[] serviceComponents = new ComponentName[componentNames.length];
+ for (int i = 0; i < componentNames.length; i++) {
+ serviceComponents[i] = getServiceComponent(componentNames[i]);
+ }
+ return serviceComponents;
+ }
+
+ private ComponentName getServiceComponent(String componentName) {
+ synchronized (mLock) {
+ ServiceInfo serviceInfo = null;
+ ComponentName serviceComponent = null;
if (!TextUtils.isEmpty(componentName)) {
try {
serviceComponent = ComponentName.unflattenFromString(componentName);
@@ -196,14 +225,14 @@ public abstract class AbstractPerUserSystemService<S extends AbstractPerUserSyst
Slog.e(mTag, "Bad ServiceInfo for '" + componentName + "': " + e);
mServiceInfo = null;
}
+ return serviceComponent;
}
- return serviceComponent;
}
/**
* Gets the user associated with this service.
*/
- public final @UserIdInt int getUserId() {
+ @UserIdInt public final int getUserId() {
return mUserId;
}
@@ -229,15 +258,34 @@ public abstract class AbstractPerUserSystemService<S extends AbstractPerUserSyst
/**
* Gets the current name of the service, which is either the default service or the
- * {@link AbstractMasterSystemService#setTemporaryService(int, String, int) temporary one}.
+ * {@link AbstractMasterSystemService#setTemporaryService(int, String, int) temporary one}.
*/
- protected final @Nullable String getComponentNameLocked() {
+ @Nullable
+ @GuardedBy("mLock")
+ protected final String getComponentNameLocked() {
return mMaster.mServiceNameResolver.getServiceName(mUserId);
}
/**
+ * Gets the current name of the service, which is either the default service or the
+ * {@link AbstractMasterSystemService#setTemporaryService(int, String, int) temporary one}.
+ */
+ @Nullable
+ @GuardedBy("mLock")
+ protected final String getComponentNameForMultipleLocked(String serviceName) {
+ String[] services = mMaster.mServiceNameResolver.getServiceNameList(mUserId);
+ for (int i = 0; i < services.length; i++) {
+ if (serviceName.equals(services[i])) {
+ return services[i];
+ }
+ }
+ return null;
+ }
+
+ /**
* Checks whether the current service for the user was temporarily set.
*/
+ @GuardedBy("mLock")
public final boolean isTemporaryServiceSetLocked() {
return mMaster.mServiceNameResolver.isTemporary(mUserId);
}
@@ -245,6 +293,7 @@ public abstract class AbstractPerUserSystemService<S extends AbstractPerUserSyst
/**
* Resets the temporary service implementation to the default component.
*/
+ @GuardedBy("mLock")
protected final void resetTemporaryServiceLocked() {
mMaster.mServiceNameResolver.resetTemporaryService(mUserId);
}
@@ -268,6 +317,7 @@ public abstract class AbstractPerUserSystemService<S extends AbstractPerUserSyst
return mServiceInfo == null ? null : mServiceInfo.getComponentName();
}
}
+
/**
* Gets the name of the of the app this service binds to, or {@code null} if the service is
* disabled.
@@ -303,8 +353,10 @@ public abstract class AbstractPerUserSystemService<S extends AbstractPerUserSyst
/**
* Removes the service from the main service's cache.
*/
- protected final void removeSelfFromCacheLocked() {
- mMaster.removeCachedServiceLocked(mUserId);
+ protected final void removeSelfFromCache() {
+ synchronized (mMaster.mLock) {
+ mMaster.removeCachedServiceListLocked(mUserId);
+ }
}
/**
@@ -327,6 +379,7 @@ public abstract class AbstractPerUserSystemService<S extends AbstractPerUserSyst
* Gets the target SDK level of the service this service binds to,
* or {@code 0} if the service is disabled.
*/
+ @GuardedBy("mLock")
public final int getTargedSdkLocked() {
return mServiceInfo == null ? 0 : mServiceInfo.applicationInfo.targetSdkVersion;
}
@@ -334,6 +387,7 @@ public abstract class AbstractPerUserSystemService<S extends AbstractPerUserSyst
/**
* Gets whether the device already finished setup.
*/
+ @GuardedBy("mLock")
protected final boolean isSetupCompletedLocked() {
return mSetupComplete;
}
@@ -348,19 +402,32 @@ public abstract class AbstractPerUserSystemService<S extends AbstractPerUserSyst
// TODO(b/117779333): support proto
@GuardedBy("mLock")
protected void dumpLocked(@NonNull String prefix, @NonNull PrintWriter pw) {
- pw.print(prefix); pw.print("User: "); pw.println(mUserId);
+ pw.print(prefix);
+ pw.print("User: ");
+ pw.println(mUserId);
if (mServiceInfo != null) {
- pw.print(prefix); pw.print("Service Label: "); pw.println(getServiceLabelLocked());
- pw.print(prefix); pw.print("Target SDK: "); pw.println(getTargedSdkLocked());
+ pw.print(prefix);
+ pw.print("Service Label: ");
+ pw.println(getServiceLabelLocked());
+ pw.print(prefix);
+ pw.print("Target SDK: ");
+ pw.println(getTargedSdkLocked());
}
if (mMaster.mServiceNameResolver != null) {
- pw.print(prefix); pw.print("Name resolver: ");
- mMaster.mServiceNameResolver.dumpShort(pw, mUserId); pw.println();
+ pw.print(prefix);
+ pw.print("Name resolver: ");
+ mMaster.mServiceNameResolver.dumpShort(pw, mUserId);
+ pw.println();
}
- pw.print(prefix); pw.print("Disabled by UserManager: "); pw.println(mDisabled);
- pw.print(prefix); pw.print("Setup complete: "); pw.println(mSetupComplete);
+ pw.print(prefix);
+ pw.print("Disabled by UserManager: ");
+ pw.println(mDisabled);
+ pw.print(prefix);
+ pw.print("Setup complete: ");
+ pw.println(mSetupComplete);
if (mServiceInfo != null) {
- pw.print(prefix); pw.print("Service UID: ");
+ pw.print(prefix);
+ pw.print("Service UID: ");
pw.println(mServiceInfo.applicationInfo.uid);
}
pw.println();
diff --git a/services/core/java/com/android/server/infra/FrameworkResourcesServiceNameResolver.java b/services/core/java/com/android/server/infra/FrameworkResourcesServiceNameResolver.java
index 35d59561fdeb..db2cb52d778e 100644
--- a/services/core/java/com/android/server/infra/FrameworkResourcesServiceNameResolver.java
+++ b/services/core/java/com/android/server/infra/FrameworkResourcesServiceNameResolver.java
@@ -15,6 +15,7 @@
*/
package com.android.server.infra;
+import android.annotation.ArrayRes;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.StringRes;
@@ -33,6 +34,7 @@ import android.util.TimeUtils;
import com.android.internal.annotations.GuardedBy;
import java.io.PrintWriter;
+import java.util.Arrays;
/**
* Gets the service name using a framework resources, temporarily changing the service if necessary
@@ -47,20 +49,20 @@ public final class FrameworkResourcesServiceNameResolver implements ServiceNameR
/** Handler message to {@link #resetTemporaryService(int)} */
private static final int MSG_RESET_TEMPORARY_SERVICE = 0;
- private final @NonNull Context mContext;
- private final @NonNull Object mLock = new Object();
- private final @StringRes int mResourceId;
- private @Nullable NameResolverListener mOnSetCallback;
-
+ @NonNull private final Context mContext;
+ @NonNull private final Object mLock = new Object();
+ @StringRes private final int mStringResourceId;
+ @ArrayRes private final int mArrayResourceId;
+ private final boolean mIsMultiple;
/**
- * Map of temporary service name set by {@link #setTemporaryService(int, String, int)},
+ * Map of temporary service name list set by {@link #setTemporaryServices(int, String[], int)},
* keyed by {@code userId}.
*
- * <p>Typically used by Shell command and/or CTS tests.
+ * <p>Typically used by Shell command and/or CTS tests to configure temporary services if
+ * mIsMultiple is true.
*/
@GuardedBy("mLock")
- private final SparseArray<String> mTemporaryServiceNames = new SparseArray<>();
-
+ private final SparseArray<String[]> mTemporaryServiceNamesList = new SparseArray<>();
/**
* Map of default services that have been disabled by
* {@link #setDefaultServiceEnabled(int, boolean)},keyed by {@code userId}.
@@ -69,7 +71,7 @@ public final class FrameworkResourcesServiceNameResolver implements ServiceNameR
*/
@GuardedBy("mLock")
private final SparseBooleanArray mDefaultServicesDisabled = new SparseBooleanArray();
-
+ @Nullable private NameResolverListener mOnSetCallback;
/**
* When the temporary service will expire (and reset back to the default).
*/
@@ -85,7 +87,22 @@ public final class FrameworkResourcesServiceNameResolver implements ServiceNameR
public FrameworkResourcesServiceNameResolver(@NonNull Context context,
@StringRes int resourceId) {
mContext = context;
- mResourceId = resourceId;
+ mStringResourceId = resourceId;
+ mArrayResourceId = -1;
+ mIsMultiple = false;
+ }
+
+ public FrameworkResourcesServiceNameResolver(@NonNull Context context,
+ @ArrayRes int resourceId, boolean isMultiple) {
+ if (!isMultiple) {
+ throw new UnsupportedOperationException("Please use "
+ + "FrameworkResourcesServiceNameResolver(context, @StringRes int) constructor "
+ + "if single service mode is requested.");
+ }
+ mContext = context;
+ mStringResourceId = -1;
+ mArrayResourceId = resourceId;
+ mIsMultiple = true;
}
@Override
@@ -96,22 +113,31 @@ public final class FrameworkResourcesServiceNameResolver implements ServiceNameR
}
@Override
+ public String getServiceName(@UserIdInt int userId) {
+ String[] serviceNames = getServiceNameList(userId);
+ return (serviceNames == null || serviceNames.length == 0) ? null : serviceNames[0];
+ }
+
+ @Override
public String getDefaultServiceName(@UserIdInt int userId) {
- synchronized (mLock) {
- final String name = mContext.getString(mResourceId);
- return TextUtils.isEmpty(name) ? null : name;
- }
+ String[] serviceNames = getDefaultServiceNameList(userId);
+ return (serviceNames == null || serviceNames.length == 0) ? null : serviceNames[0];
}
+ /**
+ * Gets the default list of the service names for the given user.
+ *
+ * <p>Typically implemented by services which want to provide multiple backends.
+ */
@Override
- public String getServiceName(@UserIdInt int userId) {
+ public String[] getServiceNameList(int userId) {
synchronized (mLock) {
- final String temporaryName = mTemporaryServiceNames.get(userId);
- if (temporaryName != null) {
+ String[] temporaryNames = mTemporaryServiceNamesList.get(userId);
+ if (temporaryNames != null) {
// Always log it, as it should only be used on CTS or during development
- Slog.w(TAG, "getServiceName(): using temporary name " + temporaryName
- + " for user " + userId);
- return temporaryName;
+ Slog.w(TAG, "getServiceName(): using temporary name "
+ + Arrays.toString(temporaryNames) + " for user " + userId);
+ return temporaryNames;
}
final boolean disabled = mDefaultServicesDisabled.get(userId);
if (disabled) {
@@ -120,22 +146,50 @@ public final class FrameworkResourcesServiceNameResolver implements ServiceNameR
+ "user " + userId);
return null;
}
- return getDefaultServiceName(userId);
+ return getDefaultServiceNameList(userId);
+
+ }
+ }
+
+ /**
+ * Gets the default list of the service names for the given user.
+ *
+ * <p>Typically implemented by services which want to provide multiple backends.
+ */
+ @Override
+ public String[] getDefaultServiceNameList(int userId) {
+ synchronized (mLock) {
+ if (mIsMultiple) {
+ return mContext.getResources().getStringArray(mArrayResourceId);
+ } else {
+ final String name = mContext.getString(mStringResourceId);
+ return TextUtils.isEmpty(name) ? new String[0] : new String[] { name };
+ }
}
}
@Override
+ public boolean isConfiguredInMultipleMode() {
+ return mIsMultiple;
+ }
+
+ @Override
public boolean isTemporary(@UserIdInt int userId) {
synchronized (mLock) {
- return mTemporaryServiceNames.get(userId) != null;
+ return mTemporaryServiceNamesList.get(userId) != null;
}
}
@Override
public void setTemporaryService(@UserIdInt int userId, @NonNull String componentName,
int durationMs) {
+ setTemporaryServices(userId, new String[]{componentName}, durationMs);
+ }
+
+ @Override
+ public void setTemporaryServices(int userId, @NonNull String[] componentNames, int durationMs) {
synchronized (mLock) {
- mTemporaryServiceNames.put(userId, componentName);
+ mTemporaryServiceNamesList.put(userId, componentNames);
if (mTemporaryHandler == null) {
mTemporaryHandler = new Handler(Looper.getMainLooper(), null, true) {
@@ -155,8 +209,10 @@ public final class FrameworkResourcesServiceNameResolver implements ServiceNameR
}
mTemporaryServiceExpiration = SystemClock.elapsedRealtime() + durationMs;
mTemporaryHandler.sendEmptyMessageDelayed(MSG_RESET_TEMPORARY_SERVICE, durationMs);
- notifyTemporaryServiceNameChangedLocked(userId, componentName,
- /* isTemporary= */ true);
+ for (int i = 0; i < componentNames.length; i++) {
+ notifyTemporaryServiceNameChangedLocked(userId, componentNames[i],
+ /* isTemporary= */ true);
+ }
}
}
@@ -164,8 +220,8 @@ public final class FrameworkResourcesServiceNameResolver implements ServiceNameR
public void resetTemporaryService(@UserIdInt int userId) {
synchronized (mLock) {
Slog.i(TAG, "resetting temporary service for user " + userId + " from "
- + mTemporaryServiceNames.get(userId));
- mTemporaryServiceNames.remove(userId);
+ + Arrays.toString(mTemporaryServiceNamesList.get(userId)));
+ mTemporaryServiceNamesList.remove(userId);
if (mTemporaryHandler != null) {
mTemporaryHandler.removeMessages(MSG_RESET_TEMPORARY_SERVICE);
mTemporaryHandler = null;
@@ -207,16 +263,21 @@ public final class FrameworkResourcesServiceNameResolver implements ServiceNameR
@Override
public String toString() {
- return "FrameworkResourcesServiceNamer[temps=" + mTemporaryServiceNames + "]";
+ synchronized (mLock) {
+ return "FrameworkResourcesServiceNamer[temps=" + mTemporaryServiceNamesList + "]";
+ }
}
// TODO(b/117779333): support proto
@Override
public void dumpShort(@NonNull PrintWriter pw) {
synchronized (mLock) {
- pw.print("FrameworkResourcesServiceNamer: resId="); pw.print(mResourceId);
- pw.print(", numberTemps="); pw.print(mTemporaryServiceNames.size());
- pw.print(", enabledDefaults="); pw.print(mDefaultServicesDisabled.size());
+ pw.print("FrameworkResourcesServiceNamer: resId=");
+ pw.print(mStringResourceId);
+ pw.print(", numberTemps=");
+ pw.print(mTemporaryServiceNamesList.size());
+ pw.print(", enabledDefaults=");
+ pw.print(mDefaultServicesDisabled.size());
}
}
@@ -224,13 +285,17 @@ public final class FrameworkResourcesServiceNameResolver implements ServiceNameR
@Override
public void dumpShort(@NonNull PrintWriter pw, @UserIdInt int userId) {
synchronized (mLock) {
- final String temporaryName = mTemporaryServiceNames.get(userId);
- if (temporaryName != null) {
- pw.print("tmpName="); pw.print(temporaryName);
+ final String[] temporaryNames = mTemporaryServiceNamesList.get(userId);
+ if (temporaryNames != null) {
+ pw.print("tmpName=");
+ pw.print(Arrays.toString(temporaryNames));
final long ttl = mTemporaryServiceExpiration - SystemClock.elapsedRealtime();
- pw.print(" (expires in "); TimeUtils.formatDuration(ttl, pw); pw.print("), ");
+ pw.print(" (expires in ");
+ TimeUtils.formatDuration(ttl, pw);
+ pw.print("), ");
}
- pw.print("defaultName="); pw.print(getDefaultServiceName(userId));
+ pw.print("defaultName=");
+ pw.print(getDefaultServiceName(userId));
final boolean disabled = mDefaultServicesDisabled.get(userId);
pw.println(disabled ? " (disabled)" : " (enabled)");
}
diff --git a/services/core/java/com/android/server/infra/ServiceNameResolver.java b/services/core/java/com/android/server/infra/ServiceNameResolver.java
index e20c45992e05..7d85fdb45266 100644
--- a/services/core/java/com/android/server/infra/ServiceNameResolver.java
+++ b/services/core/java/com/android/server/infra/ServiceNameResolver.java
@@ -34,7 +34,7 @@ public interface ServiceNameResolver {
/**
* Listener for name changes.
*/
- public interface NameResolverListener {
+ interface NameResolverListener {
/**
* The name change callback.
@@ -64,6 +64,30 @@ public interface ServiceNameResolver {
String getDefaultServiceName(@UserIdInt int userId);
/**
+ * Gets the default list of names of the services for the given user.
+ *
+ * <p>Typically implemented by reading a Settings property or framework resource.
+ */
+ @Nullable
+ default String[] getDefaultServiceNameList(@UserIdInt int userId) {
+ if (isConfiguredInMultipleMode()) {
+ throw new UnsupportedOperationException("getting default service list not supported");
+ } else {
+ return new String[] { getDefaultServiceName(userId) };
+ }
+ }
+
+ /**
+ * Returns whether the resolver is configured to connect to multiple backend services.
+ * The default return type is false.
+ *
+ * <p>Typically implemented by reading a Settings property or framework resource.
+ */
+ default boolean isConfiguredInMultipleMode() {
+ return false;
+ }
+
+ /**
* Gets the current name of the service for the given user
*
* @return either the temporary name (set by
@@ -76,6 +100,18 @@ public interface ServiceNameResolver {
}
/**
+ * Gets the current name of the service for the given user
+ *
+ * @return either the temporary name (set by
+ * {@link #setTemporaryService(int, String, int)}, or the
+ * {@link #getDefaultServiceName(int) default name}.
+ */
+ @Nullable
+ default String[] getServiceNameList(@UserIdInt int userId) {
+ return getDefaultServiceNameList(userId);
+ }
+
+ /**
* Checks whether the current service is temporary for the given user.
*/
default boolean isTemporary(@SuppressWarnings("unused") @UserIdInt int userId) {
@@ -85,11 +121,11 @@ public interface ServiceNameResolver {
/**
* Temporarily sets the service implementation for the given user.
*
- * @param userId user handle
+ * @param userId user handle
* @param componentName name of the new component
- * @param durationMs how long the change will be valid (the service will be automatically reset
- * to the default component after this timeout expires).
- *
+ * @param durationMs how long the change will be valid (the service will be automatically
+ * reset
+ * to the default component after this timeout expires).
* @throws UnsupportedOperationException if not implemented.
*/
default void setTemporaryService(@UserIdInt int userId, @NonNull String componentName,
@@ -98,10 +134,24 @@ public interface ServiceNameResolver {
}
/**
+ * Temporarily sets the service implementation for the given user.
+ *
+ * @param userId user handle
+ * @param componentNames list of the names of the new component
+ * @param durationMs how long the change will be valid (the service will be automatically
+ * reset
+ * to the default component after this timeout expires).
+ * @throws UnsupportedOperationException if not implemented.
+ */
+ default void setTemporaryServices(@UserIdInt int userId, @NonNull String[] componentNames,
+ int durationMs) {
+ throw new UnsupportedOperationException("temporary user not supported");
+ }
+
+ /**
* Resets the temporary service implementation to the default component for the given user.
*
* @param userId user handle
- *
* @throws UnsupportedOperationException if not implemented.
*/
default void resetTemporaryService(@UserIdInt int userId) {
@@ -114,11 +164,11 @@ public interface ServiceNameResolver {
* <p>Typically used during CTS tests to make sure only the default service doesn't interfere
* with the test results.
*
- * @param userId user handle
+ * @param userId user handle
* @param enabled whether the default service should be used when the temporary service is not
- * set. If the service enabled state is already that value, the command is ignored and this
- * method return {@code false}.
- *
+ * set. If the service enabled state is already that value, the command is
+ * ignored and this
+ * method return {@code false}.
* @return whether the enabled state changed.
* @throws UnsupportedOperationException if not implemented.
*/
@@ -133,7 +183,6 @@ public interface ServiceNameResolver {
* with the test results.
*
* @param userId user handle
- *
* @throws UnsupportedOperationException if not implemented.
*/
default boolean isDefaultServiceEnabled(@UserIdInt int userId) {
diff --git a/services/core/java/com/android/server/input/GestureMonitorSpyWindow.java b/services/core/java/com/android/server/input/GestureMonitorSpyWindow.java
index dbd3f3529208..d238dae634ad 100644
--- a/services/core/java/com/android/server/input/GestureMonitorSpyWindow.java
+++ b/services/core/java/com/android/server/input/GestureMonitorSpyWindow.java
@@ -19,6 +19,7 @@ package com.android.server.input;
import static android.os.InputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
import android.os.IBinder;
+import android.os.InputConfig;
import android.view.InputApplicationHandle;
import android.view.InputChannel;
import android.view.InputMonitor;
@@ -56,18 +57,13 @@ class GestureMonitorSpyWindow {
mWindowHandle.name = name;
mWindowHandle.token = mClientChannel.getToken();
mWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY;
- mWindowHandle.layoutParamsFlags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
mWindowHandle.dispatchingTimeoutMillis = DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
- mWindowHandle.visible = true;
- mWindowHandle.focusable = false;
- mWindowHandle.hasWallpaper = false;
- mWindowHandle.paused = false;
mWindowHandle.ownerPid = pid;
mWindowHandle.ownerUid = uid;
- mWindowHandle.inputFeatures = WindowManager.LayoutParams.INPUT_FEATURE_SPY;
mWindowHandle.scaleFactor = 1.0f;
- mWindowHandle.trustedOverlay = true;
mWindowHandle.replaceTouchableRegionWithCrop(null /* use this surface's bounds */);
+ mWindowHandle.inputConfig =
+ InputConfig.NOT_FOCUSABLE | InputConfig.SPY | InputConfig.TRUSTED_OVERLAY;
final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
t.setInputWindowInfo(mInputSurface, mWindowHandle);
diff --git a/services/core/java/com/android/server/inputmethod/HandwritingEventReceiverSurface.java b/services/core/java/com/android/server/inputmethod/HandwritingEventReceiverSurface.java
index 3c454080ef1c..1a19385e71c5 100644
--- a/services/core/java/com/android/server/inputmethod/HandwritingEventReceiverSurface.java
+++ b/services/core/java/com/android/server/inputmethod/HandwritingEventReceiverSurface.java
@@ -19,6 +19,7 @@ package com.android.server.inputmethod;
import static android.os.InputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
import android.annotation.NonNull;
+import android.os.InputConfig;
import android.os.Process;
import android.view.InputApplicationHandle;
import android.view.InputChannel;
@@ -56,20 +57,17 @@ final class HandwritingEventReceiverSurface {
mWindowHandle.name = name;
mWindowHandle.token = mClientChannel.getToken();
mWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY;
- mWindowHandle.layoutParamsFlags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
- | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
mWindowHandle.dispatchingTimeoutMillis = DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
- mWindowHandle.visible = true;
- mWindowHandle.focusable = false;
- mWindowHandle.hasWallpaper = false;
- mWindowHandle.paused = false;
mWindowHandle.ownerPid = Process.myPid();
mWindowHandle.ownerUid = Process.myUid();
- mWindowHandle.inputFeatures = WindowManager.LayoutParams.INPUT_FEATURE_SPY
- | WindowManager.LayoutParams.INPUT_FEATURE_INTERCEPTS_STYLUS;
mWindowHandle.scaleFactor = 1.0f;
- mWindowHandle.trustedOverlay = true;
mWindowHandle.replaceTouchableRegionWithCrop(null /* use this surface's bounds */);
+ mWindowHandle.inputConfig =
+ InputConfig.NOT_FOCUSABLE
+ | InputConfig.NOT_TOUCHABLE
+ | InputConfig.SPY
+ | InputConfig.INTERCEPTS_STYLUS
+ | InputConfig.TRUSTED_OVERLAY;
final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
t.setInputWindowInfo(mInputSurface, mWindowHandle);
@@ -85,7 +83,7 @@ final class HandwritingEventReceiverSurface {
void startIntercepting(int imePid, int imeUid) {
mWindowHandle.ownerPid = imePid;
mWindowHandle.ownerUid = imeUid;
- mWindowHandle.inputFeatures &= ~WindowManager.LayoutParams.INPUT_FEATURE_SPY;
+ mWindowHandle.inputConfig &= ~InputConfig.SPY;
new SurfaceControl.Transaction()
.setInputWindowInfo(mInputSurface, mWindowHandle)
diff --git a/services/core/java/com/android/server/inputmethod/IInputMethodInvoker.java b/services/core/java/com/android/server/inputmethod/IInputMethodInvoker.java
index 6cb3b3b6740d..e62c5c13f04d 100644
--- a/services/core/java/com/android/server/inputmethod/IInputMethodInvoker.java
+++ b/services/core/java/com/android/server/inputmethod/IInputMethodInvoker.java
@@ -32,6 +32,7 @@ import android.view.inputmethod.InputBinding;
import android.view.inputmethod.InputMethodSubtype;
import com.android.internal.inputmethod.IInputMethodPrivilegedOperations;
+import com.android.internal.inputmethod.InputMethodNavButtonFlags;
import com.android.internal.view.IInlineSuggestionsRequestCallback;
import com.android.internal.view.IInputContext;
import com.android.internal.view.IInputMethod;
@@ -108,10 +109,10 @@ final class IInputMethodInvoker {
@AnyThread
void initializeInternal(IBinder token, IInputMethodPrivilegedOperations privOps,
int configChanges, boolean stylusHwSupported,
- boolean shouldShowImeSwitcherWhenImeIsShown) {
+ @InputMethodNavButtonFlags int navButtonFlags) {
try {
mTarget.initializeInternal(token, privOps, configChanges, stylusHwSupported,
- shouldShowImeSwitcherWhenImeIsShown);
+ navButtonFlags);
} catch (RemoteException e) {
logRemoteException(e);
}
@@ -147,20 +148,19 @@ final class IInputMethodInvoker {
@AnyThread
void startInput(IBinder startInputToken, IInputContext inputContext, EditorInfo attribute,
- boolean restarting, boolean shouldShowImeSwitcherWhenImeIsShown) {
+ boolean restarting, @InputMethodNavButtonFlags int navButtonFlags) {
try {
mTarget.startInput(startInputToken, inputContext, attribute, restarting,
- shouldShowImeSwitcherWhenImeIsShown);
+ navButtonFlags);
} catch (RemoteException e) {
logRemoteException(e);
}
}
@AnyThread
- void onShouldShowImeSwitcherWhenImeIsShownChanged(boolean shouldShowImeSwitcherWhenImeIsShown) {
+ void onNavButtonFlagsChanged(@InputMethodNavButtonFlags int navButtonFlags) {
try {
- mTarget.onShouldShowImeSwitcherWhenImeIsShownChanged(
- shouldShowImeSwitcherWhenImeIsShown);
+ mTarget.onNavButtonFlagsChanged(navButtonFlags);
} catch (RemoteException e) {
logRemoteException(e);
}
@@ -245,4 +245,13 @@ final class IInputMethodInvoker {
logRemoteException(e);
}
}
+
+ @AnyThread
+ void finishStylusHandwriting() {
+ try {
+ mTarget.finishStylusHandwriting();
+ } catch (RemoteException e) {
+ logRemoteException(e);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java
index 29dcdfaa1bba..a2d3588f0e68 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java
@@ -19,6 +19,7 @@ package com.android.server.inputmethod;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
+import android.inputmethodservice.InputMethodService;
import android.os.IBinder;
import android.view.inputmethod.InlineSuggestionsRequest;
import android.view.inputmethod.InputMethodInfo;
@@ -150,6 +151,12 @@ public abstract class InputMethodManagerInternal {
public abstract void updateImeWindowStatus(boolean disableImeIcon);
/**
+ * Finish stylus handwriting by calling {@link InputMethodService#finishStylusHandwriting()} if
+ * there is an ongoing handwriting session.
+ */
+ public abstract void maybeFinishStylusHandwriting();
+
+ /**
* Callback when the IInputMethodSession from the accessibility service with the specified
* accessibilityConnectionId is created.
*
@@ -239,6 +246,10 @@ public abstract class InputMethodManagerInternal {
@Override
public void unbindAccessibilityFromCurrentClient(int accessibilityConnectionId) {
}
+
+ @Override
+ public void maybeFinishStylusHandwriting() {
+ }
};
/**
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index efe99d7611f9..d6131d162173 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -49,6 +49,7 @@ import static android.view.WindowManager.DISPLAY_IME_POLICY_HIDE;
import static android.view.WindowManager.DISPLAY_IME_POLICY_LOCAL;
import static com.android.server.inputmethod.InputMethodBindingController.TIME_TO_RECONNECT;
+import static com.android.server.inputmethod.InputMethodUtils.isSoftInputModeStateVisibleAllowed;
import static java.lang.annotation.RetentionPolicy.SOURCE;
@@ -121,6 +122,7 @@ import android.util.PrintWriterPrinter;
import android.util.Printer;
import android.util.Slog;
import android.util.SparseArray;
+import android.util.SparseBooleanArray;
import android.util.proto.ProtoOutputStream;
import android.view.IWindowManager;
import android.view.InputChannel;
@@ -155,6 +157,7 @@ import com.android.internal.inputmethod.IInputMethodPrivilegedOperations;
import com.android.internal.inputmethod.ImeTracing;
import com.android.internal.inputmethod.InputBindResult;
import com.android.internal.inputmethod.InputMethodDebug;
+import com.android.internal.inputmethod.InputMethodNavButtonFlags;
import com.android.internal.inputmethod.SoftInputShowHideReason;
import com.android.internal.inputmethod.StartInputFlags;
import com.android.internal.inputmethod.StartInputReason;
@@ -163,6 +166,7 @@ import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.os.SomeArgs;
import com.android.internal.os.TransferPipe;
+import com.android.internal.util.ConcurrentUtils;
import com.android.internal.util.DumpUtils;
import com.android.internal.view.IInlineSuggestionsRequestCallback;
import com.android.internal.view.IInlineSuggestionsResponseCallback;
@@ -176,6 +180,7 @@ import com.android.server.AccessibilityManagerInternal;
import com.android.server.EventLogTags;
import com.android.server.LocalServices;
import com.android.server.ServiceThread;
+import com.android.server.SystemServerInitThreadPool;
import com.android.server.SystemService;
import com.android.server.inputmethod.InputMethodManagerInternal.InputMethodListListener;
import com.android.server.inputmethod.InputMethodSubtypeSwitchingController.ImeSubtypeListItem;
@@ -185,6 +190,8 @@ import com.android.server.statusbar.StatusBarManagerService;
import com.android.server.utils.PriorityDump;
import com.android.server.wm.WindowManagerInternal;
+import com.google.android.collect.Sets;
+
import java.io.FileDescriptor;
import java.io.IOException;
import java.io.PrintWriter;
@@ -199,8 +206,10 @@ import java.util.List;
import java.util.Locale;
import java.util.Objects;
import java.util.OptionalInt;
+import java.util.Set;
import java.util.WeakHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicInteger;
/**
@@ -228,6 +237,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
private static final int MSG_RESET_HANDWRITING = 1090;
private static final int MSG_START_HANDWRITING = 1100;
+ private static final int MSG_FINISH_HANDWRITING = 1110;
private static final int MSG_UNBIND_CLIENT = 3000;
private static final int MSG_UNBIND_ACCESSIBILITY_SERVICE = 3001;
@@ -265,6 +275,14 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
*/
private final boolean mPreventImeStartupUnlessTextEditor;
+ /**
+ * These IMEs are known not to behave well when evicted from memory and thus are exempt
+ * from the IME startup avoidance behavior that is enabled by
+ * {@link #mPreventImeStartupUnlessTextEditor}.
+ */
+ @NonNull
+ private final Set<String> mNonPreemptibleInputMethods;
+
@UserIdInt
private int mLastSwitchUserId;
@@ -274,6 +292,8 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
final InputMethodSettings mSettings;
final SettingsObserver mSettingsObserver;
final IWindowManager mIWindowManager;
+ private final SparseBooleanArray mLoggedDeniedGetInputMethodWindowVisibleHeightForUid =
+ new SparseBooleanArray(0);
final WindowManagerInternal mWindowManagerInternal;
final PackageManagerInternal mPackageManagerInternal;
final InputManagerInternal mInputManagerInternal;
@@ -332,6 +352,13 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
@GuardedBy("ImfLock.class")
private final HandwritingModeController mHwController;
+ @GuardedBy("ImfLock.class")
+ @Nullable
+ private OverlayableSystemBooleanResourceWrapper mImeDrawsImeNavBarRes;
+ @GuardedBy("ImfLock.class")
+ @Nullable
+ Future<?> mImeDrawsImeNavBarResLazyInitFuture;
+
static class SessionState {
final ClientState client;
final IInputMethodInvoker method;
@@ -1378,6 +1405,13 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
clearPackageChangeState();
}
+ @Override
+ public void onUidRemoved(int uid) {
+ synchronized (ImfLock.class) {
+ mLoggedDeniedGetInputMethodWindowVisibleHeightForUid.delete(uid);
+ }
+ }
+
private void clearPackageChangeState() {
// No need to lock them because we access these fields only on getRegisteredHandler().
mChangedPackages.clear();
@@ -1677,6 +1711,8 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
mBindingController = new InputMethodBindingController(this);
mPreventImeStartupUnlessTextEditor = mRes.getBoolean(
com.android.internal.R.bool.config_preventImeStartupUnlessTextEditor);
+ mNonPreemptibleInputMethods = Sets.newHashSet(mRes.getStringArray(
+ com.android.internal.R.array.config_nonPreemptibleInputMethods));
mHwController = new HandwritingModeController(thread.getLooper(),
new InkWindowInitializer());
}
@@ -1713,11 +1749,52 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
}
@GuardedBy("ImfLock.class")
+ private void maybeInitImeNavbarConfigLocked(@UserIdInt int targetUserId) {
+ // Currently, com.android.internal.R.bool.config_imeDrawsImeNavBar is overlaid only for the
+ // profile parent user.
+ // TODO(b/221443458): See if we can make OverlayManager be aware of profile groups.
+ final int profileParentUserId = mUserManagerInternal.getProfileParentId(targetUserId);
+ if (mImeDrawsImeNavBarRes != null
+ && mImeDrawsImeNavBarRes.getUserId() != profileParentUserId) {
+ mImeDrawsImeNavBarRes.close();
+ mImeDrawsImeNavBarRes = null;
+ }
+ if (mImeDrawsImeNavBarRes == null) {
+ final Context userContext;
+ if (mContext.getUserId() == profileParentUserId) {
+ userContext = mContext;
+ } else {
+ userContext = mContext.createContextAsUser(UserHandle.of(profileParentUserId),
+ 0 /* flags */);
+ }
+ mImeDrawsImeNavBarRes = OverlayableSystemBooleanResourceWrapper.create(userContext,
+ com.android.internal.R.bool.config_imeDrawsImeNavBar, mHandler, resource -> {
+ synchronized (ImfLock.class) {
+ if (resource == mImeDrawsImeNavBarRes) {
+ sendOnNavButtonFlagsChangedLocked();
+ }
+ }
+ });
+ }
+ }
+
+ @NonNull
+ private static PackageManager getPackageManagerForUser(@NonNull Context context,
+ @UserIdInt int userId) {
+ return context.getUserId() == userId
+ ? context.getPackageManager()
+ : context.createContextAsUser(UserHandle.of(userId), 0 /* flags */)
+ .getPackageManager();
+ }
+
+ @GuardedBy("ImfLock.class")
private void switchUserOnHandlerLocked(@UserIdInt int newUserId,
IInputMethodClient clientToBeReset) {
if (DEBUG) Slog.d(TAG, "Switching user stage 1/3. newUserId=" + newUserId
+ " currentUserId=" + mSettings.getCurrentUserId());
+ maybeInitImeNavbarConfigLocked(newUserId);
+
// ContentObserver should be registered again when the user is changed
mSettingsObserver.registerContentObserverLocked(newUserId);
@@ -1754,9 +1831,9 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
updateFromSettingsLocked(true);
if (initialUserSwitch) {
- InputMethodUtils.setNonSelectedSystemImesDisabledUntilUsed(mIPackageManager,
- mSettings.getEnabledInputMethodListLocked(), newUserId,
- mContext.getBasePackageName());
+ InputMethodUtils.setNonSelectedSystemImesDisabledUntilUsed(
+ getPackageManagerForUser(mContext, newUserId),
+ mSettings.getEnabledInputMethodListLocked());
}
if (DEBUG) Slog.d(TAG, "Switching user stage 3/3. newUserId=" + newUserId
@@ -1822,6 +1899,23 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
});
}
+ // TODO(b/32343335): The entire systemRunning() method needs to be revisited.
+ mImeDrawsImeNavBarResLazyInitFuture = SystemServerInitThreadPool.submit(() -> {
+ // Note that the synchronization block below guarantees that the task
+ // can never be completed before the returned Future<?> object is assigned to
+ // the "mImeDrawsImeNavBarResLazyInitFuture" field.
+ synchronized (ImfLock.class) {
+ mImeDrawsImeNavBarResLazyInitFuture = null;
+ if (currentUserId != mSettings.getCurrentUserId()) {
+ // This means that the current user is already switched to other user
+ // before the background task is executed. In this scenario the relevant
+ // field should already be initialized.
+ return;
+ }
+ maybeInitImeNavbarConfigLocked(currentUserId);
+ }
+ }, "Lazily initialize IMMS#mImeDrawsImeNavBarRes");
+
mMyPackageMonitor.register(mContext, null, UserHandle.ALL, true);
mSettingsObserver.registerContentObserverLocked(currentUserId);
@@ -1843,9 +1937,9 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
final boolean imeSelectedOnBoot = !TextUtils.isEmpty(defaultImiId);
buildInputMethodListLocked(!imeSelectedOnBoot /* resetDefaultEnabledIme */);
updateFromSettingsLocked(true);
- InputMethodUtils.setNonSelectedSystemImesDisabledUntilUsed(mIPackageManager,
- mSettings.getEnabledInputMethodListLocked(), currentUserId,
- mContext.getBasePackageName());
+ InputMethodUtils.setNonSelectedSystemImesDisabledUntilUsed(
+ getPackageManagerForUser(mContext, currentUserId),
+ mSettings.getEnabledInputMethodListLocked());
}
}
}
@@ -2402,12 +2496,12 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
true /* direct */);
}
- final boolean shouldShowImeSwitcherWhenImeIsShown =
- shouldShowImeSwitcherWhenImeIsShownLocked();
+ @InputMethodNavButtonFlags
+ final int navButtonFlags = getInputMethodNavButtonFlagsLocked();
final SessionState session = mCurClient.curSession;
setEnabledSessionLocked(session);
session.method.startInput(startInputToken, mCurInputContext, mCurAttribute, restarting,
- shouldShowImeSwitcherWhenImeIsShown);
+ navButtonFlags);
if (mShowRequested) {
if (DEBUG) Slog.v(TAG, "Attach new input asks to show input");
showCurrentInputLocked(mCurFocusedWindow, getAppShowFlagsLocked(), null,
@@ -2490,7 +2584,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
@StartInputFlags int startInputFlags, @StartInputReason int startInputReason,
int unverifiedTargetSdkVersion) {
// If no method is currently selected, do nothing.
- String selectedMethodId = getSelectedMethodIdLocked();
+ final String selectedMethodId = getSelectedMethodIdLocked();
if (selectedMethodId == null) {
return InputBindResult.NO_IME;
}
@@ -2534,10 +2628,8 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
mCurAttribute = attribute;
// If configured, we want to avoid starting up the IME if it is not supposed to be showing
- if (mPreventImeStartupUnlessTextEditor
- && !InputMethodUtils.isSoftInputModeStateVisibleAllowed(unverifiedTargetSdkVersion,
- startInputFlags)
- && !mShowRequested) {
+ if (shouldPreventImeStartupLocked(selectedMethodId, startInputFlags,
+ unverifiedTargetSdkVersion)) {
if (DEBUG) {
Slog.d(TAG, "Avoiding IME startup and unbinding current input method.");
}
@@ -2579,6 +2671,34 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
}
@GuardedBy("ImfLock.class")
+ private boolean shouldPreventImeStartupLocked(
+ @NonNull String selectedMethodId,
+ @StartInputFlags int startInputFlags,
+ int unverifiedTargetSdkVersion) {
+ // Fast-path for the majority of cases
+ if (!mPreventImeStartupUnlessTextEditor) {
+ return false;
+ }
+
+ final boolean imeVisibleAllowed =
+ isSoftInputModeStateVisibleAllowed(unverifiedTargetSdkVersion, startInputFlags);
+
+ return !(imeVisibleAllowed
+ || mShowRequested
+ || isNonPreemptibleImeLocked(selectedMethodId));
+ }
+
+ /** Return {@code true} if the given IME is non-preemptible like the tv remote service. */
+ @GuardedBy("ImfLock.class")
+ private boolean isNonPreemptibleImeLocked(@NonNull String selectedMethodId) {
+ final InputMethodInfo imi = mMethodMap.get(selectedMethodId);
+ if (imi != null) {
+ return mNonPreemptibleInputMethods.contains(imi.getPackageName());
+ }
+ return false;
+ }
+
+ @GuardedBy("ImfLock.class")
private boolean isSelectedMethodBoundLocked() {
String curId = getCurIdLocked();
return curId != null && curId.equals(getSelectedMethodIdLocked())
@@ -2671,7 +2791,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
+ mCurTokenDisplayId);
}
inputMethod.initializeInternal(token, new InputMethodPrivilegedOperationsImpl(this, token),
- configChanges, supportStylusHw, shouldShowImeSwitcherWhenImeIsShownLocked());
+ configChanges, supportStylusHw, getInputMethodNavButtonFlagsLocked());
}
@AnyThread
@@ -2928,9 +3048,20 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
}
@GuardedBy("ImfLock.class")
- boolean shouldShowImeSwitcherWhenImeIsShownLocked() {
- return shouldShowImeSwitcherLocked(
+ @InputMethodNavButtonFlags
+ private int getInputMethodNavButtonFlagsLocked() {
+ if (mImeDrawsImeNavBarResLazyInitFuture != null) {
+ // TODO(b/225366708): Avoid Future.get(), which is internally used here.
+ ConcurrentUtils.waitForFutureNoInterrupt(mImeDrawsImeNavBarResLazyInitFuture,
+ "Waiting for the lazy init of mImeDrawsImeNavBarRes");
+ }
+ final boolean canImeDrawsImeNavBar =
+ mImeDrawsImeNavBarRes != null && mImeDrawsImeNavBarRes.get();
+ final boolean shouldShowImeSwitcherWhenImeIsShown = shouldShowImeSwitcherLocked(
InputMethodService.IME_ACTIVE | InputMethodService.IME_VISIBLE);
+ return (canImeDrawsImeNavBar ? InputMethodNavButtonFlags.IME_DRAWS_IME_NAV_BAR : 0)
+ | (shouldShowImeSwitcherWhenImeIsShown
+ ? InputMethodNavButtonFlags.SHOW_IME_SWITCHER_WHEN_IME_IS_SHOWN : 0);
}
@GuardedBy("ImfLock.class")
@@ -3193,7 +3324,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
// the same enabled IMEs list.
mSwitchingController.resetCircularListLocked(mContext);
- sendShouldShowImeSwitcherWhenImeIsShownLocked();
+ sendOnNavButtonFlagsChangedLocked();
}
@GuardedBy("ImfLock.class")
@@ -3762,7 +3893,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
case LayoutParams.SOFT_INPUT_STATE_VISIBLE:
if ((softInputMode & LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0) {
if (DEBUG) Slog.v(TAG, "Window asks to show input going forward");
- if (InputMethodUtils.isSoftInputModeStateVisibleAllowed(
+ if (isSoftInputModeStateVisibleAllowed(
unverifiedTargetSdkVersion, startInputFlags)) {
if (attribute != null) {
res = startInputUncheckedLocked(cs, inputContext, attribute,
@@ -3780,7 +3911,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
break;
case LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE:
if (DEBUG) Slog.v(TAG, "Window asks to always show input");
- if (InputMethodUtils.isSoftInputModeStateVisibleAllowed(
+ if (isSoftInputModeStateVisibleAllowed(
unverifiedTargetSdkVersion, startInputFlags)) {
if (!sameWindowFocused) {
if (attribute != null) {
@@ -4150,13 +4281,26 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
* @return {@link WindowManagerInternal#getInputMethodWindowVisibleHeight(int)}
*/
@Override
- public int getInputMethodWindowVisibleHeight() {
- // TODO(yukawa): Should we verify the display ID?
- final int curTokenDisplayId;
- synchronized (ImfLock.class) {
- curTokenDisplayId = mCurTokenDisplayId;
- }
- return mWindowManagerInternal.getInputMethodWindowVisibleHeight(curTokenDisplayId);
+ @Deprecated
+ public int getInputMethodWindowVisibleHeight(@NonNull IInputMethodClient client) {
+ int callingUid = Binder.getCallingUid();
+ return Binder.withCleanCallingIdentity(() -> {
+ final int curTokenDisplayId;
+ synchronized (ImfLock.class) {
+ if (!canInteractWithImeLocked(callingUid, client,
+ "getInputMethodWindowVisibleHeight")) {
+ if (!mLoggedDeniedGetInputMethodWindowVisibleHeightForUid.get(callingUid)) {
+ EventLog.writeEvent(0x534e4554, "204906124", callingUid, "");
+ mLoggedDeniedGetInputMethodWindowVisibleHeightForUid.put(callingUid, true);
+ }
+ return 0;
+ }
+ // This should probably use the caller's display id, but because this is unsupported
+ // and maintained only for compatibility, there's no point in fixing it.
+ curTokenDisplayId = mCurTokenDisplayId;
+ }
+ return mWindowManagerInternal.getInputMethodWindowVisibleHeight(curTokenDisplayId);
+ });
}
@Override
@@ -4353,7 +4497,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
}
@BinderThread
- private void finishStylusHandwriting(int requestId) {
+ private void resetStylusHandwriting(int requestId) {
synchronized (ImfLock.class) {
final OptionalInt curRequest = mHwController.getCurrentRequestId();
if (!curRequest.isPresent() || curRequest.getAsInt() != requestId) {
@@ -4657,7 +4801,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
case MSG_HARD_KEYBOARD_SWITCH_CHANGED:
mMenuController.handleHardKeyboardStatusChange(msg.arg1 == 1);
synchronized (ImfLock.class) {
- sendShouldShowImeSwitcherWhenImeIsShownLocked();
+ sendOnNavButtonFlagsChangedLocked();
}
return true;
case MSG_SYSTEM_UNLOCK_USER: {
@@ -4720,6 +4864,14 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
}
}
return true;
+ case MSG_FINISH_HANDWRITING:
+ synchronized (ImfLock.class) {
+ IInputMethodInvoker curMethod = getCurMethodLocked();
+ if (curMethod != null && mHwController.getCurrentRequestId().isPresent()) {
+ curMethod.finishStylusHandwriting();
+ }
+ }
+ return true;
}
return false;
}
@@ -4927,7 +5079,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
// the same enabled IMEs list.
mSwitchingController.resetCircularListLocked(mContext);
- sendShouldShowImeSwitcherWhenImeIsShownLocked();
+ sendOnNavButtonFlagsChangedLocked();
// Notify InputMethodListListeners of the new installed InputMethods.
final List<InputMethodInfo> inputMethodList = new ArrayList<>(mMethodList);
@@ -4936,14 +5088,13 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
}
@GuardedBy("ImfLock.class")
- void sendShouldShowImeSwitcherWhenImeIsShownLocked() {
+ void sendOnNavButtonFlagsChangedLocked() {
final IInputMethodInvoker curMethod = mBindingController.getCurMethod();
if (curMethod == null) {
// No need to send the data if the IME is not yet bound.
return;
}
- curMethod.onShouldShowImeSwitcherWhenImeIsShownChanged(
- shouldShowImeSwitcherWhenImeIsShownLocked());
+ curMethod.onNavButtonFlagsChanged(getInputMethodNavButtonFlagsLocked());
}
@GuardedBy("ImfLock.class")
@@ -5359,6 +5510,12 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
}
}
}
+
+ @Override
+ public void maybeFinishStylusHandwriting() {
+ mHandler.removeMessages(MSG_FINISH_HANDWRITING);
+ mHandler.obtainMessage(MSG_FINISH_HANDWRITING).sendToTarget();
+ }
}
@BinderThread
@@ -6055,10 +6212,9 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
setInputMethodEnabledLocked(imi.getId(), true);
}
updateInputMethodsFromSettingsLocked(true /* enabledMayChange */);
- InputMethodUtils.setNonSelectedSystemImesDisabledUntilUsed(mIPackageManager,
- mSettings.getEnabledInputMethodListLocked(),
- mSettings.getCurrentUserId(),
- mContext.getBasePackageName());
+ InputMethodUtils.setNonSelectedSystemImesDisabledUntilUsed(
+ getPackageManagerForUser(mContext, mSettings.getCurrentUserId()),
+ mSettings.getEnabledInputMethodListLocked());
nextIme = mSettings.getSelectedInputMethod();
nextEnabledImes = mSettings.getEnabledInputMethodListLocked();
} else {
@@ -6313,8 +6469,8 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
@BinderThread
@Override
- public void finishStylusHandwriting(int requestId) {
- mImms.finishStylusHandwriting(requestId);
+ public void resetStylusHandwriting(int requestId) {
+ mImms.resetStylusHandwriting(requestId);
}
}
}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodMenuController.java b/services/core/java/com/android/server/inputmethod/InputMethodMenuController.java
index 98bde11ad517..c255fe14c03e 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodMenuController.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodMenuController.java
@@ -203,7 +203,7 @@ final class InputMethodMenuController {
attrs.setTitle("Select input method");
w.setAttributes(attrs);
mService.updateSystemUiLocked();
- mService.sendShouldShowImeSwitcherWhenImeIsShownLocked();
+ mService.sendOnNavButtonFlagsChangedLocked();
mSwitchingDialog.show();
}
}
@@ -239,7 +239,7 @@ final class InputMethodMenuController {
mSwitchingDialogTitleView = null;
mService.updateSystemUiLocked();
- mService.sendShouldShowImeSwitcherWhenImeIsShownLocked();
+ mService.sendOnNavButtonFlagsChangedLocked();
mDialogBuilder = null;
mIms = null;
}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodUtils.java b/services/core/java/com/android/server/inputmethod/InputMethodUtils.java
index e619fff24d22..4633df23516d 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodUtils.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodUtils.java
@@ -18,17 +18,16 @@ package com.android.server.inputmethod;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.UserHandleAware;
import android.annotation.UserIdInt;
import android.app.AppOpsManager;
import android.content.ContentResolver;
import android.content.Context;
import android.content.pm.ApplicationInfo;
-import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.os.Build;
import android.os.LocaleList;
-import android.os.RemoteException;
import android.os.UserHandle;
import android.provider.Settings;
import android.text.TextUtils;
@@ -663,8 +662,9 @@ final class InputMethodUtils {
return !subtype.isAuxiliary();
}
- static void setNonSelectedSystemImesDisabledUntilUsed(IPackageManager packageManager,
- List<InputMethodInfo> enabledImis, @UserIdInt int userId, String callingPackage) {
+ @UserHandleAware
+ static void setNonSelectedSystemImesDisabledUntilUsed(PackageManager packageManagerForUser,
+ List<InputMethodInfo> enabledImis) {
if (DEBUG) {
Slog.d(TAG, "setNonSelectedSystemImesDisabledUntilUsed");
}
@@ -675,7 +675,8 @@ final class InputMethodUtils {
}
// Only the current spell checker should be treated as an enabled one.
final SpellCheckerInfo currentSpellChecker =
- TextServicesManagerInternal.get().getCurrentSpellCheckerForUser(userId);
+ TextServicesManagerInternal.get().getCurrentSpellCheckerForUser(
+ packageManagerForUser.getUserId());
for (final String packageName : systemImesDisabledUntilUsed) {
if (DEBUG) {
Slog.d(TAG, "check " + packageName);
@@ -702,11 +703,12 @@ final class InputMethodUtils {
}
ApplicationInfo ai = null;
try {
- ai = packageManager.getApplicationInfo(packageName,
- PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS, userId);
- } catch (RemoteException e) {
+ ai = packageManagerForUser.getApplicationInfo(packageName,
+ PackageManager.ApplicationInfoFlags.of(
+ PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS));
+ } catch (PackageManager.NameNotFoundException e) {
Slog.w(TAG, "getApplicationInfo failed. packageName=" + packageName
- + " userId=" + userId, e);
+ + " userId=" + packageManagerForUser.getUserId(), e);
continue;
}
if (ai == null) {
@@ -717,18 +719,18 @@ final class InputMethodUtils {
if (!isSystemPackage) {
continue;
}
- setDisabledUntilUsed(packageManager, packageName, userId, callingPackage);
+ setDisabledUntilUsed(packageManagerForUser, packageName);
}
}
- private static void setDisabledUntilUsed(IPackageManager packageManager, String packageName,
- int userId, String callingPackage) {
+ private static void setDisabledUntilUsed(PackageManager packageManagerForUser,
+ String packageName) {
final int state;
try {
- state = packageManager.getApplicationEnabledSetting(packageName, userId);
- } catch (RemoteException e) {
+ state = packageManagerForUser.getApplicationEnabledSetting(packageName);
+ } catch (IllegalArgumentException e) {
Slog.w(TAG, "getApplicationEnabledSetting failed. packageName=" + packageName
- + " userId=" + userId, e);
+ + " userId=" + packageManagerForUser.getUserId(), e);
return;
}
if (state == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT
@@ -737,12 +739,12 @@ final class InputMethodUtils {
Slog.d(TAG, "Update state(" + packageName + "): DISABLED_UNTIL_USED");
}
try {
- packageManager.setApplicationEnabledSetting(packageName,
+ packageManagerForUser.setApplicationEnabledSetting(packageName,
PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED,
- 0 /* newState */, userId, callingPackage);
- } catch (RemoteException e) {
+ 0 /* newState */);
+ } catch (IllegalArgumentException e) {
Slog.w(TAG, "setApplicationEnabledSetting failed. packageName=" + packageName
- + " userId=" + userId + " callingPackage=" + callingPackage, e);
+ + " userId=" + packageManagerForUser.getUserId(), e);
return;
}
} else {
diff --git a/services/core/java/com/android/server/inputmethod/OverlayableSystemBooleanResourceWrapper.java b/services/core/java/com/android/server/inputmethod/OverlayableSystemBooleanResourceWrapper.java
new file mode 100644
index 000000000000..33e7a7621340
--- /dev/null
+++ b/services/core/java/com/android/server/inputmethod/OverlayableSystemBooleanResourceWrapper.java
@@ -0,0 +1,159 @@
+/*
+ * 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.inputmethod;
+
+import static android.content.Intent.ACTION_OVERLAY_CHANGED;
+
+import android.annotation.AnyThread;
+import android.annotation.BoolRes;
+import android.annotation.NonNull;
+import android.annotation.UserHandleAware;
+import android.annotation.UserIdInt;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.os.Handler;
+import android.os.PatternMatcher;
+import android.util.Slog;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.Consumer;
+
+/**
+ * A wrapper object for any boolean resource defined in {@code "android"} package, in a way that is
+ * aware of per-user Runtime Resource Overlay (RRO).
+ */
+final class OverlayableSystemBooleanResourceWrapper implements AutoCloseable {
+ private static final String TAG = "OverlayableSystemBooleanResourceWrapper";
+
+ private static final String SYSTEM_PACKAGE_NAME = "android";
+
+ @UserIdInt
+ private final int mUserId;
+ @NonNull
+ private final AtomicBoolean mValueRef;
+ @NonNull
+ private final AtomicReference<Runnable> mCleanerRef;
+
+ /**
+ * Creates {@link OverlayableSystemBooleanResourceWrapper} for the given boolean resource ID
+ * with a value change callback for the user associated with the {@link Context}.
+ *
+ * @param userContext The {@link Context} to be used to access the resource. This needs to be
+ * associated with the right user because the Runtime Resource Overlay (RRO)
+ * is per-user configuration.
+ * @param boolResId The resource ID to be queried.
+ * @param handler {@link Handler} to be used to dispatch {@code callback}.
+ * @param callback The callback to be notified when the specified value might be updated.
+ * The callback needs to take care of spurious wakeup. The value returned from
+ * {@link #get()} may look to be exactly the same as the previously read value
+ * e.g. when the value is changed from {@code false} to {@code true} to
+ * {@code false} in a very short period of time, because {@link #get()} always
+ * does volatile-read.
+ * @return New {@link OverlayableSystemBooleanResourceWrapper}.
+ */
+ @NonNull
+ @UserHandleAware
+ static OverlayableSystemBooleanResourceWrapper create(@NonNull Context userContext,
+ @BoolRes int boolResId, @NonNull Handler handler,
+ @NonNull Consumer<OverlayableSystemBooleanResourceWrapper> callback) {
+
+ // Note that we cannot fully trust this initial value due to the dead time between obtaining
+ // the value here and setting up a broadcast receiver for change callback below.
+ // We will refresh the value again later after setting up the change callback anyway.
+ final AtomicBoolean valueRef = new AtomicBoolean(evaluate(userContext, boolResId));
+
+ final AtomicReference<Runnable> cleanerRef = new AtomicReference<>();
+
+ final OverlayableSystemBooleanResourceWrapper object =
+ new OverlayableSystemBooleanResourceWrapper(userContext.getUserId(), valueRef,
+ cleanerRef);
+
+ final IntentFilter intentFilter = new IntentFilter(ACTION_OVERLAY_CHANGED);
+ intentFilter.addDataScheme(IntentFilter.SCHEME_PACKAGE);
+ intentFilter.addDataSchemeSpecificPart(SYSTEM_PACKAGE_NAME, PatternMatcher.PATTERN_LITERAL);
+
+ final BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final boolean newValue = evaluate(userContext, boolResId);
+ if (newValue != valueRef.getAndSet(newValue)) {
+ callback.accept(object);
+ }
+ }
+ };
+ userContext.registerReceiver(broadcastReceiver, intentFilter,
+ null /* broadcastPermission */, handler,
+ Context.RECEIVER_NOT_EXPORTED);
+ cleanerRef.set(() -> userContext.unregisterReceiver(broadcastReceiver));
+
+ // Make sure that the initial observable value is obtained after the change callback is set.
+ valueRef.set(evaluate(userContext, boolResId));
+ return object;
+ }
+
+ private OverlayableSystemBooleanResourceWrapper(@UserIdInt int userId,
+ @NonNull AtomicBoolean valueRef, @NonNull AtomicReference<Runnable> cleanerRef) {
+ mUserId = userId;
+ mValueRef = valueRef;
+ mCleanerRef = cleanerRef;
+ }
+
+ /**
+ * @return The boolean resource value.
+ */
+ @AnyThread
+ boolean get() {
+ return mValueRef.get();
+ }
+
+ /**
+ * @return The user ID associated with this resource reader.
+ */
+ @AnyThread
+ @UserIdInt
+ int getUserId() {
+ return mUserId;
+ }
+
+ @AnyThread
+ private static boolean evaluate(@NonNull Context context, @BoolRes int boolResId) {
+ try {
+ return context.getPackageManager()
+ .getResourcesForApplication(SYSTEM_PACKAGE_NAME)
+ .getBoolean(boolResId);
+ } catch (PackageManager.NameNotFoundException e) {
+ Slog.e(TAG, "getResourcesForApplication(\"" + SYSTEM_PACKAGE_NAME + "\") failed", e);
+ return false;
+ }
+ }
+
+ /**
+ * Cleans up the callback.
+ */
+ @AnyThread
+ @Override
+ public void close() {
+ final Runnable cleaner = mCleanerRef.getAndSet(null);
+ if (cleaner != null) {
+ cleaner.run();
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/locales/LocaleManagerService.java b/services/core/java/com/android/server/locales/LocaleManagerService.java
index 176c08c8da29..924db6a49eeb 100644
--- a/services/core/java/com/android/server/locales/LocaleManagerService.java
+++ b/services/core/java/com/android/server/locales/LocaleManagerService.java
@@ -22,12 +22,14 @@ import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
+import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
import android.app.ILocaleManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
+import android.content.res.Configuration;
import android.os.Binder;
import android.os.HandlerThread;
import android.os.LocaleList;
@@ -154,6 +156,12 @@ public class LocaleManagerService extends SystemService {
}
@Override
+ @NonNull
+ public LocaleList getSystemLocales() throws RemoteException {
+ return LocaleManagerService.this.getSystemLocales();
+ }
+
+ @Override
public void onShellCommand(FileDescriptor in, FileDescriptor out,
FileDescriptor err, String[] args, ShellCallback callback,
ResultReceiver resultReceiver) {
@@ -426,6 +434,32 @@ public class LocaleManagerService extends SystemService {
return null;
}
+ /**
+ * Returns the current system locales.
+ */
+ @NonNull
+ public LocaleList getSystemLocales() throws RemoteException {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ return getSystemLocalesUnchecked();
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @NonNull
+ private LocaleList getSystemLocalesUnchecked() throws RemoteException {
+ LocaleList systemLocales = null;
+ Configuration conf = ActivityManager.getService().getConfiguration();
+ if (conf != null) {
+ systemLocales = conf.getLocales();
+ }
+ if (systemLocales == null) {
+ systemLocales = LocaleList.getEmptyLocaleList();
+ }
+ return systemLocales;
+ }
+
private void logMetric(@NonNull AppLocaleChangedAtomRecord atomRecordForMetrics) {
FrameworkStatsLog.write(FrameworkStatsLog.APPLICATION_LOCALES_CHANGED,
atomRecordForMetrics.mCallingUid,
diff --git a/services/core/java/com/android/server/locales/TEST_MAPPING b/services/core/java/com/android/server/locales/TEST_MAPPING
index 27d2851a1bbe..160542b6aa0f 100644
--- a/services/core/java/com/android/server/locales/TEST_MAPPING
+++ b/services/core/java/com/android/server/locales/TEST_MAPPING
@@ -9,10 +9,13 @@
]
},
{
- "name": "CtsLocaleManagerTestCases"
- },
- {
"name": "CtsLocaleManagerHostTestCases"
}
+ ],
+ "postsubmit": [
+ // TODO(b/225192026): Move back to presubmit after b/225192026 is fixed
+ {
+ "name": "CtsLocaleManagerTestCases"
+ }
]
}
diff --git a/services/core/java/com/android/server/location/LocationPermissions.java b/services/core/java/com/android/server/location/LocationPermissions.java
index be702d906d3b..ca2ff60203ca 100644
--- a/services/core/java/com/android/server/location/LocationPermissions.java
+++ b/services/core/java/com/android/server/location/LocationPermissions.java
@@ -19,7 +19,6 @@ package com.android.server.location;
import static android.Manifest.permission.ACCESS_COARSE_LOCATION;
import static android.Manifest.permission.ACCESS_FINE_LOCATION;
import static android.Manifest.permission.LOCATION_BYPASS;
-import static android.Manifest.permission.WRITE_SECURE_SETTINGS;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import android.annotation.IntDef;
@@ -134,15 +133,11 @@ public final class LocationPermissions {
* perissions.
*/
public static void enforceBypassPermission(Context context, int uid, int pid) {
- if (context.checkPermission(WRITE_SECURE_SETTINGS, pid, uid) == PERMISSION_GRANTED) {
- // TODO: disallow WRITE_SECURE_SETTINGS permission.
- return;
- }
if (context.checkPermission(LOCATION_BYPASS, pid, uid) == PERMISSION_GRANTED) {
return;
}
throw new SecurityException("uid" + uid + " does not have " + LOCATION_BYPASS
- + "or " + WRITE_SECURE_SETTINGS + ".");
+ + ".");
}
/**
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 cd2ba393f6f2..8407a117be94 100644
--- a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
@@ -1184,6 +1184,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
mAlarmManager.cancel(mBatchingAlarm);
mBatchingAlarm = null;
}
+ mGnssNative.flushBatch();
mGnssNative.stopBatch();
mBatchingStarted = false;
}
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 0f4648a3f0f8..135af2d73904 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -252,8 +252,6 @@ public class LockSettingsService extends ILockSettings.Stub {
private final RebootEscrowManager mRebootEscrowManager;
- private boolean mFirstCallToVold;
-
// Current password metric for all users on the device. Updated when user unlocks
// the device or changes password. Removed when user is stopped.
@GuardedBy("this")
@@ -373,7 +371,7 @@ public class LockSettingsService extends ILockSettings.Stub {
LockscreenCredential profileUserPassword) {
if (DEBUG) Slog.v(TAG, "Check child profile lock for user: " + profileUserId);
// Only for profiles that shares credential with parent
- if (!isCredentialSharedWithParent(profileUserId)) {
+ if (!isCredentialSharableWithParent(profileUserId)) {
return;
}
// Do not tie profile when work challenge is enabled
@@ -597,8 +595,6 @@ public class LockSettingsService extends ILockSettings.Stub {
mStrongAuth = injector.getStrongAuth();
mActivityManager = injector.getActivityManager();
- mFirstCallToVold = true;
-
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_USER_ADDED);
filter.addAction(Intent.ACTION_USER_STARTING);
@@ -689,19 +685,19 @@ public class LockSettingsService extends ILockSettings.Stub {
}
private String getEncryptionNotificationTitle() {
- return mInjector.getDevicePolicyManager().getString(
+ return mInjector.getDevicePolicyManager().getResources().getString(
PROFILE_ENCRYPTED_TITLE,
() -> mContext.getString(R.string.profile_encrypted_title));
}
private String getEncryptionNotificationDetail() {
- return mInjector.getDevicePolicyManager().getString(
+ return mInjector.getDevicePolicyManager().getResources().getString(
PROFILE_ENCRYPTED_DETAIL,
() -> mContext.getString(R.string.profile_encrypted_detail));
}
private String getEncryptionNotificationMessage() {
- return mInjector.getDevicePolicyManager().getString(
+ return mInjector.getDevicePolicyManager().getResources().getString(
PROFILE_ENCRYPTED_MESSAGE,
() -> mContext.getString(R.string.profile_encrypted_message));
}
@@ -789,7 +785,7 @@ public class LockSettingsService extends ILockSettings.Stub {
private void ensureProfileKeystoreUnlocked(int userId) {
final KeyStore ks = KeyStore.getInstance();
if (ks.state(userId) == KeyStore.State.LOCKED
- && isCredentialSharedWithParent(userId)
+ && isCredentialSharableWithParent(userId)
&& hasUnifiedChallenge(userId)) {
Slog.i(TAG, "Profile got unlocked, will unlock its keystore");
// If boot took too long and the password in vold got expired, parent keystore will
@@ -810,7 +806,7 @@ public class LockSettingsService extends ILockSettings.Stub {
// Hide notification first, as tie managed profile lock takes time
hideEncryptionNotification(new UserHandle(userId));
- if (isCredentialSharedWithParent(userId)) {
+ if (isCredentialSharableWithParent(userId)) {
tieProfileLockIfNecessary(userId, LockscreenCredential.createNone());
}
@@ -1077,7 +1073,7 @@ public class LockSettingsService extends ILockSettings.Stub {
final int userCount = users.size();
for (int i = 0; i < userCount; i++) {
UserInfo user = users.get(i);
- if (isCredentialSharedWithParent(user.id)
+ if (isCredentialSharableWithParent(user.id)
&& !getSeparateProfileChallengeEnabledInternal(user.id)) {
success &= SyntheticPasswordCrypto.migrateLockSettingsKey(
PROFILE_KEY_NAME_ENCRYPT + user.id);
@@ -1471,7 +1467,7 @@ public class LockSettingsService extends ILockSettings.Stub {
Thread.currentThread().interrupt();
}
- if (isCredentialSharedWithParent(userId)) {
+ if (isCredentialSharableWithParent(userId)) {
if (!hasUnifiedChallenge(userId)) {
mBiometricDeferredQueue.processPendingLockoutResets();
}
@@ -1480,7 +1476,7 @@ public class LockSettingsService extends ILockSettings.Stub {
for (UserInfo profile : mUserManager.getProfiles(userId)) {
if (profile.id == userId) continue;
- if (!isCredentialSharedWithParent(profile.id)) continue;
+ if (!isCredentialSharableWithParent(profile.id)) continue;
if (hasUnifiedChallenge(profile.id)) {
if (mUserManager.isUserRunning(profile.id)) {
@@ -1517,7 +1513,7 @@ public class LockSettingsService extends ILockSettings.Stub {
}
private Map<Integer, LockscreenCredential> getDecryptedPasswordsForAllTiedProfiles(int userId) {
- if (isCredentialSharedWithParent(userId)) {
+ if (isCredentialSharableWithParent(userId)) {
return null;
}
Map<Integer, LockscreenCredential> result = new ArrayMap<>();
@@ -1525,7 +1521,7 @@ public class LockSettingsService extends ILockSettings.Stub {
final int size = profiles.size();
for (int i = 0; i < size; i++) {
final UserInfo profile = profiles.get(i);
- if (!isCredentialSharedWithParent(profile.id)) {
+ if (!isCredentialSharableWithParent(profile.id)) {
continue;
}
final int profileUserId = profile.id;
@@ -1560,7 +1556,7 @@ public class LockSettingsService extends ILockSettings.Stub {
*/
private void synchronizeUnifiedWorkChallengeForProfiles(int userId,
Map<Integer, LockscreenCredential> profilePasswordMap) {
- if (isCredentialSharedWithParent(userId)) {
+ if (isCredentialSharableWithParent(userId)) {
return;
}
final boolean isSecure = isUserSecure(userId);
@@ -1569,7 +1565,7 @@ public class LockSettingsService extends ILockSettings.Stub {
for (int i = 0; i < size; i++) {
final UserInfo profile = profiles.get(i);
final int profileUserId = profile.id;
- if (isCredentialSharedWithParent(profileUserId)) {
+ if (isCredentialSharableWithParent(profileUserId)) {
if (getSeparateProfileChallengeEnabledInternal(profileUserId)) {
continue;
}
@@ -1596,12 +1592,12 @@ public class LockSettingsService extends ILockSettings.Stub {
}
private boolean isProfileWithUnifiedLock(int userId) {
- return isCredentialSharedWithParent(userId)
+ return isCredentialSharableWithParent(userId)
&& !getSeparateProfileChallengeEnabledInternal(userId);
}
private boolean isProfileWithSeparatedLock(int userId) {
- return isCredentialSharedWithParent(userId)
+ return isCredentialSharableWithParent(userId)
&& getSeparateProfileChallengeEnabledInternal(userId);
}
@@ -1719,7 +1715,7 @@ public class LockSettingsService extends ILockSettings.Stub {
setSeparateProfileChallengeEnabledLocked(userId, true, /* unused */ null);
notifyPasswordChanged(credential, userId);
}
- if (isCredentialSharedWithParent(userId)) {
+ if (isCredentialSharableWithParent(userId)) {
// Make sure the profile doesn't get locked straight after setting work challenge.
setDeviceUnlockedForUser(userId);
}
@@ -1734,7 +1730,7 @@ public class LockSettingsService extends ILockSettings.Stub {
/**
* @param savedCredential if the user is a profile with
- * {@link UserManager#isCredentialSharedWithParent()} with unified challenge and
+ * {@link UserManager#isCredentialSharableWithParent()} with unified challenge and
* savedCredential is empty, LSS will try to re-derive the profile password internally.
* TODO (b/80170828): Fix this so profile password is always passed in.
* @param isLockTiedToParent is {@code true} if {@code userId} is a profile and its new
@@ -1800,7 +1796,10 @@ public class LockSettingsService extends ILockSettings.Stub {
}
private void onPostPasswordChanged(LockscreenCredential newCredential, int userHandle) {
- updateEncryptionPasswordIfNeeded(newCredential, userHandle);
+ if (userHandle == UserHandle.USER_SYSTEM && isDeviceEncryptionEnabled() &&
+ shouldEncryptWithCredentials() && newCredential.isNone()) {
+ setCredentialRequiredToDecrypt(false);
+ }
if (newCredential.isPattern()) {
setBoolean(LockPatternUtils.PATTERN_EVER_CHOSEN_KEY, true, userHandle);
}
@@ -1809,26 +1808,6 @@ public class LockSettingsService extends ILockSettings.Stub {
}
/**
- * Update device encryption password if calling user is USER_SYSTEM and device supports
- * encryption.
- */
- private void updateEncryptionPasswordIfNeeded(LockscreenCredential credential, int userHandle) {
- // Update the device encryption password.
- if (userHandle != UserHandle.USER_SYSTEM || !isDeviceEncryptionEnabled()) {
- return;
- }
- if (!shouldEncryptWithCredentials()) {
- updateEncryptionPassword(StorageManager.CRYPT_TYPE_DEFAULT, null);
- return;
- }
- if (credential.isNone()) {
- // Set the encryption password to default.
- setCredentialRequiredToDecrypt(false);
- }
- updateEncryptionPassword(credential.getStorageCryptType(), credential.getCredential());
- }
-
- /**
* Store the hash of the *current* password in the password history list, if device policy
* enforces password history requirement.
*/
@@ -1927,8 +1906,8 @@ public class LockSettingsService extends ILockSettings.Stub {
}
}
- protected boolean isCredentialSharedWithParent(int userId) {
- return getUserManagerFromCache(userId).isCredentialSharedWithParent();
+ protected boolean isCredentialSharableWithParent(int userId) {
+ return getUserManagerFromCache(userId).isCredentialSharableWithParent();
}
private VerifyCredentialResponse convertResponse(GateKeeperResponse gateKeeperResponse) {
@@ -1942,34 +1921,6 @@ public class LockSettingsService extends ILockSettings.Stub {
}
}
- /** Update the encryption password if it is enabled **/
- @Override
- public void updateEncryptionPassword(final int type, final byte[] password) {
- if (!hasSecureLockScreen() && password != null && password.length != 0) {
- throw new UnsupportedOperationException(
- "This operation requires the lock screen feature.");
- }
- if (!isDeviceEncryptionEnabled()) {
- return;
- }
- final IBinder service = ServiceManager.getService("mount");
- if (service == null) {
- Slog.e(TAG, "Could not find the mount service to update the encryption password");
- return;
- }
-
- // TODO(b/120484642): This is a location where we still use a String for vold
- String passwordString = password != null ? new String(password) : null;
- mHandler.post(() -> {
- IStorageManager storageManager = mInjector.getStorageManager();
- try {
- storageManager.changeEncryptionPassword(type, passwordString);
- } catch (RemoteException e) {
- Slog.e(TAG, "Error changing encryption password", e);
- }
- });
- }
-
/** Register the given WeakEscrowTokenRemovedListener. */
@Override
public boolean registerWeakEscrowTokenRemovedListener(
@@ -2206,7 +2157,7 @@ public class LockSettingsService extends ILockSettings.Stub {
final List<UserInfo> profiles = mUserManager.getProfiles(userId);
for (UserInfo pi : profiles) {
// Unlock profile which shares credential with parent with unified lock
- if (isCredentialSharedWithParent(pi.id)
+ if (isCredentialSharableWithParent(pi.id)
&& !getSeparateProfileChallengeEnabledInternal(pi.id)
&& mStorage.hasChildProfileLock(pi.id)) {
try {
@@ -2519,77 +2470,6 @@ public class LockSettingsService extends ILockSettings.Stub {
});
}
- private LockscreenCredential createPattern(String patternString) {
- final byte[] patternBytes = patternString.getBytes();
- LockscreenCredential pattern = LockscreenCredential.createPattern(
- LockPatternUtils.byteArrayToPattern(patternBytes));
- Arrays.fill(patternBytes, (byte) 0);
- return pattern;
- }
-
- @Override
- public boolean checkVoldPassword(int userId) {
- if (!mFirstCallToVold) {
- return false;
- }
- mFirstCallToVold = false;
-
- checkPasswordReadPermission();
-
- // There's no guarantee that this will safely connect, but if it fails
- // we will simply show the lock screen when we shouldn't, so relatively
- // benign. There is an outside chance something nasty would happen if
- // this service restarted before vold stales out the password in this
- // case. The nastiness is limited to not showing the lock screen when
- // we should, within the first minute of decrypting the phone if this
- // service can't connect to vold, it restarts, and then the new instance
- // does successfully connect.
- final IStorageManager service = mInjector.getStorageManager();
- // TODO(b/120484642): Update vold to return a password as a byte array
- String password;
- final long identity = Binder.clearCallingIdentity();
- try {
- password = service.getPassword();
- service.clearPassword();
- } catch (RemoteException e) {
- Slog.w(TAG, "vold getPassword() failed", e);
- return false;
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- if (TextUtils.isEmpty(password)) {
- return false;
- }
-
- try {
- final LockscreenCredential credential;
- switch (getCredentialTypeInternal(userId)) {
- case CREDENTIAL_TYPE_PATTERN:
- credential = createPattern(password);
- break;
- case CREDENTIAL_TYPE_PIN:
- credential = LockscreenCredential.createPin(password);
- break;
- case CREDENTIAL_TYPE_PASSWORD:
- credential = LockscreenCredential.createPassword(password);
- break;
- default:
- credential = null;
- Slog.e(TAG, "Unknown credential type");
- }
-
- if (credential != null
- && checkCredential(credential, userId, null /* progressCallback */)
- .getResponseCode() == GateKeeperResponse.RESPONSE_OK) {
- return true;
- }
- } catch (Exception e) {
- Slog.e(TAG, "checkVoldPassword failed: ", e);
- }
-
- return false;
- }
-
private void removeUser(int userId, boolean unknownUser) {
Slog.i(TAG, "RemoveUser: " + userId);
removeBiometricsForUser(userId);
@@ -2600,7 +2480,7 @@ public class LockSettingsService extends ILockSettings.Stub {
mManagedProfilePasswordCache.removePassword(userId);
gateKeeperClearSecureUserId(userId);
- if (unknownUser || isCredentialSharedWithParent(userId)) {
+ if (unknownUser || isCredentialSharableWithParent(userId)) {
removeKeystoreProfileKey(userId);
}
// Clean up storage last, this is to ensure that cleanupDataForReusedUserIdIfNecessary()
@@ -3320,7 +3200,7 @@ public class LockSettingsService extends ILockSettings.Stub {
* Returns a fixed pseudorandom byte string derived from the user's synthetic password.
* This is used to salt the password history hash to protect the hash against offline
* bruteforcing, since rederiving this value requires a successful authentication.
- * If user is a profile with {@link UserManager#isCredentialSharedWithParent()} true and with
+ * If user is a profile with {@link UserManager#isCredentialSharableWithParent()} true and with
* unified challenge, currentCredential is ignored.
*/
@Override
diff --git a/services/core/java/com/android/server/logcat/LogAccessConfirmationActivity.java b/services/core/java/com/android/server/logcat/LogAccessConfirmationActivity.java
deleted file mode 100644
index 6b442a6a395e..000000000000
--- a/services/core/java/com/android/server/logcat/LogAccessConfirmationActivity.java
+++ /dev/null
@@ -1,130 +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.server.logcat;
-
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.content.IntentSender;
-import android.os.Bundle;
-import android.os.ServiceManager;
-import android.os.logcat.ILogcatManagerService;
-import android.util.Slog;
-import android.view.View;
-import android.widget.TextView;
-
-import com.android.internal.R;
-import com.android.internal.app.AlertActivity;
-import com.android.internal.app.AlertController;
-
-
-/**
- * This dialog is shown to the user before an activity in a harmful app is launched.
- *
- * See {@code PackageManager.setLogcatAppInfo} for more info.
- */
-public class LogAccessConfirmationActivity extends AlertActivity implements
- DialogInterface.OnClickListener {
- private static final String TAG = LogAccessConfirmationActivity.class.getSimpleName();
-
- private String mPackageName;
- private IntentSender mTarget;
- private final ILogcatManagerService mLogcatManagerService =
- ILogcatManagerService.Stub.asInterface(ServiceManager.getService("logcat"));
-
- private int mUid;
- private int mGid;
- private int mPid;
- private int mFd;
-
- private static final String EXTRA_UID = "uid";
- private static final String EXTRA_GID = "gid";
- private static final String EXTRA_PID = "pid";
- private static final String EXTRA_FD = "fd";
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- final Intent intent = getIntent();
- mPackageName = intent.getStringExtra(Intent.EXTRA_PACKAGE_NAME);
- mUid = intent.getIntExtra("uid", 0);
- mGid = intent.getIntExtra("gid", 0);
- mPid = intent.getIntExtra("pid", 0);
- mFd = intent.getIntExtra("fd", 0);
-
- final AlertController.AlertParams p = mAlertParams;
- p.mTitle = getString(R.string.log_access_confirmation_title);
- p.mView = createView();
-
- p.mPositiveButtonText = getString(R.string.log_access_confirmation_allow);
- p.mPositiveButtonListener = this;
- p.mNegativeButtonText = getString(R.string.log_access_confirmation_deny);
- p.mNegativeButtonListener = this;
-
- mAlert.installContent(mAlertParams);
- }
-
- private View createView() {
- final View view = getLayoutInflater().inflate(R.layout.harmful_app_warning_dialog,
- null /*root*/);
- ((TextView) view.findViewById(R.id.app_name_text))
- .setText(mPackageName);
- ((TextView) view.findViewById(R.id.message))
- .setText(getIntent().getExtras().getString("body"));
- return view;
- }
-
- @Override
- public void onClick(DialogInterface dialog, int which) {
- switch (which) {
- case DialogInterface.BUTTON_POSITIVE:
- try {
- mLogcatManagerService.approve(mUid, mGid, mPid, mFd);
- } catch (Throwable t) {
- Slog.e(TAG, "Could not start the LogcatManagerService.", t);
- }
- finish();
- break;
- case DialogInterface.BUTTON_NEGATIVE:
- try {
- mLogcatManagerService.decline(mUid, mGid, mPid, mFd);
- } catch (Throwable t) {
- Slog.e(TAG, "Could not start the LogcatManagerService.", t);
- }
- finish();
- break;
- }
- }
-
- /**
- * Create the Intent for a LogAccessConfirmationActivity.
- */
- public static Intent createIntent(Context context, String targetPackageName,
- IntentSender target, int uid, int gid, int pid, int fd) {
- final Intent intent = new Intent();
- intent.setClass(context, LogAccessConfirmationActivity.class);
- intent.putExtra(Intent.EXTRA_PACKAGE_NAME, targetPackageName);
- intent.putExtra(EXTRA_UID, uid);
- intent.putExtra(EXTRA_GID, gid);
- intent.putExtra(EXTRA_PID, pid);
- intent.putExtra(EXTRA_FD, fd);
-
- return intent;
- }
-
-}
diff --git a/services/core/java/com/android/server/logcat/LogAccessDialogActivity.java b/services/core/java/com/android/server/logcat/LogAccessDialogActivity.java
new file mode 100644
index 000000000000..8be90e0cc622
--- /dev/null
+++ b/services/core/java/com/android/server/logcat/LogAccessDialogActivity.java
@@ -0,0 +1,170 @@
+/*
+ * 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.logcat;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.UserHandle;
+import android.os.logcat.ILogcatManagerService;
+import android.util.Slog;
+import android.view.View;
+import android.widget.Button;
+import android.widget.TextView;
+
+import com.android.internal.R;
+
+/**
+ * Dialog responsible for obtaining user consent per-use log access
+ */
+public class LogAccessDialogActivity extends Activity implements
+ View.OnClickListener {
+ private static final String TAG = LogAccessDialogActivity.class.getSimpleName();
+ private Context mContext;
+
+ private final ILogcatManagerService mLogcatManagerService =
+ ILogcatManagerService.Stub.asInterface(ServiceManager.getService("logcat"));
+
+ private String mPackageName;
+
+ private int mUid;
+ private int mGid;
+ private int mPid;
+ private int mFd;
+ private String mAlertTitle;
+ private AlertDialog.Builder mAlertDialog;
+ private AlertDialog mAlert;
+
+ private static final int DIALOG_TIME_OUT = Build.IS_DEBUGGABLE ? 60000 : 300000;
+ private static final int MSG_DISMISS_DIALOG = 0;
+
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ mContext = this;
+
+ Intent intent = getIntent();
+ mPackageName = intent.getStringExtra(Intent.EXTRA_PACKAGE_NAME);
+ mUid = intent.getIntExtra("com.android.server.logcat.uid", 0);
+ mGid = intent.getIntExtra("com.android.server.logcat.gid", 0);
+ mPid = intent.getIntExtra("com.android.server.logcat.pid", 0);
+ mFd = intent.getIntExtra("com.android.server.logcat.fd", 0);
+ mAlertTitle = getTitleString(mContext, mPackageName, mUid);
+
+ if (mAlertTitle != null) {
+
+ mAlertDialog = new AlertDialog.Builder(this);
+ mAlertDialog.setView(createView());
+
+ mAlert = mAlertDialog.create();
+ mAlert.show();
+ mHandler.sendEmptyMessageDelayed(MSG_DISMISS_DIALOG, DIALOG_TIME_OUT);
+
+ }
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ if (mAlert != null && mAlert.isShowing()) {
+ mAlert.dismiss();
+ }
+ mAlert = null;
+ }
+
+ private Handler mHandler = new Handler() {
+ public void handleMessage(android.os.Message msg) {
+ switch (msg.what) {
+ case MSG_DISMISS_DIALOG:
+ if (mAlert != null) {
+ mAlert.dismiss();
+ mAlert = null;
+ try {
+ mLogcatManagerService.decline(mUid, mGid, mPid, mFd);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Fails to call remote functions", e);
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ };
+
+ private String getTitleString(Context context, String callingPackage, int uid) {
+ PackageManager pm = context.getPackageManager();
+ try {
+ return context.getString(
+ com.android.internal.R.string.log_access_confirmation_title,
+ pm.getApplicationInfoAsUser(callingPackage,
+ PackageManager.MATCH_DIRECT_BOOT_AUTO,
+ UserHandle.getUserId(uid)).loadLabel(pm));
+ } catch (NameNotFoundException e) {
+ Slog.e(TAG, "App name is unknown.", e);
+ return null;
+ }
+ }
+
+ private View createView() {
+ final View view = getLayoutInflater().inflate(
+ R.layout.log_access_user_consent_dialog_permission, null /*root*/);
+
+ ((TextView) view.findViewById(R.id.log_access_dialog_title))
+ .setText(mAlertTitle);
+
+ Button button_allow = (Button) view.findViewById(R.id.log_access_dialog_allow_button);
+ button_allow.setOnClickListener(this);
+
+ Button button_deny = (Button) view.findViewById(R.id.log_access_dialog_deny_button);
+ button_deny.setOnClickListener(this);
+
+ return view;
+ }
+
+ @Override
+ public void onClick(View view) {
+ switch (view.getId()) {
+ case R.id.log_access_dialog_allow_button:
+ try {
+ mLogcatManagerService.approve(mUid, mGid, mPid, mFd);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Fails to call remote functions", e);
+ }
+ finish();
+ break;
+ case R.id.log_access_dialog_deny_button:
+ try {
+ mLogcatManagerService.decline(mUid, mGid, mPid, mFd);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Fails to call remote functions", e);
+ }
+ finish();
+ break;
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/logcat/LogcatManagerService.java b/services/core/java/com/android/server/logcat/LogcatManagerService.java
index 490e00e70f26..7b63fa24088b 100644
--- a/services/core/java/com/android/server/logcat/LogcatManagerService.java
+++ b/services/core/java/com/android/server/logcat/LogcatManagerService.java
@@ -18,15 +18,12 @@ package com.android.server.logcat;
import android.annotation.NonNull;
import android.app.ActivityManager;
-import android.app.ActivityManager.RunningAppProcessInfo;
import android.app.ActivityManagerInternal;
-import android.app.Notification;
-import android.app.NotificationManager;
-import android.app.PendingIntent;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.Binder;
import android.os.ILogd;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -34,16 +31,14 @@ import android.os.UserHandle;
import android.os.logcat.ILogcatManagerService;
import android.util.Slog;
-import com.android.internal.R;
-import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.util.ArrayUtils;
import com.android.server.LocalServices;
import com.android.server.SystemService;
-import java.util.Arrays;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
+
/**
* Service responsible for managing the access to Logcat.
*/
@@ -54,43 +49,16 @@ public final class LogcatManagerService extends SystemService {
private final BinderService mBinderService;
private final ExecutorService mThreadExecutor;
private ILogd mLogdService;
- private NotificationManager mNotificationManager;
private @NonNull ActivityManager mActivityManager;
private ActivityManagerInternal mActivityManagerInternal;
private static final int MAX_UID_IMPORTANCE_COUNT_LISTENER = 2;
- private static int sUidImportanceListenerCount = 0;
- private static final int AID_SHELL_UID = 2000;
-
- // TODO This allowlist is just a temporary workaround for the tests:
- // FrameworksServicesTests
- // PlatformRuleTests
- // After adapting the test suites, the allowlist will be removed in
- // the upcoming bug fix patches.
- private static final String[] ALLOWABLE_TESTING_PACKAGES = {
- "android.platform.test.rule.tests",
- "com.android.frameworks.servicestests"
- };
-
- // TODO Same as the above ALLOWABLE_TESTING_PACKAGES.
- private boolean isAllowableTestingPackage(int uid) {
- PackageManager pm = mContext.getPackageManager();
-
- String[] packageNames = pm.getPackagesForUid(uid);
-
- if (ArrayUtils.isEmpty(packageNames)) {
- return false;
- }
-
- for (String name : packageNames) {
- Slog.e(TAG, "isAllowableTestingPackage: " + name);
-
- if (Arrays.asList(ALLOWABLE_TESTING_PACKAGES).contains(name)) {
- return true;
- }
- }
-
- return false;
- };
+ private static final String TARGET_PACKAGE_NAME = "android";
+ private static final String TARGET_ACTIVITY_NAME =
+ "com.android.server.logcat.LogAccessDialogActivity";
+ private static final String EXTRA_UID = "com.android.server.logcat.uid";
+ private static final String EXTRA_GID = "com.android.server.logcat.gid";
+ private static final String EXTRA_PID = "com.android.server.logcat.pid";
+ private static final String EXTRA_FD = "com.android.server.logcat.fd";
private final class BinderService extends ILogcatManagerService.Stub {
@Override
@@ -110,7 +78,7 @@ public final class LogcatManagerService extends SystemService {
try {
getLogdService().approve(uid, gid, pid, fd);
} catch (RemoteException e) {
- e.printStackTrace();
+ Slog.e(TAG, "Fails to call remote functions", e);
}
}
@@ -119,7 +87,7 @@ public final class LogcatManagerService extends SystemService {
try {
getLogdService().decline(uid, gid, pid, fd);
} catch (RemoteException e) {
- e.printStackTrace();
+ Slog.e(TAG, "Fails to call remote functions", e);
}
}
}
@@ -133,46 +101,16 @@ public final class LogcatManagerService extends SystemService {
}
}
- private String getBodyString(Context context, String callingPackage, int uid) {
- PackageManager pm = context.getPackageManager();
- try {
- return context.getString(
- com.android.internal.R.string.log_access_confirmation_body,
- pm.getApplicationInfoAsUser(callingPackage, PackageManager.MATCH_DIRECT_BOOT_AUTO,
- UserHandle.getUserId(uid)).loadLabel(pm));
- } catch (NameNotFoundException e) {
- // App name is unknown.
- return null;
- }
- }
-
- private void sendNotification(int notificationId, String clientInfo, int uid, int gid, int pid,
- int fd) {
-
+ private void showDialog(int uid, int gid, int pid, int fd) {
final ActivityManagerInternal activityManagerInternal =
LocalServices.getService(ActivityManagerInternal.class);
PackageManager pm = mContext.getPackageManager();
String packageName = activityManagerInternal.getPackageNameByPid(pid);
if (packageName != null) {
- String notificationBody = getBodyString(mContext, packageName, uid);
-
- final Intent mIntent = LogAccessConfirmationActivity.createIntent(mContext,
- packageName, null, uid, gid, pid, fd);
-
- if (notificationBody == null) {
- // Decline the logd access if the nofitication body is unknown
- Slog.e(TAG, "Unknown notification body, declining the logd access");
- declineLogdAccess(uid, gid, pid, fd);
- return;
- }
-
- // TODO Next version will replace notification with dialogue
- // per UX guidance.
- generateNotificationWithBodyContent(notificationId, clientInfo, notificationBody,
- mIntent);
+ Intent mIntent = createIntent(packageName, uid, gid, pid, fd);
+ mContext.startActivityAsUser(mIntent, UserHandle.SYSTEM);
return;
-
}
String[] packageNames = pm.getPackagesForUid(uid);
@@ -186,115 +124,28 @@ public final class LogcatManagerService extends SystemService {
String firstPackageName = packageNames[0];
- if (firstPackageName == null || firstPackageName.length() == 0) {
+ if (firstPackageName.isEmpty() || firstPackageName == null) {
// Decline the logd access if the package name from uid is unknown
Slog.e(TAG, "Unknown calling package name, declining the logd access");
declineLogdAccess(uid, gid, pid, fd);
return;
}
- String notificationBody = getBodyString(mContext, firstPackageName, uid);
-
- final Intent mIntent = LogAccessConfirmationActivity.createIntent(mContext,
- firstPackageName, null, uid, gid, pid, fd);
-
- if (notificationBody == null) {
- Slog.e(TAG, "Unknown notification body, declining the logd access");
- declineLogdAccess(uid, gid, pid, fd);
- return;
- }
-
- // TODO Next version will replace notification with dialogue
- // per UX guidance.
- generateNotificationWithBodyContent(notificationId, clientInfo,
- notificationBody, mIntent);
+ final Intent mIntent = createIntent(firstPackageName, uid, gid, pid, fd);
+ mContext.startActivityAsUser(mIntent, UserHandle.SYSTEM);
}
private void declineLogdAccess(int uid, int gid, int pid, int fd) {
try {
getLogdService().decline(uid, gid, pid, fd);
- } catch (RemoteException ex) {
- Slog.e(TAG, "Fails to call remote functions ", ex);
- }
- }
-
- private void generateNotificationWithBodyContent(int notificationId, String clientInfo,
- String notificationBody, Intent intent) {
- final Notification.Builder notificationBuilder = new Notification.Builder(
- mContext,
- SystemNotificationChannels.ACCESSIBILITY_SECURITY_POLICY);
- intent.setFlags(
- Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
- intent.setIdentifier(String.valueOf(notificationId) + clientInfo);
- intent.putExtra("body", notificationBody);
-
- notificationBuilder
- .setSmallIcon(R.drawable.ic_info)
- .setContentTitle(
- mContext.getString(R.string.log_access_confirmation_title))
- .setContentText(notificationBody)
- .setContentIntent(
- PendingIntent.getActivity(mContext, 0, intent,
- PendingIntent.FLAG_IMMUTABLE))
- .setTicker(mContext.getString(R.string.log_access_confirmation_title))
- .setOnlyAlertOnce(true)
- .setAutoCancel(true);
- mNotificationManager.notify(notificationId, notificationBuilder.build());
- }
-
- /**
- * A class which watches an uid for background access and notifies the logdMonitor when
- * the package status becomes foreground (importance change)
- */
- private class UidImportanceListener implements ActivityManager.OnUidImportanceListener {
- private final int mExpectedUid;
- private final int mExpectedGid;
- private final int mExpectedPid;
- private final int mExpectedFd;
- private int mExpectedImportance;
- private int mCurrentImportance = RunningAppProcessInfo.IMPORTANCE_GONE;
-
- UidImportanceListener(int uid, int gid, int pid, int fd, int importance) {
- mExpectedUid = uid;
- mExpectedGid = gid;
- mExpectedPid = pid;
- mExpectedFd = fd;
- mExpectedImportance = importance;
- }
-
- @Override
- public void onUidImportance(int uid, int importance) {
- if (uid == mExpectedUid) {
- mCurrentImportance = importance;
-
- /**
- * 1) If the process status changes to foreground, send a notification
- * for user consent.
- * 2) If the process status remains background, we decline logd access request.
- **/
- if (importance <= RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE) {
- String clientInfo = getClientInfo(uid, mExpectedGid, mExpectedPid, mExpectedFd);
- sendNotification(0, clientInfo, uid, mExpectedGid, mExpectedPid,
- mExpectedFd);
- mActivityManager.removeOnUidImportanceListener(this);
-
- synchronized (LogcatManagerService.this) {
- sUidImportanceListenerCount--;
- }
- } else {
- try {
- getLogdService().decline(uid, mExpectedGid, mExpectedPid, mExpectedFd);
- } catch (RemoteException ex) {
- Slog.e(TAG, "Fails to call remote functions ", ex);
- }
- }
- }
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Fails to call remote functions", e);
}
}
private static String getClientInfo(int uid, int gid, int pid, int fd) {
return "UID=" + Integer.toString(uid) + " GID=" + Integer.toString(gid) + " PID="
- + Integer.toString(pid) + " FD=" + Integer.toString(fd);
+ + Integer.toString(pid) + " FD=" + Integer.toString(fd);
}
private class LogdMonitor implements Runnable {
@@ -338,18 +189,22 @@ public final class LogcatManagerService extends SystemService {
try {
getLogdService().approve(mUid, mGid, mPid, mFd);
} catch (RemoteException e) {
- e.printStackTrace();
+ Slog.e(TAG, "Fails to call remote functions", e);
}
return;
}
- // TODO Temporarily approve all the requests to unblock testing failures.
- try {
- getLogdService().approve(mUid, mGid, mPid, mFd);
- } catch (RemoteException e) {
- e.printStackTrace();
+ final int procState = mActivityManager.getUidImportance(Binder.getCallingUid());
+ // If the process is foreground, send a notification for user consent
+ if (procState <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE) {
+ showDialog(mUid, mGid, mPid, mFd);
+ } else {
+ /**
+ * If the process is background, decline the logd access.
+ **/
+ declineLogdAccess(mUid, mGid, mPid, mFd);
+ return;
}
- return;
}
}
}
@@ -360,7 +215,6 @@ public final class LogcatManagerService extends SystemService {
mBinderService = new BinderService();
mThreadExecutor = Executors.newCachedThreadPool();
mActivityManager = context.getSystemService(ActivityManager.class);
- mNotificationManager = mContext.getSystemService(NotificationManager.class);
}
@Override
@@ -375,4 +229,23 @@ public final class LogcatManagerService extends SystemService {
private void addLogdService() {
mLogdService = ILogd.Stub.asInterface(ServiceManager.getService("logd"));
}
+
+ /**
+ * Create the Intent for LogAccessDialogActivity.
+ */
+ public Intent createIntent(String targetPackageName, int uid, int gid, int pid, int fd) {
+ final Intent intent = new Intent();
+
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+
+ intent.putExtra(Intent.EXTRA_PACKAGE_NAME, targetPackageName);
+ intent.putExtra(EXTRA_UID, uid);
+ intent.putExtra(EXTRA_GID, gid);
+ intent.putExtra(EXTRA_PID, pid);
+ intent.putExtra(EXTRA_FD, fd);
+
+ intent.setComponent(new ComponentName(TARGET_PACKAGE_NAME, TARGET_ACTIVITY_NAME));
+
+ return intent;
+ }
}
diff --git a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
index 3ce8e4659737..1937852fa333 100644
--- a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
+++ b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
@@ -45,6 +45,7 @@ import android.os.RemoteException;
import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.Slog;
+import android.window.WindowContainerToken;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.DumpUtils;
@@ -410,6 +411,7 @@ public final class MediaProjectionManagerService extends SystemService
private IBinder mToken;
private IBinder.DeathRecipient mDeathEater;
private boolean mRestoreSystemAlertWindow;
+ private WindowContainerToken mTaskRecordingWindowContainerToken = null;
MediaProjection(int type, int uid, String packageName, int targetSdkVersion,
boolean isPrivileged) {
@@ -568,7 +570,7 @@ public final class MediaProjectionManagerService extends SystemService
}
}
- @Override
+ @Override // Binder call
public void registerCallback(IMediaProjectionCallback callback) {
if (callback == null) {
throw new IllegalArgumentException("callback must not be null");
@@ -576,7 +578,7 @@ public final class MediaProjectionManagerService extends SystemService
mCallbackDelegate.add(callback);
}
- @Override
+ @Override // Binder call
public void unregisterCallback(IMediaProjectionCallback callback) {
if (callback == null) {
throw new IllegalArgumentException("callback must not be null");
@@ -584,6 +586,17 @@ public final class MediaProjectionManagerService extends SystemService
mCallbackDelegate.remove(callback);
}
+ @Override // Binder call
+ public void setTaskRecordingWindowContainerToken(WindowContainerToken token) {
+ // TODO(b/221417940) set the task id to record from sysui, for the package chosen.
+ mTaskRecordingWindowContainerToken = token;
+ }
+
+ @Override // Binder call
+ public WindowContainerToken getTaskRecordingWindowContainerToken() {
+ return mTaskRecordingWindowContainerToken;
+ }
+
public MediaProjectionInfo getProjectionInfo() {
return new MediaProjectionInfo(packageName, userHandle);
}
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 48ad22cb12ff..c25e60864a68 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -90,6 +90,8 @@ import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
import static android.net.NetworkPolicyManager.RULE_REJECT_RESTRICTED_MODE;
import static android.net.NetworkPolicyManager.RULE_TEMPORARY_ALLOW_METERED;
import static android.net.NetworkPolicyManager.SUBSCRIPTION_OVERRIDE_UNMETERED;
+import static android.net.NetworkPolicyManager.allowedReasonsToString;
+import static android.net.NetworkPolicyManager.blockedReasonsToString;
import static android.net.NetworkPolicyManager.isProcStateAllowedWhileIdleOrPowerSaveMode;
import static android.net.NetworkPolicyManager.isProcStateAllowedWhileInLowPowerStandby;
import static android.net.NetworkPolicyManager.isProcStateAllowedWhileOnRestrictBackground;
@@ -594,7 +596,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
@GuardedBy("mUidRulesFirstLock")
private final SparseArray<UidState> mUidState = new SparseArray<>();
- @GuardedBy("mUidRulesFirstLock")
+ @GuardedBy("mUidBlockedState")
private final SparseArray<UidBlockedState> mUidBlockedState = new SparseArray<>();
/** Objects used temporarily while computing the new blocked state for each uid. */
@@ -1011,10 +1013,10 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
final IntentFilter packageFilter = new IntentFilter();
packageFilter.addAction(ACTION_PACKAGE_ADDED);
packageFilter.addDataScheme("package");
- mContext.registerReceiver(mPackageReceiver, packageFilter, null, mHandler);
+ mContext.registerReceiverForAllUsers(mPackageReceiver, packageFilter, null, mHandler);
// listen for UID changes to update policy
- mContext.registerReceiver(
+ mContext.registerReceiverForAllUsers(
mUidRemovedReceiver, new IntentFilter(ACTION_UID_REMOVED), null, mHandler);
// listen for user changes to update policy
@@ -3930,7 +3932,9 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
final SparseBooleanArray knownUids = new SparseBooleanArray();
collectKeys(mUidState, knownUids);
- collectKeys(mUidBlockedState, knownUids);
+ synchronized (mUidBlockedState) {
+ collectKeys(mUidBlockedState, knownUids);
+ }
fout.println("Status for all known UIDs:");
fout.increaseIndent();
@@ -3948,12 +3952,14 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
fout.print(uidState.toString());
}
- final UidBlockedState uidBlockedState = mUidBlockedState.get(uid);
- if (uidBlockedState == null) {
- fout.print(" blocked_state={null}");
- } else {
- fout.print(" blocked_state=");
- fout.print(uidBlockedState.toString());
+ synchronized (mUidBlockedState) {
+ final UidBlockedState uidBlockedState = mUidBlockedState.get(uid);
+ if (uidBlockedState == null) {
+ fout.print(" blocked_state={null}");
+ } else {
+ fout.print(" blocked_state=");
+ fout.print(uidBlockedState);
+ }
}
fout.println();
}
@@ -4094,7 +4100,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
"updateNetworkStats: " + uid + "/" + (uidForeground ? "F" : "B"));
}
try {
- mNetworkStats.setUidForeground(uid, uidForeground);
+ mNetworkStats.noteUidForeground(uid, uidForeground);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
}
@@ -4128,9 +4134,9 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
mUidFirewallRestrictedModeRules.clear();
forEachUid("updateRestrictedModeAllowlist", uid -> {
synchronized (mUidRulesFirstLock) {
- final UidBlockedState uidBlockedState = updateBlockedReasonsForRestrictedModeUL(
+ final int effectiveBlockedReasons = updateBlockedReasonsForRestrictedModeUL(
uid);
- final int newFirewallRule = getRestrictedModeFirewallRule(uidBlockedState);
+ final int newFirewallRule = getRestrictedModeFirewallRule(effectiveBlockedReasons);
// setUidFirewallRulesUL will allowlist all uids that are passed to it, so only add
// non-default rules.
@@ -4150,7 +4156,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
@VisibleForTesting
@GuardedBy("mUidRulesFirstLock")
void updateRestrictedModeForUidUL(int uid) {
- final UidBlockedState uidBlockedState = updateBlockedReasonsForRestrictedModeUL(uid);
+ final int effectiveBlockedReasons = updateBlockedReasonsForRestrictedModeUL(uid);
// if restricted networking mode is on, and the app has an access exemption, the uid rule
// will not change, but the firewall rule will have to be updated.
@@ -4158,37 +4164,48 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
// Note: setUidFirewallRule also updates mUidFirewallRestrictedModeRules.
// In this case, default firewall rules can also be added.
setUidFirewallRuleUL(FIREWALL_CHAIN_RESTRICTED, uid,
- getRestrictedModeFirewallRule(uidBlockedState));
+ getRestrictedModeFirewallRule(effectiveBlockedReasons));
}
}
@GuardedBy("mUidRulesFirstLock")
- private UidBlockedState updateBlockedReasonsForRestrictedModeUL(int uid) {
- final UidBlockedState uidBlockedState = getOrCreateUidBlockedStateForUid(
- mUidBlockedState, uid);
- final int oldEffectiveBlockedReasons = uidBlockedState.effectiveBlockedReasons;
- if (mRestrictedNetworkingMode) {
- uidBlockedState.blockedReasons |= BLOCKED_REASON_RESTRICTED_MODE;
- } else {
- uidBlockedState.blockedReasons &= ~BLOCKED_REASON_RESTRICTED_MODE;
- }
- if (hasRestrictedModeAccess(uid)) {
- uidBlockedState.allowedReasons |= ALLOWED_REASON_RESTRICTED_MODE_PERMISSIONS;
- } else {
- uidBlockedState.allowedReasons &= ~ALLOWED_REASON_RESTRICTED_MODE_PERMISSIONS;
+ private int updateBlockedReasonsForRestrictedModeUL(int uid) {
+ final boolean hasRestrictedModeAccess = hasRestrictedModeAccess(uid);
+ final int oldEffectiveBlockedReasons;
+ final int newEffectiveBlockedReasons;
+ final int uidRules;
+ synchronized (mUidBlockedState) {
+ final UidBlockedState uidBlockedState = getOrCreateUidBlockedStateForUid(
+ mUidBlockedState, uid);
+ oldEffectiveBlockedReasons = uidBlockedState.effectiveBlockedReasons;
+ if (mRestrictedNetworkingMode) {
+ uidBlockedState.blockedReasons |= BLOCKED_REASON_RESTRICTED_MODE;
+ } else {
+ uidBlockedState.blockedReasons &= ~BLOCKED_REASON_RESTRICTED_MODE;
+ }
+ if (hasRestrictedModeAccess) {
+ uidBlockedState.allowedReasons |= ALLOWED_REASON_RESTRICTED_MODE_PERMISSIONS;
+ } else {
+ uidBlockedState.allowedReasons &= ~ALLOWED_REASON_RESTRICTED_MODE_PERMISSIONS;
+ }
+ uidBlockedState.updateEffectiveBlockedReasons();
+
+ newEffectiveBlockedReasons = uidBlockedState.effectiveBlockedReasons;
+ uidRules = oldEffectiveBlockedReasons == newEffectiveBlockedReasons
+ ? RULE_NONE
+ : uidBlockedState.deriveUidRules();
}
- uidBlockedState.updateEffectiveBlockedReasons();
- if (oldEffectiveBlockedReasons != uidBlockedState.effectiveBlockedReasons) {
+ if (oldEffectiveBlockedReasons != newEffectiveBlockedReasons) {
postBlockedReasonsChangedMsg(uid,
- uidBlockedState.effectiveBlockedReasons, oldEffectiveBlockedReasons);
+ newEffectiveBlockedReasons, oldEffectiveBlockedReasons);
- postUidRulesChangedMsg(uid, uidBlockedState.deriveUidRules());
+ postUidRulesChangedMsg(uid, uidRules);
}
- return uidBlockedState;
+ return newEffectiveBlockedReasons;
}
- private static int getRestrictedModeFirewallRule(UidBlockedState uidBlockedState) {
- if ((uidBlockedState.effectiveBlockedReasons & BLOCKED_REASON_RESTRICTED_MODE) != 0) {
+ private static int getRestrictedModeFirewallRule(int effectiveBlockedReasons) {
+ if ((effectiveBlockedReasons & BLOCKED_REASON_RESTRICTED_MODE) != 0) {
// rejected in restricted mode, this is the default behavior.
return FIREWALL_RULE_DEFAULT;
} else {
@@ -4292,12 +4309,10 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
mUidFirewallLowPowerStandbyModeRules.clear();
for (int i = mUidState.size() - 1; i >= 0; i--) {
final int uid = mUidState.keyAt(i);
- UidBlockedState uidBlockedState = mUidBlockedState.get(uid);
- if (hasInternetPermissionUL(uid) && uidBlockedState != null
- && (uidBlockedState.effectiveBlockedReasons
+ final int effectiveBlockedReasons = getEffectiveBlockedReasons(uid);
+ if (hasInternetPermissionUL(uid) && (effectiveBlockedReasons
& BLOCKED_REASON_LOW_POWER_STANDBY) == 0) {
- mUidFirewallLowPowerStandbyModeRules.put(mUidBlockedState.keyAt(i),
- FIREWALL_RULE_ALLOW);
+ mUidFirewallLowPowerStandbyModeRules.put(uid, FIREWALL_RULE_ALLOW);
}
}
setUidFirewallRulesUL(FIREWALL_CHAIN_LOW_POWER_STANDBY,
@@ -4316,10 +4331,9 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
return;
}
- final UidBlockedState uidBlockedState = mUidBlockedState.get(uid);
- if (mUidState.contains(uid) && uidBlockedState != null
- && (uidBlockedState.effectiveBlockedReasons & BLOCKED_REASON_LOW_POWER_STANDBY)
- == 0) {
+ final int effectiveBlockedReasons = getEffectiveBlockedReasons(uid);
+ if (mUidState.contains(uid)
+ && (effectiveBlockedReasons & BLOCKED_REASON_LOW_POWER_STANDBY) == 0) {
mUidFirewallLowPowerStandbyModeRules.put(uid, FIREWALL_RULE_ALLOW);
setUidFirewallRuleUL(FIREWALL_CHAIN_LOW_POWER_STANDBY, uid, FIREWALL_RULE_ALLOW);
} else {
@@ -4448,9 +4462,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
if (!isUidValidForDenylistRulesUL(uid)) {
continue;
}
- final UidBlockedState uidBlockedState = getOrCreateUidBlockedStateForUid(
- mUidBlockedState, uid);
- if (!enableChain && (uidBlockedState.blockedReasons & ~BLOCKED_METERED_REASON_MASK)
+ final int blockedReasons = getBlockedReasons(uid);
+ if (!enableChain && (blockedReasons & ~BLOCKED_METERED_REASON_MASK)
== BLOCKED_REASON_NONE) {
// Chain isn't enabled and the uid had no restrictions to begin with.
continue;
@@ -4692,7 +4705,9 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
@GuardedBy("mUidRulesFirstLock")
private void onUidDeletedUL(int uid) {
// First cleanup in-memory state synchronously...
- mUidBlockedState.delete(uid);
+ synchronized (mUidBlockedState) {
+ mUidBlockedState.delete(uid);
+ }
mUidPolicy.delete(uid);
mUidFirewallStandbyRules.delete(uid);
mUidFirewallDozableRules.delete(uid);
@@ -4804,11 +4819,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
final int uidPolicy = mUidPolicy.get(uid, POLICY_NONE);
final boolean isForeground = isUidForegroundOnRestrictBackgroundUL(uid);
final boolean isRestrictedByAdmin = isRestrictedByAdminUL(uid);
- final UidBlockedState uidBlockedState = getOrCreateUidBlockedStateForUid(
- mUidBlockedState, uid);
- final UidBlockedState previousUidBlockedState = getOrCreateUidBlockedStateForUid(
- mTmpUidBlockedState, uid);
- previousUidBlockedState.copyFrom(uidBlockedState);
final boolean isDenied = (uidPolicy & POLICY_REJECT_METERED_BACKGROUND) != 0;
final boolean isAllowed = (uidPolicy & POLICY_ALLOW_METERED_BACKGROUND) != 0;
@@ -4823,18 +4833,47 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
newAllowedReasons |= (isForeground ? ALLOWED_METERED_REASON_FOREGROUND : 0);
newAllowedReasons |= (isAllowed ? ALLOWED_METERED_REASON_USER_EXEMPTED : 0);
- uidBlockedState.blockedReasons = (uidBlockedState.blockedReasons
- & ~BLOCKED_METERED_REASON_MASK) | newBlockedReasons;
- uidBlockedState.allowedReasons = (uidBlockedState.allowedReasons
- & ~ALLOWED_METERED_REASON_MASK) | newAllowedReasons;
- uidBlockedState.updateEffectiveBlockedReasons();
- final int oldEffectiveBlockedReasons = previousUidBlockedState.effectiveBlockedReasons;
- final int newEffectiveBlockedReasons = uidBlockedState.effectiveBlockedReasons;
+ final int oldEffectiveBlockedReasons;
+ final int newEffectiveBlockedReasons;
+ final int oldAllowedReasons;
+ final int uidRules;
+ synchronized (mUidBlockedState) {
+ final UidBlockedState uidBlockedState = getOrCreateUidBlockedStateForUid(
+ mUidBlockedState, uid);
+ final UidBlockedState previousUidBlockedState = getOrCreateUidBlockedStateForUid(
+ mTmpUidBlockedState, uid);
+ previousUidBlockedState.copyFrom(uidBlockedState);
+
+ uidBlockedState.blockedReasons = (uidBlockedState.blockedReasons
+ & ~BLOCKED_METERED_REASON_MASK) | newBlockedReasons;
+ uidBlockedState.allowedReasons = (uidBlockedState.allowedReasons
+ & ~ALLOWED_METERED_REASON_MASK) | newAllowedReasons;
+ uidBlockedState.updateEffectiveBlockedReasons();
+
+ oldEffectiveBlockedReasons = previousUidBlockedState.effectiveBlockedReasons;
+ newEffectiveBlockedReasons = uidBlockedState.effectiveBlockedReasons;
+ oldAllowedReasons = previousUidBlockedState.allowedReasons;
+ uidRules = (oldEffectiveBlockedReasons == newEffectiveBlockedReasons)
+ ? RULE_NONE : uidBlockedState.deriveUidRules();
+
+ if (LOGV) {
+ Log.v(TAG, "updateRuleForRestrictBackgroundUL(" + uid + ")"
+ + ": isForeground=" + isForeground
+ + ", isDenied=" + isDenied
+ + ", isAllowed=" + isAllowed
+ + ", isRestrictedByAdmin=" + isRestrictedByAdmin
+ + ", oldBlockedState=" + previousUidBlockedState
+ + ", newBlockedState=" + uidBlockedState
+ + ", newBlockedMeteredReasons=" + blockedReasonsToString(newBlockedReasons)
+ + ", newAllowedMeteredReasons=" + allowedReasonsToString(
+ newAllowedReasons));
+ }
+ }
if (oldEffectiveBlockedReasons != newEffectiveBlockedReasons) {
postBlockedReasonsChangedMsg(uid,
newEffectiveBlockedReasons, oldEffectiveBlockedReasons);
- postUidRulesChangedMsg(uid, uidBlockedState.deriveUidRules());
+ postUidRulesChangedMsg(uid, uidRules);
}
// Note that the conditionals below are for avoiding unnecessary calls to netd.
@@ -4850,29 +4889,11 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
final int allowlistReasons = ALLOWED_METERED_REASON_FOREGROUND
| ALLOWED_METERED_REASON_USER_EXEMPTED;
- final int oldAllowedReasons = previousUidBlockedState.allowedReasons;
if ((oldAllowedReasons & allowlistReasons) != ALLOWED_REASON_NONE
|| (newAllowedReasons & allowlistReasons) != ALLOWED_REASON_NONE) {
setMeteredNetworkAllowlist(uid,
(newAllowedReasons & allowlistReasons) != ALLOWED_REASON_NONE);
}
-
- if (LOGV) {
- Log.v(TAG, "updateRuleForRestrictBackgroundUL(" + uid + ")"
- + ": isForeground=" +isForeground
- + ", isDenied=" + isDenied
- + ", isAllowed=" + isAllowed
- + ", isRestrictedByAdmin=" + isRestrictedByAdmin
- + ", oldBlockedState=" + previousUidBlockedState.toString()
- + ", newBlockedState=" + uidBlockedState.toString()
- + ", oldBlockedMeteredReasons=" + NetworkPolicyManager.blockedReasonsToString(
- uidBlockedState.blockedReasons & BLOCKED_METERED_REASON_MASK)
- + ", oldBlockedMeteredEffectiveReasons="
- + NetworkPolicyManager.blockedReasonsToString(
- uidBlockedState.effectiveBlockedReasons & BLOCKED_METERED_REASON_MASK)
- + ", oldAllowedMeteredReasons=" + NetworkPolicyManager.blockedReasonsToString(
- uidBlockedState.allowedReasons & BLOCKED_METERED_REASON_MASK));
- }
}
/**
@@ -4932,56 +4953,66 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
final boolean isWhitelisted = isWhitelistedFromPowerSaveUL(uid, mDeviceIdleMode);
- final UidBlockedState uidBlockedState = getOrCreateUidBlockedStateForUid(
- mUidBlockedState, uid);
- final UidBlockedState previousUidBlockedState = getOrCreateUidBlockedStateForUid(
- mTmpUidBlockedState, uid);
- previousUidBlockedState.copyFrom(uidBlockedState);
-
- int newBlockedReasons = BLOCKED_REASON_NONE;
- int newAllowedReasons = ALLOWED_REASON_NONE;
- newBlockedReasons |= (mRestrictPower ? BLOCKED_REASON_BATTERY_SAVER : 0);
- newBlockedReasons |= (mDeviceIdleMode ? BLOCKED_REASON_DOZE : 0);
- newBlockedReasons |= (mLowPowerStandbyActive ? BLOCKED_REASON_LOW_POWER_STANDBY : 0);
- newBlockedReasons |= (isUidIdle ? BLOCKED_REASON_APP_STANDBY : 0);
- newBlockedReasons |= (uidBlockedState.blockedReasons & BLOCKED_REASON_RESTRICTED_MODE);
-
- newAllowedReasons |= (isSystem(uid) ? ALLOWED_REASON_SYSTEM : 0);
- newAllowedReasons |= (isForeground ? ALLOWED_REASON_FOREGROUND : 0);
- newAllowedReasons |= (isTop ? ALLOWED_REASON_TOP : 0);
- newAllowedReasons |= (isWhitelistedFromPowerSaveUL(uid, true)
- ? ALLOWED_REASON_POWER_SAVE_ALLOWLIST : 0);
- newAllowedReasons |= (isWhitelistedFromPowerSaveExceptIdleUL(uid)
- ? ALLOWED_REASON_POWER_SAVE_EXCEPT_IDLE_ALLOWLIST : 0);
- newAllowedReasons |= (uidBlockedState.allowedReasons
- & ALLOWED_REASON_RESTRICTED_MODE_PERMISSIONS);
- newAllowedReasons |= (isAllowlistedFromLowPowerStandbyUL(uid))
- ? ALLOWED_REASON_LOW_POWER_STANDBY_ALLOWLIST : 0;
-
- uidBlockedState.blockedReasons = (uidBlockedState.blockedReasons
- & BLOCKED_METERED_REASON_MASK) | newBlockedReasons;
- uidBlockedState.allowedReasons = (uidBlockedState.allowedReasons
- & ALLOWED_METERED_REASON_MASK) | newAllowedReasons;
- uidBlockedState.updateEffectiveBlockedReasons();
- if (previousUidBlockedState.effectiveBlockedReasons
- != uidBlockedState.effectiveBlockedReasons) {
- postBlockedReasonsChangedMsg(uid,
- uidBlockedState.effectiveBlockedReasons,
- previousUidBlockedState.effectiveBlockedReasons);
+ final int oldEffectiveBlockedReasons;
+ final int newEffectiveBlockedReasons;
+ final int uidRules;
+ synchronized (mUidBlockedState) {
+ final UidBlockedState uidBlockedState = getOrCreateUidBlockedStateForUid(
+ mUidBlockedState, uid);
+ final UidBlockedState previousUidBlockedState = getOrCreateUidBlockedStateForUid(
+ mTmpUidBlockedState, uid);
+ previousUidBlockedState.copyFrom(uidBlockedState);
+
+ int newBlockedReasons = BLOCKED_REASON_NONE;
+ int newAllowedReasons = ALLOWED_REASON_NONE;
+ newBlockedReasons |= (mRestrictPower ? BLOCKED_REASON_BATTERY_SAVER : 0);
+ newBlockedReasons |= (mDeviceIdleMode ? BLOCKED_REASON_DOZE : 0);
+ newBlockedReasons |= (mLowPowerStandbyActive ? BLOCKED_REASON_LOW_POWER_STANDBY : 0);
+ newBlockedReasons |= (isUidIdle ? BLOCKED_REASON_APP_STANDBY : 0);
+ newBlockedReasons |= (uidBlockedState.blockedReasons & BLOCKED_REASON_RESTRICTED_MODE);
+
+ newAllowedReasons |= (isSystem(uid) ? ALLOWED_REASON_SYSTEM : 0);
+ newAllowedReasons |= (isForeground ? ALLOWED_REASON_FOREGROUND : 0);
+ newAllowedReasons |= (isTop ? ALLOWED_REASON_TOP : 0);
+ newAllowedReasons |= (isWhitelistedFromPowerSaveUL(uid, true)
+ ? ALLOWED_REASON_POWER_SAVE_ALLOWLIST : 0);
+ newAllowedReasons |= (isWhitelistedFromPowerSaveExceptIdleUL(uid)
+ ? ALLOWED_REASON_POWER_SAVE_EXCEPT_IDLE_ALLOWLIST : 0);
+ newAllowedReasons |= (uidBlockedState.allowedReasons
+ & ALLOWED_REASON_RESTRICTED_MODE_PERMISSIONS);
+ newAllowedReasons |= (isAllowlistedFromLowPowerStandbyUL(uid))
+ ? ALLOWED_REASON_LOW_POWER_STANDBY_ALLOWLIST : 0;
+
+ uidBlockedState.blockedReasons = (uidBlockedState.blockedReasons
+ & BLOCKED_METERED_REASON_MASK) | newBlockedReasons;
+ uidBlockedState.allowedReasons = (uidBlockedState.allowedReasons
+ & ALLOWED_METERED_REASON_MASK) | newAllowedReasons;
+ uidBlockedState.updateEffectiveBlockedReasons();
- postUidRulesChangedMsg(uid, uidBlockedState.deriveUidRules());
+ if (LOGV) {
+ Log.v(TAG, "updateRulesForPowerRestrictionsUL(" + uid + ")"
+ + ", isIdle: " + isUidIdle
+ + ", mRestrictPower: " + mRestrictPower
+ + ", mDeviceIdleMode: " + mDeviceIdleMode
+ + ", isForeground=" + isForeground
+ + ", isTop=" + isTop
+ + ", isWhitelisted=" + isWhitelisted
+ + ", oldUidBlockedState=" + previousUidBlockedState
+ + ", newUidBlockedState=" + uidBlockedState);
+ }
+
+ oldEffectiveBlockedReasons = previousUidBlockedState.effectiveBlockedReasons;
+ newEffectiveBlockedReasons = uidBlockedState.effectiveBlockedReasons;
+ uidRules = oldEffectiveBlockedReasons == newEffectiveBlockedReasons
+ ? RULE_NONE
+ : uidBlockedState.deriveUidRules();
}
+ if (oldEffectiveBlockedReasons != newEffectiveBlockedReasons) {
+ postBlockedReasonsChangedMsg(uid,
+ oldEffectiveBlockedReasons,
+ newEffectiveBlockedReasons);
- if (LOGV) {
- Log.v(TAG, "updateRulesForPowerRestrictionsUL(" + uid + ")"
- + ", isIdle: " + isUidIdle
- + ", mRestrictPower: " + mRestrictPower
- + ", mDeviceIdleMode: " + mDeviceIdleMode
- + ", isForeground=" + isForeground
- + ", isTop=" + isTop
- + ", isWhitelisted=" + isWhitelisted
- + ", oldUidBlockedState=" + previousUidBlockedState.toString()
- + ", newUidBlockedState=" + uidBlockedState.toString());
+ postUidRulesChangedMsg(uid, uidRules);
}
}
@@ -5420,7 +5451,12 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
if (LOGV) Slog.v(TAG, "setMeteredNetworkDenylist " + uid + ": " + enable);
try {
mNetworkManager.setUidOnMeteredNetworkDenylist(uid, enable);
- mLogger.meteredAllowlistChanged(uid, enable);
+ mLogger.meteredDenylistChanged(uid, enable);
+ if (Process.isApplicationUid(uid)) {
+ final int sdkSandboxUid = Process.toSdkSandboxUid(uid);
+ mNetworkManager.setUidOnMeteredNetworkDenylist(sdkSandboxUid, enable);
+ mLogger.meteredDenylistChanged(sdkSandboxUid, enable);
+ }
} catch (IllegalStateException e) {
Log.wtf(TAG, "problem setting denylist (" + enable + ") rules for " + uid, e);
} catch (RemoteException e) {
@@ -5432,7 +5468,12 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
if (LOGV) Slog.v(TAG, "setMeteredNetworkAllowlist " + uid + ": " + enable);
try {
mNetworkManager.setUidOnMeteredNetworkAllowlist(uid, enable);
- mLogger.meteredDenylistChanged(uid, enable);
+ mLogger.meteredAllowlistChanged(uid, enable);
+ if (Process.isApplicationUid(uid)) {
+ final int sdkSandboxUid = Process.toSdkSandboxUid(uid);
+ mNetworkManager.setUidOnMeteredNetworkAllowlist(sdkSandboxUid, enable);
+ mLogger.meteredAllowlistChanged(sdkSandboxUid, enable);
+ }
} catch (IllegalStateException e) {
Log.wtf(TAG, "problem setting allowlist (" + enable + ") rules for " + uid, e);
} catch (RemoteException e) {
@@ -5471,12 +5512,31 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
}
+ private void addSdkSandboxUidsIfNeeded(SparseIntArray uidRules) {
+ final int size = uidRules.size();
+ final SparseIntArray sdkSandboxUids = new SparseIntArray();
+ for (int index = 0; index < size; index++) {
+ final int uid = uidRules.keyAt(index);
+ final int rule = uidRules.valueAt(index);
+ if (Process.isApplicationUid(uid)) {
+ sdkSandboxUids.put(Process.toSdkSandboxUid(uid), rule);
+ }
+ }
+
+ for (int index = 0; index < sdkSandboxUids.size(); index++) {
+ final int uid = sdkSandboxUids.keyAt(index);
+ final int rule = sdkSandboxUids.valueAt(index);
+ uidRules.put(uid, rule);
+ }
+ }
+
/**
* Set uid rules on a particular firewall chain. This is going to synchronize the rules given
* here to netd. It will clean up dead rules and make sure the target chain only contains rules
* specified here.
*/
private void setUidFirewallRulesUL(int chain, SparseIntArray uidRules) {
+ addSdkSandboxUidsIfNeeded(uidRules);
try {
int size = uidRules.size();
int[] uids = new int[size];
@@ -5519,6 +5579,11 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
try {
mNetworkManager.setFirewallUidRule(chain, uid, rule);
mLogger.uidFirewallRuleChanged(chain, uid, rule);
+ if (Process.isApplicationUid(uid)) {
+ final int sdkSandboxUid = Process.toSdkSandboxUid(uid);
+ mNetworkManager.setFirewallUidRule(chain, sdkSandboxUid, rule);
+ mLogger.uidFirewallRuleChanged(chain, sdkSandboxUid, rule);
+ }
} catch (IllegalStateException e) {
Log.wtf(TAG, "problem setting firewall uid rules", e);
} catch (RemoteException e) {
@@ -5555,15 +5620,16 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
*/
private void resetUidFirewallRules(int uid) {
try {
- mNetworkManager.setFirewallUidRule(FIREWALL_CHAIN_DOZABLE, uid, FIREWALL_RULE_DEFAULT);
- mNetworkManager.setFirewallUidRule(FIREWALL_CHAIN_STANDBY, uid, FIREWALL_RULE_DEFAULT);
- mNetworkManager
- .setFirewallUidRule(FIREWALL_CHAIN_POWERSAVE, uid, FIREWALL_RULE_DEFAULT);
- mNetworkManager
- .setFirewallUidRule(FIREWALL_CHAIN_RESTRICTED, uid, FIREWALL_RULE_DEFAULT);
- mNetworkManager
- .setFirewallUidRule(FIREWALL_CHAIN_LOW_POWER_STANDBY, uid,
- FIREWALL_RULE_DEFAULT);
+ mNetworkManager.setFirewallUidRule(FIREWALL_CHAIN_DOZABLE, uid,
+ FIREWALL_RULE_DEFAULT);
+ mNetworkManager.setFirewallUidRule(FIREWALL_CHAIN_STANDBY, uid,
+ FIREWALL_RULE_DEFAULT);
+ mNetworkManager.setFirewallUidRule(FIREWALL_CHAIN_POWERSAVE, uid,
+ FIREWALL_RULE_DEFAULT);
+ mNetworkManager.setFirewallUidRule(FIREWALL_CHAIN_RESTRICTED, uid,
+ FIREWALL_RULE_DEFAULT);
+ mNetworkManager.setFirewallUidRule(FIREWALL_CHAIN_LOW_POWER_STANDBY, uid,
+ FIREWALL_RULE_DEFAULT);
mNetworkManager.setUidOnMeteredNetworkAllowlist(uid, false);
mLogger.meteredAllowlistChanged(uid, false);
mNetworkManager.setUidOnMeteredNetworkDenylist(uid, false);
@@ -5573,6 +5639,9 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
} catch (RemoteException e) {
// ignored; service lives in system_server
}
+ if (Process.isApplicationUid(uid)) {
+ resetUidFirewallRules(Process.toSdkSandboxUid(uid));
+ }
}
@Deprecated
@@ -5728,7 +5797,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
mContext.enforceCallingOrSelfPermission(OBSERVE_NETWORK_POLICY, TAG);
int blockedReasons;
- synchronized (mUidRulesFirstLock) {
+ synchronized (mUidBlockedState) {
final UidBlockedState uidBlockedState = mUidBlockedState.get(uid);
blockedReasons = uidBlockedState == null
? BLOCKED_REASON_NONE : uidBlockedState.effectiveBlockedReasons;
@@ -5746,7 +5815,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
@Override
public boolean isUidRestrictedOnMeteredNetworks(int uid) {
mContext.enforceCallingOrSelfPermission(OBSERVE_NETWORK_POLICY, TAG);
- synchronized (mUidRulesFirstLock) {
+ synchronized (mUidBlockedState) {
final UidBlockedState uidBlockedState = mUidBlockedState.get(uid);
int blockedReasons = uidBlockedState == null
? BLOCKED_REASON_NONE : uidBlockedState.effectiveBlockedReasons;
@@ -5994,10 +6063,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
return restrictedUids != null && restrictedUids.contains(uid);
}
- private static boolean hasRule(int uidRules, int rule) {
- return (uidRules & rule) != 0;
- }
-
private static boolean getBooleanDefeatingNullable(@Nullable PersistableBundle bundle,
String key, boolean defaultValue) {
return (bundle != null) ? bundle.getBoolean(key, defaultValue) : defaultValue;
@@ -6013,16 +6078,39 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
return uidBlockedState;
}
+ private int getEffectiveBlockedReasons(int uid) {
+ synchronized (mUidBlockedState) {
+ final UidBlockedState uidBlockedState = mUidBlockedState.get(uid);
+ return uidBlockedState == null
+ ? BLOCKED_REASON_NONE
+ : uidBlockedState.effectiveBlockedReasons;
+ }
+ }
+
+ private int getBlockedReasons(int uid) {
+ synchronized (mUidBlockedState) {
+ final UidBlockedState uidBlockedState = mUidBlockedState.get(uid);
+ return uidBlockedState == null
+ ? BLOCKED_REASON_NONE
+ : uidBlockedState.blockedReasons;
+ }
+ }
+
@VisibleForTesting
static final class UidBlockedState {
public int blockedReasons;
public int allowedReasons;
public int effectiveBlockedReasons;
+ private UidBlockedState(int blockedReasons, int allowedReasons,
+ int effectiveBlockedReasons) {
+ this.blockedReasons = blockedReasons;
+ this.allowedReasons = allowedReasons;
+ this.effectiveBlockedReasons = effectiveBlockedReasons;
+ }
+
UidBlockedState() {
- blockedReasons = BLOCKED_REASON_NONE;
- allowedReasons = ALLOWED_REASON_NONE;
- effectiveBlockedReasons = BLOCKED_REASON_NONE;
+ this(BLOCKED_REASON_NONE, ALLOWED_REASON_NONE, BLOCKED_REASON_NONE);
}
void updateEffectiveBlockedReasons() {
@@ -6259,7 +6347,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
}
if (LOGV) {
- Slog.v(TAG, "uidBlockedState=" + this.toString()
+ Slog.v(TAG, "uidBlockedState=" + this
+ " -> uidRule=" + uidRulesToString(uidRule));
}
return uidRule;
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index c4731aa7b522..1885b5596e3e 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -630,6 +630,7 @@ public class NotificationManagerService extends SystemService {
private int mWarnRemoteViewsSizeBytes;
private int mStripRemoteViewsSizeBytes;
final boolean mEnableAppSettingMigration;
+ private boolean mForceUserSetOnUpgrade;
private MetricsLogger mMetricsLogger;
private TriPredicate<String, Integer, String> mAllowedManagedServicePackages;
@@ -1623,18 +1624,6 @@ public class NotificationManagerService extends SystemService {
}
};
- @VisibleForTesting
- final IAppOpsCallback mAppOpsCallback = new IAppOpsCallback.Stub() {
- @Override public void opChanged(int op, int uid, String packageName) {
- if (mEnableAppSettingMigration) {
- int opValue = mAppOps.checkOpNoThrow(
- AppOpsManager.OP_POST_NOTIFICATION, uid, packageName);
- boolean blocked = op != MODE_ALLOWED;
- sendAppBlockStateChangedBroadcast(packageName, uid, blocked);
- }
- }
- };
-
private final BroadcastReceiver mPackageIntentReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -2133,12 +2122,6 @@ public class NotificationManagerService extends SystemService {
mUsageStatsManagerInternal = usageStatsManagerInternal;
mAppOps = appOps;
mAppOpsService = iAppOps;
- try {
- mAppOpsService.startWatchingMode(
- AppOpsManager.OP_POST_NOTIFICATION, null, mAppOpsCallback);
- } catch (RemoteException e) {
- Slog.e(TAG, "Could not register OP_POST_NOTIFICATION listener");
- }
mAppUsageStats = appUsageStats;
mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
mCompanionManager = companionManager;
@@ -2312,6 +2295,7 @@ public class NotificationManagerService extends SystemService {
mMsgPkgsAllowedAsConvos = Set.of(getStringArrayResource(
com.android.internal.R.array.config_notificationMsgPkgsAllowedAsConvos));
+
mStatsManager = statsManager;
mToastRateLimiter = toastRateLimiter;
@@ -2404,6 +2388,9 @@ public class NotificationManagerService extends SystemService {
WorkerHandler handler = new WorkerHandler(Looper.myLooper());
+ mForceUserSetOnUpgrade = getContext().getResources().getBoolean(
+ R.bool.config_notificationForceUserSetOnUpgrade);
+
init(handler, new RankingHandlerWorker(mRankingThread.getLooper()),
AppGlobals.getPackageManager(), getContext().getPackageManager(),
getLocalService(LightsManager.class),
@@ -2432,7 +2419,8 @@ public class NotificationManagerService extends SystemService {
LocalServices.getService(ActivityManagerInternal.class),
createToastRateLimiter(), new PermissionHelper(LocalServices.getService(
PermissionManagerServiceInternal.class), AppGlobals.getPackageManager(),
- AppGlobals.getPermissionManager(), mEnableAppSettingMigration),
+ AppGlobals.getPermissionManager(), mEnableAppSettingMigration,
+ mForceUserSetOnUpgrade),
LocalServices.getService(UsageStatsManagerInternal.class));
publishBinderService(Context.NOTIFICATION_SERVICE, mService, /* allowIsolated= */ false,
@@ -3409,6 +3397,7 @@ public class NotificationManagerService extends SystemService {
}
mPermissionHelper.setNotificationPermission(
pkg, UserHandle.getUserId(uid), enabled, true);
+ sendAppBlockStateChangedBroadcast(pkg, uid, !enabled);
} else {
synchronized (mNotificationLock) {
boolean wasEnabled = mPreferencesHelper.getImportance(pkg, uid)
@@ -3746,6 +3735,10 @@ public class NotificationManagerService extends SystemService {
if (!hadChannel && hasChannel && !hasRequestedNotificationPermission
&& startingTaskId != ActivityTaskManager.INVALID_TASK_ID) {
hasRequestedNotificationPermission = true;
+ if (mPermissionPolicyInternal == null) {
+ mPermissionPolicyInternal =
+ LocalServices.getService(PermissionPolicyInternal.class);
+ }
mHandler.post(new ShowNotificationPermissionPromptRunnable(pkg,
UserHandle.getUserId(uid), startingTaskId,
mPermissionPolicyInternal));
@@ -3764,19 +3757,7 @@ public class NotificationManagerService extends SystemService {
try {
int uid = mPackageManager.getPackageUid(pkg, 0,
UserHandle.getUserId(Binder.getCallingUid()));
- List<ActivityManager.AppTask> tasks = mAtm.getAppTasks(pkg, uid);
- for (int i = 0; i < tasks.size(); i++) {
- ActivityManager.RecentTaskInfo task = tasks.get(i).getTaskInfo();
- if (mPermissionPolicyInternal == null) {
- mPermissionPolicyInternal =
- LocalServices.getService(PermissionPolicyInternal.class);
- }
- if (mPermissionPolicyInternal != null
- && mPermissionPolicyInternal.canShowPermissionPromptForTask(task)) {
- taskId = task.taskId;
- break;
- }
- }
+ taskId = mAtm.getTaskToShowPermissionDialogOn(pkg, uid);
} catch (RemoteException e) {
// Do nothing
}
@@ -4068,13 +4049,12 @@ public class NotificationManagerService extends SystemService {
@Override
public ParceledListSlice<NotificationChannel> getNotificationChannelsBypassingDnd(
- String pkg, int userId) {
+ String pkg, int uid) {
checkCallerIsSystem();
- if (!areNotificationsEnabledForPackage(pkg,
- mPackageManagerInternal.getPackageUid(pkg, 0, userId))) {
+ if (!areNotificationsEnabledForPackage(pkg, uid)) {
return ParceledListSlice.emptyList();
}
- return mPreferencesHelper.getNotificationChannelsBypassingDnd(pkg, userId);
+ return mPreferencesHelper.getNotificationChannelsBypassingDnd(pkg, uid);
}
@Override
@@ -6095,6 +6075,7 @@ public class NotificationManagerService extends SystemService {
pw.println(" mMaxPackageEnqueueRate=" + mMaxPackageEnqueueRate);
pw.println(" hideSilentStatusBar="
+ mPreferencesHelper.shouldHideSilentStatusIcons());
+ pw.println(" mForceUserSetOnUpgrade=" + mForceUserSetOnUpgrade);
}
pw.println(" mArchive=" + mArchive.toString());
mArchive.dumpImpl(pw, filter);
diff --git a/services/core/java/com/android/server/notification/PermissionHelper.java b/services/core/java/com/android/server/notification/PermissionHelper.java
index 6b9e374771ff..b4230c11bcab 100644
--- a/services/core/java/com/android/server/notification/PermissionHelper.java
+++ b/services/core/java/com/android/server/notification/PermissionHelper.java
@@ -35,6 +35,7 @@ import android.util.ArrayMap;
import android.util.Pair;
import android.util.Slog;
+import com.android.internal.util.ArrayUtils;
import com.android.server.pm.permission.PermissionManagerServiceInternal;
import java.util.Collections;
@@ -56,13 +57,16 @@ public final class PermissionHelper {
private final IPermissionManager mPermManager;
// TODO (b/194833441): Remove when the migration is enabled
private final boolean mMigrationEnabled;
+ private final boolean mForceUserSetOnUpgrade;
public PermissionHelper(PermissionManagerServiceInternal pmi, IPackageManager packageManager,
- IPermissionManager permManager, boolean migrationEnabled) {
+ IPermissionManager permManager, boolean migrationEnabled,
+ boolean forceUserSetOnUpgrade) {
mPmi = pmi;
mPackageManager = packageManager;
mPermManager = permManager;
mMigrationEnabled = migrationEnabled;
+ mForceUserSetOnUpgrade = forceUserSetOnUpgrade;
}
public boolean isMigrationEnabled() {
@@ -178,13 +182,16 @@ public final class PermissionHelper {
boolean userSet, boolean reviewRequired) {
assertFlag();
final long callingId = Binder.clearCallingIdentity();
- // Do not change fixed permissions, and do not change non-user set permissions that are
- // granted by default, or granted by role.
- if (isPermissionFixed(packageName, userId)
- || (isPermissionGrantedByDefaultOrRole(packageName, userId) && !userSet)) {
- return;
- }
try {
+ // Do not change the permission if the package doesn't request it, do not change fixed
+ // permissions, and do not change non-user set permissions that are granted by default,
+ // or granted by role.
+ if (!packageRequestsNotificationPermission(packageName, userId)
+ || isPermissionFixed(packageName, userId)
+ || (isPermissionGrantedByDefaultOrRole(packageName, userId) && !userSet)) {
+ return;
+ }
+
boolean currentlyGranted = mPmi.checkPermission(packageName, NOTIFICATION_PERMISSION,
userId) != PackageManager.PERMISSION_DENIED;
if (grant && !reviewRequired && !currentlyGranted) {
@@ -219,8 +226,9 @@ public final class PermissionHelper {
return;
}
if (!isPermissionFixed(pkgPerm.packageName, pkgPerm.userId)) {
+ boolean userSet = mForceUserSetOnUpgrade ? true : pkgPerm.userModifiedSettings;
setNotificationPermission(pkgPerm.packageName, pkgPerm.userId, pkgPerm.granted,
- pkgPerm.userSet, !pkgPerm.userSet);
+ userSet, !userSet);
}
}
@@ -278,6 +286,19 @@ public final class PermissionHelper {
}
}
+ private boolean packageRequestsNotificationPermission(String packageName,
+ @UserIdInt int userId) {
+ assertFlag();
+ try {
+ String[] permissions = mPackageManager.getPackageInfo(packageName, GET_PERMISSIONS,
+ userId).requestedPermissions;
+ return ArrayUtils.contains(permissions, NOTIFICATION_PERMISSION);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Could not reach system server", e);
+ }
+ return false;
+ }
+
private void assertFlag() {
if (!mMigrationEnabled) {
throw new IllegalStateException("Method called without checking flag value");
@@ -288,13 +309,13 @@ public final class PermissionHelper {
public final String packageName;
public final @UserIdInt int userId;
public final boolean granted;
- public final boolean userSet;
+ public final boolean userModifiedSettings;
public PackagePermission(String pkg, int userId, boolean granted, boolean userSet) {
this.packageName = pkg;
this.userId = userId;
this.granted = granted;
- this.userSet = userSet;
+ this.userModifiedSettings = userSet;
}
@Override
@@ -302,13 +323,14 @@ public final class PermissionHelper {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
PackagePermission that = (PackagePermission) o;
- return userId == that.userId && granted == that.granted && userSet == that.userSet
+ return userId == that.userId && granted == that.granted && userModifiedSettings
+ == that.userModifiedSettings
&& Objects.equals(packageName, that.packageName);
}
@Override
public int hashCode() {
- return Objects.hash(packageName, userId, granted, userSet);
+ return Objects.hash(packageName, userId, granted, userModifiedSettings);
}
@Override
@@ -317,7 +339,7 @@ public final class PermissionHelper {
"packageName='" + packageName + '\'' +
", userId=" + userId +
", granted=" + granted +
- ", userSet=" + userSet +
+ ", userSet=" + userModifiedSettings +
'}';
}
}
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index 11858904a69a..75d7a1f510b9 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -601,8 +601,10 @@ public class PreferencesHelper implements RankingConfig {
out.attribute(null, ATT_NAME, r.pkg);
if (!notifPermissions.isEmpty()) {
Pair<Integer, String> app = new Pair(r.uid, r.pkg);
+ final Pair<Boolean, Boolean> permission = notifPermissions.get(app);
out.attributeInt(null, ATT_IMPORTANCE,
- notifPermissions.get(app).first ? IMPORTANCE_DEFAULT : IMPORTANCE_NONE);
+ permission != null && permission.first ? IMPORTANCE_DEFAULT
+ : IMPORTANCE_NONE);
notifPermissions.remove(app);
} else {
if (r.importance != DEFAULT_IMPORTANCE) {
@@ -1669,14 +1671,14 @@ public class PreferencesHelper implements RankingConfig {
}
/**
- * Gets all notification channels associated with the given pkg and userId that can bypass dnd
+ * Gets all notification channels associated with the given pkg and uid that can bypass dnd
*/
public ParceledListSlice<NotificationChannel> getNotificationChannelsBypassingDnd(String pkg,
- int userId) {
+ int uid) {
List<NotificationChannel> channels = new ArrayList<>();
synchronized (mPackagePreferences) {
final PackagePreferences r = mPackagePreferences.get(
- packagePreferencesKey(pkg, userId));
+ packagePreferencesKey(pkg, uid));
if (r != null) {
for (NotificationChannel channel : r.channels.values()) {
if (channelIsLiveLocked(r, channel) && channel.canBypassDnd()) {
diff --git a/services/core/java/com/android/server/notification/ZenModeFiltering.java b/services/core/java/com/android/server/notification/ZenModeFiltering.java
index 2a6dd8410acb..b0d40efed690 100644
--- a/services/core/java/com/android/server/notification/ZenModeFiltering.java
+++ b/services/core/java/com/android/server/notification/ZenModeFiltering.java
@@ -112,7 +112,7 @@ public class ZenModeFiltering {
}
if (zen == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS) {
if (consolidatedPolicy.allowRepeatCallers()
- && REPEAT_CALLERS.isRepeat(context, extras)) {
+ && REPEAT_CALLERS.isRepeat(context, extras, null)) {
ZenLog.traceMatchesCallFilter(true, "repeat caller");
return true;
}
@@ -229,7 +229,8 @@ public class ZenModeFiltering {
}
if (isCall(record)) {
if (policy.allowRepeatCallers()
- && REPEAT_CALLERS.isRepeat(mContext, extras(record))) {
+ && REPEAT_CALLERS.isRepeat(
+ mContext, extras(record), record.getPhoneNumbers())) {
ZenLog.traceNotIntercepted(record, "repeatCaller");
return false;
}
@@ -350,6 +351,9 @@ public class ZenModeFiltering {
private final ArrayMap<String, Long> mOtherCalls = new ArrayMap<>();
private int mThresholdMinutes;
+ // Record all people URIs in the extras bundle as well as the provided phoneNumbers set
+ // as callers. The phoneNumbers set is used to pass in any additional phone numbers
+ // associated with the people URIs as separately retrieved from contacts.
private synchronized void recordCall(Context context, Bundle extras,
ArraySet<String> phoneNumbers) {
setThresholdMinutes(context);
@@ -362,7 +366,13 @@ public class ZenModeFiltering {
recordCallers(extraPeople, phoneNumbers, now);
}
- private synchronized boolean isRepeat(Context context, Bundle extras) {
+ // Determine whether any people in the provided extras bundle or phone number set is
+ // a repeat caller. The extras bundle contains the people associated with a specific
+ // notification, and will suffice for most callers; the phoneNumbers array may be used
+ // to additionally check any specific phone numbers previously retrieved from contacts
+ // associated with the people in the extras bundle.
+ private synchronized boolean isRepeat(Context context, Bundle extras,
+ ArraySet<String> phoneNumbers) {
setThresholdMinutes(context);
if (mThresholdMinutes <= 0 || extras == null) return false;
final String[] extraPeople = ValidateNotificationPeople.getExtraPeople(extras);
@@ -370,7 +380,7 @@ public class ZenModeFiltering {
final long now = System.currentTimeMillis();
cleanUp(mTelCalls, now);
cleanUp(mOtherCalls, now);
- return checkCallers(context, extraPeople);
+ return checkCallers(context, extraPeople, phoneNumbers);
}
private synchronized void cleanUp(ArrayMap<String, Long> calls, long now) {
@@ -433,7 +443,31 @@ public class ZenModeFiltering {
}
}
- private synchronized boolean checkCallers(Context context, String[] people) {
+ // helper function to check mTelCalls array for a number, and also check its decoded
+ // version
+ private synchronized boolean checkForNumber(String number, String defaultCountryCode) {
+ if (mTelCalls.containsKey(number)) {
+ // check directly via map first
+ return true;
+ } else {
+ // see if a number that matches via areSameNumber exists
+ String numberToCheck = Uri.decode(number);
+ if (numberToCheck != null) {
+ for (String prev : mTelCalls.keySet()) {
+ if (PhoneNumberUtils.areSamePhoneNumber(
+ numberToCheck, prev, defaultCountryCode)) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ // Check whether anyone in the provided array of people URIs or phone number set matches a
+ // previously recorded phone call.
+ private synchronized boolean checkCallers(Context context, String[] people,
+ ArraySet<String> phoneNumbers) {
// get the default country code for checking telephone numbers
final String defaultCountryCode =
context.getSystemService(TelephonyManager.class).getNetworkCountryIso();
@@ -443,20 +477,8 @@ public class ZenModeFiltering {
final Uri uri = Uri.parse(person);
if ("tel".equals(uri.getScheme())) {
String number = uri.getSchemeSpecificPart();
- if (mTelCalls.containsKey(number)) {
- // check directly via map first
+ if (checkForNumber(number, defaultCountryCode)) {
return true;
- } else {
- // see if a number that matches via areSameNumber exists
- String numberToCheck = Uri.decode(number);
- if (numberToCheck != null) {
- for (String prev : mTelCalls.keySet()) {
- if (PhoneNumberUtils.areSamePhoneNumber(
- numberToCheck, prev, defaultCountryCode)) {
- return true;
- }
- }
- }
}
} else {
if (mOtherCalls.containsKey(person)) {
@@ -464,6 +486,17 @@ public class ZenModeFiltering {
}
}
}
+
+ // also check any passed-in phone numbers
+ if (phoneNumbers != null) {
+ for (String num : phoneNumbers) {
+ if (checkForNumber(num, defaultCountryCode)) {
+ return true;
+ }
+ }
+ }
+
+ // no matches
return false;
}
}
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 93f1b4741bd6..9e0c97502c4f 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -104,6 +104,7 @@ public class ZenModeHelper {
// The amount of time rules instances can exist without their owning app being installed.
private static final int RULE_INSTANCE_GRACE_PERIOD = 1000 * 60 * 60 * 72;
+ static final int RULE_LIMIT_PER_PACKAGE = 100;
// pkg|userId => uid
protected final ArrayMap<String, Integer> mRulesUidCache = new ArrayMap<>();
@@ -329,10 +330,10 @@ public class ZenModeHelper {
int newRuleInstanceCount = getCurrentInstanceCount(automaticZenRule.getOwner())
+ getCurrentInstanceCount(automaticZenRule.getConfigurationActivity())
+ 1;
- if (ruleInstanceLimit > 0 && ruleInstanceLimit < newRuleInstanceCount) {
+ if (newRuleInstanceCount > RULE_LIMIT_PER_PACKAGE
+ || (ruleInstanceLimit > 0 && ruleInstanceLimit < newRuleInstanceCount)) {
throw new IllegalArgumentException("Rule instance limit exceeded");
}
-
}
ZenModeConfig newConfig;
diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java
index 6a2b2d582458..76d3d233d49a 100644
--- a/services/core/java/com/android/server/pm/ApexManager.java
+++ b/services/core/java/com/android/server/pm/ApexManager.java
@@ -29,7 +29,6 @@ import android.apex.CompressedApexInfoList;
import android.apex.IApexService;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
-import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
import android.content.pm.SigningDetails;
import android.content.pm.parsing.result.ParseResult;
@@ -834,7 +833,7 @@ public abstract class ApexManager {
throw new RuntimeException(re);
} catch (Exception e) {
throw new PackageManagerException(
- PackageInstaller.SessionInfo.SESSION_VERIFICATION_FAILED,
+ PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE,
"apexd verification failed : " + e.getMessage());
}
}
@@ -861,7 +860,7 @@ public abstract class ApexManager {
throw new RuntimeException(re);
} catch (Exception e) {
throw new PackageManagerException(
- PackageInstaller.SessionInfo.SESSION_VERIFICATION_FAILED,
+ PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE,
"Failed to mark apexd session as ready : " + e.getMessage());
}
}
diff --git a/services/core/java/com/android/server/pm/ApkChecksums.java b/services/core/java/com/android/server/pm/ApkChecksums.java
index aa467e782e84..2824585bf5aa 100644
--- a/services/core/java/com/android/server/pm/ApkChecksums.java
+++ b/services/core/java/com/android/server/pm/ApkChecksums.java
@@ -34,6 +34,7 @@ import android.content.Context;
import android.content.pm.ApkChecksum;
import android.content.pm.Checksum;
import android.content.pm.IOnChecksumsReadyListener;
+import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.content.pm.Signature;
import android.content.pm.SigningDetails.SignatureSchemeVersion;
@@ -62,6 +63,7 @@ import android.util.apk.VerityBuilder;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.security.VerityUtils;
+import com.android.server.LocalServices;
import com.android.server.pm.parsing.pkg.AndroidPackage;
import java.io.ByteArrayOutputStream;
diff --git a/services/core/java/com/android/server/pm/AppDataHelper.java b/services/core/java/com/android/server/pm/AppDataHelper.java
index 0b0d1458c8de..5013570fa6b8 100644
--- a/services/core/java/com/android/server/pm/AppDataHelper.java
+++ b/services/core/java/com/android/server/pm/AppDataHelper.java
@@ -36,7 +36,6 @@ import android.os.storage.StorageManagerInternal;
import android.os.storage.VolumeInfo;
import android.security.AndroidKeyStoreMaintenance;
import android.system.keystore2.Domain;
-import android.system.keystore2.KeyDescriptor;
import android.text.TextUtils;
import android.util.Log;
import android.util.Slog;
@@ -218,8 +217,9 @@ final class AppDataHelper {
final String seInfo = pkgSeInfo + seInfoUser;
final int targetSdkVersion = pkg.getTargetSdkVersion();
+ final boolean usesSdk = !pkg.getUsesSdkLibraries().isEmpty();
final CreateAppDataArgs args = Installer.buildCreateAppDataArgs(volumeUuid, packageName,
- userId, flags, appId, seInfo, targetSdkVersion);
+ userId, flags, appId, seInfo, targetSdkVersion, usesSdk);
args.previousAppId = previousAppId;
return batch.createAppData(args).whenComplete((ceDataInode, e) -> {
@@ -554,26 +554,6 @@ final class AppDataHelper {
return prepareAppDataFuture;
}
- public void migrateKeyStoreData(int previousAppId, int appId) {
- // If previous UID is system UID, declaring inheritKeyStoreKeys is not supported.
- // Silently ignore the request to migrate keys.
- if (previousAppId == Process.SYSTEM_UID) return;
-
- for (int userId : mPm.resolveUserIds(UserHandle.USER_ALL)) {
- int srcUid = UserHandle.getUid(userId, previousAppId);
- int destUid = UserHandle.getUid(userId, appId);
- final KeyDescriptor[] keys = AndroidKeyStoreMaintenance.listEntries(Domain.APP, srcUid);
- if (keys == null) continue;
- for (final KeyDescriptor key : keys) {
- KeyDescriptor dest = new KeyDescriptor();
- dest.domain = Domain.APP;
- dest.nspace = destUid;
- dest.alias = key.alias;
- AndroidKeyStoreMaintenance.migrateKeyNamespace(key, dest);
- }
- }
- }
-
void clearAppDataLIF(AndroidPackage pkg, int userId, int flags) {
if (pkg == null) {
return;
diff --git a/services/core/java/com/android/server/pm/AppIdSettingMap.java b/services/core/java/com/android/server/pm/AppIdSettingMap.java
new file mode 100644
index 000000000000..b41a0b8878e0
--- /dev/null
+++ b/services/core/java/com/android/server/pm/AppIdSettingMap.java
@@ -0,0 +1,147 @@
+/*
+ * 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.Process;
+import android.util.Log;
+
+import com.android.server.utils.WatchedArrayList;
+import com.android.server.utils.WatchedSparseArray;
+import com.android.server.utils.Watcher;
+
+/**
+ * A wrapper over {@link WatchedArrayList} that tracks the current (app ID -> SettingBase) mapping
+ * for non-system apps. Also tracks system app settings in an {@link WatchedSparseArray}.
+ */
+final class AppIdSettingMap {
+ /**
+ * We use an ArrayList instead of an SparseArray for non system apps because the number of apps
+ * might be big, and only ArrayList gives us a constant lookup time. For a given app ID, the
+ * index to the corresponding SettingBase object is (appId - FIRST_APPLICATION_ID). If an app ID
+ * doesn't exist (i.e., app is not installed), we fill the corresponding entry with null.
+ */
+ private WatchedArrayList<SettingBase> mNonSystemSettings = new WatchedArrayList<>();
+ private WatchedSparseArray<SettingBase> mSystemSettings = new WatchedSparseArray<>();
+ private int mFirstAvailableAppId = Process.FIRST_APPLICATION_UID;
+
+ /** Returns true if the requested AppID was valid and not already registered. */
+ public boolean registerExistingAppId(int appId, SettingBase setting, Object name) {
+ if (appId >= Process.FIRST_APPLICATION_UID) {
+ int size = mNonSystemSettings.size();
+ final int index = appId - Process.FIRST_APPLICATION_UID;
+ // fill the array until our index becomes valid
+ while (index >= size) {
+ mNonSystemSettings.add(null);
+ size++;
+ }
+ if (mNonSystemSettings.get(index) != null) {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Adding duplicate app id: " + appId
+ + " name=" + name);
+ return false;
+ }
+ mNonSystemSettings.set(index, setting);
+ } else {
+ if (mSystemSettings.get(appId) != null) {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Adding duplicate shared id: " + appId
+ + " name=" + name);
+ return false;
+ }
+ mSystemSettings.put(appId, setting);
+ }
+ return true;
+ }
+
+ public SettingBase getSetting(int appId) {
+ if (appId >= Process.FIRST_APPLICATION_UID) {
+ final int size = mNonSystemSettings.size();
+ final int index = appId - Process.FIRST_APPLICATION_UID;
+ return index < size ? mNonSystemSettings.get(index) : null;
+ } else {
+ return mSystemSettings.get(appId);
+ }
+ }
+
+ public void removeSetting(int appId) {
+ if (appId >= Process.FIRST_APPLICATION_UID) {
+ final int size = mNonSystemSettings.size();
+ final int index = appId - Process.FIRST_APPLICATION_UID;
+ if (index < size) {
+ mNonSystemSettings.set(index, null);
+ }
+ } else {
+ mSystemSettings.remove(appId);
+ }
+ setFirstAvailableAppId(appId + 1);
+ }
+
+ // This should be called (at least) whenever an application is removed
+ private void setFirstAvailableAppId(int uid) {
+ if (uid > mFirstAvailableAppId) {
+ mFirstAvailableAppId = uid;
+ }
+ }
+
+ public void replaceSetting(int appId, SettingBase setting) {
+ if (appId >= Process.FIRST_APPLICATION_UID) {
+ final int size = mNonSystemSettings.size();
+ final int index = appId - Process.FIRST_APPLICATION_UID;
+ if (index < size) {
+ mNonSystemSettings.set(index, setting);
+ } else {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Error in package manager settings: calling replaceAppIdLpw to"
+ + " replace SettingBase at appId=" + appId
+ + " but nothing is replaced.");
+ }
+ } else {
+ mSystemSettings.put(appId, setting);
+ }
+ }
+
+ /** Returns a new AppID or -1 if we could not find an available AppID to assign */
+ public int acquireAndRegisterNewAppId(SettingBase obj) {
+ final int size = mNonSystemSettings.size();
+ for (int i = mFirstAvailableAppId - Process.FIRST_APPLICATION_UID; i < size; i++) {
+ if (mNonSystemSettings.get(i) == null) {
+ mNonSystemSettings.set(i, obj);
+ return Process.FIRST_APPLICATION_UID + i;
+ }
+ }
+
+ // None left?
+ if (size > (Process.LAST_APPLICATION_UID - Process.FIRST_APPLICATION_UID)) {
+ return -1;
+ }
+
+ mNonSystemSettings.add(obj);
+ return Process.FIRST_APPLICATION_UID + size;
+ }
+
+ public AppIdSettingMap snapshot() {
+ AppIdSettingMap l = new AppIdSettingMap();
+ mNonSystemSettings.snapshot(l.mNonSystemSettings, mNonSystemSettings);
+ mSystemSettings.snapshot(l.mSystemSettings, mSystemSettings);
+ return l;
+ }
+
+ public void registerObserver(Watcher observer) {
+ mNonSystemSettings.registerObserver(observer);
+ mSystemSettings.registerObserver(observer);
+ }
+}
diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java
index d117967954d3..7b2dc28a396f 100644
--- a/services/core/java/com/android/server/pm/AppsFilter.java
+++ b/services/core/java/com/android/server/pm/AppsFilter.java
@@ -52,6 +52,7 @@ 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;
@@ -486,12 +487,12 @@ public class AppsFilter implements Watchable, Snappable {
}
/** Builder method for an AppsFilter */
- public static AppsFilter create(
- PackageManagerInternal pms, PackageManagerServiceInjector injector) {
+ public static AppsFilter create(@NonNull PackageManagerServiceInjector injector,
+ @NonNull PackageManagerInternal pmInt) {
final boolean forceSystemAppsQueryable =
injector.getContext().getResources()
.getBoolean(R.bool.config_forceSystemPackagesQueryable);
- final FeatureConfigImpl featureConfig = new FeatureConfigImpl(pms, injector);
+ final FeatureConfigImpl featureConfig = new FeatureConfigImpl(pmInt, injector);
final String[] forcedQueryablePackageNames;
if (forceSystemAppsQueryable) {
// all system apps already queryable, no need to read and parse individual exceptions
@@ -512,7 +513,7 @@ public class AppsFilter implements Watchable, Snappable {
};
AppsFilter appsFilter = new AppsFilter(stateProvider, featureConfig,
forcedQueryablePackageNames, forceSystemAppsQueryable, null,
- injector.getBackgroundExecutor(), pms);
+ injector.getBackgroundExecutor(), pmInt);
featureConfig.setAppsFilter(appsFilter);
return appsFilter;
}
diff --git a/services/core/java/com/android/server/pm/BackgroundDexOptService.java b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
index 31df0a53eaa9..d26a1ac4fba0 100644
--- a/services/core/java/com/android/server/pm/BackgroundDexOptService.java
+++ b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
@@ -19,6 +19,7 @@ package com.android.server.pm;
import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
import android.annotation.IntDef;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.job.JobInfo;
import android.app.job.JobParameters;
@@ -252,7 +253,8 @@ public final class BackgroundDexOptService {
*
* <p>This is only for shell command and only root or shell user can use this.
*
- * @param packageNames dex optimize the passed packages or all packages if null
+ * @param packageNames dex optimize the passed packages in the given order, or all packages in
+ * the default order if null
*
* @return true if dex optimization is complete. false if the task is cancelled or if there was
* an error.
@@ -267,11 +269,11 @@ public final class BackgroundDexOptService {
resetStatesForNewDexOptRunLocked(Thread.currentThread());
}
PackageManagerService pm = mInjector.getPackageManagerService();
- ArraySet<String> packagesToOptimize;
+ List<String> packagesToOptimize;
if (packageNames == null) {
- packagesToOptimize = mDexOptHelper.getOptimizablePackages();
+ packagesToOptimize = mDexOptHelper.getOptimizablePackages(pm.snapshotComputer());
} else {
- packagesToOptimize = new ArraySet<>(packageNames);
+ packagesToOptimize = packageNames;
}
return runIdleOptimization(pm, packagesToOptimize, /* isPostBootUpdate= */ false);
} finally {
@@ -334,7 +336,7 @@ public final class BackgroundDexOptService {
return false;
}
- ArraySet<String> pkgs = mDexOptHelper.getOptimizablePackages();
+ List<String> pkgs = mDexOptHelper.getOptimizablePackages(pm.snapshotComputer());
if (pkgs.isEmpty()) {
Slog.i(TAG, "No packages to optimize");
markPostBootUpdateCompleted(params);
@@ -524,7 +526,7 @@ public final class BackgroundDexOptService {
}
/** Returns true if completed */
- private boolean runIdleOptimization(PackageManagerService pm, ArraySet<String> pkgs,
+ private boolean runIdleOptimization(PackageManagerService pm, List<String> pkgs,
boolean isPostBootUpdate) {
synchronized (mLock) {
mLastExecutionStartTimeMs = SystemClock.elapsedRealtime();
@@ -556,8 +558,8 @@ public final class BackgroundDexOptService {
}
/** Gets the size of a package. */
- private long getPackageSize(PackageManagerService pm, String pkg) {
- PackageInfo info = pm.getPackageInfo(pkg, 0, UserHandle.USER_SYSTEM);
+ private long getPackageSize(@NonNull Computer snapshot, String pkg) {
+ PackageInfo info = snapshot.getPackageInfo(pkg, 0, UserHandle.USER_SYSTEM);
long size = 0;
if (info != null && info.applicationInfo != null) {
File path = Paths.get(info.applicationInfo.sourceDir).toFile();
@@ -580,10 +582,9 @@ public final class BackgroundDexOptService {
}
@Status
- private int idleOptimizePackages(PackageManagerService pm, ArraySet<String> pkgs,
+ private int idleOptimizePackages(PackageManagerService pm, List<String> pkgs,
long lowStorageThreshold, boolean isPostBootUpdate) {
ArraySet<String> updatedPackages = new ArraySet<>();
- ArraySet<String> updatedPackagesDueToSecondaryDex = new ArraySet<>();
try {
boolean supportSecondaryDex = mInjector.supportSecondaryDex();
@@ -605,8 +606,9 @@ public final class BackgroundDexOptService {
Slog.d(TAG, "Should Downgrade " + shouldDowngrade);
}
if (shouldDowngrade) {
+ final Computer snapshot = pm.snapshotComputer();
Set<String> unusedPackages =
- pm.getUnusedPackages(mDowngradeUnusedAppsThresholdInMillis);
+ snapshot.getUnusedPackages(mDowngradeUnusedAppsThresholdInMillis);
if (DEBUG) {
Slog.d(TAG, "Unsused Packages " + String.join(",", unusedPackages));
}
@@ -618,7 +620,7 @@ public final class BackgroundDexOptService {
// Should be aborted by the scheduler.
return abortCode;
}
- @DexOptResult int downgradeResult = downgradePackage(pm, pkg,
+ @DexOptResult int downgradeResult = downgradePackage(snapshot, pm, pkg,
/* isForPrimaryDex= */ true, isPostBootUpdate);
if (downgradeResult == PackageDexOptimizer.DEX_OPT_PERFORMED) {
updatedPackages.add(pkg);
@@ -629,7 +631,7 @@ public final class BackgroundDexOptService {
return status;
}
if (supportSecondaryDex) {
- downgradeResult = downgradePackage(pm, pkg,
+ downgradeResult = downgradePackage(snapshot, pm, pkg,
/* isForPrimaryDex= */false, isPostBootUpdate);
status = convertPackageDexOptimizerStatusToInternal(downgradeResult);
if (status != STATUS_OK) {
@@ -638,25 +640,12 @@ public final class BackgroundDexOptService {
}
}
- pkgs = new ArraySet<>(pkgs);
+ pkgs = new ArrayList<>(pkgs);
pkgs.removeAll(unusedPackages);
}
}
- @Status int primaryResult = optimizePackages(pkgs, lowStorageThreshold,
- /*isForPrimaryDex=*/ true, updatedPackages, isPostBootUpdate);
- if (primaryResult != STATUS_OK) {
- return primaryResult;
- }
-
- if (!supportSecondaryDex) {
- return STATUS_OK;
- }
-
- @Status int secondaryResult = optimizePackages(pkgs, lowStorageThreshold,
- /*isForPrimaryDex*/ false, updatedPackagesDueToSecondaryDex,
- isPostBootUpdate);
- return secondaryResult;
+ return optimizePackages(pkgs, lowStorageThreshold, updatedPackages, isPostBootUpdate);
} finally {
// Always let the pinner service know about changes.
notifyPinService(updatedPackages);
@@ -668,8 +657,10 @@ public final class BackgroundDexOptService {
}
@Status
- private int optimizePackages(ArraySet<String> pkgs, long lowStorageThreshold,
- boolean isForPrimaryDex, ArraySet<String> updatedPackages, boolean isPostBootUpdate) {
+ private int optimizePackages(List<String> pkgs, long lowStorageThreshold,
+ ArraySet<String> updatedPackages, boolean isPostBootUpdate) {
+ boolean supportSecondaryDex = mInjector.supportSecondaryDex();
+
for (String pkg : pkgs) {
int abortCode = abortIdleOptimizations(lowStorageThreshold);
if (abortCode != STATUS_OK) {
@@ -677,11 +668,23 @@ public final class BackgroundDexOptService {
return abortCode;
}
- @DexOptResult int result = optimizePackage(pkg, isForPrimaryDex, isPostBootUpdate);
- if (result == PackageDexOptimizer.DEX_OPT_PERFORMED) {
+ @DexOptResult int primaryResult =
+ optimizePackage(pkg, true /* isForPrimaryDex */, isPostBootUpdate);
+ if (primaryResult == PackageDexOptimizer.DEX_OPT_PERFORMED) {
updatedPackages.add(pkg);
- } else if (result != PackageDexOptimizer.DEX_OPT_SKIPPED) {
- return convertPackageDexOptimizerStatusToInternal(result);
+ } else if (primaryResult != PackageDexOptimizer.DEX_OPT_SKIPPED) {
+ return convertPackageDexOptimizerStatusToInternal(primaryResult);
+ }
+
+ if (!supportSecondaryDex) {
+ continue;
+ }
+
+ @DexOptResult int secondaryResult =
+ optimizePackage(pkg, false /* isForPrimaryDex */, isPostBootUpdate);
+ if (secondaryResult != PackageDexOptimizer.DEX_OPT_PERFORMED
+ && secondaryResult != PackageDexOptimizer.DEX_OPT_SKIPPED) {
+ return convertPackageDexOptimizerStatusToInternal(secondaryResult);
}
}
return STATUS_OK;
@@ -696,8 +699,8 @@ public final class BackgroundDexOptService {
* @return PackageDexOptimizer.DEX_*
*/
@DexOptResult
- private int downgradePackage(PackageManagerService pm, String pkg, boolean isForPrimaryDex,
- boolean isPostBootUpdate) {
+ private int downgradePackage(@NonNull Computer snapshot, PackageManagerService pm, String pkg,
+ boolean isForPrimaryDex, boolean isPostBootUpdate) {
if (DEBUG) {
Slog.d(TAG, "Downgrading " + pkg);
}
@@ -709,15 +712,15 @@ public final class BackgroundDexOptService {
if (!isPostBootUpdate) {
dexoptFlags |= DexoptOptions.DEXOPT_IDLE_BACKGROUND_JOB;
}
- long package_size_before = getPackageSize(pm, pkg);
+ long package_size_before = getPackageSize(snapshot, pkg);
int result = PackageDexOptimizer.DEX_OPT_SKIPPED;
if (isForPrimaryDex || PLATFORM_PACKAGE_NAME.equals(pkg)) {
// This applies for system apps or if packages location is not a directory, i.e.
// monolithic install.
- if (!pm.canHaveOatDir(pkg)) {
+ if (!pm.canHaveOatDir(snapshot, pkg)) {
// For apps that don't have the oat directory, instead of downgrading,
// remove their compiler artifacts from dalvik cache.
- pm.deleteOatArtifactsOfPackage(pkg);
+ pm.deleteOatArtifactsOfPackage(snapshot, pkg);
} else {
result = performDexOptPrimary(pkg, reason, dexoptFlags);
}
@@ -726,8 +729,9 @@ public final class BackgroundDexOptService {
}
if (result == PackageDexOptimizer.DEX_OPT_PERFORMED) {
+ final Computer newSnapshot = pm.snapshotComputer();
FrameworkStatsLog.write(FrameworkStatsLog.APP_DOWNGRADED, pkg, package_size_before,
- getPackageSize(pm, pkg), /*aggressive=*/ false);
+ getPackageSize(newSnapshot, pkg), /*aggressive=*/ false);
}
return result;
}
diff --git a/services/core/java/com/android/server/pm/BroadcastHelper.java b/services/core/java/com/android/server/pm/BroadcastHelper.java
index df7387dc946c..f1394d403bf7 100644
--- a/services/core/java/com/android/server/pm/BroadcastHelper.java
+++ b/services/core/java/com/android/server/pm/BroadcastHelper.java
@@ -119,14 +119,10 @@ public final class BroadcastHelper {
intent.setPackage(targetPkg);
}
// Modify the UID when posting to other users
- final String[] uidExtraNames =
- { Intent.EXTRA_UID, Intent.EXTRA_PREVIOUS_UID, Intent.EXTRA_NEW_UID };
- for (String name : uidExtraNames) {
- int uid = intent.getIntExtra(name, -1);
- if (uid >= 0 && UserHandle.getUserId(uid) != userId) {
- uid = UserHandle.getUid(userId, UserHandle.getAppId(uid));
- intent.putExtra(name, uid);
- }
+ int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
+ if (uid >= 0 && UserHandle.getUserId(uid) != userId) {
+ uid = UserHandle.getUid(userId, UserHandle.getAppId(uid));
+ intent.putExtra(Intent.EXTRA_UID, uid);
}
if (broadcastAllowList != null && PLATFORM_PACKAGE_NAME.equals(targetPkg)) {
intent.putExtra(Intent.EXTRA_VISIBILITY_ALLOW_LIST,
diff --git a/services/core/java/com/android/server/pm/Computer.java b/services/core/java/com/android/server/pm/Computer.java
index 2a4882ac7d4f..8e853019de90 100644
--- a/services/core/java/com/android/server/pm/Computer.java
+++ b/services/core/java/com/android/server/pm/Computer.java
@@ -58,10 +58,6 @@ import com.android.server.utils.WatchedLongSparseArray;
import java.io.FileDescriptor;
import java.io.PrintWriter;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
import java.util.List;
import java.util.Set;
@@ -92,92 +88,69 @@ import java.util.Set;
* and other managers (like PermissionManager) mean deadlock is possible. On the
* other hand, not overriding in {@link ComputerLocked} may leave a function walking
* unstable data.
- *
- * To coax developers to consider such issues carefully, all methods in
- * {@link Computer} must be annotated with <code>@LiveImplementation(override =
- * MANDATORY)</code> or <code>LiveImplementation(locked = NOT_ALLOWED)</code>. A unit
- * test verifies the annotation and that the annotation corresponds to the code in
- * {@link ComputerEngine} and {@link ComputerLocked}.
*/
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
public interface Computer extends PackageDataSnapshot {
/**
- * Every method must be annotated.
- */
- @Target({ ElementType.METHOD })
- @Retention(RetentionPolicy.RUNTIME)
- @interface LiveImplementation {
- // A Computer method must be annotated with one of the following values:
- // MANDATORY - the method must be overridden in ComputerEngineLive. The
- // format of the override is a call to the super method, wrapped in a
- // synchronization block.
- // NOT_ALLOWED - the method may not appear in the live computer. It must
- // be final in the ComputerEngine.
- int MANDATORY = 1;
- int NOT_ALLOWED = 2;
- int override() default MANDATORY;
- String rationale() default "";
- }
-
- /**
* Administrative statistics: record that the snapshot has been used. Every call
* to use() increments the usage counter.
*/
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
default void use() {
}
/**
* Fetch the snapshot usage counter.
* @return The number of times this snapshot was used.
*/
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
default int getUsed() {
return 0;
}
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
@NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent, String resolvedType,
@PackageManager.ResolveInfoFlagsBits long flags,
@PackageManagerInternal.PrivateResolveFlags long privateResolveFlags,
int filterCallingUid, int userId, boolean resolveForStart, boolean allowDynamicSplits);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
@NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent, String resolvedType,
long flags, int userId);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
@NonNull List<ResolveInfo> queryIntentServicesInternal(Intent intent, String resolvedType,
long flags, int userId, int callingUid, boolean includeInstantApps);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.MANDATORY)
@NonNull QueryIntentActivitiesResult queryIntentActivitiesInternalBody(Intent intent,
String resolvedType, long flags, int filterCallingUid, int userId,
boolean resolveForStart, boolean allowDynamicSplits, String pkgName,
String instantAppPkgName);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
ActivityInfo getActivityInfo(ComponentName component, long flags, int userId);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
+
+ /**
+ * Important: The provided filterCallingUid is used exclusively to filter out activities
+ * that can be seen based on user state. It's typically the original caller uid prior
+ * to clearing. Because it can only be provided by trusted code, its value can be
+ * trusted and will be used as-is; unlike userId which will be validated by this method.
+ */
ActivityInfo getActivityInfoInternal(ComponentName component, long flags,
int filterCallingUid, int userId);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.MANDATORY)
AndroidPackage getPackage(String packageName);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.MANDATORY)
AndroidPackage getPackage(int uid);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
ApplicationInfo generateApplicationInfoFromSettings(String packageName, long flags,
int filterCallingUid, int userId);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
ApplicationInfo getApplicationInfo(String packageName, long flags, int userId);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
+
+ /**
+ * Important: The provided filterCallingUid is used exclusively to filter out applications
+ * that can be seen based on user state. It's typically the original caller uid prior
+ * to clearing. Because it can only be provided by trusted code, its value can be
+ * trusted and will be used as-is; unlike userId which will be validated by this method.
+ */
ApplicationInfo getApplicationInfoInternal(String packageName, long flags,
int filterCallingUid, int userId);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
+
+ /**
+ * Report the 'Home' activity which is currently set as "always use this one". If non is set
+ * then reports the most likely home activity or null if there are more than one.
+ */
ComponentName getDefaultHomeActivity(int userId);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
ComponentName getHomeActivitiesAsUser(List<ResolveInfo> allHomeCandidates, int userId);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
CrossProfileDomainInfo getCrossProfileDomainPreferredLpr(Intent intent, String resolvedType,
long flags, int sourceUserId, int parentUserId);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
Intent getHomeIntent();
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
List<CrossProfileIntentFilter> getMatchingCrossProfileIntentFilters(Intent intent,
String resolvedType, int userId);
@@ -192,15 +165,11 @@ public interface Computer extends PackageDataSnapshot {
* @param intent
* @return A filtered list of resolved activities.
*/
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
List<ResolveInfo> applyPostResolutionFilter(@NonNull List<ResolveInfo> resolveInfos,
String ephemeralPkgName, boolean allowDynamicSplits, int filterCallingUid,
boolean resolveForStart, int userId, Intent intent);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
PackageInfo generatePackageInfo(PackageStateInternal ps, long flags, int userId);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
PackageInfo getPackageInfo(String packageName, long flags, int userId);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
PackageInfo getPackageInfoInternal(String packageName, long versionCode, long flags,
int filterCallingUid, int userId);
@@ -209,192 +178,179 @@ public interface Computer extends PackageDataSnapshot {
* known {@link PackageState} instances without a {@link PackageState#getAndroidPackage()}
* will not be represented.
*/
- @Computer.LiveImplementation(override = Computer.LiveImplementation.MANDATORY)
String[] getAllAvailablePackageNames();
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
PackageStateInternal getPackageStateInternal(String packageName);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.MANDATORY)
PackageStateInternal getPackageStateInternal(String packageName, int callingUid);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.MANDATORY)
- @Nullable PackageState getPackageStateCopied(@NonNull String packageName);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
ParceledListSlice<PackageInfo> getInstalledPackages(long flags, int userId);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
ResolveInfo createForwardingResolveInfoUnchecked(WatchedIntentFilter filter,
int sourceUserId, int targetUserId);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
ServiceInfo getServiceInfo(ComponentName component, long flags, int userId);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
SharedLibraryInfo getSharedLibraryInfo(String name, long version);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.MANDATORY)
String getInstantAppPackageName(int callingUid);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
String resolveExternalPackageName(AndroidPackage pkg);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
String resolveInternalPackageName(String packageName, long versionCode);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
String[] getPackagesForUid(int uid);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
UserInfo getProfileParent(int userId);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
boolean canViewInstantApps(int callingUid, int userId);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
boolean filterSharedLibPackage(@Nullable PackageStateInternal ps, int uid, int userId,
long flags);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
boolean isCallerSameApp(String packageName, int uid);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
boolean isComponentVisibleToInstantApp(@Nullable ComponentName component);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
boolean isComponentVisibleToInstantApp(@Nullable ComponentName component,
@PackageManager.ComponentType int type);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
- boolean isImplicitImageCaptureIntentAndNotSetByDpcLocked(Intent intent, int userId,
+
+ /**
+ * From Android R, camera intents have to match system apps. The only exception to this is if
+ * the DPC has set the camera persistent preferred activity. This case was introduced
+ * because it is important that the DPC has the ability to set both system and non-system
+ * camera persistent preferred activities.
+ *
+ * @return {@code true} if the intent is a camera intent and the persistent preferred
+ * activity was not set by the DPC.
+ */
+ boolean isImplicitImageCaptureIntentAndNotSetByDpc(Intent intent, int userId,
String resolvedType, long flags);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
boolean isInstantApp(String packageName, int userId);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
boolean isInstantAppInternal(String packageName, @UserIdInt int userId, int callingUid);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
boolean isSameProfileGroup(@UserIdInt int callerUserId, @UserIdInt int userId);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
boolean shouldFilterApplication(@Nullable PackageStateInternal ps, int callingUid,
@Nullable ComponentName component, @PackageManager.ComponentType int componentType,
int userId);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
boolean shouldFilterApplication(@Nullable PackageStateInternal ps, int callingUid,
int userId);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
boolean shouldFilterApplication(@NonNull SharedUserSetting sus, int callingUid,
int userId);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
int checkUidPermission(String permName, int uid);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.MANDATORY)
int getPackageUidInternal(String packageName, long flags, int userId, int callingUid);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
long updateFlagsForApplication(long flags, int userId);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
long updateFlagsForComponent(long flags, int userId);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
long updateFlagsForPackage(long flags, int userId);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
+
+ /**
+ * Update given flags when being used to request {@link ResolveInfo}.
+ * <p>Instant apps are resolved specially, depending upon context. Minimally,
+ * {@code}flags{@code} must have the {@link PackageManager#MATCH_INSTANT}
+ * flag set. However, this flag is only honoured in three circumstances:
+ * <ul>
+ * <li>when called from a system process</li>
+ * <li>when the caller holds the permission {@code android.permission.ACCESS_INSTANT_APPS}</li>
+ * <li>when resolution occurs to start an activity with a {@code android.intent.action.VIEW}
+ * action and a {@code android.intent.category.BROWSABLE} category</li>
+ * </ul>
+ */
long updateFlagsForResolve(long flags, int userId, int callingUid, boolean wantInstantApps,
boolean isImplicitImageCaptureIntentAndNotSetByDpc);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
long updateFlagsForResolve(long flags, int userId, int callingUid, boolean wantInstantApps,
boolean onlyExposedExplicitly, boolean isImplicitImageCaptureIntentAndNotSetByDpc);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
+
+ /**
+ * Checks if the request is from the system or an app that has the appropriate cross-user
+ * permissions defined as follows:
+ * <ul>
+ * <li>INTERACT_ACROSS_USERS_FULL if {@code requireFullPermission} is true.</li>
+ * <li>INTERACT_ACROSS_USERS if the given {@code userId} is in a different profile group
+ * to the caller.</li>
+ * <li>Otherwise, INTERACT_ACROSS_PROFILES if the given {@code userId} is in the same profile
+ * group as the caller.</li>
+ * </ul>
+ *
+ * @param checkShell whether to prevent shell from access if there's a debugging restriction
+ * @param message the message to log on security exception
+ */
void enforceCrossUserOrProfilePermission(int callingUid, @UserIdInt int userId,
boolean requireFullPermission, boolean checkShell, String message);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
+
+ /**
+ * Enforces the request is from the system or an app that has INTERACT_ACROSS_USERS
+ * or INTERACT_ACROSS_USERS_FULL permissions, if the {@code userId} is not for the caller.
+ *
+ * @param checkShell whether to prevent shell from access if there's a debugging restriction
+ * @param message the message to log on security exception
+ */
void enforceCrossUserPermission(int callingUid, @UserIdInt int userId,
boolean requireFullPermission, boolean checkShell, String message);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
void enforceCrossUserPermission(int callingUid, @UserIdInt int userId,
boolean requireFullPermission, boolean checkShell,
boolean requirePermissionWhenSameUser, String message);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.MANDATORY)
SigningDetails getSigningDetails(@NonNull String packageName);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.MANDATORY)
SigningDetails getSigningDetails(int uid);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.MANDATORY)
boolean filterAppAccess(AndroidPackage pkg, int callingUid, int userId);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.MANDATORY)
boolean filterAppAccess(String packageName, int callingUid, int userId);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.MANDATORY)
boolean filterAppAccess(int uid, int callingUid);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.MANDATORY)
void dump(int type, FileDescriptor fd, PrintWriter pw, DumpState dumpState);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
PackageManagerService.FindPreferredActivityBodyResult findPreferredActivityInternal(
Intent intent, String resolvedType, long flags, List<ResolveInfo> query, boolean always,
boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
- ResolveInfo findPersistentPreferredActivityLP(Intent intent, String resolvedType, long flags,
+ ResolveInfo findPersistentPreferredActivity(Intent intent, String resolvedType, long flags,
List<ResolveInfo> query, boolean debug, int userId);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
PreferredIntentResolver getPreferredActivities(@UserIdInt int userId);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@NonNull
ArrayMap<String, ? extends PackageStateInternal> getPackageStates();
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@Nullable
String getRenamedPackage(@NonNull String packageName);
/**
* @return set of packages to notify
*/
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@NonNull
ArraySet<String> getNotifyPackagesForReplacedReceived(@NonNull String[] packages);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@PackageManagerService.PackageStartability
int getPackageStartability(boolean safeMode, @NonNull String packageName, int callingUid,
@UserIdInt int userId);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
boolean isPackageAvailable(String packageName, @UserIdInt int userId);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@NonNull
String[] currentToCanonicalPackageNames(@NonNull String[] names);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@NonNull
String[] canonicalToCurrentPackageNames(@NonNull String[] names);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@NonNull
int[] getPackageGids(@NonNull String packageName,
@PackageManager.PackageInfoFlagsBits long flags, @UserIdInt int userId);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
int getTargetSdkVersion(@NonNull String packageName);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
boolean activitySupportsIntent(@NonNull ComponentName resolveComponentName,
@NonNull ComponentName component, @NonNull Intent intent, String resolvedType);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@Nullable
ActivityInfo getReceiverInfo(@NonNull ComponentName component,
@PackageManager.ComponentInfoFlagsBits long flags, @UserIdInt int userId);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@Nullable
ParceledListSlice<SharedLibraryInfo> getSharedLibraries(@NonNull String packageName,
@PackageManager.PackageInfoFlagsBits long flags, @UserIdInt int userId);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
boolean canRequestPackageInstalls(@NonNull String packageName, int callingUid,
int userId, boolean throwIfPermNotDeclared);
- @Computer.LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
+ /**
+ * Returns true if the system or user is explicitly preventing an otherwise valid installer to
+ * complete an install. This includes checks like unknown sources and user restrictions.
+ */
boolean isInstallDisabledForPackage(@NonNull String packageName, int uid,
@UserIdInt int userId);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@Nullable
List<VersionedPackage> getPackagesUsingSharedLibrary(@NonNull SharedLibraryInfo libInfo,
@PackageManager.PackageInfoFlagsBits long flags, int callingUid, @UserIdInt int userId);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@Nullable
ParceledListSlice<SharedLibraryInfo> getDeclaredSharedLibraries(
@NonNull String packageName, @PackageManager.PackageInfoFlagsBits long flags,
@UserIdInt int userId);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@Nullable
ProviderInfo getProviderInfo(@NonNull ComponentName component,
@PackageManager.ComponentInfoFlagsBits long flags, @UserIdInt int userId);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@Nullable
String[] getSystemSharedLibraryNames();
@@ -402,136 +358,103 @@ public interface Computer extends PackageDataSnapshot {
* @return the state if the given package has a state and isn't filtered by visibility.
* Provides no guarantee that the package is in any usable state.
*/
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@Nullable
PackageStateInternal getPackageStateFiltered(@NonNull String packageName, int callingUid,
@UserIdInt int userId);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
int checkSignatures(@NonNull String pkg1, @NonNull String pkg2);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
int checkUidSignatures(int uid1, int uid2);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
boolean hasSigningCertificate(@NonNull String packageName, @NonNull byte[] certificate,
@PackageManager.CertificateInputType int type);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
boolean hasUidSigningCertificate(int uid, @NonNull byte[] certificate,
@PackageManager.CertificateInputType int type);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@NonNull
List<String> getAllPackages();
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@Nullable
String getNameForUid(int uid);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@Nullable
String[] getNamesForUids(@NonNull int[] uids);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
int getUidForSharedUser(@NonNull String sharedUserName);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
int getFlagsForUid(int uid);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
int getPrivateFlagsForUid(int uid);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
boolean isUidPrivileged(int uid);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@NonNull
String[] getAppOpPermissionPackages(@NonNull String permissionName);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@NonNull
ParceledListSlice<PackageInfo> getPackagesHoldingPermissions(@NonNull String[] permissions,
@PackageManager.PackageInfoFlagsBits long flags, @UserIdInt int userId);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@NonNull
List<ApplicationInfo> getInstalledApplications(
@PackageManager.ApplicationInfoFlagsBits long flags, @UserIdInt int userId,
int callingUid);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@Nullable
ProviderInfo resolveContentProvider(@NonNull String name,
@PackageManager.ResolveInfoFlagsBits long flags, @UserIdInt int userId, int callingUid);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@Nullable
ProviderInfo getGrantImplicitAccessProviderInfo(int recipientUid,
@NonNull String visibleAuthority);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
void querySyncProviders(boolean safeMode, @NonNull List<String> outNames,
@NonNull List<ProviderInfo> outInfo);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@NonNull
ParceledListSlice<ProviderInfo> queryContentProviders(@Nullable String processName, int uid,
@PackageManager.ComponentInfoFlagsBits long flags, @Nullable String metaDataKey);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@Nullable
InstrumentationInfo getInstrumentationInfo(@NonNull ComponentName component, int flags);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@NonNull
ParceledListSlice<InstrumentationInfo> queryInstrumentation(
@NonNull String targetPackage, int flags);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@NonNull
List<PackageStateInternal> findSharedNonSystemLibraries(
@NonNull PackageStateInternal pkgSetting);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
boolean getApplicationHiddenSettingAsUser(@NonNull String packageName, @UserIdInt int userId);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
boolean isPackageSuspendedForUser(@NonNull String packageName, @UserIdInt int userId);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
boolean isSuspendingAnyPackages(@NonNull String suspendingPackage, @UserIdInt int userId);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@NonNull
ParceledListSlice<IntentFilter> getAllIntentFilters(@NonNull String packageName);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
boolean getBlockUninstallForUser(@NonNull String packageName, @UserIdInt int userId);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@Nullable
SparseArray<int[]> getBroadcastAllowList(@NonNull String packageName, @UserIdInt int[] userIds,
boolean isInstantApp);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@Nullable
String getInstallerPackageName(@NonNull String packageName);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@Nullable
InstallSourceInfo getInstallSourceInfo(@NonNull String packageName);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@PackageManager.EnabledState
int getApplicationEnabledSetting(@NonNull String packageName, @UserIdInt int userId);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@PackageManager.EnabledState
int getComponentEnabledSetting(@NonNull ComponentName component, int callingUid,
@UserIdInt int userId);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@PackageManager.EnabledState
int getComponentEnabledSettingInternal(@NonNull ComponentName component, int callingUid,
@UserIdInt int userId);
@@ -542,25 +465,19 @@ public interface Computer extends PackageDataSnapshot {
* are all effectively enabled for the given component. Or if the component cannot be found,
* returns false.
*/
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
boolean isComponentEffectivelyEnabled(@NonNull ComponentInfo componentInfo,
@UserIdInt int userId);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@Nullable
KeySet getKeySetByAlias(@NonNull String packageName, @NonNull String alias);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@Nullable
KeySet getSigningKeySet(@NonNull String packageName);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
boolean isPackageSignedByKeySet(@NonNull String packageName, @NonNull KeySet ks);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
boolean isPackageSignedByKeySetExactly(@NonNull String packageName, @NonNull KeySet ks);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@Nullable
int[] getVisibilityAllowList(@NonNull String packageName, @UserIdInt int userId);
@@ -570,49 +487,37 @@ public interface Computer extends PackageDataSnapshot {
* package visibility filtering is enabled on it. If the UID is part of a shared user ID,
* return {@code true} if any one application belongs to the shared user ID meets the criteria.
*/
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
boolean canQueryPackage(int callingUid, @Nullable String targetPackageName);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
int getPackageUid(@NonNull String packageName, @PackageManager.PackageInfoFlagsBits long flags,
@UserIdInt int userId);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
boolean canAccessComponent(int callingUid, @NonNull ComponentName component,
@UserIdInt int userId);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
boolean isCallerInstallerOfRecord(@NonNull AndroidPackage pkg, int callingUid);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@PackageManager.InstallReason
int getInstallReason(@NonNull String packageName, @UserIdInt int userId);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
boolean canPackageQuery(@NonNull String sourcePackageName, @NonNull String targetPackageName,
@UserIdInt int userId);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
boolean canForwardTo(@NonNull Intent intent, @Nullable String resolvedType,
@UserIdInt int sourceUserId, @UserIdInt int targetUserId);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@NonNull
List<ApplicationInfo> getPersistentApplications(boolean safeMode, int flags);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@NonNull
SparseArray<String> getAppsWithSharedUserIds();
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@NonNull
String[] getSharedUserPackagesForPackage(@NonNull String packageName, @UserIdInt int userId);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@NonNull
Set<String> getUnusedPackages(long downgradeTimeThresholdMillis);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@Nullable
CharSequence getHarmfulAppWarning(@NonNull String packageName, @UserIdInt int userId);
@@ -623,55 +528,49 @@ public interface Computer extends PackageDataSnapshot {
*
* @return The filtered packages
*/
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@NonNull
String[] filterOnlySystemPackages(@Nullable String... pkgNames);
// The methods in this block should be removed once SettingBase is interface snapshotted
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@NonNull
List<AndroidPackage> getPackagesForAppId(int appId);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
int getUidTargetSdkVersion(int uid);
/**
* @see PackageManagerInternal#getProcessesForUid(int)
*/
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@Nullable
ArrayMap<String, ProcessInfo> getProcessesForUid(int uid);
// End block
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
boolean getBlockUninstall(@UserIdInt int userId, @NonNull String packageName);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@NonNull
WatchedArrayMap<String, WatchedLongSparseArray<SharedLibraryInfo>> getSharedLibraries();
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@Nullable
Pair<PackageStateInternal, SharedUserApi> getPackageOrSharedUser(int appId);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@Nullable
SharedUserApi getSharedUser(int sharedUserAppIde);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@NonNull
ArraySet<PackageStateInternal> getSharedUserPackages(int sharedUserAppId);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@NonNull
ComponentResolverApi getComponentResolver();
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@Nullable
PackageStateInternal getDisabledSystemPackage(@NonNull String packageName);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@Nullable
ResolveInfo getInstantAppInstallerInfo();
+
+ @NonNull
+ WatchedArrayMap<String, Integer> getFrozenPackages();
+
+ @Nullable
+ ComponentName getInstantAppInstallerComponent();
}
diff --git a/services/core/java/com/android/server/pm/ComputerEngine.java b/services/core/java/com/android/server/pm/ComputerEngine.java
index 0c9855b2385d..54a103959d04 100644
--- a/services/core/java/com/android/server/pm/ComputerEngine.java
+++ b/services/core/java/com/android/server/pm/ComputerEngine.java
@@ -129,8 +129,6 @@ 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.permission.PermissionManagerServiceInternal;
-import com.android.server.pm.pkg.PackageState;
-import com.android.server.pm.pkg.PackageStateImpl;
import com.android.server.pm.pkg.PackageStateInternal;
import com.android.server.pm.pkg.PackageStateUtils;
import com.android.server.pm.pkg.PackageUserStateInternal;
@@ -466,7 +464,7 @@ public class ComputerEngine implements Computer {
flags = updateFlagsForResolve(flags, userId, filterCallingUid, resolveForStart,
comp != null || pkgName != null /*onlyExposedExplicitly*/,
- isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, userId, resolvedType,
+ isImplicitImageCaptureIntentAndNotSetByDpc(intent, userId, resolvedType,
flags));
List<ResolveInfo> list = Collections.emptyList();
boolean skipPostResolution = false;
@@ -1722,15 +1720,6 @@ public class ComputerEngine implements Computer {
return mSettings.getPackage(packageName);
}
- @Nullable
- public PackageState getPackageStateCopied(@NonNull String packageName) {
- int callingUid = Binder.getCallingUid();
- packageName = resolveInternalPackageNameInternalLocked(
- packageName, PackageManager.VERSION_CODE_HIGHEST, callingUid);
- PackageStateInternal pkgSetting = mSettings.getPackage(packageName);
- return pkgSetting == null ? null : PackageStateImpl.copy(pkgSetting);
- }
-
public final ParceledListSlice<PackageInfo> getInstalledPackages(long flags, int userId) {
final int callingUid = Binder.getCallingUid();
if (getInstantAppPackageName(callingUid) != null) {
@@ -2468,7 +2457,7 @@ public class ComputerEngine implements Computer {
* @return {@code true} if the intent is a camera intent and the persistent preferred
* activity was not set by the DPC.
*/
- public final boolean isImplicitImageCaptureIntentAndNotSetByDpcLocked(Intent intent,
+ public final boolean isImplicitImageCaptureIntentAndNotSetByDpc(Intent intent,
int userId, String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags) {
return intent.isImplicitImageCaptureIntent() && !isPersistentPreferredActivitySetByDpm(
intent, userId, resolvedType, flags);
@@ -2647,6 +2636,13 @@ public class ComputerEngine implements Computer {
public final boolean shouldFilterApplication(@Nullable PackageStateInternal ps,
int callingUid, @Nullable ComponentName component,
@PackageManager.ComponentType int componentType, int userId) {
+ if (Process.isSdkSandboxUid(callingUid)) {
+ int clientAppUid = Process.getAppUidForSdkSandboxUid(callingUid);
+ // SDK sandbox should be able to see it's client app
+ if (clientAppUid == UserHandle.getUid(userId, ps.getAppId())) {
+ return false;
+ }
+ }
// if we're in an isolated process, get the real calling UID
if (Process.isIsolated(callingUid)) {
callingUid = getIsolatedOwner(callingUid);
@@ -3228,12 +3224,12 @@ public class ComputerEngine implements Computer {
flags = updateFlagsForResolve(
flags, userId, callingUid, false /*includeInstantApps*/,
- isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, userId,
+ isImplicitImageCaptureIntentAndNotSetByDpc(intent, userId,
resolvedType, flags));
intent = PackageManagerServiceUtils.updateIntentForResolve(intent);
// Try to find a matching persistent preferred activity.
- result.mPreferredResolveInfo = findPersistentPreferredActivityLP(intent,
+ result.mPreferredResolveInfo = findPersistentPreferredActivity(intent,
resolvedType, flags, query, debug, userId);
// If a persistent preferred activity matched, use it.
@@ -3444,7 +3440,7 @@ public class ComputerEngine implements Computer {
userId, queryMayBeFiltered, callingUid, isDeviceProvisioned);
}
- public final ResolveInfo findPersistentPreferredActivityLP(Intent intent,
+ public final ResolveInfo findPersistentPreferredActivity(Intent intent,
String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags,
List<ResolveInfo> query, boolean debug, int userId) {
final int n = query.size();
@@ -5418,7 +5414,7 @@ public class ComputerEngine implements Computer {
}
long flags = updateFlagsForResolve(0, parent.id, callingUid,
false /*includeInstantApps*/,
- isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, parent.id,
+ isImplicitImageCaptureIntentAndNotSetByDpc(intent, parent.id,
resolvedType, 0));
flags |= PackageManager.MATCH_DEFAULT_ONLY;
CrossProfileDomainInfo xpDomainInfo = getCrossProfileDomainPreferredLpr(
@@ -5694,4 +5690,17 @@ public class ComputerEngine implements Computer {
public ResolveInfo getInstantAppInstallerInfo() {
return mInstantAppInstallerInfo;
}
+
+ @NonNull
+ @Override
+ public WatchedArrayMap<String, Integer> getFrozenPackages() {
+ return mFrozenPackages;
+ }
+
+ @Nullable
+ @Override
+ public ComponentName getInstantAppInstallerComponent() {
+ return mLocalInstantAppInstallerActivity == null
+ ? null : mLocalInstantAppInstallerActivity.getComponentName();
+ }
}
diff --git a/services/core/java/com/android/server/pm/ComputerLocked.java b/services/core/java/com/android/server/pm/ComputerLocked.java
index 5d89c7daeaf5..af196d51331f 100644
--- a/services/core/java/com/android/server/pm/ComputerLocked.java
+++ b/services/core/java/com/android/server/pm/ComputerLocked.java
@@ -16,62 +16,21 @@
package com.android.server.pm;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.UserIdInt;
import android.content.ComponentName;
-import android.content.Intent;
-import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
-import android.content.pm.ComponentInfo;
-import android.content.pm.InstallSourceInfo;
-import android.content.pm.InstrumentationInfo;
-import android.content.pm.KeySet;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.ParceledListSlice;
-import android.content.pm.ProcessInfo;
-import android.content.pm.ProviderInfo;
-import android.content.pm.ResolveInfo;
-import android.content.pm.ServiceInfo;
-import android.content.pm.SharedLibraryInfo;
-import android.content.pm.SigningDetails;
-import android.content.pm.VersionedPackage;
-import android.util.ArrayMap;
-import android.util.ArraySet;
-import android.util.Pair;
-import android.util.SparseArray;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
-import com.android.server.pm.pkg.PackageState;
-import com.android.server.pm.pkg.PackageStateInternal;
-import com.android.server.pm.pkg.SharedUserApi;
-import com.android.server.pm.resolution.ComponentResolverApi;
-import com.android.server.utils.WatchedArrayMap;
-import com.android.server.utils.WatchedLongSparseArray;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Set;
/**
* This subclass is the external interface to the live computer. Some internal helper
- * methods are overridden to fetch live data instead of snapshot data. For each
- * Computer interface that is overridden in this class, the override takes the PM lock
- * and then delegates to the live computer engine. This is required because there are
- * no locks taken in the engine itself.
+ * methods are overridden to fetch live data instead of snapshot data.
*/
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
public final class ComputerLocked extends ComputerEngine {
- private final Object mLock;
ComputerLocked(PackageManagerService.Snapshot args) {
super(args);
- mLock = mService.mLock;
}
protected ComponentName resolveComponentName() {
@@ -83,814 +42,4 @@ public final class ComputerLocked extends ComputerEngine {
protected ApplicationInfo androidApplication() {
return mService.getCoreAndroidApplication();
}
-
- public @NonNull List<ResolveInfo> queryIntentServicesInternalBody(Intent intent,
- String resolvedType, int flags, int userId, int callingUid,
- String instantAppPkgName) {
- synchronized (mLock) {
- return super.queryIntentServicesInternalBody(intent, resolvedType, flags, userId,
- callingUid, instantAppPkgName);
- }
- }
- public @NonNull QueryIntentActivitiesResult queryIntentActivitiesInternalBody(
- Intent intent, String resolvedType, long flags, int filterCallingUid, int userId,
- boolean resolveForStart, boolean allowDynamicSplits, String pkgName,
- String instantAppPkgName) {
- synchronized (mLock) {
- return super.queryIntentActivitiesInternalBody(intent, resolvedType, flags,
- filterCallingUid, userId, resolveForStart, allowDynamicSplits, pkgName,
- instantAppPkgName);
- }
- }
- public ActivityInfo getActivityInfoInternalBody(ComponentName component, int flags,
- int filterCallingUid, int userId) {
- synchronized (mLock) {
- return super.getActivityInfoInternalBody(component, flags, filterCallingUid,
- userId);
- }
- }
- public AndroidPackage getPackage(String packageName) {
- synchronized (mLock) {
- return super.getPackage(packageName);
- }
- }
- public AndroidPackage getPackage(int uid) {
- synchronized (mLock) {
- return super.getPackage(uid);
- }
- }
- public ApplicationInfo getApplicationInfoInternalBody(String packageName, int flags,
- int filterCallingUid, int userId) {
- synchronized (mLock) {
- return super.getApplicationInfoInternalBody(packageName, flags, filterCallingUid,
- userId);
- }
- }
- public ArrayList<ResolveInfo> filterCandidatesWithDomainPreferredActivitiesLPrBody(
- Intent intent, int matchFlags, List<ResolveInfo> candidates,
- CrossProfileDomainInfo xpDomainInfo, int userId, boolean debug) {
- synchronized (mLock) {
- return super.filterCandidatesWithDomainPreferredActivitiesLPrBody(intent,
- matchFlags, candidates, xpDomainInfo, userId, debug);
- }
- }
- public PackageInfo getPackageInfoInternalBody(String packageName, long versionCode,
- int flags, int filterCallingUid, int userId) {
- synchronized (mLock) {
- return super.getPackageInfoInternalBody(packageName, versionCode, flags,
- filterCallingUid, userId);
- }
- }
-
- @Override
- public String[] getAllAvailablePackageNames() {
- synchronized (mLock) {
- return super.getAllAvailablePackageNames();
- }
- }
-
- public PackageStateInternal getPackageStateInternal(String packageName, int callingUid) {
- synchronized (mLock) {
- return super.getPackageStateInternal(packageName, callingUid);
- }
- }
-
- @Nullable
- public PackageState getPackageStateCopied(@NonNull String packageName) {
- synchronized (mLock) {
- return super.getPackageStateCopied(packageName);
- }
- }
-
- public ParceledListSlice<PackageInfo> getInstalledPackagesBody(int flags, int userId,
- int callingUid) {
- synchronized (mLock) {
- return super.getInstalledPackagesBody(flags, userId, callingUid);
- }
- }
- public ServiceInfo getServiceInfoBody(ComponentName component, int flags, int userId,
- int callingUid) {
- synchronized (mLock) {
- return super.getServiceInfoBody(component, flags, userId, callingUid);
- }
- }
- public String getInstantAppPackageName(int callingUid) {
- synchronized (mLock) {
- return super.getInstantAppPackageName(callingUid);
- }
- }
- public String[] getPackagesForUidInternalBody(int callingUid, int userId, int appId,
- boolean isCallerInstantApp) {
- synchronized (mLock) {
- return super.getPackagesForUidInternalBody(callingUid, userId, appId,
- isCallerInstantApp);
- }
- }
- public boolean isInstantAppInternalBody(String packageName, @UserIdInt int userId,
- int callingUid) {
- synchronized (mLock) {
- return super.isInstantAppInternalBody(packageName, userId, callingUid);
- }
- }
- public boolean isInstantAppResolutionAllowedBody(Intent intent,
- List<ResolveInfo> resolvedActivities, int userId, boolean skipPackageCheck,
- int flags) {
- synchronized (mLock) {
- return super.isInstantAppResolutionAllowedBody(intent, resolvedActivities, userId,
- skipPackageCheck, flags);
- }
- }
- public int getPackageUidInternal(String packageName, int flags, int userId,
- int callingUid) {
- synchronized (mLock) {
- return super.getPackageUidInternal(packageName, flags, userId, callingUid);
- }
- }
- public SigningDetails getSigningDetails(@NonNull String packageName) {
- synchronized (mLock) {
- return super.getSigningDetails(packageName);
- }
- }
- public SigningDetails getSigningDetails(int uid) {
- synchronized (mLock) {
- return super.getSigningDetails(uid);
- }
- }
- public boolean filterAppAccess(AndroidPackage pkg, int callingUid, int userId) {
- synchronized (mLock) {
- return super.filterAppAccess(pkg, callingUid, userId);
- }
- }
- public boolean filterAppAccess(String packageName, int callingUid, int userId) {
- synchronized (mLock) {
- return super.filterAppAccess(packageName, callingUid, userId);
- }
- }
- public boolean filterAppAccess(int uid, int callingUid) {
- synchronized (mLock) {
- return super.filterAppAccess(uid, callingUid);
- }
- }
- public void dump(int type, FileDescriptor fd, PrintWriter pw, DumpState dumpState) {
- synchronized (mLock) {
- super.dump(type, fd, pw, dumpState);
- }
- }
- public PackageManagerService.FindPreferredActivityBodyResult findPreferredActivityBody(
- Intent intent, String resolvedType, int flags, List<ResolveInfo> query, boolean always,
- boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered,
- int callingUid, boolean isDeviceProvisioned) {
- synchronized (mLock) {
- return super.findPreferredActivityBody(intent, resolvedType, flags, query, always,
- removeMatches, debug, userId, queryMayBeFiltered, callingUid,
- isDeviceProvisioned);
- }
- }
-
- @Override
- public PreferredIntentResolver getPreferredActivities(int userId) {
- synchronized (mLock) {
- return super.getPreferredActivities(userId);
- }
- }
-
- @NonNull
- @Override
- public ArrayMap<String, ? extends PackageStateInternal> getPackageStates() {
- synchronized (mLock) {
- return super.getPackageStates();
- }
- }
-
- @Nullable
- @Override
- public String getRenamedPackage(@NonNull String packageName) {
- synchronized (mLock) {
- return super.getRenamedPackage(packageName);
- }
- }
-
- @NonNull
- @Override
- public ArraySet<String> getNotifyPackagesForReplacedReceived(@NonNull String[] packages) {
- synchronized (mLock) {
- return super.getNotifyPackagesForReplacedReceived(packages);
- }
- }
-
- @Override
- public int getPackageStartability(boolean safeMode, @NonNull String packageName, int callingUid,
- @UserIdInt int userId) {
- synchronized (mLock) {
- return super.getPackageStartability(safeMode, packageName, callingUid, userId);
- }
- }
-
- @Override
- public boolean isPackageAvailable(String packageName, @UserIdInt int userId) {
- synchronized (mLock) {
- return super.isPackageAvailable(packageName, userId);
- }
- }
-
- @Override
- public String[] currentToCanonicalPackageNames(String[] names) {
- synchronized (mLock) {
- return super.currentToCanonicalPackageNames(names);
- }
- }
-
- @Override
- public String[] canonicalToCurrentPackageNames(String[] names) {
- synchronized (mLock) {
- return super.canonicalToCurrentPackageNames(names);
- }
- }
-
- @Override
- public int[] getPackageGids(@NonNull String packageName,
- @PackageManager.PackageInfoFlagsBits long flags, @UserIdInt int userId) {
- synchronized (mLock) {
- return super.getPackageGids(packageName, flags, userId);
- }
- }
-
- @Override
- public int getTargetSdkVersion(@NonNull String packageName) {
- synchronized (mLock) {
- return super.getTargetSdkVersion(packageName);
- }
- }
-
- @Override
- public boolean activitySupportsIntent(@NonNull ComponentName resolveComponentName,
- @NonNull ComponentName component, @NonNull Intent intent, String resolvedType) {
- synchronized (mLock) {
- return super.activitySupportsIntent(resolveComponentName, component, intent,
- resolvedType);
- }
- }
-
- @Nullable
- @Override
- public ActivityInfo getReceiverInfo(@NonNull ComponentName component,
- @PackageManager.ComponentInfoFlagsBits long flags, @UserIdInt int userId) {
- synchronized (mLock) {
- return super.getReceiverInfo(component, flags, userId);
- }
- }
-
- @Nullable
- @Override
- public ParceledListSlice<SharedLibraryInfo> getSharedLibraries(@NonNull String packageName,
- @PackageManager.PackageInfoFlagsBits long flags, @UserIdInt int userId) {
- synchronized (mLock) {
- return super.getSharedLibraries(packageName, flags, userId);
- }
- }
-
- @Override
- public boolean canRequestPackageInstalls(@NonNull String packageName, int callingUid,
- @UserIdInt int userId, boolean throwIfPermNotDeclared) {
- synchronized (mLock) {
- return super.canRequestPackageInstalls(packageName, callingUid, userId,
- throwIfPermNotDeclared);
- }
- }
-
- @Override
- public List<VersionedPackage> getPackagesUsingSharedLibrary(@NonNull SharedLibraryInfo libInfo,
- @PackageManager.PackageInfoFlagsBits long flags, int callingUid,
- @UserIdInt int userId) {
- synchronized (mLock) {
- return super.getPackagesUsingSharedLibrary(libInfo, flags, callingUid, userId);
- }
- }
-
- @Nullable
- @Override
- public ParceledListSlice<SharedLibraryInfo> getDeclaredSharedLibraries(
- @NonNull String packageName, @PackageManager.PackageInfoFlagsBits long flags,
- @UserIdInt int userId) {
- synchronized (mLock) {
- return super.getDeclaredSharedLibraries(packageName, flags, userId);
- }
- }
-
- @Nullable
- @Override
- public ProviderInfo getProviderInfo(@NonNull ComponentName component,
- @PackageManager.ComponentInfoFlagsBits long flags, @UserIdInt int userId) {
- synchronized (mLock) {
- return super.getProviderInfo(component, flags, userId);
- }
- }
-
- @Nullable
- @Override
- public String[] getSystemSharedLibraryNames() {
- synchronized (mLock) {
- return super.getSystemSharedLibraryNames();
- }
- }
-
- @Override
- public int checkSignatures(@NonNull String pkg1,
- @NonNull String pkg2) {
- synchronized (mLock) {
- return super.checkSignatures(pkg1, pkg2);
- }
- }
-
- @Override
- public int checkUidSignatures(int uid1, int uid2) {
- synchronized (mLock) {
- return super.checkUidSignatures(uid1, uid2);
- }
- }
-
- @Override
- public boolean hasSigningCertificate(@NonNull String packageName, @NonNull byte[] certificate,
- int type) {
- synchronized (mLock) {
- return super.hasSigningCertificate(packageName, certificate, type);
- }
- }
-
- @Override
- public boolean hasUidSigningCertificate(int uid, @NonNull byte[] certificate, int type) {
- synchronized (mLock) {
- return super.hasUidSigningCertificate(uid, certificate, type);
- }
- }
-
- @Override
- public List<String> getAllPackages() {
- synchronized (mLock) {
- return super.getAllPackages();
- }
- }
-
- @Nullable
- @Override
- public String getNameForUid(int uid) {
- synchronized (mLock) {
- return super.getNameForUid(uid);
- }
- }
-
- @Nullable
- @Override
- public String[] getNamesForUids(int[] uids) {
- synchronized (mLock) {
- return super.getNamesForUids(uids);
- }
- }
-
- @Override
- public int getUidForSharedUser(@NonNull String sharedUserName) {
- synchronized (mLock) {
- return super.getUidForSharedUser(sharedUserName);
- }
- }
-
- @Override
- public int getFlagsForUid(int uid) {
- synchronized (mLock) {
- return super.getFlagsForUid(uid);
- }
- }
-
- @Override
- public int getPrivateFlagsForUid(int uid) {
- synchronized (mLock) {
- return super.getPrivateFlagsForUid(uid);
- }
- }
-
- @Override
- public boolean isUidPrivileged(int uid) {
- synchronized (mLock) {
- return super.isUidPrivileged(uid);
- }
- }
-
- @NonNull
- @Override
- public String[] getAppOpPermissionPackages(@NonNull String permissionName) {
- synchronized (mLock) {
- return super.getAppOpPermissionPackages(permissionName);
- }
- }
-
- @NonNull
- @Override
- public ParceledListSlice<PackageInfo> getPackagesHoldingPermissions(
- @NonNull String[] permissions, @PackageManager.PackageInfoFlagsBits long flags,
- @UserIdInt int userId) {
- synchronized (mLock) {
- return super.getPackagesHoldingPermissions(permissions, flags, userId);
- }
- }
-
- @NonNull
- @Override
- public List<ApplicationInfo> getInstalledApplications(
- @PackageManager.ApplicationInfoFlagsBits long flags, @UserIdInt int userId,
- int callingUid) {
- synchronized (mLock) {
- return super.getInstalledApplications(flags, userId, callingUid);
- }
- }
-
- @Nullable
- @Override
- public ProviderInfo resolveContentProvider(@NonNull String name,
- @PackageManager.ResolveInfoFlagsBits long flags, @UserIdInt int userId,
- int callingUid) {
- synchronized (mLock) {
- return super.resolveContentProvider(name, flags, userId, callingUid);
- }
- }
-
- @Nullable
- @Override
- public ProviderInfo getGrantImplicitAccessProviderInfo(int recipientUid,
- @NonNull String visibleAuthority) {
- synchronized (mLock) {
- return super.getGrantImplicitAccessProviderInfo(recipientUid, visibleAuthority);
- }
- }
-
- @Override
- public void querySyncProviders(boolean safeMode, @NonNull List<String> outNames,
- @NonNull List<ProviderInfo> outInfo) {
- synchronized (mLock) {
- super.querySyncProviders(safeMode, outNames, outInfo);
- }
- }
-
- @NonNull
- @Override
- public ParceledListSlice<ProviderInfo> queryContentProviders(@Nullable String processName,
- int uid, @PackageManager.ComponentInfoFlagsBits long flags,
- @Nullable String metaDataKey) {
- synchronized (mLock) {
- return super.queryContentProviders(processName, uid, flags, metaDataKey);
- }
- }
-
- @Nullable
- @Override
- public InstrumentationInfo getInstrumentationInfo(@NonNull ComponentName component, int flags) {
- synchronized (mLock) {
- return super.getInstrumentationInfo(component, flags);
- }
- }
-
- @NonNull
- @Override
- public ParceledListSlice<InstrumentationInfo> queryInstrumentation(
- @NonNull String targetPackage, int flags) {
- synchronized (mLock) {
- return super.queryInstrumentation(targetPackage, flags);
- }
- }
-
- @NonNull
- @Override
- public List<PackageStateInternal> findSharedNonSystemLibraries(
- @NonNull PackageStateInternal pkgSetting) {
- synchronized (mLock) {
- return super.findSharedNonSystemLibraries(pkgSetting);
- }
- }
-
- @Override
- public boolean getApplicationHiddenSettingAsUser(@NonNull String packageName,
- @UserIdInt int userId) {
- synchronized (mLock) {
- return super.getApplicationHiddenSettingAsUser(packageName, userId);
- }
- }
-
- @Override
- public boolean isPackageSuspendedForUser(@NonNull String packageName, @UserIdInt int userId) {
- synchronized (mLock) {
- return super.isPackageSuspendedForUser(packageName, userId);
- }
- }
-
- @Override
- public boolean isSuspendingAnyPackages(@NonNull String suspendingPackage,
- @UserIdInt int userId) {
- synchronized (mLock) {
- return super.isSuspendingAnyPackages(suspendingPackage, userId);
- }
- }
-
- @NonNull
- @Override
- public ParceledListSlice<IntentFilter> getAllIntentFilters(@NonNull String packageName) {
- synchronized (mLock) {
- return super.getAllIntentFilters(packageName);
- }
- }
-
- @Override
- public boolean getBlockUninstallForUser(@NonNull String packageName, @UserIdInt int userId) {
- synchronized (mLock) {
- return super.getBlockUninstallForUser(packageName, userId);
- }
- }
-
- @Nullable
- @Override
- public SparseArray<int[]> getBroadcastAllowList(@NonNull String packageName,
- @UserIdInt int[] userIds, boolean isInstantApp) {
- synchronized (mLock) {
- return super.getBroadcastAllowList(packageName, userIds, isInstantApp);
- }
- }
-
- @Nullable
- @Override
- public String getInstallerPackageName(@NonNull String packageName) {
- synchronized (mLock) {
- return super.getInstallerPackageName(packageName);
- }
- }
-
- @Nullable
- @Override
- public InstallSourceInfo getInstallSourceInfo(@NonNull String packageName) {
- synchronized (mLock) {
- return super.getInstallSourceInfo(packageName);
- }
- }
-
- @Override
- public int getApplicationEnabledSetting(@NonNull String packageName, @UserIdInt int userId) {
- synchronized (mLock) {
- return super.getApplicationEnabledSetting(packageName, userId);
- }
- }
-
- @Override
- public int getComponentEnabledSetting(@NonNull ComponentName component, int callingUid,
- @UserIdInt int userId) {
- synchronized (mLock) {
- return super.getComponentEnabledSetting(component, callingUid, userId);
- }
- }
-
- @Override
- public int getComponentEnabledSettingInternal(@NonNull ComponentName component, int callingUid,
- @UserIdInt int userId) {
- synchronized (mLock) {
- return super.getComponentEnabledSettingInternal(component, callingUid, userId);
- }
- }
-
- @Override
- public boolean isComponentEffectivelyEnabled(@NonNull ComponentInfo componentInfo,
- @UserIdInt int userId) {
- synchronized (mLock) {
- return super.isComponentEffectivelyEnabled(componentInfo, userId);
- }
- }
-
- @Nullable
- @Override
- public KeySet getKeySetByAlias(@NonNull String packageName, @NonNull String alias) {
- synchronized (mLock) {
- return super.getKeySetByAlias(packageName, alias);
- }
- }
-
- @Nullable
- @Override
- public KeySet getSigningKeySet(@NonNull String packageName) {
- synchronized (mLock) {
- return super.getSigningKeySet(packageName);
- }
- }
-
- @Override
- public boolean isPackageSignedByKeySet(@NonNull String packageName, @NonNull KeySet ks) {
- synchronized (mLock) {
- return super.isPackageSignedByKeySet(packageName, ks);
- }
- }
-
- @Override
- public boolean isPackageSignedByKeySetExactly(@NonNull String packageName, @NonNull KeySet ks) {
- synchronized (mLock) {
- return super.isPackageSignedByKeySetExactly(packageName, ks);
- }
- }
-
- @Nullable
- @Override
- public int[] getVisibilityAllowList(@NonNull String packageName, @UserIdInt int userId) {
- synchronized (mLock) {
- return super.getVisibilityAllowList(packageName, userId);
- }
- }
-
- @Override
- public boolean canQueryPackage(int callingUid, @Nullable String targetPackageName) {
- synchronized (mLock) {
- return super.canQueryPackage(callingUid, targetPackageName);
- }
- }
-
- @Override
- public int getPackageUid(@NonNull String packageName,
- @PackageManager.PackageInfoFlagsBits long flags, @UserIdInt int userId) {
- synchronized (mLock) {
- return super.getPackageUid(packageName, flags, userId);
- }
- }
-
- @Override
- public boolean canAccessComponent(int callingUid, @NonNull ComponentName component,
- @UserIdInt int userId) {
- synchronized (mLock) {
- return super.canAccessComponent(callingUid, component, userId);
- }
- }
-
- @Override
- public boolean isCallerInstallerOfRecord(@NonNull AndroidPackage pkg, int callingUid) {
- synchronized (mLock) {
- return super.isCallerInstallerOfRecord(pkg, callingUid);
- }
- }
-
- @Override
- public int getInstallReason(@NonNull String packageName, @UserIdInt int userId) {
- synchronized (mLock) {
- return super.getInstallReason(packageName, userId);
- }
- }
-
- @Override
- public boolean canPackageQuery(@NonNull String sourcePackageName,
- @NonNull String targetPackageName, @UserIdInt int userId) {
- synchronized (mLock) {
- return super.canPackageQuery(sourcePackageName, targetPackageName, userId);
- }
- }
-
- @Override
- public boolean canForwardTo(@NonNull Intent intent, @Nullable String resolvedType,
- @UserIdInt int sourceUserId, @UserIdInt int targetUserId) {
- synchronized (mLock) {
- return super.canForwardTo(intent, resolvedType, sourceUserId, targetUserId);
- }
- }
-
- @NonNull
- @Override
- public List<ApplicationInfo> getPersistentApplications(boolean safeMode, int flags) {
- synchronized (mLock) {
- return super.getPersistentApplications(safeMode, flags);
- }
- }
-
- @NonNull
- @Override
- public SparseArray<String> getAppsWithSharedUserIds() {
- synchronized (mLock) {
- return super.getAppsWithSharedUserIds();
- }
- }
-
- @NonNull
- @Override
- public String[] getSharedUserPackagesForPackage(@NonNull String packageName,
- @UserIdInt int userId) {
- synchronized (mLock) {
- return super.getSharedUserPackagesForPackage(packageName, userId);
- }
- }
-
- @NonNull
- @Override
- public Set<String> getUnusedPackages(long downgradeTimeThresholdMillis) {
- synchronized (mLock) {
- return super.getUnusedPackages(downgradeTimeThresholdMillis);
- }
- }
-
- @Nullable
- @Override
- public CharSequence getHarmfulAppWarning(@NonNull String packageName, @UserIdInt int userId) {
- synchronized (mLock) {
- return super.getHarmfulAppWarning(packageName, userId);
- }
- }
-
- @NonNull
- @Override
- public String[] filterOnlySystemPackages(@Nullable String... pkgNames) {
- synchronized (mLock) {
- return super.filterOnlySystemPackages(pkgNames);
- }
- }
-
- @NonNull
- @Override
- public List<AndroidPackage> getPackagesForAppId(int appId) {
- synchronized (mLock) {
- return super.getPackagesForAppId(appId);
- }
- }
-
- @Override
- public int getUidTargetSdkVersion(int uid) {
- synchronized (mLock) {
- return super.getUidTargetSdkVersion(uid);
- }
- }
-
- @Nullable
- @Override
- public ArrayMap<String, ProcessInfo> getProcessesForUid(int uid) {
- synchronized (mLock) {
- return super.getProcessesForUid(uid);
- }
- }
-
- @Override
- public PackageStateInternal getPackageStateFiltered(@NonNull String packageName, int callingUid,
- @UserIdInt int userId) {
- synchronized (mLock) {
- return super.getPackageStateFiltered(packageName, callingUid, userId);
- }
- }
-
- @Override
- public boolean getBlockUninstall(@UserIdInt int userId, @NonNull String packageName) {
- synchronized (mLock) {
- return super.getBlockUninstall(userId, packageName);
- }
- }
-
- @NonNull
- @Override
- public WatchedArrayMap<String, WatchedLongSparseArray<SharedLibraryInfo>> getSharedLibraries() {
- synchronized (mLock) {
- return super.getSharedLibraries();
- }
- }
-
- @Nullable
- @Override
- public Pair<PackageStateInternal, SharedUserApi> getPackageOrSharedUser(int appId) {
- synchronized (mLock) {
- return super.getPackageOrSharedUser(appId);
- }
- }
-
- @Nullable
- @Override
- public SharedUserApi getSharedUser(int sharedUserAppId) {
- synchronized (mLock) {
- return super.getSharedUser(sharedUserAppId);
- }
- }
-
- @NonNull
- @Override
- public ArraySet<PackageStateInternal> getSharedUserPackages(int sharedUserAppId) {
- synchronized (mLock) {
- return super.getSharedUserPackages(sharedUserAppId);
- }
- }
-
- @NonNull
- @Override
- public ComponentResolverApi getComponentResolver() {
- synchronized (mLock) {
- return super.getComponentResolver();
- }
- }
-
- @Nullable
- @Override
- public PackageStateInternal getDisabledSystemPackage(@NonNull String packageName) {
- synchronized (mLock) {
- return super.getDisabledSystemPackage(packageName);
- }
- }
-
- @Nullable
- @Override
- public ResolveInfo getInstantAppInstallerInfo() {
- synchronized (mLock) {
- return super.getInstantAppInstallerInfo();
- }
- }
}
diff --git a/services/core/java/com/android/server/pm/ComputerTracker.java b/services/core/java/com/android/server/pm/ComputerTracker.java
deleted file mode 100644
index 216ad71b4d5d..000000000000
--- a/services/core/java/com/android/server/pm/ComputerTracker.java
+++ /dev/null
@@ -1,1327 +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.pm;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.UserIdInt;
-import android.content.ComponentName;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.ActivityInfo;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.ComponentInfo;
-import android.content.pm.InstallSourceInfo;
-import android.content.pm.InstrumentationInfo;
-import android.content.pm.KeySet;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManagerInternal;
-import android.content.pm.ParceledListSlice;
-import android.content.pm.ProcessInfo;
-import android.content.pm.ProviderInfo;
-import android.content.pm.ResolveInfo;
-import android.content.pm.ServiceInfo;
-import android.content.pm.SharedLibraryInfo;
-import android.content.pm.SigningDetails;
-import android.content.pm.UserInfo;
-import android.content.pm.VersionedPackage;
-import android.util.ArrayMap;
-import android.util.ArraySet;
-import android.util.Pair;
-import android.util.SparseArray;
-
-import com.android.server.pm.parsing.pkg.AndroidPackage;
-import com.android.server.pm.pkg.PackageState;
-import com.android.server.pm.pkg.PackageStateInternal;
-import com.android.server.pm.pkg.SharedUserApi;
-import com.android.server.pm.resolution.ComponentResolverApi;
-import com.android.server.utils.WatchedArrayMap;
-import com.android.server.utils.WatchedLongSparseArray;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.atomic.AtomicInteger;
-
-/**
- * This subclass delegates to methods in a Computer after reference-counting the computer.
- */
-public final class ComputerTracker implements Computer {
-
- // The number of times a thread reused a computer in its stack instead of fetching
- // a snapshot computer.
- private final AtomicInteger mReusedSnapshot = new AtomicInteger(0);
-
- private final PackageManagerService mService;
- ComputerTracker(PackageManagerService s) {
- mService = s;
- }
-
- private ThreadComputer snapshot() {
- ThreadComputer current = PackageManagerService.sThreadComputer.get();
- if (current.mRefCount > 0) {
- current.acquire();
- mReusedSnapshot.incrementAndGet();
- } else {
- current.acquire(mService.snapshotComputer());
- }
- return current;
- }
-
- public @NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent,
- String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags,
- @PackageManagerInternal.PrivateResolveFlags long privateResolveFlags,
- int filterCallingUid, int userId, boolean resolveForStart,
- boolean allowDynamicSplits) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.queryIntentActivitiesInternal(intent, resolvedType, flags,
- privateResolveFlags, filterCallingUid, userId, resolveForStart,
- allowDynamicSplits);
- } finally {
- current.release();
- }
- }
- public @NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent,
- String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, int userId) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.queryIntentActivitiesInternal(intent, resolvedType, flags,
- userId);
- } finally {
- current.release();
- }
- }
- public @NonNull List<ResolveInfo> queryIntentServicesInternal(Intent intent,
- String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, int userId,
- int callingUid, boolean includeInstantApps) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.queryIntentServicesInternal(intent, resolvedType, flags,
- userId, callingUid, includeInstantApps);
- } finally {
- current.release();
- }
- }
- public @NonNull QueryIntentActivitiesResult queryIntentActivitiesInternalBody(
- Intent intent, String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags,
- int filterCallingUid, int userId, boolean resolveForStart, boolean allowDynamicSplits,
- String pkgName, String instantAppPkgName) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.queryIntentActivitiesInternalBody(intent, resolvedType,
- flags, filterCallingUid, userId, resolveForStart, allowDynamicSplits,
- pkgName, instantAppPkgName);
- } finally {
- current.release();
- }
- }
- public ActivityInfo getActivityInfo(ComponentName component,
- @PackageManager.ComponentInfoFlagsBits long flags, int userId) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.getActivityInfo(component, flags, userId);
- } finally {
- current.release();
- }
- }
- public ActivityInfo getActivityInfoInternal(ComponentName component,
- @PackageManager.ComponentInfoFlagsBits long flags,
- int filterCallingUid, int userId) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.getActivityInfoInternal(component, flags, filterCallingUid,
- userId);
- } finally {
- current.release();
- }
- }
- public AndroidPackage getPackage(String packageName) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.getPackage(packageName);
- } finally {
- current.release();
- }
- }
- public AndroidPackage getPackage(int uid) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.getPackage(uid);
- } finally {
- current.release();
- }
- }
- public ApplicationInfo generateApplicationInfoFromSettings(String packageName,
- long flags, int filterCallingUid, int userId) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.generateApplicationInfoFromSettings(packageName, flags,
- filterCallingUid, userId);
- } finally {
- current.release();
- }
- }
- public ApplicationInfo getApplicationInfo(String packageName,
- @PackageManager.ApplicationInfoFlagsBits long flags, int userId) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.getApplicationInfo(packageName, flags, userId);
- } finally {
- current.release();
- }
- }
- public ApplicationInfo getApplicationInfoInternal(String packageName,
- @PackageManager.ApplicationInfoFlagsBits long flags, int filterCallingUid, int userId) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.getApplicationInfoInternal(packageName, flags,
- filterCallingUid, userId);
- } finally {
- current.release();
- }
- }
- public ComponentName getDefaultHomeActivity(int userId) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.getDefaultHomeActivity(userId);
- } finally {
- current.release();
- }
- }
- public ComponentName getHomeActivitiesAsUser(List<ResolveInfo> allHomeCandidates,
- int userId) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.getHomeActivitiesAsUser(allHomeCandidates, userId);
- } finally {
- current.release();
- }
- }
- public CrossProfileDomainInfo getCrossProfileDomainPreferredLpr(Intent intent,
- String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, int sourceUserId,
- int parentUserId) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.getCrossProfileDomainPreferredLpr(intent, resolvedType,
- flags, sourceUserId, parentUserId);
- } finally {
- current.release();
- }
- }
- public Intent getHomeIntent() {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.getHomeIntent();
- } finally {
- current.release();
- }
- }
- public List<CrossProfileIntentFilter> getMatchingCrossProfileIntentFilters(
- Intent intent, String resolvedType, int userId) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.getMatchingCrossProfileIntentFilters(intent, resolvedType,
- userId);
- } finally {
- current.release();
- }
- }
- public List<ResolveInfo> applyPostResolutionFilter(
- @NonNull List<ResolveInfo> resolveInfos,
- String ephemeralPkgName, boolean allowDynamicSplits, int filterCallingUid,
- boolean resolveForStart, int userId, Intent intent) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.applyPostResolutionFilter(resolveInfos, ephemeralPkgName,
- allowDynamicSplits, filterCallingUid, resolveForStart, userId, intent);
- } finally {
- current.release();
- }
- }
- public PackageInfo generatePackageInfo(PackageStateInternal ps,
- @PackageManager.PackageInfoFlagsBits long flags, int userId) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.generatePackageInfo(ps, flags, userId);
- } finally {
- current.release();
- }
- }
- public PackageInfo getPackageInfo(String packageName,
- @PackageManager.PackageInfoFlagsBits long flags, int userId) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.getPackageInfo(packageName, flags, userId);
- } finally {
- current.release();
- }
- }
- public PackageInfo getPackageInfoInternal(String packageName, long versionCode,
- long flags, int filterCallingUid, int userId) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.getPackageInfoInternal(packageName, versionCode, flags,
- filterCallingUid, userId);
- } finally {
- current.release();
- }
- }
- public PackageStateInternal getPackageStateInternal(String packageName) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.getPackageStateInternal(packageName);
- } finally {
- current.release();
- }
- }
- public PackageStateInternal getPackageStateInternal(String packageName, int callingUid) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.getPackageStateInternal(packageName, callingUid);
- } finally {
- current.release();
- }
- }
-
- @Nullable
- public PackageState getPackageStateCopied(@NonNull String packageName) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.getPackageStateCopied(packageName);
- } finally {
- current.release();
- }
- }
-
- public ParceledListSlice<PackageInfo> getInstalledPackages(long flags, int userId) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.getInstalledPackages(flags, userId);
- } finally {
- current.release();
- }
- }
- public ResolveInfo createForwardingResolveInfoUnchecked(WatchedIntentFilter filter,
- int sourceUserId, int targetUserId) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.createForwardingResolveInfoUnchecked(filter, sourceUserId,
- targetUserId);
- } finally {
- current.release();
- }
- }
- public ServiceInfo getServiceInfo(ComponentName component,
- @PackageManager.ComponentInfoFlagsBits long flags, int userId) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.getServiceInfo(component, flags, userId);
- } finally {
- current.release();
- }
- }
- public SharedLibraryInfo getSharedLibraryInfo(String name, long version) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.getSharedLibraryInfo(name, version);
- } finally {
- current.release();
- }
- }
- public SigningDetails getSigningDetails(@NonNull String packageName) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.getSigningDetails(packageName);
- } finally {
- current.release();
- }
- }
- public SigningDetails getSigningDetails(int uid) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.getSigningDetails(uid);
- } finally {
- current.release();
- }
- }
- public String getInstantAppPackageName(int callingUid) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.getInstantAppPackageName(callingUid);
- } finally {
- current.release();
- }
- }
- public String resolveExternalPackageName(AndroidPackage pkg) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.resolveExternalPackageName(pkg);
- } finally {
- current.release();
- }
- }
- public String resolveInternalPackageName(String packageName, long versionCode) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.resolveInternalPackageName(packageName, versionCode);
- } finally {
- current.release();
- }
- }
- public String[] getPackagesForUid(int uid) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.getPackagesForUid(uid);
- } finally {
- current.release();
- }
- }
- public UserInfo getProfileParent(int userId) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.getProfileParent(userId);
- } finally {
- current.release();
- }
- }
- public boolean canViewInstantApps(int callingUid, int userId) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.canViewInstantApps(callingUid, userId);
- } finally {
- current.release();
- }
- }
- public boolean filterAppAccess(AndroidPackage pkg, int callingUid, int userId) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.filterAppAccess(pkg, callingUid, userId);
- } finally {
- current.release();
- }
- }
- public boolean filterAppAccess(String packageName, int callingUid, int userId) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.filterAppAccess(packageName, callingUid, userId);
- } finally {
- current.release();
- }
- }
- public boolean filterAppAccess(int uid, int callingUid) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.filterAppAccess(uid, callingUid);
- } finally {
- current.release();
- }
- }
- public boolean filterSharedLibPackage(@Nullable PackageStateInternal ps, int uid,
- int userId, @PackageManager.ComponentInfoFlagsBits long flags) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.filterSharedLibPackage(ps, uid, userId, flags);
- } finally {
- current.release();
- }
- }
- public boolean isCallerSameApp(String packageName, int uid) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.isCallerSameApp(packageName, uid);
- } finally {
- current.release();
- }
- }
- public boolean isComponentVisibleToInstantApp(@Nullable ComponentName component) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.isComponentVisibleToInstantApp(component);
- } finally {
- current.release();
- }
- }
- public boolean isComponentVisibleToInstantApp(@Nullable ComponentName component,
- @PackageManager.ComponentType int type) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.isComponentVisibleToInstantApp(component, type);
- } finally {
- current.release();
- }
- }
- public boolean isImplicitImageCaptureIntentAndNotSetByDpcLocked(Intent intent,
- int userId, String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent,
- userId, resolvedType, flags);
- } finally {
- current.release();
- }
- }
- public boolean isInstantApp(String packageName, int userId) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.isInstantApp(packageName, userId);
- } finally {
- current.release();
- }
- }
- public boolean isInstantAppInternal(String packageName, @UserIdInt int userId,
- int callingUid) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.isInstantAppInternal(packageName, userId, callingUid);
- } finally {
- current.release();
- }
- }
- public boolean isSameProfileGroup(@UserIdInt int callerUserId,
- @UserIdInt int userId) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.isSameProfileGroup(callerUserId, userId);
- } finally {
- current.release();
- }
- }
- public boolean shouldFilterApplication(@NonNull SharedUserSetting sus,
- int callingUid, int userId) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.shouldFilterApplication(sus, callingUid, userId);
- } finally {
- current.release();
- }
- }
- public boolean shouldFilterApplication(@Nullable PackageStateInternal ps,
- int callingUid, @Nullable ComponentName component,
- @PackageManager.ComponentType int componentType, int userId) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.shouldFilterApplication(ps, callingUid, component,
- componentType, userId);
- } finally {
- current.release();
- }
- }
- public boolean shouldFilterApplication(@Nullable PackageStateInternal ps,
- int callingUid, int userId) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.shouldFilterApplication(ps, callingUid, userId);
- } finally {
- current.release();
- }
- }
- public int checkUidPermission(String permName, int uid) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.checkUidPermission(permName, uid);
- } finally {
- current.release();
- }
- }
- public int getPackageUidInternal(String packageName,
- @PackageManager.PackageInfoFlagsBits long flags, int userId, int callingUid) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.getPackageUidInternal(packageName, flags, userId,
- callingUid);
- } finally {
- current.release();
- }
- }
- public long updateFlagsForApplication(long flags, int userId) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.updateFlagsForApplication(flags, userId);
- } finally {
- current.release();
- }
- }
- public long updateFlagsForComponent(long flags, int userId) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.updateFlagsForComponent(flags, userId);
- } finally {
- current.release();
- }
- }
- public long updateFlagsForPackage(long flags, int userId) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.updateFlagsForPackage(flags, userId);
- } finally {
- current.release();
- }
- }
- public long updateFlagsForResolve(long flags, int userId, int callingUid,
- boolean wantInstantApps, boolean isImplicitImageCaptureIntentAndNotSetByDpc) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.updateFlagsForResolve(flags, userId, callingUid,
- wantInstantApps, isImplicitImageCaptureIntentAndNotSetByDpc);
- } finally {
- current.release();
- }
- }
- public long updateFlagsForResolve(long flags, int userId, int callingUid,
- boolean wantInstantApps, boolean onlyExposedExplicitly,
- boolean isImplicitImageCaptureIntentAndNotSetByDpc) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.updateFlagsForResolve(flags, userId, callingUid,
- wantInstantApps, onlyExposedExplicitly,
- isImplicitImageCaptureIntentAndNotSetByDpc);
- } finally {
- current.release();
- }
- }
- public void dump(int type, FileDescriptor fd, PrintWriter pw, DumpState dumpState) {
- ThreadComputer current = snapshot();
- try {
- current.mComputer.dump(type, fd, pw, dumpState);
- } finally {
- current.release();
- }
- }
- public void enforceCrossUserOrProfilePermission(int callingUid, @UserIdInt int userId,
- boolean requireFullPermission, boolean checkShell, String message) {
- ThreadComputer current = snapshot();
- try {
- current.mComputer.enforceCrossUserOrProfilePermission(callingUid, userId,
- requireFullPermission, checkShell, message);
- } finally {
- current.release();
- }
- }
- public void enforceCrossUserPermission(int callingUid, @UserIdInt int userId,
- boolean requireFullPermission, boolean checkShell, String message) {
- ThreadComputer current = snapshot();
- try {
- current.mComputer.enforceCrossUserPermission(callingUid, userId,
- requireFullPermission, checkShell, message);
- } finally {
- current.release();
- }
- }
- public void enforceCrossUserPermission(int callingUid, @UserIdInt int userId,
- boolean requireFullPermission, boolean checkShell,
- boolean requirePermissionWhenSameUser, String message) {
- ThreadComputer current = snapshot();
- try {
- current.mComputer.enforceCrossUserPermission(callingUid, userId,
- requireFullPermission, checkShell, requirePermissionWhenSameUser, message);
- } finally {
- current.release();
- }
- }
- public PackageManagerService.FindPreferredActivityBodyResult findPreferredActivityInternal(
- Intent intent, String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags,
- List<ResolveInfo> query, boolean always, boolean removeMatches, boolean debug,
- int userId, boolean queryMayBeFiltered) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.findPreferredActivityInternal(intent, resolvedType, flags,
- query, always, removeMatches, debug, userId, queryMayBeFiltered);
- } finally {
- current.release();
- }
- }
- public ResolveInfo findPersistentPreferredActivityLP(Intent intent,
- String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags,
- List<ResolveInfo> query, boolean debug, int userId) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.findPersistentPreferredActivityLP(intent, resolvedType,
- flags, query, debug, userId);
- } finally {
- current.release();
- }
- }
-
- @Override
- public String[] getAllAvailablePackageNames() {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getAllAvailablePackageNames();
- }
- }
-
- @Override
- public PreferredIntentResolver getPreferredActivities(int userId) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getPreferredActivities(userId);
- }
- }
-
- @NonNull
- @Override
- public ArrayMap<String, ? extends PackageStateInternal> getPackageStates() {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getPackageStates();
- }
- }
-
- @Nullable
- @Override
- public String getRenamedPackage(@NonNull String packageName) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getRenamedPackage(packageName);
- }
- }
-
- @NonNull
- @Override
- public ArraySet<String> getNotifyPackagesForReplacedReceived(@NonNull String[] packages) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getNotifyPackagesForReplacedReceived(packages);
- }
- }
-
- @Override
- public int getPackageStartability(boolean safeMode, @NonNull String packageName, int callingUid,
- @UserIdInt int userId) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getPackageStartability(safeMode, packageName, callingUid,
- userId);
- }
- }
-
- @Override
- public boolean isPackageAvailable(String packageName, @UserIdInt int userId) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.isPackageAvailable(packageName, userId);
- }
- }
-
- @Override
- public String[] currentToCanonicalPackageNames(String[] names) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.currentToCanonicalPackageNames(names);
- }
- }
-
- @Override
- public String[] canonicalToCurrentPackageNames(String[] names) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.canonicalToCurrentPackageNames(names);
- }
- }
-
- @Override
- public int[] getPackageGids(@NonNull String packageName,
- @PackageManager.PackageInfoFlagsBits long flags, @UserIdInt int userId) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getPackageGids(packageName, flags, userId);
- }
- }
-
- @Override
- public int getTargetSdkVersion(@NonNull String packageName) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getTargetSdkVersion(packageName);
- }
- }
-
- @Override
- public boolean activitySupportsIntent(@NonNull ComponentName resolveComponentName,
- @NonNull ComponentName component, @NonNull Intent intent, String resolvedType) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.activitySupportsIntent(resolveComponentName, component, intent,
- resolvedType);
- }
- }
-
- @Nullable
- @Override
- public ActivityInfo getReceiverInfo(@NonNull ComponentName component,
- @PackageManager.ComponentInfoFlagsBits long flags, @UserIdInt int userId) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getReceiverInfo(component, flags, userId);
- }
- }
-
- @Nullable
- @Override
- public ParceledListSlice<SharedLibraryInfo> getSharedLibraries(@NonNull String packageName,
- @PackageManager.PackageInfoFlagsBits long flags, @UserIdInt int userId) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getSharedLibraries(packageName, flags, userId);
- }
- }
-
- @Override
- public boolean canRequestPackageInstalls(@NonNull String packageName, int callingUid,
- @UserIdInt int userId, boolean throwIfPermNotDeclared) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.canRequestPackageInstalls(packageName, callingUid, userId,
- throwIfPermNotDeclared);
- }
- }
-
- @Override
- public boolean isInstallDisabledForPackage(@NonNull String packageName, int uid,
- @UserIdInt int userId) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.isInstallDisabledForPackage(packageName, uid, userId);
- }
- }
-
- @Override
- public List<VersionedPackage> getPackagesUsingSharedLibrary(@NonNull SharedLibraryInfo libInfo,
- @PackageManager.PackageInfoFlagsBits long flags, int callingUid,
- @UserIdInt int userId) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getPackagesUsingSharedLibrary(libInfo, flags, callingUid,
- userId);
- }
- }
-
- @Nullable
- @Override
- public ParceledListSlice<SharedLibraryInfo> getDeclaredSharedLibraries(
- @NonNull String packageName, @PackageManager.PackageInfoFlagsBits long flags,
- @UserIdInt int userId) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getDeclaredSharedLibraries(packageName, flags, userId);
- }
- }
-
- @Nullable
- @Override
- public ProviderInfo getProviderInfo(@NonNull ComponentName component,
- @PackageManager.ComponentInfoFlagsBits long flags, @UserIdInt int userId) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getProviderInfo(component, flags, userId);
- }
- }
-
- @Nullable
- @Override
- public String[] getSystemSharedLibraryNames() {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getSystemSharedLibraryNames();
- }
- }
-
- @Override
- public int checkSignatures(@NonNull String pkg1,
- @NonNull String pkg2) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.checkSignatures(pkg1, pkg2);
- }
- }
-
- @Override
- public int checkUidSignatures(int uid1, int uid2) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.checkUidSignatures(uid1, uid2);
- }
- }
-
- @Override
- public boolean hasSigningCertificate(@NonNull String packageName, @NonNull byte[] certificate,
- int type) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.hasSigningCertificate(packageName, certificate, type);
- }
- }
-
- @Override
- public boolean hasUidSigningCertificate(int uid, @NonNull byte[] certificate, int type) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.hasUidSigningCertificate(uid, certificate, type);
- }
- }
-
- @Override
- public List<String> getAllPackages() {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getAllPackages();
- }
- }
-
- @Nullable
- @Override
- public String getNameForUid(int uid) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getNameForUid(uid);
- }
- }
-
- @Nullable
- @Override
- public String[] getNamesForUids(int[] uids) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getNamesForUids(uids);
- }
- }
-
- @Override
- public int getUidForSharedUser(@NonNull String sharedUserName) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getUidForSharedUser(sharedUserName);
- }
- }
-
- @Override
- public int getFlagsForUid(int uid) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getFlagsForUid(uid);
- }
- }
-
- @Override
- public int getPrivateFlagsForUid(int uid) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getPrivateFlagsForUid(uid);
- }
- }
-
- @Override
- public boolean isUidPrivileged(int uid) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.isUidPrivileged(uid);
- }
- }
-
- @NonNull
- @Override
- public String[] getAppOpPermissionPackages(@NonNull String permissionName) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getAppOpPermissionPackages(permissionName);
- }
- }
-
- @NonNull
- @Override
- public ParceledListSlice<PackageInfo> getPackagesHoldingPermissions(
- @NonNull String[] permissions, @PackageManager.PackageInfoFlagsBits long flags,
- @UserIdInt int userId) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getPackagesHoldingPermissions(permissions, flags, userId);
- }
- }
-
- @NonNull
- @Override
- public List<ApplicationInfo> getInstalledApplications(
- @PackageManager.ApplicationInfoFlagsBits long flags, @UserIdInt int userId,
- int callingUid) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getInstalledApplications(flags, userId, callingUid);
- }
- }
-
- @Nullable
- @Override
- public ProviderInfo resolveContentProvider(@NonNull String name,
- @PackageManager.ResolveInfoFlagsBits long flags, @UserIdInt int userId,
- int callingUid) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.resolveContentProvider(name, flags, userId, callingUid);
- }
- }
-
- @Nullable
- @Override
- public ProviderInfo getGrantImplicitAccessProviderInfo(int recipientUid,
- @NonNull String visibleAuthority) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getGrantImplicitAccessProviderInfo(recipientUid,
- visibleAuthority);
- }
- }
-
- @Override
- public void querySyncProviders(boolean safeMode, @NonNull List<String> outNames,
- @NonNull List<ProviderInfo> outInfo) {
- try (ThreadComputer current = snapshot()) {
- current.mComputer.querySyncProviders(safeMode, outNames, outInfo);
- }
- }
-
- @NonNull
- @Override
- public ParceledListSlice<ProviderInfo> queryContentProviders(@Nullable String processName,
- int uid, @PackageManager.ComponentInfoFlagsBits long flags,
- @Nullable String metaDataKey) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.queryContentProviders(processName, uid, flags, metaDataKey);
- }
- }
-
- @Nullable
- @Override
- public InstrumentationInfo getInstrumentationInfo(@NonNull ComponentName component, int flags) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getInstrumentationInfo(component, flags);
- }
- }
-
- @NonNull
- @Override
- public ParceledListSlice<InstrumentationInfo> queryInstrumentation(
- @NonNull String targetPackage, int flags) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.queryInstrumentation(targetPackage, flags);
- }
- }
-
- @NonNull
- @Override
- public List<PackageStateInternal> findSharedNonSystemLibraries(
- @NonNull PackageStateInternal pkgSetting) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.findSharedNonSystemLibraries(pkgSetting);
- }
- }
-
- @Override
- public boolean getApplicationHiddenSettingAsUser(@NonNull String packageName,
- @UserIdInt int userId) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getApplicationHiddenSettingAsUser(packageName, userId);
- }
- }
-
- @Override
- public boolean isPackageSuspendedForUser(@NonNull String packageName, @UserIdInt int userId) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.isPackageSuspendedForUser(packageName, userId);
- }
- }
-
- @Override
- public boolean isSuspendingAnyPackages(@NonNull String suspendingPackage,
- @UserIdInt int userId) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.isSuspendingAnyPackages(suspendingPackage, userId);
- }
- }
-
- @NonNull
- @Override
- public ParceledListSlice<IntentFilter> getAllIntentFilters(@NonNull String packageName) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getAllIntentFilters(packageName);
- }
- }
-
- @Override
- public boolean getBlockUninstallForUser(@NonNull String packageName, @UserIdInt int userId) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getBlockUninstallForUser(packageName, userId);
- }
- }
-
- @Nullable
- @Override
- public SparseArray<int[]> getBroadcastAllowList(@NonNull String packageName,
- @UserIdInt int[] userIds, boolean isInstantApp) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getBroadcastAllowList(packageName, userIds, isInstantApp);
- }
- }
-
- @Nullable
- @Override
- public String getInstallerPackageName(@NonNull String packageName) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getInstallerPackageName(packageName);
- }
- }
-
- @Nullable
- @Override
- public InstallSourceInfo getInstallSourceInfo(@NonNull String packageName) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getInstallSourceInfo(packageName);
- }
- }
-
- @Override
- public int getApplicationEnabledSetting(@NonNull String packageName, @UserIdInt int userId) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getApplicationEnabledSetting(packageName, userId);
- }
- }
-
- @Override
- public int getComponentEnabledSetting(@NonNull ComponentName component, int callingUid,
- @UserIdInt int userId) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getComponentEnabledSetting(component, callingUid, userId);
- }
- }
-
- @Override
- public int getComponentEnabledSettingInternal(@NonNull ComponentName component, int callingUid,
- @UserIdInt int userId) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getComponentEnabledSettingInternal(
- component, callingUid, userId);
- }
- }
-
- @Override
- public boolean isComponentEffectivelyEnabled(@NonNull ComponentInfo componentInfo,
- @UserIdInt int userId) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.isComponentEffectivelyEnabled(componentInfo, userId);
- }
- }
-
- @Nullable
- @Override
- public KeySet getKeySetByAlias(@NonNull String packageName, @NonNull String alias) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getKeySetByAlias(packageName, alias);
- }
- }
-
- @Nullable
- @Override
- public KeySet getSigningKeySet(@NonNull String packageName) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getSigningKeySet(packageName);
- }
- }
-
- @Override
- public boolean isPackageSignedByKeySet(@NonNull String packageName, @NonNull KeySet ks) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.isPackageSignedByKeySet(packageName, ks);
- }
- }
-
- @Override
- public boolean isPackageSignedByKeySetExactly(@NonNull String packageName, @NonNull KeySet ks) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.isPackageSignedByKeySetExactly(packageName, ks);
- }
- }
-
- @Nullable
- @Override
- public int[] getVisibilityAllowList(@NonNull String packageName, @UserIdInt int userId) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getVisibilityAllowList(packageName, userId);
- }
- }
-
- @Override
- public boolean canQueryPackage(int callingUid, @Nullable String targetPackageName) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.canQueryPackage(callingUid, targetPackageName);
- }
- }
-
- @Override
- public int getPackageUid(@NonNull String packageName,
- @PackageManager.PackageInfoFlagsBits long flags, @UserIdInt int userId) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getPackageUid(packageName, flags, userId);
- }
- }
-
- @Override
- public boolean canAccessComponent(int callingUid, @NonNull ComponentName component,
- @UserIdInt int userId) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.canAccessComponent(callingUid, component, userId);
- }
- }
-
- @Override
- public boolean isCallerInstallerOfRecord(@NonNull AndroidPackage pkg, int callingUid) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.isCallerInstallerOfRecord(pkg, callingUid);
- }
- }
-
- @Override
- public int getInstallReason(@NonNull String packageName, @UserIdInt int userId) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getInstallReason(packageName, userId);
- }
- }
-
- @Override
- public boolean canPackageQuery(@NonNull String sourcePackageName,
- @NonNull String targetPackageName, @UserIdInt int userId) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.canPackageQuery(sourcePackageName, targetPackageName, userId);
- }
- }
-
- @Override
- public boolean canForwardTo(@NonNull Intent intent, @Nullable String resolvedType,
- @UserIdInt int sourceUserId, @UserIdInt int targetUserId) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.canForwardTo(intent, resolvedType, sourceUserId, targetUserId);
- }
- }
-
- @NonNull
- @Override
- public List<ApplicationInfo> getPersistentApplications(boolean safeMode, int flags) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getPersistentApplications(safeMode, flags);
- }
- }
-
- @NonNull
- @Override
- public SparseArray<String> getAppsWithSharedUserIds() {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getAppsWithSharedUserIds();
- }
- }
-
- @NonNull
- @Override
- public String[] getSharedUserPackagesForPackage(@NonNull String packageName,
- @UserIdInt int userId) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getSharedUserPackagesForPackage(packageName, userId);
- }
- }
-
- @NonNull
- @Override
- public Set<String> getUnusedPackages(long downgradeTimeThresholdMillis) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getUnusedPackages(downgradeTimeThresholdMillis);
- }
- }
-
- @Nullable
- @Override
- public CharSequence getHarmfulAppWarning(@NonNull String packageName, @UserIdInt int userId) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getHarmfulAppWarning(packageName, userId);
- }
- }
-
- @NonNull
- @Override
- public String[] filterOnlySystemPackages(@Nullable String... pkgNames) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.filterOnlySystemPackages(pkgNames);
- }
- }
-
- @NonNull
- @Override
- public List<AndroidPackage> getPackagesForAppId(int appId) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getPackagesForAppId(appId);
- }
- }
-
- @Override
- public int getUidTargetSdkVersion(int uid) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getUidTargetSdkVersion(uid);
- }
- }
-
- @Nullable
- @Override
- public ArrayMap<String, ProcessInfo> getProcessesForUid(int uid) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getProcessesForUid(uid);
- }
- }
-
- @Override
- public PackageStateInternal getPackageStateFiltered(@NonNull String packageName, int callingUid,
- @UserIdInt int userId) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getPackageStateFiltered(packageName, callingUid, userId);
- }
- }
-
- @Override
- public boolean getBlockUninstall(@UserIdInt int userId, @NonNull String packageName) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getBlockUninstall(userId, packageName);
- }
- }
-
- @NonNull
- @Override
- public WatchedArrayMap<String, WatchedLongSparseArray<SharedLibraryInfo>> getSharedLibraries() {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getSharedLibraries();
- }
- }
-
- @Nullable
- @Override
- public Pair<PackageStateInternal, SharedUserApi> getPackageOrSharedUser(int appId) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getPackageOrSharedUser(appId);
- }
- }
-
- @Nullable
- @Override
- public SharedUserApi getSharedUser(int sharedUserAppId) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getSharedUser(sharedUserAppId);
- }
- }
-
- @NonNull
- @Override
- public ArraySet<PackageStateInternal> getSharedUserPackages(int sharedUserAppId) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getSharedUserPackages(sharedUserAppId);
- }
- }
-
- @NonNull
- @Override
- public ComponentResolverApi getComponentResolver() {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getComponentResolver();
- }
- }
-
- @Nullable
- @Override
- public PackageStateInternal getDisabledSystemPackage(@NonNull String packageName) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getDisabledSystemPackage(packageName);
- }
- }
-
- @Nullable
- @Override
- public ResolveInfo getInstantAppInstallerInfo() {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getInstantAppInstallerInfo();
- }
- }
-}
diff --git a/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java b/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java
index b30798485bf7..89f8be27096a 100644
--- a/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java
+++ b/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java
@@ -112,7 +112,9 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub {
String callingFeatureId,
ComponentName component,
@UserIdInt int userId,
- boolean launchMainActivity) throws RemoteException {
+ boolean launchMainActivity,
+ IBinder targetTask,
+ Bundle options) throws RemoteException {
Objects.requireNonNull(callingPackage);
Objects.requireNonNull(component);
@@ -145,8 +147,12 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub {
if (launchMainActivity) {
launchIntent.setAction(Intent.ACTION_MAIN);
launchIntent.addCategory(Intent.CATEGORY_LAUNCHER);
- launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
- | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
+ if (targetTask == null) {
+ launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+ | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
+ } else {
+ launchIntent.addFlags(Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
+ }
// Only package name is set here, as opposed to component name, because intent action
// and category are ignored if component name is present while we are resolving intent.
launchIntent.setPackage(component.getPackageName());
@@ -170,15 +176,20 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub {
}
verifyActivityCanHandleIntentAndExported(launchIntent, component, callingUid, userId);
+ // Always show the cross profile animation
+ if (options == null) {
+ options = ActivityOptions.makeOpenCrossProfileAppsAnimation().toBundle();
+ } else {
+ options.putAll(ActivityOptions.makeOpenCrossProfileAppsAnimation().toBundle());
+ }
+
launchIntent.setPackage(null);
launchIntent.setComponent(component);
mInjector.getActivityTaskManagerInternal().startActivityAsUser(
caller, callingPackage, callingFeatureId, launchIntent,
- /* resultTo= */ null,
- Intent.FLAG_ACTIVITY_NEW_TASK,
- launchMainActivity
- ? ActivityOptions.makeOpenCrossProfileAppsAnimation().toBundle()
- : null,
+ targetTask,
+ /* startFlags= */ 0,
+ options,
userId);
}
@@ -225,6 +236,13 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub {
verifyActivityCanHandleIntent(launchIntent, callingUid, userId);
+ // Always show the cross profile animation
+ if (options == null) {
+ options = ActivityOptions.makeOpenCrossProfileAppsAnimation().toBundle();
+ } else {
+ options.putAll(ActivityOptions.makeOpenCrossProfileAppsAnimation().toBundle());
+ }
+
mInjector.getActivityTaskManagerInternal()
.startActivityAsUser(
caller,
diff --git a/services/core/java/com/android/server/pm/DeletePackageHelper.java b/services/core/java/com/android/server/pm/DeletePackageHelper.java
index 5b7cf2dc8559..0e1c1ad4120f 100644
--- a/services/core/java/com/android/server/pm/DeletePackageHelper.java
+++ b/services/core/java/com/android/server/pm/DeletePackageHelper.java
@@ -66,6 +66,8 @@ import com.android.server.pm.pkg.PackageStateInternal;
import com.android.server.pm.pkg.PackageUserState;
import com.android.server.wm.ActivityTaskManagerInternal;
+import dalvik.system.VMRuntime;
+
import java.util.Collections;
import java.util.List;
@@ -145,6 +147,7 @@ final class DeletePackageHelper {
final SparseArray<TempUserState> priorUserStates;
/** enabled state of the uninstalled application */
synchronized (mPm.mLock) {
+ final Computer computer = mPm.snapshotComputer();
uninstalledPs = mPm.mSettings.getPackageLPr(packageName);
if (uninstalledPs == null) {
Slog.w(TAG, "Not removing non-existent package " + packageName);
@@ -168,10 +171,10 @@ final class DeletePackageHelper {
if (pkg != null) {
SharedLibraryInfo libraryInfo = null;
if (pkg.getStaticSharedLibName() != null) {
- libraryInfo = mPm.getSharedLibraryInfo(pkg.getStaticSharedLibName(),
+ libraryInfo = computer.getSharedLibraryInfo(pkg.getStaticSharedLibName(),
pkg.getStaticSharedLibVersion());
} else if (pkg.getSdkLibName() != null) {
- libraryInfo = mPm.getSharedLibraryInfo(pkg.getSdkLibName(),
+ libraryInfo = computer.getSharedLibraryInfo(pkg.getSdkLibName(),
pkg.getSdkLibVersionMajor());
}
@@ -181,7 +184,7 @@ final class DeletePackageHelper {
continue;
}
List<VersionedPackage> libClientPackages =
- mPm.getPackagesUsingSharedLibrary(libraryInfo,
+ computer.getPackagesUsingSharedLibrary(libraryInfo,
MATCH_KNOWN_PACKAGES, Process.SYSTEM_UID, currUserId);
if (!ArrayUtils.isEmpty(libClientPackages)) {
Slog.w(TAG, "Not removing package " + pkg.getManifestPackageName()
@@ -241,12 +244,13 @@ final class DeletePackageHelper {
if (res) {
final boolean killApp = (deleteFlags & PackageManager.DELETE_DONT_KILL_APP) == 0;
info.sendPackageRemovedBroadcasts(killApp, removedBySystem);
- if (disabledSystemPs != null) {
- info.sendSystemPackageUpdatedBroadcasts(disabledSystemPs.getAppId());
- }
+ info.sendSystemPackageUpdatedBroadcasts();
}
- // Force a gc here.
- Runtime.getRuntime().gc();
+
+ // Force a gc to clear up things.
+ // Ask for a background one, it's fine to go on and not block here.
+ VMRuntime.getRuntime().requestConcurrentGC();
+
// Delete the resources here after sending the broadcast to let
// other processes clean up before deleting resources.
synchronized (mPm.mInstallLock) {
@@ -451,11 +455,11 @@ final class DeletePackageHelper {
if (affectedUserIds == null) {
affectedUserIds = mPm.resolveUserIds(userId);
}
+ final Computer snapshot = mPm.snapshotComputer();
for (final int affectedUserId : affectedUserIds) {
if (hadSuspendAppsPermission.get(affectedUserId)) {
- mPm.unsuspendForSuspendingPackage(mPm.snapshotComputer(), packageName,
- affectedUserId);
- mPm.removeAllDistractingPackageRestrictions(affectedUserId);
+ mPm.unsuspendForSuspendingPackage(snapshot, packageName, affectedUserId);
+ mPm.removeAllDistractingPackageRestrictions(snapshot, affectedUserId);
}
}
@@ -598,9 +602,6 @@ final class DeletePackageHelper {
if (outInfo != null) {
// Delete the updated package
outInfo.mIsRemovedPackageSystemUpdate = true;
- if (disabledPs.getAppId() != deletedPs.getAppId()) {
- outInfo.mNewAppId = disabledPs.getAppId();
- }
}
if (disabledPs.getVersionCode() < deletedPs.getVersionCode()
@@ -621,7 +622,8 @@ final class DeletePackageHelper {
final int callingUid = Binder.getCallingUid();
mPm.mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.DELETE_PACKAGES, null);
- final boolean canViewInstantApps = mPm.canViewInstantApps(callingUid, userId);
+ final Computer snapshot = mPm.snapshotComputer();
+ final boolean canViewInstantApps = snapshot.canViewInstantApps(callingUid, userId);
Preconditions.checkNotNull(versionedPackage);
Preconditions.checkNotNull(observer);
Preconditions.checkArgumentInRange(versionedPackage.getLongVersionCode(),
@@ -644,12 +646,13 @@ final class DeletePackageHelper {
}
// Normalize package name to handle renamed packages and static libs
- final String internalPackageName = mPm.resolveInternalPackageName(packageName, versionCode);
+ final String internalPackageName =
+ snapshot.resolveInternalPackageName(packageName, versionCode);
final int uid = Binder.getCallingUid();
- if (!isOrphaned(internalPackageName)
+ if (!isOrphaned(snapshot, internalPackageName)
&& !allowSilentUninstall
- && !isCallerAllowedToSilentlyUninstall(uid, internalPackageName)) {
+ && !isCallerAllowedToSilentlyUninstall(snapshot, uid, internalPackageName)) {
mPm.mHandler.post(() -> {
try {
final Intent intent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE);
@@ -680,7 +683,7 @@ final class DeletePackageHelper {
return;
}
- if (!deleteAllUsers && mPm.getBlockUninstallForUser(internalPackageName, userId)) {
+ if (!deleteAllUsers && snapshot.getBlockUninstallForUser(internalPackageName, userId)) {
mPm.mHandler.post(() -> {
try {
observer.onPackageDeleted(packageName,
@@ -700,11 +703,14 @@ final class DeletePackageHelper {
// Queue up an async operation since the package deletion may take a little while.
mPm.mHandler.post(() -> {
int returnCode;
- final PackageSetting ps = mPm.mSettings.getPackageLPr(internalPackageName);
+ final Computer innerSnapshot = mPm.snapshotComputer();
+ final PackageStateInternal packageState =
+ innerSnapshot.getPackageStateInternal(internalPackageName);
boolean doDeletePackage = true;
- if (ps != null) {
+ if (packageState != null) {
final boolean targetIsInstantApp =
- ps.getInstantApp(UserHandle.getUserId(callingUid));
+ packageState.getUserStateOrDefault(UserHandle.getUserId(callingUid))
+ .isInstantApp();
doDeletePackage = !targetIsInstantApp
|| canViewInstantApps;
}
@@ -713,7 +719,7 @@ final class DeletePackageHelper {
returnCode = deletePackageX(internalPackageName, versionCode,
userId, deleteFlags, false /*removedBySystem*/);
} else {
- int[] blockUninstallUserIds = getBlockUninstallForUsers(
+ int[] blockUninstallUserIds = getBlockUninstallForUsers(innerSnapshot,
internalPackageName, users);
// If nobody is blocking uninstall, proceed with delete for all users
if (ArrayUtils.isEmpty(blockUninstallUserIds)) {
@@ -752,51 +758,53 @@ final class DeletePackageHelper {
});
}
- private boolean isOrphaned(String packageName) {
- final PackageStateInternal packageState = mPm.getPackageStateInternal(packageName);
+ private boolean isOrphaned(@NonNull Computer snapshot, String packageName) {
+ final PackageStateInternal packageState = snapshot.getPackageStateInternal(packageName);
return packageState != null && packageState.getInstallSource().isOrphaned;
}
- private boolean isCallerAllowedToSilentlyUninstall(int callingUid, String pkgName) {
+ private boolean isCallerAllowedToSilentlyUninstall(@NonNull Computer snapshot, int callingUid,
+ String pkgName) {
if (callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID
|| UserHandle.getAppId(callingUid) == Process.SYSTEM_UID) {
return true;
}
final int callingUserId = UserHandle.getUserId(callingUid);
// If the caller installed the pkgName, then allow it to silently uninstall.
- if (callingUid == mPm.getPackageUid(
- mPm.getInstallerPackageName(pkgName), 0, callingUserId)) {
+ if (callingUid == snapshot.getPackageUid(snapshot.getInstallerPackageName(pkgName), 0,
+ callingUserId)) {
return true;
}
// Allow package verifier to silently uninstall.
- if (mPm.mRequiredVerifierPackage != null && callingUid == mPm.getPackageUid(
- mPm.mRequiredVerifierPackage, 0, callingUserId)) {
+ if (mPm.mRequiredVerifierPackage != null && callingUid == snapshot
+ .getPackageUid(mPm.mRequiredVerifierPackage, 0, callingUserId)) {
return true;
}
// Allow package uninstaller to silently uninstall.
- if (mPm.mRequiredUninstallerPackage != null && callingUid == mPm.getPackageUid(
- mPm.mRequiredUninstallerPackage, 0, callingUserId)) {
+ if (mPm.mRequiredUninstallerPackage != null && callingUid == snapshot
+ .getPackageUid(mPm.mRequiredUninstallerPackage, 0, callingUserId)) {
return true;
}
// Allow storage manager to silently uninstall.
- if (mPm.mStorageManagerPackage != null && callingUid == mPm.getPackageUid(
+ if (mPm.mStorageManagerPackage != null && callingUid == snapshot.getPackageUid(
mPm.mStorageManagerPackage, 0, callingUserId)) {
return true;
}
// Allow caller having MANAGE_PROFILE_AND_DEVICE_OWNERS permission to silently
// uninstall for device owner provisioning.
- return mPm.checkUidPermission(MANAGE_PROFILE_AND_DEVICE_OWNERS, callingUid)
+ return snapshot.checkUidPermission(MANAGE_PROFILE_AND_DEVICE_OWNERS, callingUid)
== PERMISSION_GRANTED;
}
- private int[] getBlockUninstallForUsers(String packageName, int[] userIds) {
+ private int[] getBlockUninstallForUsers(@NonNull Computer snapshot, String packageName,
+ int[] userIds) {
int[] result = EMPTY_INT_ARRAY;
for (int userId : userIds) {
- if (mPm.getBlockUninstallForUser(packageName, userId)) {
+ if (snapshot.getBlockUninstallForUser(packageName, userId)) {
result = ArrayUtils.appendInt(result, userId);
}
}
@@ -894,8 +902,8 @@ final class DeletePackageHelper {
int installedForUsersCount = 0;
synchronized (mPm.mLock) {
// Normalize package name to handle renamed packages and static libs
- final String internalPkgName = mPm.resolveInternalPackageName(packageName,
- versionCode);
+ final String internalPkgName = mPm.snapshotComputer()
+ .resolveInternalPackageName(packageName, versionCode);
final PackageSetting ps = mPm.mSettings.getPackageLPr(internalPkgName);
if (ps != null) {
int[] installedUsers = ps.queryInstalledUsers(mUserManagerInternal.getUserIds(),
diff --git a/services/core/java/com/android/server/pm/DexOptHelper.java b/services/core/java/com/android/server/pm/DexOptHelper.java
index c8326931f6fd..bb2ba5cc498d 100644
--- a/services/core/java/com/android/server/pm/DexOptHelper.java
+++ b/services/core/java/com/android/server/pm/DexOptHelper.java
@@ -266,8 +266,9 @@ final class DexOptHelper {
return;
}
+ final Computer snapshot = mPm.snapshotComputer();
List<PackageStateInternal> pkgSettings =
- getPackagesForDexopt(mPm.getPackageStates().values(), mPm);
+ getPackagesForDexopt(snapshot.getPackageStates().values(), mPm);
List<AndroidPackage> pkgs = new ArrayList<>(pkgSettings.size());
for (int index = 0; index < pkgSettings.size(); index++) {
@@ -282,17 +283,19 @@ final class DexOptHelper {
final int elapsedTimeSeconds =
(int) TimeUnit.NANOSECONDS.toSeconds(System.nanoTime() - startTime);
+ final Computer newSnapshot = mPm.snapshotComputer();
+
MetricsLogger.histogram(mPm.mContext, "opt_dialog_num_dexopted", stats[0]);
MetricsLogger.histogram(mPm.mContext, "opt_dialog_num_skipped", stats[1]);
MetricsLogger.histogram(mPm.mContext, "opt_dialog_num_failed", stats[2]);
- MetricsLogger.histogram(
- mPm.mContext, "opt_dialog_num_total", getOptimizablePackages().size());
+ MetricsLogger.histogram(mPm.mContext, "opt_dialog_num_total",
+ getOptimizablePackages(newSnapshot).size());
MetricsLogger.histogram(mPm.mContext, "opt_dialog_time_s", elapsedTimeSeconds);
}
- public ArraySet<String> getOptimizablePackages() {
- ArraySet<String> pkgs = new ArraySet<>();
- mPm.forEachPackageState(packageState -> {
+ public List<String> getOptimizablePackages(@NonNull Computer snapshot) {
+ ArrayList<String> pkgs = new ArrayList<>();
+ mPm.forEachPackageState(snapshot, packageState -> {
final AndroidPackage pkg = packageState.getPkg();
if (pkg != null && mPm.mPackageDexOptimizer.canOptimizePackage(pkg)) {
pkgs.add(packageState.getPackageName());
@@ -302,9 +305,10 @@ final class DexOptHelper {
}
/*package*/ boolean performDexOpt(DexoptOptions options) {
- if (mPm.getInstantAppPackageName(Binder.getCallingUid()) != null) {
+ final Computer snapshot = mPm.snapshotComputer();
+ if (snapshot.getInstantAppPackageName(Binder.getCallingUid()) != null) {
return false;
- } else if (mPm.isInstantApp(options.getPackageName(), UserHandle.getCallingUserId())) {
+ } else if (snapshot.isInstantApp(options.getPackageName(), UserHandle.getCallingUserId())) {
return false;
}
@@ -416,10 +420,10 @@ final class DexOptHelper {
mPm.getDexManager().getPackageUseInfoOrDefault(p.getPackageName()), options);
}
- public void forceDexOpt(String packageName) {
+ public void forceDexOpt(@NonNull Computer snapshot, String packageName) {
PackageManagerServiceUtils.enforceSystemOrRoot("forceDexOpt");
- final PackageStateInternal packageState = mPm.getPackageStateInternal(packageName);
+ final PackageStateInternal packageState = snapshot.getPackageStateInternal(packageName);
final AndroidPackage pkg = packageState == null ? null : packageState.getPkg();
if (packageState == null || pkg == null) {
throw new IllegalArgumentException("Unknown package: " + packageName);
@@ -484,19 +488,21 @@ final class DexOptHelper {
ArrayList<PackageStateInternal> sortTemp = new ArrayList<>(remainingPkgSettings.size());
+ final Computer snapshot = packageManagerService.snapshotComputer();
+
// Give priority to core apps.
- applyPackageFilter(pkgSetting -> pkgSetting.getPkg().isCoreApp(), result,
+ applyPackageFilter(snapshot, pkgSetting -> pkgSetting.getPkg().isCoreApp(), result,
remainingPkgSettings, sortTemp, packageManagerService);
// Give priority to system apps that listen for pre boot complete.
Intent intent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED);
final ArraySet<String> pkgNames = getPackageNamesForIntent(intent, UserHandle.USER_SYSTEM);
- applyPackageFilter(pkgSetting -> pkgNames.contains(pkgSetting.getPackageName()), result,
+ applyPackageFilter(snapshot, pkgSetting -> pkgNames.contains(pkgSetting.getPackageName()), result,
remainingPkgSettings, sortTemp, packageManagerService);
// Give priority to apps used by other apps.
DexManager dexManager = packageManagerService.getDexManager();
- applyPackageFilter(pkgSetting ->
+ applyPackageFilter(snapshot, pkgSetting ->
dexManager.getPackageUseInfoOrDefault(pkgSetting.getPackageName())
.isAnyCodePathUsedByOtherApps(),
result, remainingPkgSettings, sortTemp, packageManagerService);
@@ -534,7 +540,7 @@ final class DexOptHelper {
// No historical info. Take all.
remainingPredicate = pkgSetting -> true;
}
- applyPackageFilter(remainingPredicate, result, remainingPkgSettings, sortTemp,
+ applyPackageFilter(snapshot, remainingPredicate, result, remainingPkgSettings, sortTemp,
packageManagerService);
if (debug) {
@@ -549,7 +555,7 @@ final class DexOptHelper {
// package will be removed from {@code packages} and added to {@code result} with its
// dependencies. If usage data is available, the positive packages will be sorted by usage
// data (with {@code sortTemp} as temporary storage).
- private static void applyPackageFilter(
+ private static void applyPackageFilter(@NonNull Computer snapshot,
Predicate<PackageStateInternal> filter,
Collection<PackageStateInternal> result,
Collection<PackageStateInternal> packages,
@@ -567,8 +573,7 @@ final class DexOptHelper {
for (PackageStateInternal pkgSetting : sortTemp) {
result.add(pkgSetting);
- List<PackageStateInternal> deps =
- packageManagerService.findSharedNonSystemLibraries(pkgSetting);
+ List<PackageStateInternal> deps = snapshot.findSharedNonSystemLibraries(pkgSetting);
if (!deps.isEmpty()) {
deps.removeAll(result);
result.addAll(deps);
diff --git a/services/core/java/com/android/server/pm/DomainVerificationConnection.java b/services/core/java/com/android/server/pm/DomainVerificationConnection.java
index db8c6dc60b5e..20e4dd8a995b 100644
--- a/services/core/java/com/android/server/pm/DomainVerificationConnection.java
+++ b/services/core/java/com/android/server/pm/DomainVerificationConnection.java
@@ -21,7 +21,6 @@ import static com.android.server.pm.PackageManagerService.DOMAIN_VERIFICATION;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
-import android.content.pm.PackageManagerInternal;
import android.os.Binder;
import android.os.Message;
import android.os.UserHandle;
@@ -35,13 +34,10 @@ import com.android.server.pm.verify.domain.proxy.DomainVerificationProxyV2;
public final class DomainVerificationConnection implements DomainVerificationService.Connection,
DomainVerificationProxyV1.Connection, DomainVerificationProxyV2.Connection {
final PackageManagerService mPm;
- final PackageManagerInternal mPmInternal;
final UserManagerInternal mUmInternal;
- // TODO(b/198166813): remove PMS dependency
DomainVerificationConnection(PackageManagerService pm) {
mPm = pm;
- mPmInternal = mPm.mInjector.getLocalService(PackageManagerInternal.class);
mUmInternal = mPm.mInjector.getLocalService(UserManagerInternal.class);
}
@@ -82,18 +78,18 @@ public final class DomainVerificationConnection implements DomainVerificationSer
@Override
public boolean isCallerPackage(int callingUid, @NonNull String packageName) {
final int callingUserId = UserHandle.getUserId(callingUid);
- return callingUid == mPmInternal.getPackageUid(packageName, 0, callingUserId);
+ return callingUid == mPm.snapshotComputer().getPackageUid(packageName, 0, callingUserId);
}
@Nullable
@Override
public AndroidPackage getPackage(@NonNull String packageName) {
- return mPmInternal.getPackage(packageName);
+ return mPm.snapshotComputer().getPackage(packageName);
}
@Override
public boolean filterAppAccess(String packageName, int callingUid, int userId) {
- return mPmInternal.filterAppAccess(packageName, callingUid, userId);
+ return mPm.snapshotComputer().filterAppAccess(packageName, callingUid, userId);
}
@Override
@@ -108,6 +104,6 @@ public final class DomainVerificationConnection implements DomainVerificationSer
@NonNull
public Computer snapshot() {
- return (Computer) mPmInternal.snapshot();
+ return mPm.snapshotComputer();
}
}
diff --git a/services/core/java/com/android/server/pm/DumpHelper.java b/services/core/java/com/android/server/pm/DumpHelper.java
index 2b46ed404945..f83ef5aea23a 100644
--- a/services/core/java/com/android/server/pm/DumpHelper.java
+++ b/services/core/java/com/android/server/pm/DumpHelper.java
@@ -55,6 +55,7 @@ final class DumpHelper {
@NeverCompile // Avoid size overhead of debugging code.
public void doDump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ final Computer snapshot = mPm.snapshotComputer();
DumpState dumpState = new DumpState();
ArraySet<String> permissionNames = null;
@@ -121,7 +122,7 @@ final class DumpHelper {
}
// Normalize package name to handle renamed packages and static libs
- pkg = mPm.resolveInternalPackageName(pkg, PackageManager.VERSION_CODE_HIGHEST);
+ pkg = snapshot.resolveInternalPackageName(pkg, PackageManager.VERSION_CODE_HIGHEST);
pw.println(mPm.checkPermission(perm, pkg, user));
return;
@@ -243,7 +244,7 @@ final class DumpHelper {
// Return if the package doesn't exist.
if (packageName != null
- && mPm.getPackageStateInternal(packageName) == null
+ && snapshot.getPackageStateInternal(packageName) == null
&& !mPm.mApexManager.isApexPackage(packageName)) {
pw.println("Unable to find package: " + packageName);
return;
@@ -257,7 +258,7 @@ final class DumpHelper {
if (!checkin
&& dumpState.isDumping(DumpState.DUMP_VERSION)
&& packageName == null) {
- mPm.dumpComputer(DumpState.DUMP_VERSION, fd, pw, dumpState);
+ snapshot.dump(DumpState.DUMP_VERSION, fd, pw, dumpState);
}
if (!checkin
@@ -273,7 +274,7 @@ final class DumpHelper {
final String knownPackage = PackageManagerInternal.knownPackageToString(i);
ipw.print(knownPackage);
ipw.println(":");
- final String[] pkgNames = mPm.getKnownPackageNamesInternal(i,
+ final String[] pkgNames = mPm.getKnownPackageNamesInternal(snapshot, i,
UserHandle.USER_SYSTEM);
ipw.increaseIndent();
if (ArrayUtils.isEmpty(pkgNames)) {
@@ -299,14 +300,14 @@ final class DumpHelper {
pw.print(" Required: ");
pw.print(requiredVerifierPackage);
pw.print(" (uid=");
- pw.print(mPm.getPackageUid(requiredVerifierPackage, MATCH_DEBUG_TRIAGED_MISSING,
- UserHandle.USER_SYSTEM));
+ pw.print(snapshot.getPackageUid(requiredVerifierPackage,
+ MATCH_DEBUG_TRIAGED_MISSING, UserHandle.USER_SYSTEM));
pw.println(")");
} else if (requiredVerifierPackage != null) {
pw.print("vrfy,"); pw.print(requiredVerifierPackage);
pw.print(",");
- pw.println(mPm.getPackageUid(requiredVerifierPackage, MATCH_DEBUG_TRIAGED_MISSING,
- UserHandle.USER_SYSTEM));
+ pw.println(snapshot.getPackageUid(requiredVerifierPackage,
+ MATCH_DEBUG_TRIAGED_MISSING, UserHandle.USER_SYSTEM));
}
}
@@ -324,14 +325,14 @@ final class DumpHelper {
pw.print(" Using: ");
pw.print(verifierPackageName);
pw.print(" (uid=");
- pw.print(mPm.getPackageUid(verifierPackageName, MATCH_DEBUG_TRIAGED_MISSING,
- UserHandle.USER_SYSTEM));
+ pw.print(snapshot.getPackageUid(verifierPackageName,
+ MATCH_DEBUG_TRIAGED_MISSING, UserHandle.USER_SYSTEM));
pw.println(")");
} else if (verifierPackageName != null) {
pw.print("dv,"); pw.print(verifierPackageName);
pw.print(",");
- pw.println(mPm.getPackageUid(verifierPackageName, MATCH_DEBUG_TRIAGED_MISSING,
- UserHandle.USER_SYSTEM));
+ pw.println(snapshot.getPackageUid(verifierPackageName,
+ MATCH_DEBUG_TRIAGED_MISSING, UserHandle.USER_SYSTEM));
}
} else {
pw.println();
@@ -341,7 +342,7 @@ final class DumpHelper {
if (dumpState.isDumping(DumpState.DUMP_LIBS)
&& packageName == null) {
- mPm.dumpComputer(DumpState.DUMP_LIBS, fd, pw, dumpState);
+ snapshot.dump(DumpState.DUMP_LIBS, fd, pw, dumpState);
}
if (dumpState.isDumping(DumpState.DUMP_FEATURES)
@@ -387,17 +388,17 @@ final class DumpHelper {
}
if (!checkin && dumpState.isDumping(DumpState.DUMP_PREFERRED)) {
- mPm.dumpComputer(DumpState.DUMP_PREFERRED, fd, pw, dumpState);
+ snapshot.dump(DumpState.DUMP_PREFERRED, fd, pw, dumpState);
}
if (!checkin
&& dumpState.isDumping(DumpState.DUMP_PREFERRED_XML)
&& packageName == null) {
- mPm.dumpComputer(DumpState.DUMP_PREFERRED_XML, fd, pw, dumpState);
+ snapshot.dump(DumpState.DUMP_PREFERRED_XML, fd, pw, dumpState);
}
if (!checkin && dumpState.isDumping(DumpState.DUMP_DOMAIN_PREFERRED)) {
- mPm.dumpComputer(DumpState.DUMP_DOMAIN_PREFERRED, fd, pw, dumpState);
+ snapshot.dump(DumpState.DUMP_DOMAIN_PREFERRED, fd, pw, dumpState);
}
if (!checkin && dumpState.isDumping(DumpState.DUMP_PERMISSIONS)) {
@@ -405,7 +406,7 @@ final class DumpHelper {
}
if (!checkin && dumpState.isDumping(DumpState.DUMP_PROVIDERS)) {
- mPm.mComponentResolver.dumpContentProviders(mPm.snapshotComputer(), pw, dumpState,
+ mPm.mComponentResolver.dumpContentProviders(snapshot, pw, dumpState,
packageName);
}
@@ -427,7 +428,7 @@ final class DumpHelper {
if (!checkin
&& dumpState.isDumping(DumpState.DUMP_QUERIES)) {
- mPm.dumpComputer(DumpState.DUMP_QUERIES, fd, pw, dumpState);
+ snapshot.dump(DumpState.DUMP_QUERIES, fd, pw, dumpState);
}
if (dumpState.isDumping(DumpState.DUMP_SHARED_USERS)) {
@@ -527,12 +528,12 @@ final class DumpHelper {
if (!checkin
&& dumpState.isDumping(DumpState.DUMP_DEXOPT)) {
- mPm.dumpComputer(DumpState.DUMP_DEXOPT, fd, pw, dumpState);
+ snapshot.dump(DumpState.DUMP_DEXOPT, fd, pw, dumpState);
}
if (!checkin
&& dumpState.isDumping(DumpState.DUMP_COMPILER_STATS)) {
- mPm.dumpComputer(DumpState.DUMP_COMPILER_STATS, fd, pw, dumpState);
+ snapshot.dump(DumpState.DUMP_COMPILER_STATS, fd, pw, dumpState);
}
if (dumpState.isDumping(DumpState.DUMP_MESSAGES)
@@ -579,7 +580,7 @@ final class DumpHelper {
pw.println(" Known digesters list flag: "
+ PackageManagerService.getKnownDigestersList());
- PerUidReadTimeouts[] items = mPm.getPerUidReadTimeouts();
+ PerUidReadTimeouts[] items = mPm.getPerUidReadTimeouts(snapshot);
pw.println(" Timeouts (" + items.length + "):");
for (PerUidReadTimeouts item : items) {
pw.print(" (");
@@ -661,13 +662,14 @@ final class DumpHelper {
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);
proto.write(
PackageServiceDumpProto.PackageShortProto.UID,
- mPm.getPackageUid(
+ snapshot.getPackageUid(
mPm.mRequiredVerifierPackage,
MATCH_DEBUG_TRIAGED_MISSING,
UserHandle.USER_SYSTEM));
@@ -682,7 +684,7 @@ final class DumpHelper {
proto.write(PackageServiceDumpProto.PackageShortProto.NAME, verifierPackageName);
proto.write(
PackageServiceDumpProto.PackageShortProto.UID,
- mPm.getPackageUid(
+ snapshot.getPackageUid(
verifierPackageName,
MATCH_DEBUG_TRIAGED_MISSING,
UserHandle.USER_SYSTEM));
diff --git a/services/core/java/com/android/server/pm/DynamicCodeLoggingService.java b/services/core/java/com/android/server/pm/DynamicCodeLoggingService.java
index c65c2b112706..b4bcd5b3308c 100644
--- a/services/core/java/com/android/server/pm/DynamicCodeLoggingService.java
+++ b/services/core/java/com/android/server/pm/DynamicCodeLoggingService.java
@@ -22,11 +22,12 @@ import android.app.job.JobScheduler;
import android.app.job.JobService;
import android.content.ComponentName;
import android.content.Context;
+import android.content.pm.PackageManagerInternal;
import android.os.Process;
-import android.os.ServiceManager;
import android.util.EventLog;
import android.util.Log;
+import com.android.server.LocalServices;
import com.android.server.pm.dex.DynamicCodeLogger;
import libcore.util.HexEncoding;
@@ -133,8 +134,7 @@ public class DynamicCodeLoggingService extends JobService {
}
private static DynamicCodeLogger getDynamicCodeLogger() {
- PackageManagerService pm = (PackageManagerService) ServiceManager.getService("package");
- return pm.getDexManager().getDynamicCodeLogger();
+ return LocalServices.getService(PackageManagerInternal.class).getDynamicCodeLogger();
}
private class IdleLoggingThread extends Thread {
diff --git a/services/core/java/com/android/server/pm/IPackageManagerBase.java b/services/core/java/com/android/server/pm/IPackageManagerBase.java
new file mode 100644
index 000000000000..e1aee6d747f4
--- /dev/null
+++ b/services/core/java/com/android/server/pm/IPackageManagerBase.java
@@ -0,0 +1,1189 @@
+/*
+ * 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.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SuppressLint;
+import android.annotation.UserIdInt;
+import android.app.role.RoleManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.IPackageDeleteObserver;
+import android.content.pm.IPackageDeleteObserver2;
+import android.content.pm.IPackageInstaller;
+import android.content.pm.IPackageManager;
+import android.content.pm.IPackageStatsObserver;
+import android.content.pm.InstallSourceInfo;
+import android.content.pm.InstrumentationInfo;
+import android.content.pm.IntentFilterVerificationInfo;
+import android.content.pm.KeySet;
+import android.content.pm.ModuleInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ParceledListSlice;
+import android.content.pm.PermissionGroupInfo;
+import android.content.pm.PermissionInfo;
+import android.content.pm.ProviderInfo;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.content.pm.SharedLibraryInfo;
+import android.content.pm.VersionedPackage;
+import android.content.pm.dex.IArtManager;
+import android.os.Binder;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.Trace;
+import android.os.UserHandle;
+import android.permission.PermissionManager;
+
+import com.android.internal.R;
+import com.android.internal.content.InstallLocationUtils;
+import com.android.internal.util.CollectionUtils;
+import com.android.server.pm.pkg.PackageStateInternal;
+import com.android.server.pm.verify.domain.DomainVerificationManagerInternal;
+import com.android.server.pm.verify.domain.proxy.DomainVerificationProxyV1;
+
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Contains all simply proxy methods which need a snapshot instance and just calls a method on it,
+ * with no additional logic. Separated with all methods marked final and deprecated to prevent their
+ * use from other methods which may need a snapshot for non-trivial reasons.
+ */
+public abstract class IPackageManagerBase extends IPackageManager.Stub {
+
+ @NonNull
+ private final PackageManagerService mService;
+
+ @NonNull
+ private final Context mContext;
+
+ @NonNull private final DexOptHelper mDexOptHelper;
+ @NonNull private final ModuleInfoProvider mModuleInfoProvider;
+ @NonNull private final PreferredActivityHelper mPreferredActivityHelper;
+ @NonNull private final ResolveIntentHelper mResolveIntentHelper;
+
+ @NonNull
+ private final DomainVerificationManagerInternal mDomainVerificationManager;
+
+ @NonNull
+ private final DomainVerificationConnection mDomainVerificationConnection;
+
+ @NonNull
+ private final PackageInstallerService mInstallerService;
+
+ @NonNull
+ private final PackageProperty mPackageProperty;
+
+ @NonNull
+ private final ComponentName mResolveComponentName;
+
+ @Nullable
+ private final ComponentName mInstantAppResolverSettingsComponent;
+
+ @NonNull
+ private final String mRequiredSupplementalProcessPackage;
+
+ @Nullable
+ private final String mServicesExtensionPackageName;
+
+ @Nullable
+ private final String mSharedSystemSharedLibraryPackageName;
+
+ public IPackageManagerBase(@NonNull PackageManagerService service, @NonNull Context context,
+ @NonNull DexOptHelper dexOptHelper, @NonNull ModuleInfoProvider moduleInfoProvider,
+ @NonNull PreferredActivityHelper preferredActivityHelper,
+ @NonNull ResolveIntentHelper resolveIntentHelper,
+ @NonNull DomainVerificationManagerInternal domainVerificationManager,
+ @NonNull DomainVerificationConnection domainVerificationConnection,
+ @NonNull PackageInstallerService installerService,
+ @NonNull PackageProperty packageProperty, @NonNull ComponentName resolveComponentName,
+ @Nullable ComponentName instantAppResolverSettingsComponent,
+ @NonNull String requiredSupplementalProcessPackage,
+ @Nullable String servicesExtensionPackageName,
+ @Nullable String sharedSystemSharedLibraryPackageName) {
+ mService = service;
+ mContext = context;
+ mDexOptHelper = dexOptHelper;
+ mModuleInfoProvider = moduleInfoProvider;
+ mPreferredActivityHelper = preferredActivityHelper;
+ mResolveIntentHelper = resolveIntentHelper;
+ mDomainVerificationManager = domainVerificationManager;
+ mDomainVerificationConnection = domainVerificationConnection;
+ mInstallerService = installerService;
+ mPackageProperty = packageProperty;
+ mResolveComponentName = resolveComponentName;
+ mInstantAppResolverSettingsComponent = instantAppResolverSettingsComponent;
+ mRequiredSupplementalProcessPackage = requiredSupplementalProcessPackage;
+ mServicesExtensionPackageName = servicesExtensionPackageName;
+ mSharedSystemSharedLibraryPackageName = sharedSystemSharedLibraryPackageName;
+ }
+
+ protected Computer snapshot() {
+ return mService.snapshotComputer();
+ }
+
+ @Override
+ @Deprecated
+ public final boolean activitySupportsIntent(ComponentName component, Intent intent,
+ String resolvedType) {
+ return snapshot().activitySupportsIntent(mResolveComponentName, component, intent,
+ resolvedType);
+ }
+
+ @Override
+ @Deprecated
+ public final void addCrossProfileIntentFilter(IntentFilter intentFilter, String ownerPackage,
+ int sourceUserId, int targetUserId, int flags) {
+ mService.addCrossProfileIntentFilter(snapshot(),
+ new WatchedIntentFilter(intentFilter), ownerPackage, sourceUserId, targetUserId,
+ flags);
+ }
+
+ // NOTE: Can't remove due to unsupported app usage
+ @Override
+ @Deprecated
+ public final boolean addPermission(PermissionInfo info) {
+ // Because this is accessed via the package manager service AIDL,
+ // go through the permission manager service AIDL
+ return mContext.getSystemService(PermissionManager.class).addPermission(info, false);
+ }
+
+ // NOTE: Can't remove due to unsupported app usage
+ @Override
+ @Deprecated
+ public final boolean addPermissionAsync(PermissionInfo info) {
+ // Because this is accessed via the package manager service AIDL,
+ // go through the permission manager service AIDL
+ return mContext.getSystemService(PermissionManager.class).addPermission(info, true);
+ }
+
+ @Override
+ @Deprecated
+ public final void addPersistentPreferredActivity(IntentFilter filter, ComponentName activity,
+ int userId) {
+ mPreferredActivityHelper.addPersistentPreferredActivity(new WatchedIntentFilter(filter),
+ activity, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final void addPreferredActivity(IntentFilter filter, int match,
+ ComponentName[] set, ComponentName activity, int userId, boolean removeExisting) {
+ mPreferredActivityHelper.addPreferredActivity(snapshot(),
+ new WatchedIntentFilter(filter), match, set, activity, true, userId,
+ "Adding preferred", removeExisting);
+ }
+
+ /*
+ * Returns if intent can be forwarded from the sourceUserId to the targetUserId
+ */
+ @Override
+ @Deprecated
+ public final boolean canForwardTo(@NonNull Intent intent, @Nullable String resolvedType,
+ @UserIdInt int sourceUserId, @UserIdInt int targetUserId) {
+ return snapshot().canForwardTo(intent, resolvedType, sourceUserId, targetUserId);
+ }
+
+ @Override
+ @Deprecated
+ public final boolean canRequestPackageInstalls(String packageName, int userId) {
+ return snapshot().canRequestPackageInstalls(packageName, Binder.getCallingUid(), userId,
+ true /* throwIfPermNotDeclared*/);
+ }
+
+ @Override
+ @Deprecated
+ public final String[] canonicalToCurrentPackageNames(String[] names) {
+ return snapshot().canonicalToCurrentPackageNames(names);
+ }
+
+ // NOTE: Can't remove due to unsupported app usage
+ @Override
+ @Deprecated
+ public final int checkPermission(String permName, String pkgName, int userId) {
+ return mService.checkPermission(permName, pkgName, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final int checkSignatures(@NonNull String pkg1, @NonNull String pkg2) {
+ return snapshot().checkSignatures(pkg1, pkg2);
+ }
+
+ @Override
+ @Deprecated
+ public final int checkUidPermission(String permName, int uid) {
+ return snapshot().checkUidPermission(permName, uid);
+ }
+
+ @Override
+ @Deprecated
+ public final int checkUidSignatures(int uid1, int uid2) {
+ return snapshot().checkUidSignatures(uid1, uid2);
+ }
+
+ @Override
+ @Deprecated
+ public final void clearPackagePersistentPreferredActivities(String packageName, int userId) {
+ mPreferredActivityHelper.clearPackagePersistentPreferredActivities(packageName, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final void clearPackagePreferredActivities(String packageName) {
+ mPreferredActivityHelper.clearPackagePreferredActivities(snapshot(),
+ packageName);
+ }
+
+ @Override
+ @Deprecated
+ public final String[] currentToCanonicalPackageNames(String[] names) {
+ return snapshot().currentToCanonicalPackageNames(names);
+ }
+
+ @Override
+ @Deprecated
+ public final void deleteExistingPackageAsUser(VersionedPackage versionedPackage,
+ final IPackageDeleteObserver2 observer, final int userId) {
+ mService.deleteExistingPackageAsUser(versionedPackage, observer, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final void deletePackageAsUser(String packageName, int versionCode,
+ IPackageDeleteObserver observer, int userId, int flags) {
+ deletePackageVersioned(new VersionedPackage(packageName, versionCode),
+ new PackageManager.LegacyPackageDeleteObserver(observer).getBinder(), userId,
+ flags);
+ }
+
+ @Override
+ @Deprecated
+ public final void deletePackageVersioned(VersionedPackage versionedPackage,
+ final IPackageDeleteObserver2 observer, final int userId, final int deleteFlags) {
+ mService.deletePackageVersioned(versionedPackage, observer, userId, deleteFlags);
+ }
+
+ @Override
+ @Deprecated
+ public final ResolveInfo findPersistentPreferredActivity(Intent intent, int userId) {
+ return mPreferredActivityHelper.findPersistentPreferredActivity(snapshot(), intent, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final void forceDexOpt(String packageName) {
+ mDexOptHelper.forceDexOpt(snapshot(), packageName);
+ }
+
+ @Override
+ @Deprecated
+ public final ActivityInfo getActivityInfo(ComponentName component,
+ @PackageManager.ComponentInfoFlagsBits long flags, int userId) {
+ return snapshot().getActivityInfo(component, flags, userId);
+ }
+
+ @NonNull
+ @Override
+ @Deprecated
+ public final ParceledListSlice<IntentFilter> getAllIntentFilters(@NonNull String packageName) {
+ return snapshot().getAllIntentFilters(packageName);
+ }
+
+ @Override
+ @Deprecated
+ public final List<String> getAllPackages() {
+ return snapshot().getAllPackages();
+ }
+
+ // NOTE: Can't remove due to unsupported app usage
+ @NonNull
+ @Override
+ @Deprecated
+ public final String[] getAppOpPermissionPackages(@NonNull String permissionName) {
+ return snapshot().getAppOpPermissionPackages(permissionName);
+ }
+
+ @Override
+ @Deprecated
+ public final String getAppPredictionServicePackageName() {
+ return mService.mAppPredictionServicePackage;
+ }
+
+ @PackageManager.EnabledState
+ @Override
+ @Deprecated
+ public final int getApplicationEnabledSetting(@NonNull String packageName,
+ @UserIdInt int userId) {
+ return snapshot().getApplicationEnabledSetting(packageName, userId);
+ }
+
+ /**
+ * Returns true if application is not found or there was an error. Otherwise it returns the
+ * hidden state of the package for the given user.
+ */
+ @Override
+ @Deprecated
+ public final boolean getApplicationHiddenSettingAsUser(@NonNull String packageName,
+ @UserIdInt int userId) {
+ return snapshot().getApplicationHiddenSettingAsUser(packageName, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final ApplicationInfo getApplicationInfo(String packageName,
+ @PackageManager.ApplicationInfoFlagsBits long flags, int userId) {
+ return snapshot().getApplicationInfo(packageName, flags, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final IArtManager getArtManager() {
+ return mService.mArtManagerService;
+ }
+
+ @Override
+ @Deprecated
+ public final @Nullable
+ String getAttentionServicePackageName() {
+ return mService.ensureSystemPackageName(snapshot(),
+ mService.getPackageFromComponentString(R.string.config_defaultAttentionService));
+ }
+
+ @Override
+ @Deprecated
+ public final boolean getBlockUninstallForUser(@NonNull String packageName,
+ @UserIdInt int userId) {
+ return snapshot().getBlockUninstallForUser(packageName, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final int getComponentEnabledSetting(@NonNull ComponentName component, int userId) {
+ return snapshot().getComponentEnabledSetting(component, Binder.getCallingUid(), userId);
+ }
+
+ @Override
+ @Deprecated
+ public final String getContentCaptureServicePackageName() {
+ return mService.ensureSystemPackageName(snapshot(),
+ mService.getPackageFromComponentString(
+ R.string.config_defaultContentCaptureService));
+ }
+
+ @Nullable
+ @Override
+ @Deprecated
+ public final ParceledListSlice<SharedLibraryInfo> getDeclaredSharedLibraries(
+ @NonNull String packageName, @PackageManager.PackageInfoFlagsBits long flags,
+ @NonNull int userId) {
+ return snapshot().getDeclaredSharedLibraries(packageName, flags, userId);
+ }
+
+ /**
+ * Non-Binder method, support for the backup/restore mechanism: write the default browser (etc)
+ * settings in its canonical XML format. Returns the default browser XML representation as a
+ * byte array, or null if there is none.
+ */
+ @Override
+ @Deprecated
+ public final byte[] getDefaultAppsBackup(int userId) {
+ return mPreferredActivityHelper.getDefaultAppsBackup(userId);
+ }
+
+ @Override
+ @Deprecated
+ public final String getDefaultTextClassifierPackageName() {
+ return mService.mDefaultTextClassifierPackage;
+ }
+
+ @Override
+ @Deprecated
+ public final int getFlagsForUid(int uid) {
+ return snapshot().getFlagsForUid(uid);
+ }
+
+ @Nullable
+ @Override
+ @Deprecated
+ public final CharSequence getHarmfulAppWarning(@NonNull String packageName,
+ @UserIdInt int userId) {
+ return snapshot().getHarmfulAppWarning(packageName, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final ComponentName getHomeActivities(List<ResolveInfo> allHomeCandidates) {
+ final Computer snapshot = snapshot();
+ if (snapshot.getInstantAppPackageName(Binder.getCallingUid()) != null) {
+ return null;
+ }
+ return snapshot.getHomeActivitiesAsUser(allHomeCandidates,
+ UserHandle.getCallingUserId());
+ }
+
+ @Deprecated
+ public final String getIncidentReportApproverPackageName() {
+ return mService.mIncidentReportApproverPackage;
+ }
+
+ @Override
+ @Deprecated
+ public final int getInstallLocation() {
+ // allow instant app access
+ return android.provider.Settings.Global.getInt(mContext.getContentResolver(),
+ android.provider.Settings.Global.DEFAULT_INSTALL_LOCATION,
+ InstallLocationUtils.APP_INSTALL_AUTO);
+ }
+
+ @PackageManager.InstallReason
+ @Override
+ @Deprecated
+ public final int getInstallReason(@NonNull String packageName, @UserIdInt int userId) {
+ return snapshot().getInstallReason(packageName, userId);
+ }
+
+ @Override
+ @Nullable
+ @Deprecated
+ public final InstallSourceInfo getInstallSourceInfo(@NonNull String packageName) {
+ return snapshot().getInstallSourceInfo(packageName);
+ }
+
+ @Override
+ @Deprecated
+ public final ParceledListSlice<ApplicationInfo> getInstalledApplications(
+ @PackageManager.ApplicationInfoFlagsBits long flags, int userId) {
+ final int callingUid = Binder.getCallingUid();
+ return new ParceledListSlice<>(
+ snapshot().getInstalledApplications(flags, userId, callingUid));
+ }
+
+ @Override
+ @Deprecated
+ public final List<ModuleInfo> getInstalledModules(int flags) {
+ return mModuleInfoProvider.getInstalledModules(flags);
+ }
+
+ @Override
+ @Deprecated
+ public final ParceledListSlice<PackageInfo> getInstalledPackages(
+ @PackageManager.PackageInfoFlagsBits long flags, int userId) {
+ return snapshot().getInstalledPackages(flags, userId);
+ }
+
+ @Nullable
+ @Override
+ @Deprecated
+ public final String getInstallerPackageName(@NonNull String packageName) {
+ return snapshot().getInstallerPackageName(packageName);
+ }
+
+ @Override
+ @Deprecated
+ public final ComponentName getInstantAppInstallerComponent() {
+ final Computer snapshot = snapshot();
+ if (snapshot.getInstantAppPackageName(Binder.getCallingUid()) != null) {
+ return null;
+ }
+ return snapshot.getInstantAppInstallerComponent();
+ }
+
+ @Override
+ @Deprecated
+ public final @Nullable
+ ComponentName getInstantAppResolverComponent() {
+ final Computer snapshot = snapshot();
+ if (snapshot.getInstantAppPackageName(Binder.getCallingUid()) != null) {
+ return null;
+ }
+ return mService.getInstantAppResolver(snapshot);
+ }
+
+ @Override
+ @Deprecated
+ public final ComponentName getInstantAppResolverSettingsComponent() {
+ return mInstantAppResolverSettingsComponent;
+ }
+
+ @Nullable
+ @Override
+ @Deprecated
+ public final InstrumentationInfo getInstrumentationInfo(@NonNull ComponentName component,
+ int flags) {
+ return snapshot().getInstrumentationInfo(component, flags);
+ }
+
+ @Override
+ @Deprecated
+ public final @NonNull
+ ParceledListSlice<IntentFilterVerificationInfo>
+ getIntentFilterVerifications(String packageName) {
+ return ParceledListSlice.emptyList();
+ }
+
+ @Override
+ @Deprecated
+ public final int getIntentVerificationStatus(String packageName, int userId) {
+ return mDomainVerificationManager.getLegacyState(packageName, userId);
+ }
+
+ @Nullable
+ @Override
+ @Deprecated
+ public final KeySet getKeySetByAlias(@NonNull String packageName, @NonNull String alias) {
+ return snapshot().getKeySetByAlias(packageName, alias);
+ }
+
+ @Override
+ @Deprecated
+ public final ModuleInfo getModuleInfo(String packageName,
+ @PackageManager.ModuleInfoFlags int flags) {
+ return mModuleInfoProvider.getModuleInfo(packageName, flags);
+ }
+
+ @Nullable
+ @Override
+ @Deprecated
+ public final String getNameForUid(int uid) {
+ return snapshot().getNameForUid(uid);
+ }
+
+ @Nullable
+ @Override
+ @Deprecated
+ public final String[] getNamesForUids(@NonNull int[] uids) {
+ return snapshot().getNamesForUids(uids);
+ }
+
+ @Override
+ @Deprecated
+ public final int[] getPackageGids(String packageName,
+ @PackageManager.PackageInfoFlagsBits long flags, int userId) {
+ return snapshot().getPackageGids(packageName, flags, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final PackageInfo getPackageInfo(String packageName,
+ @PackageManager.PackageInfoFlagsBits long flags, int userId) {
+ return snapshot().getPackageInfo(packageName, flags, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final PackageInfo getPackageInfoVersioned(VersionedPackage versionedPackage,
+ @PackageManager.PackageInfoFlagsBits long flags, int userId) {
+ return snapshot().getPackageInfoInternal(versionedPackage.getPackageName(),
+ versionedPackage.getLongVersionCode(), flags, Binder.getCallingUid(), userId);
+ }
+
+ @Override
+ @Deprecated
+ public final IPackageInstaller getPackageInstaller() {
+ // Return installer service for internal calls.
+ if (PackageManagerServiceUtils.isSystemOrRoot()) {
+ return mInstallerService;
+ }
+ final Computer snapshot = snapshot();
+ // Return null for InstantApps.
+ if (snapshot.getInstantAppPackageName(Binder.getCallingUid()) != null) {
+ return null;
+ }
+ return mInstallerService;
+ }
+
+ @Override
+ @Deprecated
+ public final void getPackageSizeInfo(final String packageName, int userId,
+ final IPackageStatsObserver observer) {
+ throw new UnsupportedOperationException(
+ "Shame on you for calling the hidden API getPackageSizeInfo(). Shame!");
+ }
+
+ @Override
+ @Deprecated
+ public final int getPackageUid(@NonNull String packageName,
+ @PackageManager.PackageInfoFlagsBits long flags, @UserIdInt int userId) {
+ return snapshot().getPackageUid(packageName, flags, userId);
+ }
+
+ /**
+ * <em>IMPORTANT:</em> Not all packages returned by this method may be known
+ * to the system. There are two conditions in which this may occur:
+ * <ol>
+ * <li>The package is on adoptable storage and the device has been removed</li>
+ * <li>The package is being removed and the internal structures are partially updated</li>
+ * </ol>
+ * The second is an artifact of the current data structures and should be fixed. See
+ * b/111075456 for one such instance.
+ * This binder API is cached. If the algorithm in this method changes,
+ * or if the underlying objecs (as returned by getSettingLPr()) change
+ * then the logic that invalidates the cache must be revisited. See
+ * calls to invalidateGetPackagesForUidCache() to locate the points at
+ * which the cache is invalidated.
+ */
+ @Override
+ @Deprecated
+ public final String[] getPackagesForUid(int uid) {
+ final int callingUid = Binder.getCallingUid();
+ final int userId = UserHandle.getUserId(uid);
+ snapshot().enforceCrossUserOrProfilePermission(callingUid, userId,
+ /* requireFullPermission */ false,
+ /* checkShell */ false, "getPackagesForUid");
+ return snapshot().getPackagesForUid(uid);
+ }
+
+ @Override
+ @Deprecated
+ public final ParceledListSlice<PackageInfo> getPackagesHoldingPermissions(
+ @NonNull String[] permissions, @PackageManager.PackageInfoFlagsBits long flags,
+ @UserIdInt int userId) {
+ return snapshot().getPackagesHoldingPermissions(permissions, flags, userId);
+ }
+
+ // NOTE: Can't remove due to unsupported app usage
+ @Override
+ @Deprecated
+ public final PermissionGroupInfo getPermissionGroupInfo(String groupName, int flags) {
+ return mService.getPermissionGroupInfo(groupName, flags);
+ }
+
+ @Override
+ @Deprecated
+ public final @NonNull
+ ParceledListSlice<ApplicationInfo> getPersistentApplications(int flags) {
+ final Computer snapshot = snapshot();
+ if (snapshot.getInstantAppPackageName(Binder.getCallingUid()) != null) {
+ return ParceledListSlice.emptyList();
+ }
+ return new ParceledListSlice<>(snapshot.getPersistentApplications(isSafeMode(), flags));
+ }
+
+ @Override
+ @Deprecated
+ public final int getPreferredActivities(List<IntentFilter> outFilters,
+ List<ComponentName> outActivities, String packageName) {
+ return mPreferredActivityHelper.getPreferredActivities(snapshot(), outFilters,
+ outActivities, packageName);
+ }
+
+ /**
+ * Non-Binder method, support for the backup/restore mechanism: write the full set of preferred
+ * activities in its canonical XML format. Returns the XML output as a byte array, or null if
+ * there is none.
+ */
+ @Override
+ @Deprecated
+ public final byte[] getPreferredActivityBackup(int userId) {
+ return mPreferredActivityHelper.getPreferredActivityBackup(userId);
+ }
+
+ @Override
+ @Deprecated
+ public final int getPrivateFlagsForUid(int uid) {
+ return snapshot().getPrivateFlagsForUid(uid);
+ }
+
+ @Override
+ @Deprecated
+ public final PackageManager.Property getProperty(String propertyName, String packageName,
+ String className) {
+ Objects.requireNonNull(propertyName);
+ Objects.requireNonNull(packageName);
+ PackageStateInternal packageState = snapshot().getPackageStateFiltered(packageName,
+ Binder.getCallingUid(), UserHandle.getCallingUserId());
+ if (packageState == null) {
+ return null;
+ }
+ return mPackageProperty.getProperty(propertyName, packageName, className);
+ }
+
+ @Nullable
+ @Override
+ @Deprecated
+ public final ProviderInfo getProviderInfo(@NonNull ComponentName component,
+ @PackageManager.ComponentInfoFlagsBits long flags, @UserIdInt int userId) {
+ return snapshot().getProviderInfo(component, flags, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final ActivityInfo getReceiverInfo(ComponentName component,
+ @PackageManager.ComponentInfoFlagsBits long flags, int userId) {
+ return snapshot().getReceiverInfo(component, flags, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final @Nullable
+ String getRotationResolverPackageName() {
+ return mService.ensureSystemPackageName(snapshot(),
+ mService.getPackageFromComponentString(
+ R.string.config_defaultRotationResolverService));
+ }
+
+ @Nullable
+ @Override
+ @Deprecated
+ public final ServiceInfo getServiceInfo(@NonNull ComponentName component,
+ @PackageManager.ComponentInfoFlagsBits long flags, @UserIdInt int userId) {
+ return snapshot().getServiceInfo(component, flags, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final @NonNull
+ String getServicesSystemSharedLibraryPackageName() {
+ return mServicesExtensionPackageName;
+ }
+
+ @Override
+ @Deprecated
+ public final String getSetupWizardPackageName() {
+ if (Binder.getCallingUid() != Process.SYSTEM_UID) {
+ throw new SecurityException("Non-system caller");
+ }
+ return mService.mSetupWizardPackage;
+ }
+
+ @Override
+ @Deprecated
+ public final ParceledListSlice<SharedLibraryInfo> getSharedLibraries(String packageName,
+ @PackageManager.PackageInfoFlagsBits long flags, int userId) {
+ return snapshot().getSharedLibraries(packageName, flags, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final @NonNull
+ String getSharedSystemSharedLibraryPackageName() {
+ return mSharedSystemSharedLibraryPackageName;
+ }
+
+ @Nullable
+ @Override
+ @Deprecated
+ public final KeySet getSigningKeySet(@NonNull String packageName) {
+ return snapshot().getSigningKeySet(packageName);
+ }
+
+ @Override
+ @Deprecated
+ public final String getSdkSandboxPackageName() {
+ return mService.getSdkSandboxPackageName();
+ }
+
+ @Override
+ @Deprecated
+ public final String getSystemCaptionsServicePackageName() {
+ return mService.ensureSystemPackageName(snapshot(),
+ mService.getPackageFromComponentString(
+ R.string.config_defaultSystemCaptionsService));
+ }
+
+ @Nullable
+ @Override
+ @Deprecated
+ public final String[] getSystemSharedLibraryNames() {
+ return snapshot().getSystemSharedLibraryNames();
+ }
+
+ @Override
+ @Deprecated
+ public final String getSystemTextClassifierPackageName() {
+ return mService.mSystemTextClassifierPackageName;
+ }
+
+ @Override
+ @Deprecated
+ public final int getTargetSdkVersion(@NonNull String packageName) {
+ return snapshot().getTargetSdkVersion(packageName);
+ }
+
+ @Override
+ @Deprecated
+ public final int getUidForSharedUser(@NonNull String sharedUserName) {
+ return snapshot().getUidForSharedUser(sharedUserName);
+ }
+
+ @SuppressLint("MissingPermission")
+ @Override
+ @Deprecated
+ public final String getWellbeingPackageName() {
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ return CollectionUtils.firstOrNull(
+ mContext.getSystemService(RoleManager.class).getRoleHolders(
+ RoleManager.ROLE_SYSTEM_WELLBEING));
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ // NOTE: Can't remove due to unsupported app usage
+ @SuppressLint("MissingPermission")
+ @Override
+ @Deprecated
+ public final void grantRuntimePermission(String packageName, String permName,
+ final int userId) {
+ // Because this is accessed via the package manager service AIDL,
+ // go through the permission manager service AIDL
+ mContext.getSystemService(PermissionManager.class)
+ .grantRuntimePermission(packageName, permName, UserHandle.of(userId));
+ }
+
+ @Override
+ @Deprecated
+ public final boolean hasSigningCertificate(@NonNull String packageName,
+ @NonNull byte[] certificate,
+ @PackageManager.CertificateInputType int type) {
+ return snapshot().hasSigningCertificate(packageName, certificate, type);
+ }
+
+ @Override
+ @Deprecated
+ public final boolean hasSystemFeature(String name, int version) {
+ return mService.hasSystemFeature(name, version);
+ }
+
+ @Override
+ @Deprecated
+ public final boolean hasSystemUidErrors() {
+ // allow instant applications
+ return false;
+ }
+
+ @Override
+ @Deprecated
+ public final boolean hasUidSigningCertificate(int uid, @NonNull byte[] certificate,
+ @PackageManager.CertificateInputType int type) {
+ return snapshot().hasUidSigningCertificate(uid, certificate, type);
+ }
+
+ @Override
+ @Deprecated
+ public final boolean isDeviceUpgrading() {
+ return mService.isDeviceUpgrading();
+ }
+
+ @Override
+ @Deprecated
+ public final boolean isFirstBoot() {
+ return mService.isFirstBoot();
+ }
+
+ @Override
+ @Deprecated
+ public final boolean isInstantApp(String packageName, int userId) {
+ return snapshot().isInstantApp(packageName, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final boolean isOnlyCoreApps() {
+ return mService.isOnlyCoreApps();
+ }
+
+ @Override
+ @Deprecated
+ public final boolean isPackageAvailable(String packageName, int userId) {
+ return snapshot().isPackageAvailable(packageName, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final boolean isPackageDeviceAdminOnAnyUser(String packageName) {
+ return mService.isPackageDeviceAdminOnAnyUser(snapshot(),
+ packageName);
+ }
+
+ @Override
+ @Deprecated
+ public final boolean isPackageSignedByKeySet(@NonNull String packageName, @NonNull KeySet ks) {
+ return snapshot().isPackageSignedByKeySet(packageName, ks);
+ }
+
+ @Override
+ @Deprecated
+ public final boolean isPackageSignedByKeySetExactly(@NonNull String packageName,
+ @NonNull KeySet ks) {
+ return snapshot().isPackageSignedByKeySetExactly(packageName, ks);
+ }
+
+ @Override
+ @Deprecated
+ public final boolean isPackageSuspendedForUser(@NonNull String packageName,
+ @UserIdInt int userId) {
+ return snapshot().isPackageSuspendedForUser(packageName, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final boolean isSafeMode() {
+ // allow instant applications
+ return mService.getSafeMode();
+ }
+
+ @Override
+ @Deprecated
+ public final boolean isStorageLow() {
+ return mService.isStorageLow();
+ }
+
+ @Override
+ @Deprecated
+ public final boolean isUidPrivileged(int uid) {
+ return snapshot().isUidPrivileged(uid);
+ }
+
+ /**
+ * Ask the package manager to perform a dex-opt with the given compiler filter.
+ * <p>
+ * Note: exposed only for the shell command to allow moving packages explicitly to a definite
+ * state.
+ */
+ @Override
+ @Deprecated
+ public final boolean performDexOptMode(String packageName,
+ boolean checkProfiles, String targetCompilerFilter, boolean force,
+ boolean bootComplete, String splitName) {
+ return mDexOptHelper.performDexOptMode(packageName, checkProfiles, targetCompilerFilter,
+ force, bootComplete, splitName);
+ }
+
+ /**
+ * Ask the package manager to perform a dex-opt with the given compiler filter on the secondary
+ * dex files belonging to the given package.
+ * <p>
+ * Note: exposed only for the shell command to allow moving packages explicitly to a definite
+ * state.
+ */
+ @Override
+ @Deprecated
+ public final boolean performDexOptSecondary(String packageName, String compilerFilter,
+ boolean force) {
+ return mDexOptHelper.performDexOptSecondary(packageName, compilerFilter, force);
+ }
+
+ @Override
+ @Deprecated
+ public final @NonNull
+ ParceledListSlice<ResolveInfo> queryIntentActivities(Intent intent,
+ String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, int userId) {
+ try {
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "queryIntentActivities");
+
+ return new ParceledListSlice<>(snapshot().queryIntentActivitiesInternal(intent,
+ resolvedType, flags, userId));
+ } finally {
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+ }
+ }
+
+ @NonNull
+ @Override
+ @Deprecated
+ public final ParceledListSlice<ProviderInfo> queryContentProviders(@Nullable String processName,
+ int uid, @PackageManager.ComponentInfoFlagsBits long flags,
+ @Nullable String metaDataKey) {
+ return snapshot().queryContentProviders(processName, uid, flags, metaDataKey);
+ }
+
+ @NonNull
+ @Override
+ @Deprecated
+ public final ParceledListSlice<InstrumentationInfo> queryInstrumentation(
+ @NonNull String targetPackage, int flags) {
+ return snapshot().queryInstrumentation(targetPackage, flags);
+ }
+
+ @Override
+ @Deprecated
+ public final @NonNull
+ ParceledListSlice<ResolveInfo> queryIntentActivityOptions(
+ ComponentName caller, Intent[] specifics, String[] specificTypes, Intent intent,
+ String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, int userId) {
+ return new ParceledListSlice<>(mResolveIntentHelper.queryIntentActivityOptionsInternal(
+ snapshot(), caller, specifics, specificTypes, intent, resolvedType, flags,
+ userId));
+ }
+
+ @Override
+ @Deprecated
+ public final @NonNull
+ ParceledListSlice<ResolveInfo> queryIntentContentProviders(Intent intent,
+ String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, int userId) {
+ return new ParceledListSlice<>(mResolveIntentHelper.queryIntentContentProvidersInternal(
+ snapshot(), intent, resolvedType, flags, userId));
+ }
+
+ @Override
+ @Deprecated
+ public final @NonNull
+ ParceledListSlice<ResolveInfo> queryIntentReceivers(Intent intent,
+ String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, int userId) {
+ return new ParceledListSlice<>(mResolveIntentHelper.queryIntentReceiversInternal(
+ snapshot(), intent, resolvedType, flags, userId, Binder.getCallingUid()));
+ }
+
+ @Override
+ @Deprecated
+ public final @NonNull
+ ParceledListSlice<ResolveInfo> queryIntentServices(Intent intent,
+ String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, int userId) {
+ final int callingUid = Binder.getCallingUid();
+ return new ParceledListSlice<>(snapshot().queryIntentServicesInternal(
+ intent, resolvedType, flags, userId, callingUid, false /*includeInstantApps*/));
+ }
+
+ @Override
+ @Deprecated
+ public final void querySyncProviders(List<String> outNames, List<ProviderInfo> outInfo) {
+ snapshot().querySyncProviders(isSafeMode(), outNames, outInfo);
+ }
+
+ @Override
+ @Deprecated
+ public final void removePermission(String permName) {
+ // Because this is accessed via the package manager service AIDL,
+ // go through the permission manager service AIDL
+ mContext.getSystemService(PermissionManager.class).removePermission(permName);
+ }
+
+ @Override
+ @Deprecated
+ public final void replacePreferredActivity(IntentFilter filter, int match,
+ ComponentName[] set, ComponentName activity, int userId) {
+ mPreferredActivityHelper.replacePreferredActivity(snapshot(),
+ new WatchedIntentFilter(filter), match, set, activity, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final ProviderInfo resolveContentProvider(String name,
+ @PackageManager.ResolveInfoFlagsBits long flags, int userId) {
+ return snapshot().resolveContentProvider(name, flags, userId, Binder.getCallingUid());
+ }
+
+ @Override
+ @Deprecated
+ public final void resetApplicationPreferences(int userId) {
+ mPreferredActivityHelper.resetApplicationPreferences(userId);
+ }
+
+ @Override
+ @Deprecated
+ public final ResolveInfo resolveIntent(Intent intent, String resolvedType,
+ @PackageManager.ResolveInfoFlagsBits long flags, int userId) {
+ return mResolveIntentHelper.resolveIntentInternal(snapshot(), intent,
+ resolvedType, flags, 0 /*privateResolveFlags*/, userId, false,
+ Binder.getCallingUid());
+ }
+
+ @Override
+ @Deprecated
+ public final ResolveInfo resolveService(Intent intent, String resolvedType,
+ @PackageManager.ResolveInfoFlagsBits long flags, int userId) {
+ final int callingUid = Binder.getCallingUid();
+ return mResolveIntentHelper.resolveServiceInternal(snapshot(), intent,
+ resolvedType, flags, userId, callingUid);
+ }
+
+ @Override
+ @Deprecated
+ public final void restoreDefaultApps(byte[] backup, int userId) {
+ mPreferredActivityHelper.restoreDefaultApps(backup, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final void restorePreferredActivities(byte[] backup, int userId) {
+ mPreferredActivityHelper.restorePreferredActivities(backup, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final void setHomeActivity(ComponentName comp, int userId) {
+ mPreferredActivityHelper.setHomeActivity(snapshot(), comp, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final void setLastChosenActivity(Intent intent, String resolvedType, int flags,
+ IntentFilter filter, int match, ComponentName activity) {
+ mPreferredActivityHelper.setLastChosenActivity(snapshot(), intent, resolvedType,
+ flags, new WatchedIntentFilter(filter), match, activity);
+ }
+
+ @Override
+ @Deprecated
+ public final boolean updateIntentVerificationStatus(String packageName, int status,
+ int userId) {
+ return mDomainVerificationManager.setLegacyUserState(packageName, userId, status);
+ }
+
+ @Override
+ @Deprecated
+ public final void verifyIntentFilter(int id, int verificationCode, List<String> failedDomains) {
+ DomainVerificationProxyV1.queueLegacyVerifyResult(mContext, mDomainVerificationConnection,
+ id, verificationCode, failedDomains, Binder.getCallingUid());
+ }
+
+ @Override
+ @Deprecated
+ public final boolean canPackageQuery(@NonNull String sourcePackageName,
+ @NonNull String targetPackageName, @UserIdInt int userId) {
+ return snapshot().canPackageQuery(sourcePackageName, targetPackageName, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final void deletePreloadsFileCache() throws RemoteException {
+ mService.deletePreloadsFileCache();
+ }
+
+ @Override
+ @Deprecated
+ public final void setSystemAppHiddenUntilInstalled(String packageName, boolean hidden)
+ throws RemoteException {
+ mService.setSystemAppHiddenUntilInstalled(snapshot(), packageName, hidden);
+ }
+
+ @Override
+ @Deprecated
+ public final boolean setSystemAppInstallState(String packageName,
+ boolean installed, int userId) throws RemoteException {
+ return mService.setSystemAppInstallState(snapshot(), packageName, installed, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final void finishPackageInstall(int token, boolean didLaunch) throws RemoteException {
+ mService.finishPackageInstall(token, didLaunch);
+ }
+}
diff --git a/services/core/java/com/android/server/pm/IncrementalProgressListener.java b/services/core/java/com/android/server/pm/IncrementalProgressListener.java
index fa11924218d4..703bbda92182 100644
--- a/services/core/java/com/android/server/pm/IncrementalProgressListener.java
+++ b/services/core/java/com/android/server/pm/IncrementalProgressListener.java
@@ -33,7 +33,8 @@ final class IncrementalProgressListener extends IPackageLoadingProgressCallback.
@Override
public void onPackageLoadingProgressChanged(float progress) {
- PackageStateInternal packageState = mPm.getPackageStateInternal(mPackageName);
+ PackageStateInternal packageState = mPm.snapshotComputer()
+ .getPackageStateInternal(mPackageName);
if (packageState == null) {
return;
}
diff --git a/services/core/java/com/android/server/pm/InitAndSystemPackageHelper.java b/services/core/java/com/android/server/pm/InitAppsHelper.java
index 6dbe9b6f89f6..15f26e7a6d6c 100644
--- a/services/core/java/com/android/server/pm/InitAndSystemPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InitAppsHelper.java
@@ -30,7 +30,9 @@ import static com.android.server.pm.PackageManagerService.SCAN_NO_DEX;
import static com.android.server.pm.PackageManagerService.SCAN_REQUIRE_KNOWN;
import static com.android.server.pm.PackageManagerService.SYSTEM_PARTITIONS;
import static com.android.server.pm.PackageManagerService.TAG;
+import static com.android.server.pm.pkg.parsing.ParsingPackageUtils.PARSE_CHECK_MAX_SDK_VERSION;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.pm.parsing.ApkLiteParseUtils;
import android.os.Environment;
@@ -60,14 +62,24 @@ import java.util.concurrent.ExecutorService;
* further cleanup and eventually all the installation/scanning related logic will go to another
* class.
*/
-final class InitAndSystemPackageHelper {
+final class InitAppsHelper {
private final PackageManagerService mPm;
-
private final List<ScanPartition> mDirsToScanAsSystem;
private final int mScanFlags;
private final int mSystemParseFlags;
private final int mSystemScanFlags;
private final InstallPackageHelper mInstallPackageHelper;
+ private final ApexManager mApexManager;
+ private final ExecutorService mExecutorService;
+ /* Tracks how long system scan took */
+ private long mSystemScanTime;
+ /* Track of the number of cached system apps */
+ private int mCachedSystemApps;
+ /* Track of the number of system apps */
+ private int mSystemPackagesCount;
+ private final boolean mIsDeviceUpgrading;
+ private final boolean mIsOnlyCoreApps;
+ private final List<ScanPartition> mSystemPartitions;
/**
* Tracks new system packages [received in an OTA] that we expect to
@@ -75,21 +87,33 @@ final class InitAndSystemPackageHelper {
* are package location.
*/
private final ArrayMap<String, File> mExpectingBetter = new ArrayMap<>();
+ /* Tracks of any system packages that no longer exist that needs to be pruned. */
+ private final List<String> mPossiblyDeletedUpdatedSystemApps = new ArrayList<>();
+ // Tracks of stub packages that must either be replaced with full versions in the /data
+ // partition or be disabled.
+ private final List<String> mStubSystemApps = new ArrayList<>();
// TODO(b/198166813): remove PMS dependency
- InitAndSystemPackageHelper(PackageManagerService pm) {
+ InitAppsHelper(PackageManagerService pm, ApexManager apexManager,
+ InstallPackageHelper installPackageHelper,
+ List<ScanPartition> systemPartitions) {
mPm = pm;
- mInstallPackageHelper = new InstallPackageHelper(pm);
+ mApexManager = apexManager;
+ mInstallPackageHelper = installPackageHelper;
+ mSystemPartitions = systemPartitions;
mDirsToScanAsSystem = getSystemScanPartitions();
+ mIsDeviceUpgrading = mPm.isDeviceUpgrading();
+ mIsOnlyCoreApps = mPm.isOnlyCoreApps();
// Set flag to monitor and not change apk file paths when scanning install directories.
int scanFlags = SCAN_BOOTING | SCAN_INITIAL;
- if (mPm.isDeviceUpgrading() || mPm.isFirstBoot()) {
+ if (mIsDeviceUpgrading || mPm.isFirstBoot()) {
mScanFlags = scanFlags | SCAN_FIRST_BOOT_OR_UPGRADE;
} else {
mScanFlags = scanFlags;
}
mSystemParseFlags = mPm.getDefParseFlags() | ParsingPackageUtils.PARSE_IS_SYSTEM_DIR;
mSystemScanFlags = scanFlags | SCAN_AS_SYSTEM;
+ mExecutorService = ParallelPackageParser.makeExecutorService();
}
private List<File> getFrameworkResApkSplitFiles() {
@@ -117,7 +141,7 @@ final class InitAndSystemPackageHelper {
private List<ScanPartition> getSystemScanPartitions() {
final List<ScanPartition> scanPartitions = new ArrayList<>();
- scanPartitions.addAll(mPm.mInjector.getSystemPartitions());
+ scanPartitions.addAll(mSystemPartitions);
scanPartitions.addAll(getApexScanPartitions());
Slog.d(TAG, "Directories scanned as system partitions: " + scanPartitions);
return scanPartitions;
@@ -125,8 +149,7 @@ final class InitAndSystemPackageHelper {
private List<ScanPartition> getApexScanPartitions() {
final List<ScanPartition> scanPartitions = new ArrayList<>();
- final List<ApexManager.ActiveApexInfo> activeApexInfos =
- mPm.mApexManager.getActiveApexInfos();
+ final List<ApexManager.ActiveApexInfo> activeApexInfos = mApexManager.getActiveApexInfos();
for (int i = 0; i < activeApexInfos.size(); i++) {
final ScanPartition scanPartition = resolveApexToScanPartition(activeApexInfos.get(i));
if (scanPartition != null) {
@@ -143,117 +166,134 @@ final class InitAndSystemPackageHelper {
if (apexInfo.preInstalledApexPath.getAbsolutePath().equals(
sp.getFolder().getAbsolutePath())
|| apexInfo.preInstalledApexPath.getAbsolutePath().startsWith(
- sp.getFolder().getAbsolutePath() + File.separator)) {
+ sp.getFolder().getAbsolutePath() + File.separator)) {
return new ScanPartition(apexInfo.apexDirectory, sp, SCAN_AS_APK_IN_APEX);
}
}
return null;
}
- public OverlayConfig initPackages(
- WatchedArrayMap<String, PackageSetting> packageSettings, int[] userIds,
- long startTime) {
- PackageParser2 packageParser = mPm.mInjector.getScanningCachingPackageParser();
-
- ExecutorService executorService = ParallelPackageParser.makeExecutorService();
+ /**
+ * Install apps from system dirs.
+ */
+ @GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
+ public OverlayConfig initSystemApps(PackageParser2 packageParser,
+ WatchedArrayMap<String, PackageSetting> packageSettings,
+ int[] userIds, long startTime) {
// Prepare apex package info before scanning APKs, this information is needed when
// scanning apk in apex.
- mPm.mApexManager.scanApexPackagesTraced(packageParser, executorService);
+ mApexManager.scanApexPackagesTraced(packageParser, mExecutorService);
- scanSystemDirs(packageParser, executorService);
+ scanSystemDirs(packageParser, mExecutorService);
// Parse overlay configuration files to set default enable state, mutability, and
// priority of system overlays.
final ArrayMap<String, File> apkInApexPreInstalledPaths = new ArrayMap<>();
- for (ApexManager.ActiveApexInfo apexInfo : mPm.mApexManager.getActiveApexInfos()) {
- for (String packageName : mPm.mApexManager.getApksInApex(apexInfo.apexModuleName)) {
+ for (ApexManager.ActiveApexInfo apexInfo : mApexManager.getActiveApexInfos()) {
+ for (String packageName : mApexManager.getApksInApex(apexInfo.apexModuleName)) {
apkInApexPreInstalledPaths.put(packageName, apexInfo.preInstalledApexPath);
}
}
- OverlayConfig overlayConfig = OverlayConfig.initializeSystemInstance(
- consumer -> mPm.forEachPackage(
+ final OverlayConfig overlayConfig = OverlayConfig.initializeSystemInstance(
+ consumer -> mPm.forEachPackage(mPm.snapshotComputer(),
pkg -> consumer.accept(pkg, pkg.isSystem(),
- apkInApexPreInstalledPaths.get(pkg.getPackageName()))));
- // Prune any system packages that no longer exist.
- final List<String> possiblyDeletedUpdatedSystemApps = new ArrayList<>();
- // Stub packages must either be replaced with full versions in the /data
- // partition or be disabled.
- final List<String> stubSystemApps = new ArrayList<>();
-
- if (!mPm.isOnlyCoreApps()) {
+ apkInApexPreInstalledPaths.get(pkg.getPackageName()))));
+
+ if (!mIsOnlyCoreApps) {
// do this first before mucking with mPackages for the "expecting better" case
- updateStubSystemAppsList(stubSystemApps);
+ updateStubSystemAppsList(mStubSystemApps);
mInstallPackageHelper.prepareSystemPackageCleanUp(packageSettings,
- possiblyDeletedUpdatedSystemApps, mExpectingBetter, userIds);
+ mPossiblyDeletedUpdatedSystemApps, mExpectingBetter, userIds);
}
- final int cachedSystemApps = PackageCacher.sCachedPackageReadCount.get();
+ logSystemAppsScanningTime(startTime);
+ return overlayConfig;
+ }
+
+ @GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
+ private void logSystemAppsScanningTime(long startTime) {
+ mCachedSystemApps = PackageCacher.sCachedPackageReadCount.get();
// Remove any shared userIDs that have no associated packages
mPm.mSettings.pruneSharedUsersLPw();
- final long systemScanTime = SystemClock.uptimeMillis() - startTime;
- final int systemPackagesCount = mPm.mPackages.size();
- Slog.i(TAG, "Finished scanning system apps. Time: " + systemScanTime
- + " ms, packageCount: " + systemPackagesCount
+ mSystemScanTime = SystemClock.uptimeMillis() - startTime;
+ mSystemPackagesCount = mPm.mPackages.size();
+ Slog.i(TAG, "Finished scanning system apps. Time: " + mSystemScanTime
+ + " ms, packageCount: " + mSystemPackagesCount
+ " , timePerPackage: "
- + (systemPackagesCount == 0 ? 0 : systemScanTime / systemPackagesCount)
- + " , cached: " + cachedSystemApps);
- if (mPm.isDeviceUpgrading() && systemPackagesCount > 0) {
+ + (mSystemPackagesCount == 0 ? 0 : mSystemScanTime / mSystemPackagesCount)
+ + " , cached: " + mCachedSystemApps);
+ if (mIsDeviceUpgrading && mSystemPackagesCount > 0) {
//CHECKSTYLE:OFF IndentationCheck
FrameworkStatsLog.write(FrameworkStatsLog.BOOT_TIME_EVENT_DURATION_REPORTED,
BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_SYSTEM_APP_AVG_SCAN_TIME,
- systemScanTime / systemPackagesCount);
+ mSystemScanTime / mSystemPackagesCount);
//CHECKSTYLE:ON IndentationCheck
}
+ }
- if (!mPm.isOnlyCoreApps()) {
+ /**
+ * Install apps/updates from data dir and fix system apps that are affected.
+ */
+ @GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
+ public void initNonSystemApps(PackageParser2 packageParser, @NonNull int[] userIds,
+ long startTime) {
+ if (!mIsOnlyCoreApps) {
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,
SystemClock.uptimeMillis());
scanDirTracedLI(mPm.getAppInstallDir(), /* frameworkSplits= */ null, 0,
- mScanFlags | SCAN_REQUIRE_KNOWN, 0,
- packageParser, executorService);
-
+ mScanFlags | SCAN_REQUIRE_KNOWN,
+ packageParser, mExecutorService);
}
- List<Runnable> unfinishedTasks = executorService.shutdownNow();
+ List<Runnable> unfinishedTasks = mExecutorService.shutdownNow();
if (!unfinishedTasks.isEmpty()) {
throw new IllegalStateException("Not all tasks finished before calling close: "
+ unfinishedTasks);
}
-
- if (!mPm.isOnlyCoreApps()) {
- mInstallPackageHelper.cleanupDisabledPackageSettings(possiblyDeletedUpdatedSystemApps,
- userIds, mScanFlags);
- mInstallPackageHelper.checkExistingBetterPackages(mExpectingBetter,
- stubSystemApps, mSystemScanFlags, mSystemParseFlags);
-
- // Uncompress and install any stubbed system applications.
- // This must be done last to ensure all stubs are replaced or disabled.
- mInstallPackageHelper.installSystemStubPackages(stubSystemApps, mScanFlags);
-
- final int cachedNonSystemApps = PackageCacher.sCachedPackageReadCount.get()
- - cachedSystemApps;
-
- final long dataScanTime = SystemClock.uptimeMillis() - systemScanTime - startTime;
- final int dataPackagesCount = mPm.mPackages.size() - systemPackagesCount;
- Slog.i(TAG, "Finished scanning non-system apps. Time: " + dataScanTime
- + " ms, packageCount: " + dataPackagesCount
- + " , timePerPackage: "
- + (dataPackagesCount == 0 ? 0 : dataScanTime / dataPackagesCount)
- + " , cached: " + cachedNonSystemApps);
- if (mPm.isDeviceUpgrading() && dataPackagesCount > 0) {
- //CHECKSTYLE:OFF IndentationCheck
- FrameworkStatsLog.write(
- FrameworkStatsLog.BOOT_TIME_EVENT_DURATION_REPORTED,
- BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_DATA_APP_AVG_SCAN_TIME,
- dataScanTime / dataPackagesCount);
- //CHECKSTYLE:OFF IndentationCheck
- }
+ if (!mIsOnlyCoreApps) {
+ fixSystemPackages(userIds);
+ logNonSystemAppScanningTime(startTime);
}
mExpectingBetter.clear();
-
mPm.mSettings.pruneRenamedPackagesLPw();
- packageParser.close();
- return overlayConfig;
+ }
+
+ /**
+ * Clean up system packages now that some system package updates have been installed from
+ * the data dir. Also install system stub packages as the last step.
+ */
+ @GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
+ private void fixSystemPackages(@NonNull int[] userIds) {
+ mInstallPackageHelper.cleanupDisabledPackageSettings(mPossiblyDeletedUpdatedSystemApps,
+ userIds, mScanFlags);
+ mInstallPackageHelper.checkExistingBetterPackages(mExpectingBetter,
+ mStubSystemApps, mSystemScanFlags, mSystemParseFlags);
+
+ // Uncompress and install any stubbed system applications.
+ // This must be done last to ensure all stubs are replaced or disabled.
+ mInstallPackageHelper.installSystemStubPackages(mStubSystemApps, mScanFlags);
+ }
+
+ @GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
+ private void logNonSystemAppScanningTime(long startTime) {
+ final int cachedNonSystemApps = PackageCacher.sCachedPackageReadCount.get()
+ - mCachedSystemApps;
+
+ final long dataScanTime = SystemClock.uptimeMillis() - mSystemScanTime - startTime;
+ final int dataPackagesCount = mPm.mPackages.size() - mSystemPackagesCount;
+ Slog.i(TAG, "Finished scanning non-system apps. Time: " + dataScanTime
+ + " ms, packageCount: " + dataPackagesCount
+ + " , timePerPackage: "
+ + (dataPackagesCount == 0 ? 0 : dataScanTime / dataPackagesCount)
+ + " , cached: " + cachedNonSystemApps);
+ if (mIsDeviceUpgrading && dataPackagesCount > 0) {
+ //CHECKSTYLE:OFF IndentationCheck
+ FrameworkStatsLog.write(
+ FrameworkStatsLog.BOOT_TIME_EVENT_DURATION_REPORTED,
+ BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_DATA_APP_AVG_SCAN_TIME,
+ dataScanTime / dataPackagesCount);
+ //CHECKSTYLE:OFF IndentationCheck
+ }
}
/**
@@ -273,13 +313,13 @@ final class InitAndSystemPackageHelper {
continue;
}
scanDirTracedLI(partition.getOverlayFolder(), /* frameworkSplits= */ null,
- mSystemParseFlags, mSystemScanFlags | partition.scanFlag, 0,
+ mSystemParseFlags, mSystemScanFlags | partition.scanFlag,
packageParser, executorService);
}
scanDirTracedLI(frameworkDir, null,
mSystemParseFlags,
- mSystemScanFlags | SCAN_NO_DEX | SCAN_AS_PRIVILEGED, 0,
+ mSystemScanFlags | SCAN_NO_DEX | SCAN_AS_PRIVILEGED,
packageParser, executorService);
if (!mPm.mPackages.containsKey("android")) {
throw new IllegalStateException(
@@ -291,11 +331,11 @@ final class InitAndSystemPackageHelper {
if (partition.getPrivAppFolder() != null) {
scanDirTracedLI(partition.getPrivAppFolder(), /* frameworkSplits= */ null,
mSystemParseFlags,
- mSystemScanFlags | SCAN_AS_PRIVILEGED | partition.scanFlag, 0,
+ mSystemScanFlags | SCAN_AS_PRIVILEGED | partition.scanFlag,
packageParser, executorService);
}
scanDirTracedLI(partition.getAppFolder(), /* frameworkSplits= */ null,
- mSystemParseFlags, mSystemScanFlags | partition.scanFlag, 0,
+ mSystemParseFlags, mSystemScanFlags | partition.scanFlag,
packageParser, executorService);
}
}
@@ -313,12 +353,16 @@ final class InitAndSystemPackageHelper {
@GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
private void scanDirTracedLI(File scanDir, List<File> frameworkSplits,
- final int parseFlags, int scanFlags,
- long currentTime, PackageParser2 packageParser, ExecutorService executorService) {
+ int parseFlags, int scanFlags,
+ PackageParser2 packageParser, ExecutorService executorService) {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanDir [" + scanDir.getAbsolutePath() + "]");
try {
+ if ((scanFlags & SCAN_AS_APK_IN_APEX) != 0) {
+ // when scanning apk in apexes, we want to check the maxSdkVersion
+ parseFlags |= PARSE_CHECK_MAX_SDK_VERSION;
+ }
mInstallPackageHelper.installPackagesFromDir(scanDir, frameworkSplits, parseFlags,
- scanFlags, currentTime, packageParser, executorService);
+ scanFlags, packageParser, executorService);
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index a780f3c7eac5..870a11ac2d61 100644
--- a/services/core/java/com/android/server/pm/InstallPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java
@@ -86,6 +86,7 @@ import static com.android.server.pm.PackageManagerServiceUtils.compareSignatures
import static com.android.server.pm.PackageManagerServiceUtils.compressedFileExists;
import static com.android.server.pm.PackageManagerServiceUtils.deriveAbiOverride;
import static com.android.server.pm.PackageManagerServiceUtils.logCriticalInfo;
+import static com.android.server.pm.SharedUidMigration.BEST_EFFORT;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -287,6 +288,12 @@ final class InstallPackageHelper {
SharedUserSetting sharedUserSetting = mPm.mSettings.getSharedUserSettingLPr(pkgSetting);
if (sharedUserSetting != null) {
sharedUserSetting.addPackage(pkgSetting);
+ if (parsedPackage.isLeavingSharedUid()
+ && SharedUidMigration.applyStrategy(BEST_EFFORT)
+ && sharedUserSetting.isSingleUser()) {
+ // Attempt the transparent shared UID migration
+ mPm.mSettings.convertSharedUserSettingsLPw(sharedUserSetting);
+ }
}
if (reconciledPkg.mInstallArgs != null
&& reconciledPkg.mInstallArgs.mForceQueryableOverride) {
@@ -520,8 +527,10 @@ final class InstallPackageHelper {
+ android.Manifest.permission.INSTALL_PACKAGES + ".");
}
PackageSetting pkgSetting;
- mPm.enforceCrossUserPermission(callingUid, userId, true /* requireFullPermission */,
- true /* checkShell */, "installExistingPackage for user " + userId);
+ final Computer preLockSnapshot = mPm.snapshotComputer();
+ preLockSnapshot.enforceCrossUserPermission(callingUid, userId,
+ true /* requireFullPermission */, true /* checkShell */,
+ "installExistingPackage for user " + userId);
if (mPm.isUserRestricted(userId, UserManager.DISALLOW_INSTALL_APPS)) {
return PackageManager.INSTALL_FAILED_USER_RESTRICTED;
}
@@ -536,11 +545,12 @@ final class InstallPackageHelper {
// writer
synchronized (mPm.mLock) {
+ final Computer snapshot = mPm.snapshotComputer();
pkgSetting = mPm.mSettings.getPackageLPr(packageName);
if (pkgSetting == null) {
return PackageManager.INSTALL_FAILED_INVALID_URI;
}
- if (!mPm.canViewInstantApps(callingUid, UserHandle.getUserId(callingUid))) {
+ if (!snapshot.canViewInstantApps(callingUid, UserHandle.getUserId(callingUid))) {
// only allow the existing package to be used if it's installed as a full
// application for at least one user
boolean installAllowed = false;
@@ -590,7 +600,8 @@ final class InstallPackageHelper {
mAppDataHelper.prepareAppDataAfterInstallLIF(pkgSetting.getPkg());
}
}
- mPm.sendPackageAddedForUser(packageName, pkgSetting, userId, DataLoaderType.NONE);
+ mPm.sendPackageAddedForUser(mPm.snapshotComputer(), packageName, pkgSetting, userId,
+ DataLoaderType.NONE);
synchronized (mPm.mLock) {
mPm.updateSequenceNumberLP(pkgSetting, new int[]{ userId });
}
@@ -951,10 +962,6 @@ final class InstallPackageHelper {
createdAppId.put(packageName, optimisticallyRegisterAppId(result));
versionInfos.put(result.mPkgSetting.getPkg().getPackageName(),
mPm.getSettingsVersionForPackage(result.mPkgSetting.getPkg()));
- if (result.needsNewAppId()) {
- request.mInstallResult.mRemovedInfo.mNewAppId =
- result.mPkgSetting.getAppId();
- }
} catch (PackageManagerException e) {
request.mInstallResult.setError("Scanning Failed.", e);
return;
@@ -1899,8 +1906,8 @@ final class InstallPackageHelper {
AndroidPackage oldPackage = mPm.mPackages.get(packageName);
// Set the update and install times
- PackageStateInternal deletedPkgSetting = mPm.getPackageStateInternal(
- oldPackage.getPackageName());
+ PackageStateInternal deletedPkgSetting = mPm.snapshotComputer()
+ .getPackageStateInternal(oldPackage.getPackageName());
reconciledPkg.mPkgSetting
.setFirstInstallTimeFromReplaced(deletedPkgSetting, request.mAllUsers)
.setLastUpdateTime(System.currentTimeMillis());
@@ -2216,23 +2223,8 @@ final class InstallPackageHelper {
}
incrementalStorages.add(storage);
}
- int previousAppId = 0;
- if (reconciledPkg.mScanResult.needsNewAppId()) {
- // Only set previousAppId if the app is migrating out of shared UID
- previousAppId = reconciledPkg.mScanResult.mPreviousAppId;
-
- if (pkg.shouldInheritKeyStoreKeys()) {
- // Migrate keystore data
- mAppDataHelper.migrateKeyStoreData(
- previousAppId, reconciledPkg.mPkgSetting.getAppId());
- }
-
- if (reconciledPkg.mInstallResult.mRemovedInfo.mRemovedAppId == previousAppId) {
- // If the previous app ID is removed, clear the keys
- mAppDataHelper.clearKeystoreData(UserHandle.USER_ALL, previousAppId);
- }
- }
- mAppDataHelper.prepareAppDataPostCommitLIF(pkg, previousAppId);
+ // Hardcode previousAppId to 0 to disable any data migration (http://b/221088088)
+ mAppDataHelper.prepareAppDataPostCommitLIF(pkg, 0);
if (reconciledPkg.mPrepareResult.mClearCodeCache) {
mAppDataHelper.clearAppDataLIF(pkg, UserHandle.USER_ALL,
FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL
@@ -2583,9 +2575,10 @@ final class InstallPackageHelper {
size = i;
mPm.mPendingBroadcasts.clear();
}
+ final Computer snapshot = mPm.snapshotComputer();
// Send broadcasts
for (int i = 0; i < size; i++) {
- mPm.sendPackageChangedBroadcast(packages[i], true /* dontKillApp */,
+ mPm.sendPackageChangedBroadcast(snapshot, packages[i], true /* dontKillApp */,
components[i], uids[i], null /* reason */);
}
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
@@ -2602,11 +2595,9 @@ final class InstallPackageHelper {
final int dataLoaderType = installArgs.mDataLoaderType;
final boolean succeeded = res.mReturnCode == PackageManager.INSTALL_SUCCEEDED;
final boolean update = res.mRemovedInfo != null && res.mRemovedInfo.mRemovedPackage != null;
- final int previousAppId = (res.mRemovedInfo != null && res.mRemovedInfo.mNewAppId >= 0)
- ? res.mRemovedInfo.mUid : Process.INVALID_UID;
final String packageName = res.mName;
final PackageStateInternal pkgSetting =
- succeeded ? mPm.getPackageStateInternal(packageName) : null;
+ succeeded ? mPm.snapshotComputer().getPackageStateInternal(packageName) : null;
final boolean removedBeforeUpdate = (pkgSetting == null)
|| (pkgSetting.isSystem() && !pkgSetting.getPath().getPath().equals(
res.mPkg.getPath()));
@@ -2704,17 +2695,14 @@ final class InstallPackageHelper {
// sendPackageAddedForNewUsers also deals with system apps
int appId = UserHandle.getAppId(res.mUid);
boolean isSystem = res.mPkg.isSystem();
- mPm.sendPackageAddedForNewUsers(packageName, isSystem || virtualPreload,
- virtualPreload /*startReceiver*/, appId, firstUserIds, firstInstantUserIds,
- dataLoaderType);
+ mPm.sendPackageAddedForNewUsers(mPm.snapshotComputer(), packageName,
+ isSystem || virtualPreload, virtualPreload /*startReceiver*/, appId,
+ firstUserIds, firstInstantUserIds, dataLoaderType);
// Send added for users that don't see the package for the first time
Bundle extras = new Bundle();
extras.putInt(Intent.EXTRA_UID, res.mUid);
- if (previousAppId != Process.INVALID_UID) {
- extras.putBoolean(Intent.EXTRA_UID_CHANGING, true);
- extras.putInt(Intent.EXTRA_PREVIOUS_UID, previousAppId);
- } else if (update) {
+ if (update) {
extras.putBoolean(Intent.EXTRA_REPLACING, true);
}
extras.putInt(PackageInstaller.EXTRA_DATA_LOADER_TYPE, dataLoaderType);
@@ -2722,7 +2710,8 @@ final class InstallPackageHelper {
final SparseArray<int[]> newBroadcastAllowList;
synchronized (mPm.mLock) {
newBroadcastAllowList = mPm.mAppsFilter.getVisibilityAllowList(
- mPm.getPackageStateInternal(packageName, Process.SYSTEM_UID),
+ mPm.snapshotComputer()
+ .getPackageStateInternal(packageName, Process.SYSTEM_UID),
updateUserIds, mPm.mSettings.getPackagesLocked());
}
mPm.sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
@@ -2757,27 +2746,24 @@ final class InstallPackageHelper {
// Send replaced for users that don't see the package for the first time
if (update) {
- // Only send PACKAGE_REPLACED if appId has not changed
- if (previousAppId == Process.INVALID_UID) {
- mPm.sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED,
- packageName, extras, 0 /*flags*/,
- null /*targetPackage*/, null /*finishedReceiver*/,
- updateUserIds, instantUserIds, res.mRemovedInfo.mBroadcastAllowList,
+ mPm.sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED,
+ packageName, extras, 0 /*flags*/,
+ null /*targetPackage*/, null /*finishedReceiver*/,
+ updateUserIds, instantUserIds, res.mRemovedInfo.mBroadcastAllowList,
+ null);
+ if (installerPackageName != null) {
+ mPm.sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName,
+ extras, 0 /*flags*/,
+ installerPackageName, null /*finishedReceiver*/,
+ updateUserIds, instantUserIds, null /*broadcastAllowList*/,
+ null);
+ }
+ if (notifyVerifier) {
+ mPm.sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName,
+ extras, 0 /*flags*/,
+ mPm.mRequiredVerifierPackage, null /*finishedReceiver*/,
+ updateUserIds, instantUserIds, null /*broadcastAllowList*/,
null);
- if (installerPackageName != null) {
- mPm.sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName,
- extras, 0 /*flags*/,
- installerPackageName, null /*finishedReceiver*/,
- updateUserIds, instantUserIds, null /*broadcastAllowList*/,
- null);
- }
- if (notifyVerifier) {
- mPm.sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName,
- extras, 0 /*flags*/,
- mPm.mRequiredVerifierPackage, null /*finishedReceiver*/,
- updateUserIds, instantUserIds, null /*broadcastAllowList*/,
- null);
- }
}
mPm.sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED,
null /*package*/, null /*extras*/, 0 /*flags*/,
@@ -2827,11 +2813,12 @@ final class InstallPackageHelper {
}
} else if (!ArrayUtils.isEmpty(res.mLibraryConsumers)) { // if static shared lib
// No need to kill consumers if it's installation of new version static shared lib.
+ final Computer snapshot = mPm.snapshotComputer();
final boolean dontKillApp = !update && res.mPkg.getStaticSharedLibName() != null;
for (int i = 0; i < res.mLibraryConsumers.size(); i++) {
AndroidPackage pkg = res.mLibraryConsumers.get(i);
// send broadcast that all consumers of the static shared library have changed
- mPm.sendPackageChangedBroadcast(pkg.getPackageName(), dontKillApp,
+ mPm.sendPackageChangedBroadcast(snapshot, pkg.getPackageName(), dontKillApp,
new ArrayList<>(Collections.singletonList(pkg.getPackageName())),
pkg.getUid(), null);
}
@@ -2875,13 +2862,14 @@ final class InstallPackageHelper {
VMRuntime.getRuntime().requestConcurrentGC();
}
+ final Computer snapshot = mPm.snapshotComputer();
// Notify DexManager that the package was installed for new users.
// The updated users should already be indexed and the package code paths
// should not change.
// Don't notify the manager for ephemeral apps as they are not expected to
// survive long enough to benefit of background optimizations.
for (int userId : firstUserIds) {
- PackageInfo info = mPm.getPackageInfo(packageName, /*flags*/ 0, userId);
+ PackageInfo info = snapshot.getPackageInfo(packageName, /*flags*/ 0, userId);
// There's a race currently where some install events may interleave with an
// uninstall. This can lead to package info being null (b/36642664).
if (info != null) {
@@ -2988,7 +2976,6 @@ final class InstallPackageHelper {
* APK will be installed and the package will be disabled. To recover from this situation,
* the user will need to go into system settings and re-enable the package.
*/
- @GuardedBy({"mPm.mLock", "mPm.mInstallLock"})
boolean enableCompressedPackage(AndroidPackage stubPkg,
@NonNull PackageSetting stubPkgSetting) {
final int parseFlags = mPm.getDefParseFlags() | ParsingPackageUtils.PARSE_CHATTY
@@ -2998,8 +2985,8 @@ final class InstallPackageHelper {
try (PackageFreezer freezer =
mPm.freezePackage(stubPkg.getPackageName(), "setEnabledSetting")) {
pkg = installStubPackageLI(stubPkg, parseFlags, 0 /*scanFlags*/);
+ mAppDataHelper.prepareAppDataAfterInstallLIF(pkg);
synchronized (mPm.mLock) {
- mAppDataHelper.prepareAppDataAfterInstallLIF(pkg);
try {
mSharedLibraries.updateSharedLibrariesLPw(
pkg, stubPkgSetting, null, null,
@@ -3027,8 +3014,7 @@ final class InstallPackageHelper {
installPackageFromSystemLIF(stubPkg.getPath(),
mPm.mUserManager.getUserIds() /*allUserHandles*/,
null /*origUserHandles*/,
- true /*writeSettings*/,
- Process.INVALID_UID /*previousAppId*/);
+ true /*writeSettings*/);
} catch (PackageManagerException pme) {
// Serious WTF; we have to be able to install the stub
Slog.wtf(TAG, "Failed to restore system package:" + stubPkg.getPackageName(),
@@ -3056,7 +3042,7 @@ final class InstallPackageHelper {
return true;
}
- @GuardedBy({"mPm.mLock", "mPm.mInstallLock"})
+ @GuardedBy("mPm.mInstallLock")
private AndroidPackage installStubPackageLI(AndroidPackage stubPkg,
@ParsingPackageUtils.ParseFlags int parseFlags,
@PackageManagerService.ScanFlags int scanFlags)
@@ -3076,7 +3062,7 @@ final class InstallPackageHelper {
final RemovePackageHelper removePackageHelper = new RemovePackageHelper(mPm);
removePackageHelper.removePackageLI(stubPkg, true /*chatty*/);
try {
- return scanSystemPackageTracedLI(scanFile, parseFlags, scanFlags, 0, null);
+ return scanSystemPackageTracedLI(scanFile, parseFlags, scanFlags, null);
} catch (PackageManagerException e) {
Slog.w(TAG, "Failed to install compressed system package:" + stubPkg.getPackageName(),
e);
@@ -3149,27 +3135,26 @@ final class InstallPackageHelper {
mPm.mSettings.enableSystemPackageLPw(disabledPs.getPkg().getPackageName());
// Remove any native libraries from the upgraded package.
PackageManagerServiceUtils.removeNativeBinariesLI(deletedPs);
-
- // Install the system package
- if (DEBUG_REMOVE) Slog.d(TAG, "Re-installing system package: " + disabledPs);
- try {
- synchronized (mPm.mInstallLock) {
- final int[] origUsers = outInfo == null ? null : outInfo.mOrigUsers;
- final int previousAppId = disabledPs.getAppId() != deletedPs.getAppId()
- ? deletedPs.getAppId() : Process.INVALID_UID;
- installPackageFromSystemLIF(disabledPs.getPathString(), allUserHandles,
- origUsers, writeSettings, previousAppId);
- }
- } catch (PackageManagerException e) {
- Slog.w(TAG, "Failed to restore system package:" + deletedPs.getPackageName() + ": "
- + e.getMessage());
- // TODO(b/194319951): can we avoid this; throw would come from scan...
- throw new SystemDeleteException(e);
- } finally {
- if (disabledPs.getPkg().isStub()) {
- // We've re-installed the stub; make sure it's disabled here. If package was
- // originally enabled, we'll install the compressed version of the application
- // and re-enable it afterward.
+ }
+ // Install the system package
+ if (DEBUG_REMOVE) Slog.d(TAG, "Re-installing system package: " + disabledPs);
+ try {
+ synchronized (mPm.mInstallLock) {
+ final int[] origUsers = outInfo == null ? null : outInfo.mOrigUsers;
+ installPackageFromSystemLIF(disabledPs.getPathString(), allUserHandles,
+ origUsers, writeSettings);
+ }
+ } catch (PackageManagerException e) {
+ Slog.w(TAG, "Failed to restore system package:" + deletedPs.getPackageName() + ": "
+ + e.getMessage());
+ // TODO(b/194319951): can we avoid this; throw would come from scan...
+ throw new SystemDeleteException(e);
+ } finally {
+ if (disabledPs.getPkg().isStub()) {
+ // We've re-installed the stub; make sure it's disabled here. If package was
+ // originally enabled, we'll install the compressed version of the application
+ // and re-enable it afterward.
+ synchronized (mPm.mLock) {
disableStubPackage(action, deletedPs, allUserHandles);
}
}
@@ -3197,10 +3182,10 @@ final class InstallPackageHelper {
/**
* Installs a package that's already on the system partition.
*/
- @GuardedBy({"mPm.mLock", "mPm.mInstallLock"})
+ @GuardedBy("mPm.mInstallLock")
private void installPackageFromSystemLIF(@NonNull String codePathString,
@NonNull int[] allUserHandles, @Nullable int[] origUserHandles,
- boolean writeSettings, int previousAppId)
+ boolean writeSettings)
throws PackageManagerException {
final File codePath = new File(codePathString);
@ParsingPackageUtils.ParseFlags int parseFlags =
@@ -3209,7 +3194,7 @@ final class InstallPackageHelper {
| ParsingPackageUtils.PARSE_IS_SYSTEM_DIR;
@PackageManagerService.ScanFlags int scanFlags = mPm.getSystemPackageScanFlags(codePath);
final AndroidPackage pkg = scanSystemPackageTracedLI(
- codePath, parseFlags, scanFlags, 0 /*currentTime*/, null);
+ codePath, parseFlags, scanFlags, null);
PackageSetting pkgSetting = mPm.mSettings.getPackageLPr(pkg.getPackageName());
@@ -3223,13 +3208,12 @@ final class InstallPackageHelper {
mAppDataHelper.prepareAppDataAfterInstallLIF(pkg);
- setPackageInstalledForSystemPackage(pkg, allUserHandles,
- origUserHandles, writeSettings, previousAppId);
+ setPackageInstalledForSystemPackage(pkg, allUserHandles, origUserHandles, writeSettings);
}
private void setPackageInstalledForSystemPackage(@NonNull AndroidPackage pkg,
@NonNull int[] allUserHandles, @Nullable int[] origUserHandles,
- boolean writeSettings, int previousAppId) {
+ boolean writeSettings) {
// writer
synchronized (mPm.mLock) {
PackageSetting ps = mPm.mSettings.getPackageLPr(pkg.getPackageName());
@@ -3263,7 +3247,7 @@ final class InstallPackageHelper {
// The method below will take care of removing obsolete permissions and granting
// install permissions.
- mPm.mPermissionManager.onPackageInstalled(pkg, previousAppId,
+ mPm.mPermissionManager.onPackageInstalled(pkg, Process.INVALID_UID,
PermissionManagerServiceInternal.PackageInstalledParams.DEFAULT,
UserHandle.USER_ALL);
for (final int userId : allUserHandles) {
@@ -3384,7 +3368,7 @@ final class InstallPackageHelper {
mRemovePackageHelper.removePackageLI(pkg, true);
try {
final File codePath = new File(pkg.getPath());
- scanSystemPackageTracedLI(codePath, 0, scanFlags, 0, null);
+ scanSystemPackageTracedLI(codePath, 0, scanFlags, null);
} catch (PackageManagerException e) {
Slog.e(TAG, "Failed to parse updated, ex-system package: "
+ e.getMessage());
@@ -3405,7 +3389,7 @@ final class InstallPackageHelper {
@GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
public void installPackagesFromDir(File scanDir, List<File> frameworkSplits, int parseFlags,
- int scanFlags, long currentTime, PackageParser2 packageParser,
+ int scanFlags, PackageParser2 packageParser,
ExecutorService executorService) {
final File[] files = scanDir.listFiles();
if (ArrayUtils.isEmpty(files)) {
@@ -3448,7 +3432,7 @@ final class InstallPackageHelper {
parseResult.parsedPackage);
}
try {
- addForInitLI(parseResult.parsedPackage, parseFlags, scanFlags, currentTime,
+ addForInitLI(parseResult.parsedPackage, parseFlags, scanFlags,
null);
} catch (PackageManagerException e) {
errorCode = e.error;
@@ -3511,7 +3495,7 @@ final class InstallPackageHelper {
try {
final AndroidPackage newPkg = scanSystemPackageTracedLI(
- scanFile, reparseFlags, rescanFlags, 0, null);
+ scanFile, reparseFlags, rescanFlags, null);
// We rescanned a stub, add it to the list of stubbed system packages
if (newPkg.isStub()) {
stubSystemApps.add(packageName);
@@ -3525,14 +3509,14 @@ final class InstallPackageHelper {
/**
* Traces a package scan.
- * @see #scanSystemPackageLI(File, int, int, long, UserHandle)
+ * @see #scanSystemPackageLI(File, int, int, UserHandle)
*/
@GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
public AndroidPackage scanSystemPackageTracedLI(File scanFile, final int parseFlags,
- int scanFlags, long currentTime, UserHandle user) throws PackageManagerException {
+ int scanFlags, UserHandle user) throws PackageManagerException {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanPackage [" + scanFile.toString() + "]");
try {
- return scanSystemPackageLI(scanFile, parseFlags, scanFlags, currentTime, user);
+ return scanSystemPackageLI(scanFile, parseFlags, scanFlags, user);
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
@@ -3544,7 +3528,7 @@ final class InstallPackageHelper {
*/
@GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
private AndroidPackage scanSystemPackageLI(File scanFile, int parseFlags, int scanFlags,
- long currentTime, UserHandle user) throws PackageManagerException {
+ UserHandle user) throws PackageManagerException {
if (DEBUG_INSTALL) Slog.d(TAG, "Parsing: " + scanFile);
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parsePackage");
@@ -3560,7 +3544,7 @@ final class InstallPackageHelper {
PackageManagerService.renameStaticSharedLibraryPackage(parsedPackage);
}
- return addForInitLI(parsedPackage, parseFlags, scanFlags, currentTime, user);
+ return addForInitLI(parsedPackage, parseFlags, scanFlags, user);
}
/**
@@ -3579,11 +3563,11 @@ final class InstallPackageHelper {
@GuardedBy({"mPm.mLock", "mPm.mInstallLock"})
private AndroidPackage addForInitLI(ParsedPackage parsedPackage,
@ParsingPackageUtils.ParseFlags int parseFlags,
- @PackageManagerService.ScanFlags int scanFlags, long currentTime,
+ @PackageManagerService.ScanFlags int scanFlags,
@Nullable UserHandle user) throws PackageManagerException {
final Pair<ScanResult, Boolean> scanResultPair = scanSystemPackageLI(
- parsedPackage, parseFlags, scanFlags, currentTime, user);
+ parsedPackage, parseFlags, scanFlags, user);
final ScanResult scanResult = scanResultPair.first;
boolean shouldHideSystemApp = scanResultPair.second;
if (scanResult.mSuccess) {
@@ -3701,7 +3685,14 @@ final class InstallPackageHelper {
}
disabledPkgSetting = mPm.mSettings.getDisabledSystemPkgLPr(
parsedPackage.getPackageName());
- if (parsedPackage.getSharedUserId() != null && !parsedPackage.isLeavingSharedUid()) {
+
+ boolean ignoreSharedUserId = false;
+ if (installedPkgSetting == null) {
+ // We can directly ignore sharedUserSetting for new installs
+ ignoreSharedUserId = parsedPackage.isLeavingSharedUid();
+ }
+
+ if (!ignoreSharedUserId && parsedPackage.getSharedUserId() != null) {
sharedUserSetting = mPm.mSettings.getSharedUserLPw(
parsedPackage.getSharedUserId(),
0 /*pkgFlags*/, 0 /*pkgPrivateFlags*/, true /*create*/);
@@ -3771,7 +3762,7 @@ final class InstallPackageHelper {
private Pair<ScanResult, Boolean> scanSystemPackageLI(ParsedPackage parsedPackage,
@ParsingPackageUtils.ParseFlags int parseFlags,
- @PackageManagerService.ScanFlags int scanFlags, long currentTime,
+ @PackageManagerService.ScanFlags int scanFlags,
@Nullable UserHandle user) throws PackageManagerException {
final boolean scanSystemPartition =
(parseFlags & ParsingPackageUtils.PARSE_IS_SYSTEM_DIR) != 0;
@@ -3959,7 +3950,7 @@ final class InstallPackageHelper {
}
final ScanResult scanResult = scanPackageNewLI(parsedPackage, parseFlags,
- scanFlags | SCAN_UPDATE_SIGNATURE, currentTime, user, null);
+ scanFlags | SCAN_UPDATE_SIGNATURE, 0 /* currentTime */, user, null);
return new Pair<>(scanResult, shouldHideSystemApp);
}
diff --git a/services/core/java/com/android/server/pm/InstallParams.java b/services/core/java/com/android/server/pm/InstallParams.java
index 6c80976c0f78..18d2b0c23320 100644
--- a/services/core/java/com/android/server/pm/InstallParams.java
+++ b/services/core/java/com/android/server/pm/InstallParams.java
@@ -289,8 +289,8 @@ final class InstallParams extends HandlerParams {
*/
private int fixUpInstallReason(String installerPackageName, int installerUid,
int installReason) {
- if (mPm.checkUidPermission(android.Manifest.permission.INSTALL_PACKAGES, installerUid)
- == PERMISSION_GRANTED) {
+ if (mPm.snapshotComputer().checkUidPermission(android.Manifest.permission.INSTALL_PACKAGES,
+ installerUid) == PERMISSION_GRANTED) {
// If the install is being performed by a system app, we trust that app to have set the
// install reason correctly.
return installReason;
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index 742cc0237cec..45c5116bea59 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -27,6 +27,7 @@ import android.os.CreateAppDataArgs;
import android.os.CreateAppDataResult;
import android.os.IBinder;
import android.os.IInstalld;
+import android.os.ReconcileSdkDataArgs;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.storage.CrateMetadata;
@@ -88,10 +89,19 @@ public class Installer extends SystemService {
*/
public static final int PROFILE_ANALYSIS_DONT_OPTIMIZE_EMPTY_PROFILES = 3;
+ /**
+ * The results of {@code getOdexVisibility}. See
+ * {@link #getOdexVisibility(String, String, String)} for details.
+ */
+ public static final int ODEX_NOT_FOUND = 0;
+ public static final int ODEX_IS_PUBLIC = 1;
+ public static final int ODEX_IS_PRIVATE = 2;
+
public static final int FLAG_STORAGE_DE = IInstalld.FLAG_STORAGE_DE;
public static final int FLAG_STORAGE_CE = IInstalld.FLAG_STORAGE_CE;
public static final int FLAG_STORAGE_EXTERNAL = IInstalld.FLAG_STORAGE_EXTERNAL;
+ public static final int FLAG_STORAGE_SDK = IInstalld.FLAG_STORAGE_SDK;
public static final int FLAG_CLEAR_CACHE_ONLY = IInstalld.FLAG_CLEAR_CACHE_ONLY;
public static final int FLAG_CLEAR_CODE_CACHE_ONLY = IInstalld.FLAG_CLEAR_CODE_CACHE_ONLY;
@@ -190,12 +200,16 @@ public class Installer extends SystemService {
// We explicitly do NOT set previousAppId because the default value should always be 0.
// Manually override previousAppId after building CreateAppDataArgs for specific behaviors.
static CreateAppDataArgs buildCreateAppDataArgs(String uuid, String packageName,
- int userId, int flags, int appId, String seInfo, int targetSdkVersion) {
+ int userId, int flags, int appId, String seInfo, int targetSdkVersion,
+ boolean usesSdk) {
final CreateAppDataArgs args = new CreateAppDataArgs();
args.uuid = uuid;
args.packageName = packageName;
args.userId = userId;
args.flags = flags;
+ if (usesSdk) {
+ args.flags |= FLAG_STORAGE_SDK;
+ }
args.appId = appId;
args.seInfo = seInfo;
args.targetSdkVersion = targetSdkVersion;
@@ -210,11 +224,28 @@ public class Installer extends SystemService {
return result;
}
+ static ReconcileSdkDataArgs buildReconcileSdkDataArgs(String uuid, String packageName,
+ List<String> subDirNames, int userId, int appId,
+ String seInfo, int flags) {
+ final ReconcileSdkDataArgs args = new ReconcileSdkDataArgs();
+ args.uuid = uuid;
+ args.packageName = packageName;
+ args.subDirNames = subDirNames;
+ args.userId = userId;
+ args.appId = appId;
+ args.previousAppId = 0;
+ args.seInfo = seInfo;
+ args.flags = flags;
+ return args;
+ }
+
public @NonNull CreateAppDataResult createAppData(@NonNull CreateAppDataArgs args)
throws InstallerException {
if (!checkBeforeRemote()) {
return buildPlaceholderCreateAppDataResult();
}
+ // Hardcode previousAppId to 0 to disable any data migration (http://b/221088088)
+ args.previousAppId = 0;
try {
return mInstalld.createAppData(args);
} catch (Exception e) {
@@ -229,6 +260,10 @@ public class Installer extends SystemService {
Arrays.fill(results, buildPlaceholderCreateAppDataResult());
return results;
}
+ // Hardcode previousAppId to 0 to disable any data migration (http://b/221088088)
+ for (final CreateAppDataArgs arg : args) {
+ arg.previousAppId = 0;
+ }
try {
return mInstalld.createAppDataBatched(args);
} catch (Exception e) {
@@ -236,6 +271,18 @@ public class Installer extends SystemService {
}
}
+ void reconcileSdkData(@NonNull ReconcileSdkDataArgs args)
+ throws InstallerException {
+ if (!checkBeforeRemote()) {
+ return;
+ }
+ try {
+ mInstalld.reconcileSdkData(args);
+ } catch (Exception e) {
+ throw InstallerException.from(e);
+ }
+ }
+
/**
* Class that collects multiple {@code installd} operations together in an
* attempt to more efficiently execute them in bulk.
@@ -827,6 +874,15 @@ public class Installer extends SystemService {
}
}
+ /**
+ * Prepares the app profile for the package at the given path:
+ * <ul>
+ * <li>Creates the current profile for the given user ID, unless the user ID is
+ * {@code UserHandle.USER_NULL}.</li>
+ * <li>Merges the profile from the dex metadata file (if present) into the reference
+ * profile.</li>
+ * </ul>
+ */
public boolean prepareAppProfile(String pkg, @UserIdInt int userId, @AppIdInt int appId,
String profileName, String codePath, String dexMetadataPath) throws InstallerException {
if (!checkBeforeRemote()) return false;
@@ -977,6 +1033,33 @@ public class Installer extends SystemService {
}
}
+ /**
+ * Returns the visibility of the optimized artifacts.
+ *
+ * @param packageName name of the package.
+ * @param apkPath path to the APK.
+ * @param instructionSet instruction set of the optimized artifacts.
+ * @param outputPath path to the directory that contains the optimized artifacts (i.e., the
+ * directory that {@link #dexopt} outputs to).
+ *
+ * @return {@link #ODEX_NOT_FOUND} if the optimized artifacts are not found, or
+ * {@link #ODEX_IS_PUBLIC} if the optimized artifacts are accessible by all apps, or
+ * {@link #ODEX_IS_PRIVATE} if the optimized artifacts are only accessible by this app.
+ *
+ * @throws InstallerException if failed to get the visibility of the optimized artifacts.
+ */
+ public int getOdexVisibility(String packageName, String apkPath, String instructionSet,
+ String outputPath) throws InstallerException {
+ if (!checkBeforeRemote()) return -1;
+ BlockGuard.getVmPolicy().onPathAccess(apkPath);
+ BlockGuard.getVmPolicy().onPathAccess(outputPath);
+ try {
+ return mInstalld.getOdexVisibility(packageName, apkPath, instructionSet, outputPath);
+ } catch (Exception e) {
+ throw InstallerException.from(e);
+ }
+ }
+
public static class InstallerException extends Exception {
public InstallerException(String detailMessage) {
super(detailMessage);
diff --git a/services/core/java/com/android/server/pm/IntentResolverInterceptor.java b/services/core/java/com/android/server/pm/IntentResolverInterceptor.java
new file mode 100644
index 000000000000..0ee07b650cf5
--- /dev/null
+++ b/services/core/java/com/android/server/pm/IntentResolverInterceptor.java
@@ -0,0 +1,126 @@
+/*
+ * 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 com.android.server.wm.ActivityInterceptorCallback.INTENT_RESOLVER_ORDERED_ID;
+
+import android.Manifest;
+import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.app.ActivityTaskManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.os.RemoteException;
+import android.provider.DeviceConfig;
+import android.util.Slog;
+
+import com.android.internal.R;
+import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
+import com.android.server.LocalServices;
+import com.android.server.wm.ActivityInterceptorCallback;
+import com.android.server.wm.ActivityInterceptorCallback.ActivityInterceptorInfo;
+import com.android.server.wm.ActivityTaskManagerInternal;
+
+/**
+ * Service to register an {@code ActivityInterceptorCallback} that modifies any {@code Intent}
+ * that's being used to launch a user-space {@code ChooserActivity}, by adding
+ * EXTRA_PERMISSION_TOKEN, a Binder representing a single-use-only permission to invoke the
+ * #startActivityAsCaller() API (which normally isn't available in user-space); and setting the
+ * destination component to the delegated component when appropriate.
+ */
+public final class IntentResolverInterceptor {
+ private static final String TAG = "IntentResolverIntercept";
+
+ private final Context mContext;
+ private boolean mUseDelegateChooser;
+
+ private final ActivityInterceptorCallback mActivityInterceptorCallback =
+ new ActivityInterceptorCallback() {
+ @Nullable
+ @Override
+ public ActivityInterceptResult intercept(ActivityInterceptorInfo info) {
+ if (mUseDelegateChooser && isChooserActivity(info)) {
+ return new ActivityInterceptResult(
+ modifyChooserIntent(info.intent),
+ info.checkedOptions);
+ }
+ return null;
+ }
+ };
+
+ public IntentResolverInterceptor(Context context) {
+ mContext = context;
+ }
+
+ /**
+ * Start listening for intents and USE_DELEGATE_CHOOSER property changes.
+ */
+ @RequiresPermission(Manifest.permission.READ_DEVICE_CONFIG)
+ public void registerListeners() {
+ LocalServices.getService(ActivityTaskManagerInternal.class)
+ .registerActivityStartInterceptor(INTENT_RESOLVER_ORDERED_ID,
+ mActivityInterceptorCallback);
+
+ DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_SYSTEMUI,
+ mContext.getMainExecutor(), properties -> updateUseDelegateChooser());
+ updateUseDelegateChooser();
+ }
+
+ @RequiresPermission(Manifest.permission.READ_DEVICE_CONFIG)
+ private void updateUseDelegateChooser() {
+ mUseDelegateChooser = DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_SYSTEMUI,
+ SystemUiDeviceConfigFlags.USE_DELEGATE_CHOOSER,
+ false);
+ }
+
+ private Intent modifyChooserIntent(Intent intent) {
+ intent.setComponent(getUnbundledChooserComponentName());
+ addStartActivityPermissionTokenToIntent(intent, getUnbundledChooserComponentName());
+ return intent;
+ }
+
+ private static boolean isChooserActivity(ActivityInterceptorInfo info) {
+ ComponentName targetComponent = new ComponentName(info.aInfo.packageName, info.aInfo.name);
+
+ return targetComponent.equals(getSystemChooserComponentName())
+ || targetComponent.equals(getUnbundledChooserComponentName());
+ }
+
+ private static Intent addStartActivityPermissionTokenToIntent(
+ Intent intent, ComponentName grantee) {
+ try {
+ intent.putExtra(
+ ActivityTaskManager.EXTRA_PERMISSION_TOKEN,
+ ActivityTaskManager.getService().requestStartActivityPermissionToken(grantee));
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed to add permission token to chooser intent");
+ }
+ return intent;
+ }
+
+ private static ComponentName getSystemChooserComponentName() {
+ return new ComponentName("android", "com.android.internal.app.ChooserActivity");
+ }
+
+ private static ComponentName getUnbundledChooserComponentName() {
+ return ComponentName.unflattenFromString(
+ Resources.getSystem().getString(R.string.config_chooserActivity));
+ }
+}
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index 6b3ce773fb63..5e0fc3bf91e7 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -320,8 +320,12 @@ public class LauncherAppsService extends SystemService {
private PackageInstallerService getPackageInstallerService() {
if (mPackageInstallerService == null) {
- mPackageInstallerService = ((PackageInstallerService) ((PackageManagerService)
- ServiceManager.getService("package")).getPackageInstaller());
+ try {
+ mPackageInstallerService = ((PackageInstallerService) ((IPackageManager)
+ ServiceManager.getService("package")).getPackageInstaller());
+ } catch (RemoteException e) {
+ Slog.wtf(TAG, "Error gettig IPackageInstaller", e);
+ }
}
return mPackageInstallerService;
}
@@ -1109,13 +1113,11 @@ public class LauncherAppsService extends SystemService {
// Note the target activity doesn't have to be exported.
// Flag for bubble
- if (startActivityOptions != null) {
- ActivityOptions options = ActivityOptions.fromBundle(startActivityOptions);
- if (options.isApplyActivityFlagsForBubbles()) {
- // Flag for bubble to make behaviour match documentLaunchMode=always.
- intents[0].addFlags(FLAG_ACTIVITY_NEW_DOCUMENT);
- intents[0].addFlags(FLAG_ACTIVITY_MULTIPLE_TASK);
- }
+ ActivityOptions options = ActivityOptions.fromBundle(startActivityOptions);
+ if (options != null && options.isApplyActivityFlagsForBubbles()) {
+ // Flag for bubble to make behaviour match documentLaunchMode=always.
+ intents[0].addFlags(FLAG_ACTIVITY_NEW_DOCUMENT);
+ intents[0].addFlags(FLAG_ACTIVITY_MULTIPLE_TASK);
}
intents[0].addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
diff --git a/services/core/java/com/android/server/pm/ModuleInfoProvider.java b/services/core/java/com/android/server/pm/ModuleInfoProvider.java
index 0ffc1ed9e90c..230f5558b37d 100644
--- a/services/core/java/com/android/server/pm/ModuleInfoProvider.java
+++ b/services/core/java/com/android/server/pm/ModuleInfoProvider.java
@@ -16,6 +16,7 @@
package com.android.server.pm;
+import android.annotation.NonNull;
import android.content.Context;
import android.content.pm.IPackageManager;
import android.content.pm.ModuleInfo;
@@ -25,6 +26,7 @@ import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Resources;
import android.content.res.XmlResourceParser;
import android.os.RemoteException;
+import android.os.ServiceManager;
import android.os.UserHandle;
import android.text.TextUtils;
import android.util.ArrayMap;
@@ -58,7 +60,7 @@ public class ModuleInfoProvider {
private static final String MODULE_METADATA_KEY = "android.content.pm.MODULE_METADATA";
private final Context mContext;
- private final IPackageManager mPackageManager;
+ private IPackageManager mPackageManager;
private final ApexManager mApexManager;
private final Map<String, ModuleInfo> mModuleInfo;
@@ -66,9 +68,8 @@ public class ModuleInfoProvider {
private volatile boolean mMetadataLoaded;
private volatile String mPackageName;
- ModuleInfoProvider(Context context, IPackageManager packageManager) {
+ ModuleInfoProvider(Context context) {
mContext = context;
- mPackageManager = packageManager;
mApexManager = ApexManager.getInstance();
mModuleInfo = new ArrayMap<>();
}
@@ -77,12 +78,20 @@ public class ModuleInfoProvider {
public ModuleInfoProvider(
XmlResourceParser metadata, Resources resources, ApexManager apexManager) {
mContext = null;
- mPackageManager = null;
mApexManager = apexManager;
mModuleInfo = new ArrayMap<>();
loadModuleMetadata(metadata, resources);
}
+ @NonNull
+ private IPackageManager getPackageManager() {
+ if (mPackageManager == null) {
+ mPackageManager = IPackageManager.Stub.asInterface(
+ ServiceManager.getService("package"));
+ }
+ return mPackageManager;
+ }
+
/** Called by the {@code PackageManager} when it has completed its boot sequence */
public void systemReady() {
mPackageName = mContext.getResources().getString(
@@ -95,7 +104,7 @@ public class ModuleInfoProvider {
final Resources packageResources;
final PackageInfo pi;
try {
- pi = mPackageManager.getPackageInfo(mPackageName,
+ pi = getPackageManager().getPackageInfo(mPackageName,
PackageManager.GET_META_DATA, UserHandle.USER_SYSTEM);
Context packageContext = mContext.createPackageContext(mPackageName, 0);
@@ -183,7 +192,7 @@ public class ModuleInfoProvider {
List<PackageInfo> allPackages;
try {
- allPackages = mPackageManager.getInstalledPackages(
+ allPackages = getPackageManager().getInstalledPackages(
flags | PackageManager.MATCH_APEX, UserHandle.getCallingUserId()).getList();
} catch (RemoteException e) {
Slog.w(TAG, "Unable to retrieve all package names", e);
diff --git a/services/core/java/com/android/server/pm/MovePackageHelper.java b/services/core/java/com/android/server/pm/MovePackageHelper.java
index 5fc90b1d994f..c5ca06cc7b84 100644
--- a/services/core/java/com/android/server/pm/MovePackageHelper.java
+++ b/services/core/java/com/android/server/pm/MovePackageHelper.java
@@ -57,6 +57,8 @@ import com.android.internal.os.SomeArgs;
import com.android.internal.util.FrameworkStatsLog;
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 java.io.File;
import java.util.Objects;
@@ -77,81 +79,74 @@ public final class MovePackageHelper {
final StorageManager storage = mPm.mInjector.getSystemService(StorageManager.class);
final PackageManager pm = mPm.mContext.getPackageManager();
- final String currentVolumeUuid;
- final File codeFile;
- final InstallSource installSource;
- final String packageAbiOverride;
- final int appId;
- final String seinfo;
- final String label;
- final int targetSdkVersion;
- final PackageFreezer freezer;
- final int[] installedUserIds;
- final boolean isCurrentLocationExternal;
- final String fromCodePath;
+ Computer snapshot = mPm.snapshotComputer();
+ final PackageStateInternal packageState = snapshot.getPackageStateInternal(packageName);
+ if (packageState == null
+ || packageState.getPkg() == null
+ || snapshot.shouldFilterApplication(packageState, callingUid, user.getIdentifier())) {
+ throw new PackageManagerException(MOVE_FAILED_DOESNT_EXIST, "Missing package");
+ }
+ final AndroidPackage pkg = packageState.getPkg();
+ if (pkg.isSystem()) {
+ throw new PackageManagerException(MOVE_FAILED_SYSTEM_PACKAGE,
+ "Cannot move system application");
+ }
- // reader
- synchronized (mPm.mLock) {
- final AndroidPackage pkg = mPm.mPackages.get(packageName);
- final PackageSetting ps = mPm.mSettings.getPackageLPr(packageName);
- if (pkg == null
- || ps == null
- || mPm.shouldFilterApplication(ps, callingUid, user.getIdentifier())) {
- throw new PackageManagerException(MOVE_FAILED_DOESNT_EXIST, "Missing package");
- }
- if (pkg.isSystem()) {
- throw new PackageManagerException(MOVE_FAILED_SYSTEM_PACKAGE,
- "Cannot move system application");
- }
+ final boolean isInternalStorage = VolumeInfo.ID_PRIVATE_INTERNAL.equals(volumeUuid);
+ final boolean allow3rdPartyOnInternal = mPm.mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_allow3rdPartyAppOnInternal);
+ if (isInternalStorage && !allow3rdPartyOnInternal) {
+ throw new PackageManagerException(MOVE_FAILED_3RD_PARTY_NOT_ALLOWED_ON_INTERNAL,
+ "3rd party apps are not allowed on internal storage");
+ }
- final boolean isInternalStorage = VolumeInfo.ID_PRIVATE_INTERNAL.equals(volumeUuid);
- final boolean allow3rdPartyOnInternal = mPm.mContext.getResources().getBoolean(
- com.android.internal.R.bool.config_allow3rdPartyAppOnInternal);
- if (isInternalStorage && !allow3rdPartyOnInternal) {
- throw new PackageManagerException(MOVE_FAILED_3RD_PARTY_NOT_ALLOWED_ON_INTERNAL,
- "3rd party apps are not allowed on internal storage");
- }
- currentVolumeUuid = ps.getVolumeUuid();
+ final String currentVolumeUuid = packageState.getVolumeUuid();
- final File probe = new File(pkg.getPath());
- final File probeOat = new File(probe, "oat");
- if (!probe.isDirectory() || !probeOat.isDirectory()) {
- throw new PackageManagerException(MOVE_FAILED_INTERNAL_ERROR,
- "Move only supported for modern cluster style installs");
- }
+ final File probe = new File(pkg.getPath());
+ final File probeOat = new File(probe, "oat");
+ if (!probe.isDirectory() || !probeOat.isDirectory()) {
+ throw new PackageManagerException(MOVE_FAILED_INTERNAL_ERROR,
+ "Move only supported for modern cluster style installs");
+ }
- if (Objects.equals(currentVolumeUuid, volumeUuid)) {
- throw new PackageManagerException(MOVE_FAILED_INTERNAL_ERROR,
- "Package already moved to " + volumeUuid);
- }
- if (!pkg.isExternalStorage() && mPm.isPackageDeviceAdminOnAnyUser(packageName)) {
- throw new PackageManagerException(MOVE_FAILED_DEVICE_ADMIN,
- "Device admin cannot be moved");
- }
+ if (Objects.equals(currentVolumeUuid, volumeUuid)) {
+ throw new PackageManagerException(MOVE_FAILED_INTERNAL_ERROR,
+ "Package already moved to " + volumeUuid);
+ }
+ if (!pkg.isExternalStorage()
+ && mPm.isPackageDeviceAdminOnAnyUser(snapshot, packageName)) {
+ throw new PackageManagerException(MOVE_FAILED_DEVICE_ADMIN,
+ "Device admin cannot be moved");
+ }
- if (mPm.mFrozenPackages.containsKey(packageName)) {
- throw new PackageManagerException(MOVE_FAILED_OPERATION_PENDING,
- "Failed to move already frozen package");
- }
+ if (snapshot.getFrozenPackages().containsKey(packageName)) {
+ throw new PackageManagerException(MOVE_FAILED_OPERATION_PENDING,
+ "Failed to move already frozen package");
+ }
- isCurrentLocationExternal = pkg.isExternalStorage();
- codeFile = new File(pkg.getPath());
- installSource = ps.getInstallSource();
- packageAbiOverride = ps.getCpuAbiOverride();
- appId = UserHandle.getAppId(pkg.getUid());
- seinfo = AndroidPackageUtils.getSeInfo(pkg, ps);
- label = String.valueOf(pm.getApplicationLabel(
- AndroidPackageUtils.generateAppInfoWithoutState(pkg)));
- targetSdkVersion = pkg.getTargetSdkVersion();
+ final boolean isCurrentLocationExternal = pkg.isExternalStorage();
+ final File codeFile = new File(pkg.getPath());
+ final InstallSource installSource = packageState.getInstallSource();
+ final String packageAbiOverride = packageState.getCpuAbiOverride();
+ final int appId = UserHandle.getAppId(pkg.getUid());
+ final String seinfo = AndroidPackageUtils.getSeInfo(pkg, packageState);
+ final String label = String.valueOf(pm.getApplicationLabel(
+ AndroidPackageUtils.generateAppInfoWithoutState(pkg)));
+ final int targetSdkVersion = pkg.getTargetSdkVersion();
+ final int[] installedUserIds = PackageStateUtils.queryInstalledUsers(packageState,
+ mPm.mUserManager.getUserIds(), true);
+ final String fromCodePath;
+ if (codeFile.getParentFile().getName().startsWith(
+ PackageManagerService.RANDOM_DIR_PREFIX)) {
+ fromCodePath = codeFile.getParentFile().getAbsolutePath();
+ } else {
+ fromCodePath = codeFile.getAbsolutePath();
+ }
+
+ final PackageFreezer freezer;
+ synchronized (mPm.mLock) {
freezer = mPm.freezePackage(packageName, "movePackageInternal");
- installedUserIds = ps.queryInstalledUsers(mPm.mUserManager.getUserIds(), true);
- if (codeFile.getParentFile().getName().startsWith(
- PackageManagerService.RANDOM_DIR_PREFIX)) {
- fromCodePath = codeFile.getParentFile().getAbsolutePath();
- } else {
- fromCodePath = codeFile.getAbsolutePath();
- }
}
final Bundle extras = new Bundle();
diff --git a/services/core/java/com/android/server/pm/OWNERS b/services/core/java/com/android/server/pm/OWNERS
index c219f80ac9c5..8534fabb5576 100644
--- a/services/core/java/com/android/server/pm/OWNERS
+++ b/services/core/java/com/android/server/pm/OWNERS
@@ -15,7 +15,9 @@ per-file StagingManager.java = dariofreni@google.com, ioffe@google.com, olilan@g
per-file AbstractStatsBase.java = file:dex/OWNERS
per-file BackgroundDexOptService.java = file:dex/OWNERS
per-file CompilerStats.java = file:dex/OWNERS
+per-file DexOptHelper.java = file:dex/OWNERS
per-file DynamicCodeLoggingService.java = file:dex/OWNERS
+per-file Installer.java = file:dex/OWNERS
per-file InstructionSets.java = file:dex/OWNERS
per-file OtaDexoptService.java = file:dex/OWNERS
per-file OtaDexoptShellCommand.java = file:dex/OWNERS
diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java
index bd0091480caf..cc4a76034b2b 100644
--- a/services/core/java/com/android/server/pm/OtaDexoptService.java
+++ b/services/core/java/com/android/server/pm/OtaDexoptService.java
@@ -131,8 +131,9 @@ public class OtaDexoptService extends IOtaDexopt.Stub {
Predicate<PackageStateInternal> isPlatformPackage = pkgSetting ->
PLATFORM_PACKAGE_NAME.equals(pkgSetting.getPkg().getPackageName());
// Important: the packages we need to run with ab-ota compiler-reason.
+ final Computer snapshot = mPackageManagerService.snapshotComputer();
final Collection<? extends PackageStateInternal> allPackageStates =
- mPackageManagerService.getPackageStates().values();
+ snapshot.getPackageStates().values();
important = DexOptHelper.getPackagesForDexopt(allPackageStates,mPackageManagerService,
DEBUG_DEXOPT);
// Remove Platform Package from A/B OTA b/160735835.
@@ -165,7 +166,7 @@ public class OtaDexoptService extends IOtaDexopt.Stub {
Log.i(TAG, "Low on space, deleting oat files in an attempt to free up space: "
+ DexOptHelper.packagesToString(others));
for (PackageStateInternal pkg : others) {
- mPackageManagerService.deleteOatArtifactsOfPackage(pkg.getPackageName());
+ mPackageManagerService.deleteOatArtifactsOfPackage(snapshot, pkg.getPackageName());
}
}
long spaceAvailableNow = getAvailableSpace();
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index 69d498794e64..27c6d9bec2e8 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -319,28 +319,42 @@ public class PackageDexOptimizer {
String profileName = ArtManager.getProfileName(
i == 0 ? null : pkg.getSplitNames()[i - 1]);
+ final boolean isUsedByOtherApps = options.isDexoptAsSharedLibrary()
+ || packageUseInfo.isUsedByOtherApps(path);
+ 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)
+ && isUsedByOtherApps
+ && options.getCompilationReason() != PackageManagerService.REASON_INSTALL;
String dexMetadataPath = null;
- if (options.isDexoptInstallWithDexMetadata()) {
+ if (options.isDexoptInstallWithDexMetadata() || resetProfile) {
File dexMetadataFile = DexMetadataHelper.findDexMetadataForFile(new File(path));
dexMetadataPath = dexMetadataFile == null
? null : dexMetadataFile.getAbsolutePath();
}
- final boolean isUsedByOtherApps = options.isDexoptAsSharedLibrary()
- || packageUseInfo.isUsedByOtherApps(path);
- final String compilerFilter = getRealCompilerFilter(pkg,
- options.getCompilerFilter(), isUsedByOtherApps);
// If we don't have to check for profiles updates assume
// PROFILE_ANALYSIS_DONT_OPTIMIZE_SMALL_DELTA which will be a no-op with respect to
// profiles.
- final int profileAnalysisResult = options.isCheckForProfileUpdates()
- ? analyseProfiles(pkg, sharedGid, profileName, compilerFilter)
- : PROFILE_ANALYSIS_DONT_OPTIMIZE_SMALL_DELTA;
+ 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()) {
+ 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, options);
+ final int dexoptFlags = getDexFlags(pkg, pkgSetting, compilerFilter, resetProfile,
+ options);
for (String dexCodeIsa : dexCodeInstructionSets) {
int newResult = dexOptPath(pkg, pkgSetting, path, dexCodeIsa, compilerFilter,
@@ -391,6 +405,30 @@ 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.
+ */
+ @GuardedBy("mInstallLock")
+ private boolean resetProfile(AndroidPackage pkg, String profileName, String path,
+ @Nullable String dexMetadataPath) {
+ if (dexMetadataPath != null) {
+ try {
+ mInstaller.clearAppProfiles(pkg.getPackageName(), profileName);
+ final int appId = UserHandle.getAppId(pkg.getUid());
+ mInstaller.prepareAppProfile(pkg.getPackageName(), UserHandle.USER_NULL,
+ appId, profileName, path, dexMetadataPath);
+ return true;
+ } catch (InstallerException e) {
+ Slog.w(TAG, "Failed to reset profile", e);
+ return false;
+ }
+ } else {
+ return false;
+ }
+ }
+
+ /**
* Performs dexopt on the {@code path} belonging to the package {@code pkg}.
*
* @return
@@ -405,15 +443,15 @@ public class PackageDexOptimizer {
String classLoaderContext, int dexoptFlags, int uid,
CompilerStats.PackageStats packageStats, boolean downgrade, String profileName,
String dexMetadataPath, int compilationReason) {
- int dexoptNeeded = getDexoptNeeded(path, isa, compilerFilter, classLoaderContext,
- profileAnalysisResult, downgrade);
+ String oatDir = getPackageOatDirIfSupported(pkg,
+ pkgSetting.getTransientState().isUpdatedSystemApp());
+
+ int dexoptNeeded = getDexoptNeeded(pkg.getPackageName(), path, isa, compilerFilter,
+ classLoaderContext, profileAnalysisResult, downgrade, dexoptFlags, oatDir);
if (Math.abs(dexoptNeeded) == DexFile.NO_DEXOPT_NEEDED) {
return DEX_OPT_SKIPPED;
}
- String oatDir = getPackageOatDirIfSupported(pkg,
- pkgSetting.getTransientState().isUpdatedSystemApp());
-
Log.i(TAG, "Running dexopt (dexoptNeeded=" + dexoptNeeded + ") on: " + path
+ " pkg=" + pkg.getPackageName() + " isa=" + isa
+ " dexoptFlags=" + printDexoptFlags(dexoptFlags)
@@ -456,6 +494,7 @@ public class PackageDexOptimizer {
/**
* Perform dexopt (if needed) on a system server code path).
*/
+ @GuardedBy("mInstallLock")
@DexOptResult
public int dexoptSystemServerPath(
String dexPath, PackageDexUsage.DexUseInfo dexUseInfo, DexoptOptions options) {
@@ -466,12 +505,15 @@ public class PackageDexOptimizer {
int result = DEX_OPT_SKIPPED;
for (String isa : dexUseInfo.getLoaderIsas()) {
int dexoptNeeded = getDexoptNeeded(
+ PackageManagerService.PLATFORM_PACKAGE_NAME,
dexPath,
isa,
options.getCompilerFilter(),
dexUseInfo.getClassLoaderContext(),
PROFILE_ANALYSIS_DONT_OPTIMIZE_EMPTY_PROFILES,
- /* downgrade= */ false);
+ /* downgrade= */ false,
+ dexoptFlags,
+ /* oatDir= */ null);
if (dexoptNeeded == DexFile.NO_DEXOPT_NEEDED) {
continue;
@@ -714,7 +756,7 @@ public class PackageDexOptimizer {
}
/**
- * Returns the compiler filter that should be used to optimize the package code.
+ * Returns the compiler filter that should be used to optimize the secondary dex.
* The target filter will be updated if the package code is used by other apps
* or if it has the safe mode flag set.
*/
@@ -754,12 +796,12 @@ public class PackageDexOptimizer {
}
/**
- * Returns the compiler filter that should be used to optimize the package code.
- * The target filter will be updated if the package code is used by other apps
- * or if it has the safe mode flag set.
+ * Returns the compiler filter that should be used to optimize the primary dex.
+ * The target filter will be updated if the package has the safe mode flag set. Note that this
+ * method does NOT take other app use into account. The caller should be responsible for
+ * handling the case where the package code is used by other apps.
*/
- private String getRealCompilerFilter(AndroidPackage pkg, String targetCompilerFilter,
- boolean isUsedByOtherApps) {
+ private String getRealCompilerFilter(AndroidPackage pkg, String targetCompilerFilter) {
// When an app or priv app is configured to run out of box, only verify it.
if (pkg.isUseEmbeddedDex()
|| (pkg.isPrivileged()
@@ -783,12 +825,6 @@ public class PackageDexOptimizer {
return getSafeModeCompilerFilter(targetCompilerFilter);
}
- if (isProfileGuidedCompilerFilter(targetCompilerFilter) && isUsedByOtherApps) {
- // If the dex files is used by other apps, apply the shared filter.
- return PackageManagerServiceCompilerMapping.getCompilerFilterForReason(
- PackageManagerService.REASON_SHARED);
- }
-
return targetCompilerFilter;
}
@@ -799,14 +835,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, options);
+ info.requestsIsolatedSplitLoading(), compilerFilter, false /* resetProfile */,
+ options);
}
+
private int getDexFlags(AndroidPackage pkg, @NonNull PackageStateInternal pkgSetting,
- String compilerFilter, DexoptOptions options) {
+ String compilerFilter, boolean resetProfile, DexoptOptions options) {
return getDexFlags(pkg.isDebuggable(),
AndroidPackageUtils.getHiddenApiEnforcementPolicy(pkg, pkgSetting),
pkg.getSplitDependencies(), pkg.isIsolatedSplitLoading(), compilerFilter,
- options);
+ resetProfile, options);
}
/**
@@ -815,13 +853,15 @@ public class PackageDexOptimizer {
*/
private int getDexFlags(boolean debuggable, int hiddenApiEnforcementPolicy,
SparseArray<int[]> splitDependencies, boolean requestsIsolatedSplitLoading,
- String compilerFilter, DexoptOptions options) {
+ String compilerFilter, boolean resetProfile, 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.
boolean isProfileGuidedFilter = isProfileGuidedCompilerFilter(compilerFilter);
- boolean isPublic = !isProfileGuidedFilter || options.isDexoptInstallWithDexMetadata();
+ boolean isPublic = !isProfileGuidedFilter || options.isDexoptInstallWithDexMetadata()
+ || resetProfile;
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.
@@ -866,8 +906,19 @@ public class PackageDexOptimizer {
* Assesses if there's a need to perform dexopt on {@code path} for the given
* configuration (isa, compiler filter, profile).
*/
- private int getDexoptNeeded(String path, String isa, String compilerFilter,
- String classLoaderContext, int profileAnalysisResult, boolean downgrade) {
+ @GuardedBy("mInstallLock")
+ private int getDexoptNeeded(String packageName, String path, String isa, String compilerFilter,
+ String classLoaderContext, int profileAnalysisResult, boolean downgrade,
+ int dexoptFlags, String oatDir) {
+ final boolean shouldBePublic = (dexoptFlags & DEXOPT_PUBLIC) != 0;
+ // If the artifacts should be public while the current artifacts are not, we should
+ // re-compile anyway.
+ if (shouldBePublic && isOdexPrivate(packageName, path, isa, oatDir)) {
+ // Ensure compilation by pretending a compiler filter change on the apk/odex location
+ // (the reason for the '-'. A positive value means the 'oat' location).
+ return adjustDexoptNeeded(-DexFile.DEX2OAT_FOR_FILTER);
+ }
+
int dexoptNeeded;
try {
// A profile guided optimizations with an empty profile is essentially 'verify' and
@@ -901,6 +952,18 @@ public class PackageDexOptimizer {
return compilerFilter.endsWith("-profile");
}
+ /** Returns true if the current artifacts of the app are private to the app itself. */
+ @GuardedBy("mInstallLock")
+ private boolean isOdexPrivate(String packageName, String path, String isa, String oatDir) {
+ try {
+ return mInstaller.getOdexVisibility(packageName, path, isa, oatDir)
+ == Installer.ODEX_IS_PRIVATE;
+ } catch (Exception e) {
+ Slog.w(TAG, "Failed to get odex visibility for " + path, e);
+ return false;
+ }
+ }
+
/**
* Checks if there is an update on the profile information of the {@code pkg}.
* If the compiler filter is not profile guided the method returns a safe default:
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index fe2fe097bdf6..002d500e4df5 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -334,7 +334,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
StagingManager.StagedSession stagedSession = session.mStagedSession;
if (!stagedSession.isInTerminalState() && stagedSession.hasParentSessionId()
&& getSession(stagedSession.getParentSessionId()) == null) {
- stagedSession.setSessionFailed(SessionInfo.SESSION_ACTIVATION_FAILED,
+ stagedSession.setSessionFailed(PackageManager.INSTALL_ACTIVATION_FAILED,
"An orphan staged session " + stagedSession.sessionId() + " is found, "
+ "parent " + stagedSession.getParentSessionId() + " is missing");
continue;
@@ -597,8 +597,8 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
String installerAttributionTag, int userId)
throws IOException {
final int callingUid = Binder.getCallingUid();
- mPm.enforceCrossUserPermission(
- callingUid, userId, true, true, "createSession");
+ final Computer snapshot = mPm.snapshotComputer();
+ snapshot.enforceCrossUserPermission(callingUid, userId, true, true, "createSession");
if (mPm.isUserRestricted(userId, UserManager.DISALLOW_INSTALL_APPS)) {
throw new SecurityException("User restriction prevents installing");
@@ -640,7 +640,8 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
&& params.installerPackageName.length() < SessionParams.MAX_PACKAGE_NAME_LENGTH)
? params.installerPackageName : installerPackageName;
- if ((callingUid == Process.SHELL_UID) || (callingUid == Process.ROOT_UID)) {
+ if ((callingUid == Process.SHELL_UID) || (callingUid == Process.ROOT_UID)
+ || PackageInstallerSession.isSystemDataLoaderInstallation(params)) {
params.installFlags |= PackageManager.INSTALL_FROM_ADB;
// adb installs can override the installingPackageName, but not the
// initiatingPackageName
@@ -663,11 +664,10 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
params.installFlags &= ~PackageManager.INSTALL_ALL_USERS;
params.installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
if ((params.installFlags & PackageManager.INSTALL_VIRTUAL_PRELOAD) != 0
- && !mPm.isCallerVerifier(callingUid)) {
+ && !mPm.isCallerVerifier(snapshot, callingUid)) {
params.installFlags &= ~PackageManager.INSTALL_VIRTUAL_PRELOAD;
}
- if (mContext.checkCallingOrSelfPermission(
- Manifest.permission.INSTALL_TEST_ONLY_PACKAGE)
+ if (mContext.checkCallingOrSelfPermission(Manifest.permission.INSTALL_TEST_ONLY_PACKAGE)
!= PackageManager.PERMISSION_GRANTED) {
params.installFlags &= ~PackageManager.INSTALL_ALLOW_TEST;
}
@@ -676,7 +676,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
String originatingPackageName = null;
if (params.originatingUid != SessionParams.UID_UNKNOWN
&& params.originatingUid != callingUid) {
- String[] packages = mPm.getPackagesForUid(params.originatingUid);
+ String[] packages = snapshot.getPackagesForUid(params.originatingUid);
if (packages != null && packages.length > 0) {
// Choose an arbitrary representative package in the case of a shared UID.
originatingPackageName = packages[0];
@@ -727,7 +727,8 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
if ((params.installFlags & PackageManager.INSTALL_INSTANT_APP) != 0
&& !isCalledBySystemOrShell(callingUid)
- && (mPm.getFlagsForUid(callingUid) & ApplicationInfo.FLAG_SYSTEM) == 0) {
+ && (snapshot.getFlagsForUid(callingUid) & ApplicationInfo.FLAG_SYSTEM)
+ == 0) {
throw new SecurityException(
"Only system apps could use the PackageManager.INSTALL_INSTANT_APP flag.");
}
@@ -852,7 +853,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
mSilentUpdatePolicy, mInstallThread.getLooper(), mStagingManager, sessionId,
userId, callingUid, installSource, params, createdMillis, 0L, stageDir, stageCid,
null, null, false, false, false, false, null, SessionInfo.INVALID_ID,
- false, false, false, SessionInfo.SESSION_NO_ERROR, "");
+ false, false, false, PackageManager.INSTALL_UNKNOWN, "");
synchronized (mSessions) {
mSessions.put(sessionId, session);
@@ -1037,11 +1038,12 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
return "smdl" + sessionId + ".tmp";
}
- private boolean shouldFilterSession(int uid, SessionInfo info) {
+ private boolean shouldFilterSession(@NonNull Computer snapshot, int uid, SessionInfo info) {
if (info == null) {
return false;
}
- return uid != info.getInstallerUid() && !mPm.canQueryPackage(uid, info.getAppPackageName());
+ return uid != info.getInstallerUid()
+ && !snapshot.canQueryPackage(uid, info.getAppPackageName());
}
@Override
@@ -1054,7 +1056,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
? session.generateInfoForCaller(true /* includeIcon */, callingUid)
: null;
}
- return shouldFilterSession(callingUid, result) ? null : result;
+ return shouldFilterSession(mPm.snapshotComputer(), callingUid, result) ? null : result;
}
@Override
@@ -1069,15 +1071,16 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
}
}
}
- result.removeIf(info -> shouldFilterSession(callingUid, info));
+ final Computer snapshot = mPm.snapshotComputer();
+ result.removeIf(info -> shouldFilterSession(snapshot, callingUid, info));
return new ParceledListSlice<>(result);
}
@Override
public ParceledListSlice<SessionInfo> getAllSessions(int userId) {
final int callingUid = Binder.getCallingUid();
- mPm.enforceCrossUserPermission(
- callingUid, userId, true, false, "getAllSessions");
+ final Computer snapshot = mPm.snapshotComputer();
+ snapshot.enforceCrossUserPermission(callingUid, userId, true, false, "getAllSessions");
final List<SessionInfo> result = new ArrayList<>();
synchronized (mSessions) {
@@ -1089,15 +1092,16 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
}
}
}
- result.removeIf(info -> shouldFilterSession(callingUid, info));
+ result.removeIf(info -> shouldFilterSession(snapshot, callingUid, info));
return new ParceledListSlice<>(result);
}
@Override
public ParceledListSlice<SessionInfo> getMySessions(String installerPackageName, int userId) {
- mPm.enforceCrossUserPermission(
- Binder.getCallingUid(), userId, true, false, "getMySessions");
- mAppOps.checkPackage(Binder.getCallingUid(), installerPackageName);
+ final Computer snapshot = mPm.snapshotComputer();
+ final int callingUid = Binder.getCallingUid();
+ snapshot.enforceCrossUserPermission(callingUid, userId, true, false, "getMySessions");
+ mAppOps.checkPackage(callingUid, installerPackageName);
final List<SessionInfo> result = new ArrayList<>();
synchronized (mSessions) {
@@ -1119,8 +1123,9 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
@Override
public void uninstall(VersionedPackage versionedPackage, String callerPackageName, int flags,
IntentSender statusReceiver, int userId) {
+ final Computer snapshot = mPm.snapshotComputer();
final int callingUid = Binder.getCallingUid();
- mPm.enforceCrossUserPermission(callingUid, userId, true, true, "uninstall");
+ snapshot.enforceCrossUserPermission(callingUid, userId, true, true, "uninstall");
if ((callingUid != Process.SHELL_UID) && (callingUid != Process.ROOT_UID)) {
mAppOps.checkPackage(callingUid, callerPackageName);
}
@@ -1153,7 +1158,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
.setAdmin(callerPackageName)
.write();
} else {
- ApplicationInfo appInfo = mPm.getApplicationInfo(callerPackageName, 0, userId);
+ ApplicationInfo appInfo = snapshot.getApplicationInfo(callerPackageName, 0, userId);
if (appInfo.targetSdkVersion >= Build.VERSION_CODES.P) {
mContext.enforceCallingOrSelfPermission(Manifest.permission.REQUEST_DELETE_PACKAGES,
null);
@@ -1172,7 +1177,8 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
String callerPackageName, IntentSender statusReceiver, int userId) {
final int callingUid = Binder.getCallingUid();
mContext.enforceCallingOrSelfPermission(Manifest.permission.DELETE_PACKAGES, null);
- mPm.enforceCrossUserPermission(callingUid, userId, true, true, "uninstall");
+ final Computer snapshot = mPm.snapshotComputer();
+ snapshot.enforceCrossUserPermission(callingUid, userId, true, true, "uninstall");
if ((callingUid != Process.SHELL_UID) && (callingUid != Process.ROOT_UID)) {
mAppOps.checkPackage(callingUid, callerPackageName);
}
@@ -1204,8 +1210,9 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
@Override
public void registerCallback(IPackageInstallerCallback callback, int userId) {
- mPm.enforceCrossUserPermission(
- Binder.getCallingUid(), userId, true, false, "registerCallback");
+ final Computer snapshot = mPm.snapshotComputer();
+ snapshot.enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false,
+ "registerCallback");
registerCallback(callback, eventUserId -> userId == eventUserId);
}
@@ -1293,13 +1300,13 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
}
}
- private boolean shouldFilterSession(int uid, int sessionId) {
+ private boolean shouldFilterSession(@NonNull Computer snapshot, int uid, int sessionId) {
final PackageInstallerSession session = getSession(sessionId);
if (session == null) {
return false;
}
return uid != session.getInstallerUid()
- && !mPm.canQueryPackage(uid, session.getPackageName());
+ && !snapshot.canQueryPackage(uid, session.getPackageName());
}
static class PackageDeleteObserverAdapter extends PackageDeleteObserver {
@@ -1325,7 +1332,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
private String getDeviceOwnerDeletedPackageMsg() {
DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class);
- return dpm.getString(PACKAGE_DELETED_BY_DO,
+ return dpm.getResources().getString(PACKAGE_DELETED_BY_DO,
() -> mContext.getString(R.string.package_updated_device_owner));
}
@@ -1452,11 +1459,12 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
final int sessionId = msg.arg1;
final int userId = msg.arg2;
final int n = mCallbacks.beginBroadcast();
+ final Computer snapshot = mPm.snapshotComputer();
for (int i = 0; i < n; i++) {
final IPackageInstallerCallback callback = mCallbacks.getBroadcastItem(i);
final BroadcastCookie cookie = (BroadcastCookie) mCallbacks.getBroadcastCookie(i);
if (cookie.userCheck.test(userId)
- && !shouldFilterSession(cookie.callingUid, sessionId)) {
+ && !shouldFilterSession(snapshot, cookie.callingUid, sessionId)) {
try {
invokeCallback(callback, msg);
} catch (RemoteException ignored) {
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 55fc78599661..5ba4cc115c21 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -82,7 +82,6 @@ import android.content.pm.InstallationFileParcel;
import android.content.pm.PackageInfo;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageInstaller.SessionInfo;
-import android.content.pm.PackageInstaller.SessionInfo.SessionErrorCode;
import android.content.pm.PackageInstaller.SessionParams;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
@@ -127,6 +126,7 @@ import android.system.StructStat;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
+import android.util.EventLog;
import android.util.ExceptionUtils;
import android.util.IntArray;
import android.util.MathUtils;
@@ -462,7 +462,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
@GuardedBy("mLock")
private boolean mSessionFailed;
@GuardedBy("mLock")
- private int mSessionErrorCode = SessionInfo.SESSION_NO_ERROR;
+ private int mSessionErrorCode = PackageManager.INSTALL_UNKNOWN;
@GuardedBy("mLock")
private String mSessionErrorMessage;
@@ -704,6 +704,18 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
};
+ static boolean isDataLoaderInstallation(SessionParams params) {
+ return params.dataLoaderParams != null;
+ }
+
+ static boolean isSystemDataLoaderInstallation(SessionParams params) {
+ if (!isDataLoaderInstallation(params)) {
+ return false;
+ }
+ return SYSTEM_DATA_LOADER_PACKAGE.equals(
+ params.dataLoaderParams.getComponentName().getPackageName());
+ }
+
private final Handler.Callback mHandlerCallback = new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
@@ -743,7 +755,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
};
private boolean isDataLoaderInstallation() {
- return params.dataLoaderParams != null;
+ return isDataLoaderInstallation(this.params);
}
private boolean isStreamingInstallation() {
@@ -755,11 +767,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
private boolean isSystemDataLoaderInstallation() {
- if (!isDataLoaderInstallation()) {
- return false;
- }
- return SYSTEM_DATA_LOADER_PACKAGE.equals(
- this.params.dataLoaderParams.getComponentName().getPackageName());
+ return isSystemDataLoaderInstallation(this.params);
}
/**
@@ -817,25 +825,26 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
// It is safe to access mInstallerUid and mInstallSource without lock
// because they are immutable after sealing.
+ final Computer snapshot = mPm.snapshotComputer();
final boolean isInstallPermissionGranted =
- (mPm.checkUidPermission(android.Manifest.permission.INSTALL_PACKAGES,
+ (snapshot.checkUidPermission(android.Manifest.permission.INSTALL_PACKAGES,
mInstallerUid) == PackageManager.PERMISSION_GRANTED);
final boolean isSelfUpdatePermissionGranted =
- (mPm.checkUidPermission(android.Manifest.permission.INSTALL_SELF_UPDATES,
+ (snapshot.checkUidPermission(android.Manifest.permission.INSTALL_SELF_UPDATES,
mInstallerUid) == PackageManager.PERMISSION_GRANTED);
final boolean isUpdatePermissionGranted =
- (mPm.checkUidPermission(android.Manifest.permission.INSTALL_PACKAGE_UPDATES,
+ (snapshot.checkUidPermission(android.Manifest.permission.INSTALL_PACKAGE_UPDATES,
mInstallerUid) == PackageManager.PERMISSION_GRANTED);
- final boolean isUpdateWithoutUserActionPermissionGranted = (mPm.checkUidPermission(
+ final boolean isUpdateWithoutUserActionPermissionGranted = (snapshot.checkUidPermission(
android.Manifest.permission.UPDATE_PACKAGES_WITHOUT_USER_ACTION, mInstallerUid)
== PackageManager.PERMISSION_GRANTED);
- final boolean isInstallDpcPackagesPermissionGranted = (mPm.checkUidPermission(
+ final boolean isInstallDpcPackagesPermissionGranted = (snapshot.checkUidPermission(
android.Manifest.permission.INSTALL_DPC_PACKAGES, mInstallerUid)
== PackageManager.PERMISSION_GRANTED);
- final int targetPackageUid = mPm.getPackageUid(packageName, 0, userId);
+ final int targetPackageUid = snapshot.getPackageUid(packageName, 0, userId);
final boolean isUpdate = targetPackageUid != -1 || isApexSession();
final InstallSourceInfo existingInstallSourceInfo = isUpdate
- ? mPm.getInstallSourceInfo(packageName)
+ ? snapshot.getInstallSourceInfo(packageName)
: null;
final String existingInstallerPackageName = existingInstallSourceInfo != null
? existingInstallSourceInfo.getInstallingPackageName()
@@ -859,7 +868,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
return USER_ACTION_NOT_NEEDED;
}
- if (mPm.isInstallDisabledForPackage(getInstallerPackageName(), mInstallerUid, userId)) {
+ if (snapshot.isInstallDisabledForPackage(getInstallerPackageName(), mInstallerUid,
+ userId)) {
// show the installer to account for device poslicy or unknown sources use cases
return USER_ACTION_REQUIRED;
}
@@ -1256,13 +1266,21 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
return;
}
- final String initiatingPackageName = getInstallSource().initiatingPackageName;
+ final String installerPackageName;
+ if (!TextUtils.isEmpty(getInstallSource().initiatingPackageName)) {
+ installerPackageName = getInstallSource().initiatingPackageName;
+ } else {
+ installerPackageName = getInstallSource().installerPackageName;
+ }
+ if (TextUtils.isEmpty(installerPackageName)) {
+ throw new IllegalStateException("Installer package is empty.");
+ }
final AppOpsManager appOps = mContext.getSystemService(AppOpsManager.class);
- appOps.checkPackage(Binder.getCallingUid(), initiatingPackageName);
+ appOps.checkPackage(Binder.getCallingUid(), installerPackageName);
final PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
- final AndroidPackage callingInstaller = pmi.getPackage(initiatingPackageName);
+ final AndroidPackage callingInstaller = pmi.getPackage(installerPackageName);
if (callingInstaller == null) {
throw new IllegalStateException("Can't obtain calling installer's package.");
}
@@ -2009,12 +2027,13 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
@Override
public void transfer(String packageName) {
Preconditions.checkArgument(!TextUtils.isEmpty(packageName));
- ApplicationInfo newOwnerAppInfo = mPm.getApplicationInfo(packageName, 0, userId);
+ final Computer snapshot = mPm.snapshotComputer();
+ ApplicationInfo newOwnerAppInfo = snapshot.getApplicationInfo(packageName, 0, userId);
if (newOwnerAppInfo == null) {
throw new ParcelableException(new PackageManager.NameNotFoundException(packageName));
}
- if (PackageManager.PERMISSION_GRANTED != mPm.checkUidPermission(
+ if (PackageManager.PERMISSION_GRANTED != snapshot.checkUidPermission(
Manifest.permission.INSTALL_PACKAGES, newOwnerAppInfo.uid)) {
throw new SecurityException("Destination package " + packageName + " does not have "
+ "the " + Manifest.permission.INSTALL_PACKAGES + " permission");
@@ -2329,7 +2348,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
} else {
PackageManagerException e = (PackageManagerException) t.getCause();
- setSessionFailed(SessionInfo.SESSION_ACTIVATION_FAILED,
+ setSessionFailed(e.error,
PackageManager.installStatusToString(e.error, e.getMessage()));
dispatchSessionFinished(e.error, e.getMessage(), null);
maybeFinishChildSessions(e.error, e.getMessage());
@@ -2509,7 +2528,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
// Package didn't install; no valid uid
packageUid = Process.INVALID_UID;
} else {
- packageUid = mPm.getPackageUid(packageName, 0, userId);
+ packageUid = mPm.snapshotComputer().getPackageUid(packageName, 0, userId);
}
FrameworkStatsLog.write(FrameworkStatsLog.PACKAGE_INSTALLER_V2_REPORTED,
isIncrementalInstallation(),
@@ -2667,7 +2686,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
mResolvedStagedFiles.clear();
mResolvedInheritedFiles.clear();
- final PackageInfo pkgInfo = mPm.getPackageInfo(
+ final PackageInfo pkgInfo = mPm.snapshotComputer().getPackageInfo(
params.appPackageName, PackageManager.GET_SIGNATURES
| PackageManager.MATCH_STATIC_SHARED_AND_SDK_LIBRARIES /*flags*/, userId);
@@ -2860,6 +2879,11 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
inheritFileLocked(mResolvedBaseFile);
// Collect the requiredSplitTypes from base
CollectionUtils.addAll(requiredSplitTypes, existing.getBaseRequiredSplitTypes());
+ } else if ((params.installFlags & PackageManager.INSTALL_DONT_KILL_APP) != 0) {
+ EventLog.writeEvent(0x534e4554, "219044664");
+
+ // Installing base.apk. Make sure the app is restarted.
+ params.setDontKillApp(false);
}
// Inherit splits if not overridden.
@@ -3556,6 +3580,11 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
@Override
+ public int getInstallFlags() {
+ return params.installFlags;
+ }
+
+ @Override
public DataLoaderParamsParcel getDataLoaderParams() {
mContext.enforceCallingOrSelfPermission(Manifest.permission.USE_INSTALLER_V2, null);
return params.dataLoaderParams != null ? params.dataLoaderParams.getData() : null;
@@ -3743,7 +3772,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
};
if (!manualStartAndDestroy) {
- final PerUidReadTimeouts[] perUidReadTimeouts = mPm.getPerUidReadTimeouts();
+ final PerUidReadTimeouts[] perUidReadTimeouts =
+ mPm.getPerUidReadTimeouts(mPm.snapshotComputer());
final StorageHealthCheckParams healthCheckParams = new StorageHealthCheckParams();
healthCheckParams.blockedTimeoutMs = INCREMENTAL_STORAGE_BLOCKED_TIMEOUT_MS;
@@ -3778,8 +3808,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
};
try {
- final PackageInfo pkgInfo = mPm.getPackageInfo(this.params.appPackageName, 0,
- userId);
+ final PackageInfo pkgInfo = mPm.snapshotComputer()
+ .getPackageInfo(this.params.appPackageName, 0, userId);
final File inheritedDir =
(pkgInfo != null && pkgInfo.applicationInfo != null) ? new File(
pkgInfo.applicationInfo.getCodePath()).getParentFile() : null;
@@ -4035,7 +4065,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
mSessionReady = true;
mSessionApplied = false;
mSessionFailed = false;
- mSessionErrorCode = SessionInfo.SESSION_NO_ERROR;
+ mSessionErrorCode = PackageManager.INSTALL_UNKNOWN;
mSessionErrorMessage = "";
}
mCallback.onSessionChanged(this);
@@ -4063,7 +4093,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
mSessionReady = false;
mSessionApplied = true;
mSessionFailed = false;
- mSessionErrorCode = SessionInfo.SESSION_NO_ERROR;
+ mSessionErrorCode = INSTALL_SUCCEEDED;
mSessionErrorMessage = "";
Slog.d(TAG, "Marking session " + sessionId + " as applied");
}
@@ -4093,7 +4123,6 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
/** {@hide} */
- @SessionErrorCode
int getSessionErrorCode() {
synchronized (mLock) {
return mSessionErrorCode;
@@ -4275,9 +4304,9 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
private static String getDeviceOwnerInstalledPackageMsg(Context context, boolean update) {
DevicePolicyManager dpm = context.getSystemService(DevicePolicyManager.class);
return update
- ? dpm.getString(PACKAGE_UPDATED_BY_DO,
+ ? dpm.getResources().getString(PACKAGE_UPDATED_BY_DO,
() -> context.getString(R.string.package_updated_device_owner))
- : dpm.getString(PACKAGE_INSTALLED_BY_DO,
+ : dpm.getResources().getString(PACKAGE_INSTALLED_BY_DO,
() -> context.getString(R.string.package_installed_device_owner));
}
@@ -4524,8 +4553,9 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
final String installerPackageName = readStringAttribute(in, ATTR_INSTALLER_PACKAGE_NAME);
final String installerAttributionTag = readStringAttribute(in,
ATTR_INSTALLER_ATTRIBUTION_TAG);
- final int installerUid = in.getAttributeInt(null, ATTR_INSTALLER_UID, pm.getPackageUid(
- installerPackageName, PackageManager.MATCH_UNINSTALLED_PACKAGES, userId));
+ final int installerUid = in.getAttributeInt(null, ATTR_INSTALLER_UID, pm.snapshotComputer()
+ .getPackageUid(installerPackageName, PackageManager.MATCH_UNINSTALLED_PACKAGES,
+ userId));
final String installInitiatingPackageName =
readStringAttribute(in, ATTR_INITIATING_PACKAGE_NAME);
final String installOriginatingPackageName =
@@ -4581,7 +4611,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
final boolean isFailed = in.getAttributeBoolean(null, ATTR_IS_FAILED, false);
final boolean isApplied = in.getAttributeBoolean(null, ATTR_IS_APPLIED, false);
final int sessionErrorCode = in.getAttributeInt(null, ATTR_SESSION_ERROR_CODE,
- SessionInfo.SESSION_NO_ERROR);
+ PackageManager.INSTALL_UNKNOWN);
final String sessionErrorMessage = readStringAttribute(in, ATTR_SESSION_ERROR_MESSAGE);
if (!isStagedSessionStateValid(isReady, isApplied, isFailed)) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerInternalBase.java b/services/core/java/com/android/server/pm/PackageManagerInternalBase.java
new file mode 100644
index 000000000000..2b733754685e
--- /dev/null
+++ b/services/core/java/com/android/server/pm/PackageManagerInternalBase.java
@@ -0,0 +1,751 @@
+/*
+ * 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.COMPONENT_ENABLED_STATE_DEFAULT;
+import static android.content.pm.PackageManager.RESTRICTION_NONE;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.AuxiliaryResolveInfo;
+import android.content.pm.Checksum;
+import android.content.pm.IOnChecksumsReadyListener;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
+import android.content.pm.ProcessInfo;
+import android.content.pm.ProviderInfo;
+import android.content.pm.ResolveInfo;
+import android.content.pm.SuspendDialogInfo;
+import android.os.Binder;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Process;
+import android.os.storage.StorageManager;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.SparseArray;
+
+import com.android.server.pm.dex.DexManager;
+import com.android.server.pm.dex.DynamicCodeLogger;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.permission.PermissionManagerServiceInternal;
+import com.android.server.pm.pkg.AndroidPackageApi;
+import com.android.server.pm.pkg.PackageStateInternal;
+import com.android.server.pm.pkg.PackageStateUtils;
+import com.android.server.pm.pkg.SharedUserApi;
+import com.android.server.pm.pkg.component.ParsedMainComponent;
+import com.android.server.pm.pkg.mutate.PackageStateMutator;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.concurrent.Executor;
+import java.util.function.Consumer;
+
+/**
+ * Internal manager variant of {@link IPackageManagerBase}. See that class for info.
+ * {@link PackageManagerInternal} should eventually passing in a snapshot instance, deprecating
+ * this class, but that requires much larger refactor.
+ */
+abstract class PackageManagerInternalBase extends PackageManagerInternal {
+
+ @NonNull
+ private final PackageManagerService mService;
+
+ public PackageManagerInternalBase(@NonNull PackageManagerService service) {
+ mService = service;
+ }
+
+ @NonNull protected abstract Context getContext();
+ @NonNull protected abstract PermissionManagerServiceInternal getPermissionManager();
+ @NonNull protected abstract AppDataHelper getAppDataHelper();
+ @NonNull protected abstract PackageObserverHelper getPackageObserverHelper();
+ @NonNull protected abstract ResolveIntentHelper getResolveIntentHelper();
+ @NonNull protected abstract SuspendPackageHelper getSuspendPackageHelper();
+ @NonNull protected abstract ProtectedPackages getProtectedPackages();
+ @NonNull protected abstract UserNeedsBadgingCache getUserNeedsBadging();
+ @NonNull protected abstract InstantAppRegistry getInstantAppRegistry();
+ @NonNull protected abstract ApexManager getApexManager();
+ @NonNull protected abstract DexManager getDexManager();
+
+ @Override
+ public final Computer snapshot() {
+ return mService.snapshotComputer();
+ }
+
+ @Override
+ @Deprecated
+ public final List<ApplicationInfo> getInstalledApplications(
+ @PackageManager.ApplicationInfoFlagsBits long flags, int userId, int callingUid) {
+ return snapshot().getInstalledApplications(flags, userId, callingUid);
+ }
+
+ @Override
+ @Deprecated
+ public final boolean isInstantApp(String packageName, int userId) {
+ return snapshot().isInstantApp(packageName, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final String getInstantAppPackageName(int uid) {
+ return snapshot().getInstantAppPackageName(uid);
+ }
+
+ @Override
+ @Deprecated
+ public final boolean filterAppAccess(AndroidPackage pkg, int callingUid, int userId) {
+ return snapshot().filterAppAccess(pkg, callingUid, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final boolean filterAppAccess(String packageName, int callingUid, int userId) {
+ return snapshot().filterAppAccess(packageName, callingUid, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final boolean filterAppAccess(int uid, int callingUid) {
+ return snapshot().filterAppAccess(uid, callingUid);
+ }
+
+ @Nullable
+ @Override
+ @Deprecated
+ public final int[] getVisibilityAllowList(@NonNull String packageName, int userId) {
+ return snapshot().getVisibilityAllowList(packageName, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final boolean canQueryPackage(int callingUid, @Nullable String packageName) {
+ return snapshot().canQueryPackage(callingUid, packageName);
+ }
+
+ @Override
+ @Deprecated
+ public final AndroidPackage getPackage(String packageName) {
+ return snapshot().getPackage(packageName);
+ }
+
+ @Nullable
+ @Override
+ @Deprecated
+ public final AndroidPackageApi getAndroidPackage(@NonNull String packageName) {
+ return snapshot().getPackage(packageName);
+ }
+
+ @Override
+ @Deprecated
+ public final AndroidPackage getPackage(int uid) {
+ return snapshot().getPackage(uid);
+ }
+
+ @Override
+ @Deprecated
+ public final List<AndroidPackage> getPackagesForAppId(int appId) {
+ return snapshot().getPackagesForAppId(appId);
+ }
+
+ @Nullable
+ @Override
+ @Deprecated
+ public final PackageStateInternal getPackageStateInternal(String packageName) {
+ return snapshot().getPackageStateInternal(packageName);
+ }
+
+ @NonNull
+ @Override
+ @Deprecated
+ public final ArrayMap<String, ? extends PackageStateInternal> getPackageStates() {
+ return snapshot().getPackageStates();
+ }
+
+ @Override
+ @Deprecated
+ public final void removePackageListObserver(PackageListObserver observer) {
+ getPackageObserverHelper().removeObserver(observer);
+ }
+
+ @Override
+ @Deprecated
+ public final PackageStateInternal getDisabledSystemPackage(@NonNull String packageName) {
+ return snapshot().getDisabledSystemPackage(packageName);
+ }
+
+ @Override
+ @Deprecated
+ public final @NonNull String[] getKnownPackageNames(int knownPackage, int userId) {
+ return mService.getKnownPackageNamesInternal(snapshot(), knownPackage, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final void setKeepUninstalledPackages(final List<String> packageList) {
+ mService.setKeepUninstalledPackagesInternal(snapshot(), packageList);
+ }
+
+ @Override
+ @Deprecated
+ public final boolean isPermissionsReviewRequired(String packageName, int userId) {
+ return getPermissionManager().isPermissionsReviewRequired(packageName, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final PackageInfo getPackageInfo(String packageName,
+ @PackageManager.PackageInfoFlagsBits long flags, int filterCallingUid, int userId) {
+ return snapshot().getPackageInfoInternal(packageName,
+ PackageManager.VERSION_CODE_HIGHEST, flags, filterCallingUid, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final Bundle getSuspendedPackageLauncherExtras(String packageName, int userId) {
+ return getSuspendPackageHelper().getSuspendedPackageLauncherExtras(snapshot(), packageName,
+ userId, Binder.getCallingUid());
+ }
+
+ @Override
+ @Deprecated
+ public final boolean isPackageSuspended(String packageName, int userId) {
+ return getSuspendPackageHelper().isPackageSuspended(snapshot(), packageName, userId,
+ Binder.getCallingUid());
+ }
+
+ @Override
+ @Deprecated
+ public final void removeNonSystemPackageSuspensions(String packageName, int userId) {
+ getSuspendPackageHelper().removeSuspensionsBySuspendingPackage(snapshot(),
+ new String[]{packageName},
+ (suspendingPackage) -> !PackageManagerService.PLATFORM_PACKAGE_NAME.equals(
+ suspendingPackage),
+ userId);
+ }
+
+ @Override
+ @Deprecated
+ public final void removeDistractingPackageRestrictions(String packageName, int userId) {
+ mService.removeDistractingPackageRestrictions(snapshot(), new String[]{packageName},
+ userId);
+ }
+
+ @Override
+ @Deprecated
+ public final void removeAllDistractingPackageRestrictions(int userId) {
+ mService.removeAllDistractingPackageRestrictions(snapshot(), userId);
+ }
+
+ @Override
+ @Deprecated
+ public final String getSuspendingPackage(String suspendedPackage, int userId) {
+ return getSuspendPackageHelper().getSuspendingPackage(snapshot(), suspendedPackage, userId,
+ Binder.getCallingUid());
+ }
+
+ @Override
+ @Deprecated
+ public final SuspendDialogInfo getSuspendedDialogInfo(String suspendedPackage,
+ String suspendingPackage, int userId) {
+ return getSuspendPackageHelper().getSuspendedDialogInfo(snapshot(), suspendedPackage,
+ suspendingPackage, userId, Binder.getCallingUid());
+ }
+
+ @Override
+ @Deprecated
+ public final int getDistractingPackageRestrictions(String packageName, int userId) {
+ final PackageStateInternal packageState = getPackageStateInternal(packageName);
+ return (packageState == null) ? RESTRICTION_NONE
+ : packageState.getUserStateOrDefault(userId).getDistractionFlags();
+ }
+
+ @Override
+ @Deprecated
+ public final int getPackageUid(String packageName,
+ @PackageManager.PackageInfoFlagsBits long flags, int userId) {
+ return snapshot().getPackageUidInternal(packageName, flags, userId, Process.SYSTEM_UID);
+ }
+
+ @Override
+ @Deprecated
+ public final ApplicationInfo getApplicationInfo(String packageName,
+ @PackageManager.ApplicationInfoFlagsBits long flags, int filterCallingUid, int userId) {
+ return snapshot().getApplicationInfoInternal(packageName, flags, filterCallingUid, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final ActivityInfo getActivityInfo(ComponentName component,
+ @PackageManager.ComponentInfoFlagsBits long flags, int filterCallingUid, int userId) {
+ return snapshot().getActivityInfoInternal(component, flags, filterCallingUid, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final List<ResolveInfo> queryIntentActivities(
+ Intent intent, String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags,
+ int filterCallingUid, int userId) {
+ return snapshot().queryIntentActivitiesInternal(intent, resolvedType, flags, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final List<ResolveInfo> queryIntentReceivers(Intent intent,
+ String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags,
+ int filterCallingUid, int userId) {
+ return getResolveIntentHelper().queryIntentReceiversInternal(
+ snapshot(), intent, resolvedType, flags, userId, filterCallingUid);
+ }
+
+ @Override
+ @Deprecated
+ public final List<ResolveInfo> queryIntentServices(
+ Intent intent, @PackageManager.ResolveInfoFlagsBits long flags, int callingUid,
+ int userId) {
+ final String resolvedType = intent.resolveTypeIfNeeded(getContext().getContentResolver());
+ return snapshot().queryIntentServicesInternal(intent, resolvedType, flags, userId,
+ callingUid, false);
+ }
+
+ @Override
+ @Deprecated
+ public final ComponentName getHomeActivitiesAsUser(List<ResolveInfo> allHomeCandidates,
+ int userId) {
+ return snapshot().getHomeActivitiesAsUser(allHomeCandidates, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final ComponentName getDefaultHomeActivity(int userId) {
+ return snapshot().getDefaultHomeActivity(userId);
+ }
+
+ @Override
+ @Deprecated
+ public final ComponentName getSystemUiServiceComponent() {
+ return ComponentName.unflattenFromString(getContext().getResources().getString(
+ com.android.internal.R.string.config_systemUIServiceComponent));
+ }
+
+ @Override
+ @Deprecated
+ public final void setDeviceOwnerProtectedPackages(
+ String deviceOwnerPackageName, List<String> packageNames) {
+ getProtectedPackages().setDeviceOwnerProtectedPackages(
+ deviceOwnerPackageName, packageNames);
+ }
+
+ @Override
+ @Deprecated
+ public final boolean isPackageDataProtected(int userId, String packageName) {
+ return getProtectedPackages().isPackageDataProtected(userId, packageName);
+ }
+
+ @Override
+ @Deprecated
+ public final boolean isPackageStateProtected(String packageName, int userId) {
+ return getProtectedPackages().isPackageStateProtected(userId, packageName);
+ }
+
+ @Override
+ @Deprecated
+ public final boolean isPackageEphemeral(int userId, String packageName) {
+ final PackageStateInternal packageState = getPackageStateInternal(packageName);
+ return packageState != null
+ && packageState.getUserStateOrDefault(userId).isInstantApp();
+ }
+
+ @Override
+ @Deprecated
+ public final boolean wasPackageEverLaunched(String packageName, int userId) {
+ final PackageStateInternal packageState = getPackageStateInternal(packageName);
+ if (packageState == null) {
+ throw new IllegalArgumentException("Unknown package: " + packageName);
+ }
+ return !packageState.getUserStateOrDefault(userId).isNotLaunched();
+ }
+
+ @Override
+ @Deprecated
+ public final boolean isEnabledAndMatches(ParsedMainComponent component, long flags, int userId) {
+ return PackageStateUtils.isEnabledAndMatches(
+ getPackageStateInternal(component.getPackageName()), component, flags, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final boolean userNeedsBadging(int userId) {
+ return getUserNeedsBadging().get(userId);
+ }
+
+ @Override
+ @Deprecated
+ public final String getNameForUid(int uid) {
+ return snapshot().getNameForUid(uid);
+ }
+
+ @Override
+ @Deprecated
+ public final void requestInstantAppResolutionPhaseTwo(AuxiliaryResolveInfo responseObj,
+ Intent origIntent, String resolvedType, String callingPackage,
+ @Nullable String callingFeatureId, boolean isRequesterInstantApp,
+ Bundle verificationBundle, int userId) {
+ mService.requestInstantAppResolutionPhaseTwo(responseObj, origIntent,
+ resolvedType, callingPackage, callingFeatureId, isRequesterInstantApp,
+ verificationBundle, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final void grantImplicitAccess(int userId, Intent intent,
+ int recipientAppId, int visibleUid, boolean direct) {
+ grantImplicitAccess(userId, intent, recipientAppId, visibleUid, direct,
+ false /* retainOnUpdate */);
+ }
+
+ @Override
+ @Deprecated
+ public final void grantImplicitAccess(int userId, Intent intent,
+ int recipientAppId, int visibleUid, boolean direct, boolean retainOnUpdate) {
+ mService.grantImplicitAccess(snapshot(), userId, intent,
+ recipientAppId, visibleUid, direct, retainOnUpdate);
+ }
+
+ @Override
+ @Deprecated
+ public final boolean isInstantAppInstallerComponent(ComponentName component) {
+ final ActivityInfo instantAppInstallerActivity = mService.mInstantAppInstallerActivity;
+ return instantAppInstallerActivity != null
+ && instantAppInstallerActivity.getComponentName().equals(component);
+ }
+
+ @Override
+ @Deprecated
+ public final void pruneInstantApps() {
+ getInstantAppRegistry().pruneInstantApps(snapshot());
+ }
+
+ @Override
+ @Deprecated
+ public final String getSetupWizardPackageName() {
+ return mService.mSetupWizardPackage;
+ }
+
+ @Override
+ @Deprecated
+ public final ResolveInfo resolveIntent(Intent intent, String resolvedType,
+ @PackageManager.ResolveInfoFlagsBits long flags,
+ @PackageManagerInternal.PrivateResolveFlags long privateResolveFlags, int userId,
+ boolean resolveForStart, int filterCallingUid) {
+ return getResolveIntentHelper().resolveIntentInternal(snapshot(),
+ intent, resolvedType, flags, privateResolveFlags, userId, resolveForStart,
+ filterCallingUid);
+ }
+
+ @Override
+ @Deprecated
+ public final ResolveInfo resolveService(Intent intent, String resolvedType,
+ @PackageManager.ResolveInfoFlagsBits long flags, int userId, int callingUid) {
+ return getResolveIntentHelper().resolveServiceInternal(snapshot(), intent,
+ resolvedType, flags, userId, callingUid);
+ }
+
+ @Override
+ @Deprecated
+ public final ProviderInfo resolveContentProvider(String name,
+ @PackageManager.ResolveInfoFlagsBits long flags, int userId, int callingUid) {
+ return snapshot().resolveContentProvider(name, flags, userId,callingUid);
+ }
+
+ @Override
+ @Deprecated
+ public final int getUidTargetSdkVersion(int uid) {
+ return snapshot().getUidTargetSdkVersion(uid);
+ }
+
+ @Override
+ @Deprecated
+ public final int getPackageTargetSdkVersion(String packageName) {
+ final PackageStateInternal packageState = getPackageStateInternal(packageName);
+ if (packageState != null && packageState.getPkg() != null) {
+ return packageState.getPkg().getTargetSdkVersion();
+ }
+ return Build.VERSION_CODES.CUR_DEVELOPMENT;
+ }
+
+ @Override
+ @Deprecated
+ public final boolean canAccessInstantApps(int callingUid, @UserIdInt int userId) {
+ return snapshot().canViewInstantApps(callingUid, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final boolean canAccessComponent(int callingUid, @NonNull ComponentName component,
+ @UserIdInt int userId) {
+ return snapshot().canAccessComponent(callingUid, component, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final boolean hasInstantApplicationMetadata(String packageName, int userId) {
+ return getInstantAppRegistry().hasInstantApplicationMetadata(packageName, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final SparseArray<String> getAppsWithSharedUserIds() {
+ return snapshot().getAppsWithSharedUserIds();
+ }
+
+ @Override
+ @NonNull
+ @Deprecated
+ public final String[] getSharedUserPackagesForPackage(String packageName, int userId) {
+ return snapshot().getSharedUserPackagesForPackage(packageName, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final ArrayMap<String, ProcessInfo> getProcessesForUid(int uid) {
+ return snapshot().getProcessesForUid(uid);
+ }
+
+ @Override
+ @Deprecated
+ public final int[] getPermissionGids(String permissionName, int userId) {
+ return getPermissionManager().getPermissionGids(permissionName, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final boolean isOnlyCoreApps() {
+ return mService.isOnlyCoreApps();
+ }
+
+ @Override
+ @Deprecated
+ public final void freeStorage(String volumeUuid, long bytes,
+ @StorageManager.AllocateFlags int flags) throws IOException {
+ mService.freeStorage(volumeUuid, bytes, flags);
+ }
+
+ @Override
+ @Deprecated
+ public final void freeAllAppCacheAboveQuota(@NonNull String volumeUuid) throws IOException {
+ mService.freeAllAppCacheAboveQuota(volumeUuid);
+ }
+
+ @Override
+ @Deprecated
+ public final void forEachPackageSetting(Consumer<PackageSetting> actionLocked) {
+ mService.forEachPackageSetting(actionLocked);
+ }
+
+ @Override
+ @Deprecated
+ public final void forEachPackageState(Consumer<PackageStateInternal> action) {
+ mService.forEachPackageState(snapshot(), action);
+ }
+
+ @Override
+ @Deprecated
+ public final void forEachPackage(Consumer<AndroidPackage> action) {
+ mService.forEachPackage(snapshot(), action);
+ }
+
+ @Override
+ @Deprecated
+ public final void forEachInstalledPackage(@NonNull Consumer<AndroidPackage> action,
+ @UserIdInt int userId) {
+ mService.forEachInstalledPackage(snapshot(), action, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final ArraySet<String> getEnabledComponents(String packageName, int userId) {
+ final PackageStateInternal packageState = getPackageStateInternal(packageName);
+ if (packageState == null) {
+ return new ArraySet<>();
+ }
+ return packageState.getUserStateOrDefault(userId).getEnabledComponents();
+ }
+
+ @Override
+ @Deprecated
+ public final ArraySet<String> getDisabledComponents(String packageName, int userId) {
+ final PackageStateInternal packageState = getPackageStateInternal(packageName);
+ if (packageState == null) {
+ return new ArraySet<>();
+ }
+ return packageState.getUserStateOrDefault(userId).getDisabledComponents();
+ }
+
+ @Override
+ @Deprecated
+ public final @PackageManager.EnabledState int getApplicationEnabledState(
+ String packageName, int userId) {
+ final PackageStateInternal packageState = getPackageStateInternal(packageName);
+ if (packageState == null) {
+ return COMPONENT_ENABLED_STATE_DEFAULT;
+ }
+ return packageState.getUserStateOrDefault(userId).getEnabledState();
+ }
+
+ @Override
+ @Deprecated
+ public final @PackageManager.EnabledState int getComponentEnabledSetting(
+ @NonNull ComponentName componentName, int callingUid, int userId) {
+ return snapshot().getComponentEnabledSettingInternal(
+ componentName, callingUid, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final void setEnableRollbackCode(int token, int enableRollbackCode) {
+ mService.setEnableRollbackCode(token, enableRollbackCode);
+ }
+
+ @Override
+ @Deprecated
+ public final void finishPackageInstall(int token, boolean didLaunch) {
+ mService.finishPackageInstall(token, didLaunch);
+ }
+
+ @Override
+ @Deprecated
+ public final boolean isApexPackage(String packageName) {
+ return getApexManager().isApexPackage(packageName);
+ }
+
+ @Override
+ @Deprecated
+ public final List<String> getApksInApex(String apexPackageName) {
+ return getApexManager().getApksInApex(apexPackageName);
+ }
+
+ @Override
+ @Deprecated
+ public final boolean isCallerInstallerOfRecord(@NonNull AndroidPackage pkg, int callingUid) {
+ return snapshot().isCallerInstallerOfRecord(pkg, callingUid);
+ }
+
+ @Override
+ @Deprecated
+ public final List<String> getMimeGroup(String packageName, String mimeGroup) {
+ return mService.getMimeGroupInternal(snapshot(), packageName, mimeGroup);
+ }
+
+ @Override
+ @Deprecated
+ public final boolean isSystemPackage(@NonNull String packageName) {
+ return packageName.equals(mService.ensureSystemPackageName(snapshot(), packageName));
+ }
+
+ @Override
+ @Deprecated
+ public final void unsuspendForSuspendingPackage(final String packageName, int affectedUser) {
+ mService.unsuspendForSuspendingPackage(snapshot(), packageName, affectedUser);
+ }
+
+ @Override
+ @Deprecated
+ public final boolean isSuspendingAnyPackages(String suspendingPackage, int userId) {
+ return snapshot().isSuspendingAnyPackages(suspendingPackage, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final void requestChecksums(@NonNull String packageName, boolean includeSplits,
+ @Checksum.TypeMask int optional, @Checksum.TypeMask int required,
+ @Nullable List trustedInstallers,
+ @NonNull IOnChecksumsReadyListener onChecksumsReadyListener, int userId,
+ @NonNull Executor executor, @NonNull Handler handler) {
+ mService.requestChecksumsInternal(snapshot(), packageName, includeSplits, optional,
+ required, trustedInstallers, onChecksumsReadyListener, userId, executor,
+ handler);
+ }
+
+ @Override
+ @Deprecated
+ public final boolean isPackageFrozen(@NonNull String packageName,
+ int callingUid, int userId) {
+ return snapshot().getPackageStartability(mService.getSafeMode(), packageName, callingUid, userId)
+ == PackageManagerService.PACKAGE_STARTABILITY_FROZEN;
+ }
+
+ @Override
+ @Deprecated
+ public final long deleteOatArtifactsOfPackage(String packageName) {
+ return mService.deleteOatArtifactsOfPackage(snapshot(), packageName);
+ }
+
+ @Override
+ @Deprecated
+ public final void reconcileAppsData(int userId, @StorageManager.StorageFlags int flags,
+ boolean migrateAppsData) {
+ getAppDataHelper().reconcileAppsData(userId, flags, migrateAppsData);
+ }
+
+ @Override
+ @NonNull
+ public ArraySet<PackageStateInternal> getSharedUserPackages(int sharedUserAppId) {
+ return snapshot().getSharedUserPackages(sharedUserAppId);
+ }
+
+ @Override
+ @Nullable
+ public SharedUserApi getSharedUserApi(int sharedUserAppId) {
+ return snapshot().getSharedUser(sharedUserAppId);
+ }
+
+ @NonNull
+ @Override
+ @Deprecated
+ public final PackageStateMutator.InitialState recordInitialState() {
+ return mService.recordInitialState();
+ }
+
+ @Nullable
+ @Override
+ @Deprecated
+ public final PackageStateMutator.Result commitPackageStateMutation(
+ @Nullable PackageStateMutator.InitialState state,
+ @NonNull Consumer<PackageStateMutator> consumer) {
+ return mService.commitPackageStateMutation(state, consumer);
+ }
+
+ @Override
+ @Deprecated
+ public final void shutdown() {
+ mService.shutdown();
+ }
+
+ @Override
+ @Deprecated
+ public final DynamicCodeLogger getDynamicCodeLogger() {
+ return getDexManager().getDynamicCodeLogger();
+ }
+}
diff --git a/services/core/java/com/android/server/pm/PackageManagerLocal.java b/services/core/java/com/android/server/pm/PackageManagerLocal.java
index 7b76567fcc6e..39cc37ea2e7c 100644
--- a/services/core/java/com/android/server/pm/PackageManagerLocal.java
+++ b/services/core/java/com/android/server/pm/PackageManagerLocal.java
@@ -16,8 +16,16 @@
package com.android.server.pm;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.SystemApi;
+import java.io.IOException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.List;
+
/**
* In-process API for server side PackageManager related infrastructure.
*
@@ -28,4 +36,48 @@ import android.annotation.SystemApi;
*/
@SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
public interface PackageManagerLocal {
+
+ /**
+ * Indicates if operation should include device encrypted storage.
+ */
+ int FLAG_STORAGE_DE = Installer.FLAG_STORAGE_DE;
+ /**
+ * Indicates if operation should include credential encrypted storage.
+ */
+ int FLAG_STORAGE_CE = Installer.FLAG_STORAGE_CE;
+
+ /**
+ * Constants for use with {@link #reconcileSdkData} to specify which storage areas should be
+ * included for operation.
+ *
+ * @hide
+ */
+ @IntDef(prefix = "FLAG_STORAGE_", value = {
+ FLAG_STORAGE_DE,
+ FLAG_STORAGE_CE,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface StorageFlags {}
+
+ /**
+ * Reconcile sdk data sub-directories for the given {@code packagName}.
+ *
+ * Sub directories are created if they do not exist already. If there is an existing per-
+ * sdk directory that is missing from {@code subDirNames}, then it is removed.
+ *
+ * Sdk package path is created if it doesn't exist before creating per-sdk directories.
+ *
+ * @param volumeUuid the volume in which the sdk data should be prepared.
+ * @param packageName package name of the app for which sdk data directory will be prepared.
+ * @param subDirNames names of sub directories that should be reconciled against.
+ * @param userId id of the user to whom the package belongs to.
+ * @param appId id of the package.
+ * @param previousAppId previous id of the package if package is being updated.
+ * @param flags flags from StorageManager to indicate which storage areas should be included.
+ * @param seInfo seInfo tag to be used for selinux policy.
+ * @throws IOException If any error occurs during the operation.
+ */
+ void reconcileSdkData(@Nullable String volumeUuid, @NonNull String packageName,
+ @NonNull List<String> subDirNames, int userId, int appId, int previousAppId,
+ @NonNull String seInfo, @StorageFlags int flags) throws IOException;
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerNative.java b/services/core/java/com/android/server/pm/PackageManagerNative.java
index 37daf112aa69..9a43008acfdf 100644
--- a/services/core/java/com/android/server/pm/PackageManagerNative.java
+++ b/services/core/java/com/android/server/pm/PackageManagerNative.java
@@ -71,7 +71,7 @@ final class PackageManagerNative extends IPackageManagerNative.Stub {
@Override
public String[] getAllPackages() {
- return mPm.getAllPackages().toArray(new String[0]);
+ return mPm.snapshotComputer().getAllPackages().toArray(new String[0]);
}
@Override
@@ -82,7 +82,7 @@ final class PackageManagerNative extends IPackageManagerNative.Stub {
if (uids == null || uids.length == 0) {
return null;
}
- names = mPm.getNamesForUids(uids);
+ names = mPm.snapshotComputer().getNamesForUids(uids);
results = (names != null) ? names : new String[uids.length];
// massage results so they can be parsed by the native binder
for (int i = results.length - 1; i >= 0; --i) {
@@ -104,13 +104,14 @@ final class PackageManagerNative extends IPackageManagerNative.Stub {
// NB: this differentiates between preloads and sideloads
@Override
public String getInstallerForPackage(String packageName) throws RemoteException {
- final String installerName = mPm.getInstallerPackageName(packageName);
+ final Computer snapshot = mPm.snapshotComputer();
+ final String installerName = snapshot.getInstallerPackageName(packageName);
if (!TextUtils.isEmpty(installerName)) {
return installerName;
}
// differentiate between preload and sideload
int callingUser = UserHandle.getUserId(Binder.getCallingUid());
- ApplicationInfo appInfo = mPm.getApplicationInfo(packageName,
+ ApplicationInfo appInfo = snapshot.getApplicationInfo(packageName,
/*flags*/ 0,
/*userId*/ callingUser);
if (appInfo != null && (appInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
@@ -123,7 +124,8 @@ final class PackageManagerNative extends IPackageManagerNative.Stub {
public long getVersionCodeForPackage(String packageName) throws RemoteException {
try {
int callingUser = UserHandle.getUserId(Binder.getCallingUid());
- PackageInfo pInfo = mPm.getPackageInfo(packageName, 0, callingUser);
+ PackageInfo pInfo = mPm.snapshotComputer()
+ .getPackageInfo(packageName, 0, callingUser);
if (pInfo != null) {
return pInfo.getLongVersionCode();
}
@@ -134,7 +136,7 @@ final class PackageManagerNative extends IPackageManagerNative.Stub {
@Override
public int getTargetSdkVersionForPackage(String packageName) throws RemoteException {
- int targetSdk = mPm.getTargetSdkVersion(packageName);
+ int targetSdk = mPm.snapshotComputer().getTargetSdkVersion(packageName);
if (targetSdk != -1) {
return targetSdk;
}
@@ -145,7 +147,8 @@ final class PackageManagerNative extends IPackageManagerNative.Stub {
@Override
public boolean isPackageDebuggable(String packageName) throws RemoteException {
int callingUser = UserHandle.getCallingUserId();
- ApplicationInfo appInfo = mPm.getApplicationInfo(packageName, 0, callingUser);
+ ApplicationInfo appInfo = mPm.snapshotComputer()
+ .getApplicationInfo(packageName, 0, callingUser);
if (appInfo != null) {
return (0 != (appInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE));
}
@@ -157,9 +160,10 @@ final class PackageManagerNative extends IPackageManagerNative.Stub {
public boolean[] isAudioPlaybackCaptureAllowed(String[] packageNames)
throws RemoteException {
int callingUser = UserHandle.getUserId(Binder.getCallingUid());
+ final Computer snapshot = mPm.snapshotComputer();
boolean[] results = new boolean[packageNames.length];
for (int i = results.length - 1; i >= 0; --i) {
- ApplicationInfo appInfo = mPm.getApplicationInfo(packageNames[i], 0, callingUser);
+ ApplicationInfo appInfo = snapshot.getApplicationInfo(packageNames[i], 0, callingUser);
results[i] = appInfo != null && appInfo.isAudioPlaybackCaptureAllowed();
}
return results;
@@ -168,7 +172,7 @@ final class PackageManagerNative extends IPackageManagerNative.Stub {
@Override
public int getLocationFlags(String packageName) throws RemoteException {
int callingUser = UserHandle.getUserId(Binder.getCallingUid());
- ApplicationInfo appInfo = mPm.getApplicationInfo(packageName,
+ ApplicationInfo appInfo = mPm.snapshotComputer().getApplicationInfo(packageName,
/*flags*/ 0,
/*userId*/ callingUser);
if (appInfo == null) {
@@ -188,7 +192,8 @@ final class PackageManagerNative extends IPackageManagerNative.Stub {
@Override
public boolean hasSha256SigningCertificate(String packageName, byte[] certificate)
throws RemoteException {
- return mPm.hasSigningCertificate(packageName, certificate, CERT_INPUT_SHA256);
+ return mPm.snapshotComputer()
+ .hasSigningCertificate(packageName, certificate, CERT_INPUT_SHA256);
}
@Override
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index f07418f6007f..c7a101e2af4d 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -29,7 +29,6 @@ import static android.content.pm.PackageManager.MATCH_DISABLED_COMPONENTS;
import static android.content.pm.PackageManager.MATCH_FACTORY_ONLY;
import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
-import static android.content.pm.PackageManager.RESTRICTION_NONE;
import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
import static android.os.storage.StorageManager.FLAG_STORAGE_CE;
import static android.os.storage.StorageManager.FLAG_STORAGE_DE;
@@ -83,21 +82,15 @@ import android.content.pm.IDexModuleRegisterCallback;
import android.content.pm.IOnChecksumsReadyListener;
import android.content.pm.IPackageChangeObserver;
import android.content.pm.IPackageDataObserver;
-import android.content.pm.IPackageDeleteObserver;
import android.content.pm.IPackageDeleteObserver2;
import android.content.pm.IPackageInstallObserver2;
-import android.content.pm.IPackageInstaller;
import android.content.pm.IPackageLoadingProgressCallback;
import android.content.pm.IPackageManager;
import android.content.pm.IPackageMoveObserver;
-import android.content.pm.IPackageStatsObserver;
import android.content.pm.IncrementalStatesInfo;
import android.content.pm.InstallSourceInfo;
import android.content.pm.InstantAppInfo;
import android.content.pm.InstantAppRequest;
-import android.content.pm.InstrumentationInfo;
-import android.content.pm.IntentFilterVerificationInfo;
-import android.content.pm.KeySet;
import android.content.pm.ModuleInfo;
import android.content.pm.PackageChangeEvent;
import android.content.pm.PackageInfo;
@@ -105,20 +98,12 @@ import android.content.pm.PackageInfoLite;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.ComponentEnabledSetting;
-import android.content.pm.PackageManager.ComponentType;
-import android.content.pm.PackageManager.LegacyPackageDeleteObserver;
-import android.content.pm.PackageManager.ModuleInfoFlags;
-import android.content.pm.PackageManager.Property;
-import android.content.pm.PackageManager.PropertyLocation;
import android.content.pm.PackageManagerInternal;
import android.content.pm.PackagePartitions;
import android.content.pm.ParceledListSlice;
import android.content.pm.PermissionGroupInfo;
-import android.content.pm.PermissionInfo;
-import android.content.pm.ProcessInfo;
import android.content.pm.ProviderInfo;
import android.content.pm.ResolveInfo;
-import android.content.pm.ServiceInfo;
import android.content.pm.SharedLibraryInfo;
import android.content.pm.Signature;
import android.content.pm.SigningDetails;
@@ -127,7 +112,6 @@ import android.content.pm.TestUtilityService;
import android.content.pm.UserInfo;
import android.content.pm.VerifierDeviceIdentity;
import android.content.pm.VersionedPackage;
-import android.content.pm.dex.IArtManager;
import android.content.pm.overlay.OverlayPaths;
import android.content.pm.parsing.PackageLite;
import android.content.res.Resources;
@@ -148,6 +132,7 @@ import android.os.Parcel;
import android.os.ParcelableException;
import android.os.PersistableBundle;
import android.os.Process;
+import android.os.ReconcileSdkDataArgs;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ServiceManager;
@@ -229,10 +214,7 @@ import com.android.server.pm.permission.LegacyPermissionManagerInternal;
import com.android.server.pm.permission.LegacyPermissionManagerService;
import com.android.server.pm.permission.PermissionManagerService;
import com.android.server.pm.permission.PermissionManagerServiceInternal;
-import com.android.server.pm.pkg.AndroidPackageApi;
-import com.android.server.pm.pkg.PackageState;
import com.android.server.pm.pkg.PackageStateInternal;
-import com.android.server.pm.pkg.PackageStateUtils;
import com.android.server.pm.pkg.PackageUserState;
import com.android.server.pm.pkg.PackageUserStateInternal;
import com.android.server.pm.pkg.SharedUserApi;
@@ -247,7 +229,6 @@ import com.android.server.pm.resolution.ComponentResolverApi;
import com.android.server.pm.verify.domain.DomainVerificationManagerInternal;
import com.android.server.pm.verify.domain.DomainVerificationService;
import com.android.server.pm.verify.domain.proxy.DomainVerificationProxy;
-import com.android.server.pm.verify.domain.proxy.DomainVerificationProxyV1;
import com.android.server.sdksandbox.SdkSandboxManagerLocal;
import com.android.server.storage.DeviceStorageMonitorInternal;
import com.android.server.utils.SnapshotCache;
@@ -334,8 +315,8 @@ import java.util.function.Consumer;
* $ cts-tradefed run commandAndExit cts -m CtsAppSecurityHostTestCases
* </pre>
*/
-public class PackageManagerService extends IPackageManager.Stub
- implements PackageSender, TestUtilityService {
+public class PackageManagerService implements PackageSender, TestUtilityService {
+
static final String TAG = "PackageManager";
public static final boolean DEBUG_SETTINGS = false;
static final boolean DEBUG_PREFERRED = false;
@@ -417,7 +398,8 @@ public class PackageManagerService extends IPackageManager.Stub
public @interface ScanFlags {}
/**
- * Used as the result code of the {@link #getPackageStartability}.
+ * Used as the result code of the {@link Computer#getPackageStartability(boolean, String, int,
+ * int)}.
*/
@IntDef(value = {
PACKAGE_STARTABILITY_OK,
@@ -430,40 +412,43 @@ public class PackageManagerService extends IPackageManager.Stub
public @interface PackageStartability {}
/**
- * Used as the result code of the {@link #getPackageStartability} to indicate
- * the given package is allowed to start.
+ * Used as the result code of the {@link Computer#getPackageStartability(boolean, String, int,
+ * int)} to indicate the given package is allowed to start.
*/
public static final int PACKAGE_STARTABILITY_OK = 0;
/**
- * Used as the result code of the {@link #getPackageStartability} to indicate
- * the given package is <b>not</b> allowed to start because it's not found
+ * Used as the result code of the {@link Computer#getPackageStartability(boolean, String, int,
+ * int)} to indicate the given package is <b>not</b> allowed to start because it's not found
* (could be due to that package is invisible to the given user).
*/
public static final int PACKAGE_STARTABILITY_NOT_FOUND = 1;
/**
- * Used as the result code of the {@link #getPackageStartability} to indicate
- * the given package is <b>not</b> allowed to start because it's not a system app
- * and the system is running in safe mode.
+ * Used as the result code of the {@link Computer#getPackageStartability(boolean, String, int,
+ * int)} to indicate the given package is <b>not</b> allowed to start because it's not a system
+ * app and the system is running in safe mode.
*/
public static final int PACKAGE_STARTABILITY_NOT_SYSTEM = 2;
/**
- * Used as the result code of the {@link #getPackageStartability} to indicate
- * the given package is <b>not</b> allowed to start because it's currently frozen.
+ * Used as the result code of the {@link Computer#getPackageStartability(boolean, String, int,
+ * int)} to indicate the given package is <b>not</b> allowed to start because it's currently
+ * frozen.
*/
public static final int PACKAGE_STARTABILITY_FROZEN = 3;
/**
- * Used as the result code of the {@link #getPackageStartability} to indicate
- * the given package is <b>not</b> allowed to start because it doesn't support
+ * Used as the result code of the {@link Computer#getPackageStartability(boolean, String, int,
+ * int)} to indicate the given package is <b>not</b> allowed to start because it doesn't support
* direct boot.
*/
public static final int PACKAGE_STARTABILITY_DIRECT_BOOT_UNSUPPORTED = 4;
private static final String STATIC_SHARED_LIB_DELIMITER = "_";
- /** Extension of the compressed packages */
+ /**
+ * Extension of the compressed packages
+ */
public final static String COMPRESSED_EXTENSION = ".gz";
/** Suffix of stub packages on the system partition */
public final static String STUB_SUFFIX = "-Stub";
@@ -648,7 +633,6 @@ public class PackageManagerService extends IPackageManager.Stub
*/
boolean mPromoteSystemApps;
- private final PackageManagerInternal mPmInternal;
private final TestUtilityService mTestUtilityService;
@Watched
@@ -951,13 +935,14 @@ public class PackageManagerService extends IPackageManager.Stub
private final BroadcastHelper mBroadcastHelper;
private final RemovePackageHelper mRemovePackageHelper;
private final DeletePackageHelper mDeletePackageHelper;
- private final InitAndSystemPackageHelper mInitAndSystemPackageHelper;
+ private final InitAppsHelper mInitAppsHelper;
private final AppDataHelper mAppDataHelper;
private final InstallPackageHelper mInstallPackageHelper;
private final PreferredActivityHelper mPreferredActivityHelper;
private final ResolveIntentHelper mResolveIntentHelper;
private final DexOptHelper mDexOptHelper;
private final SuspendPackageHelper mSuspendPackageHelper;
+ private final IntentResolverInterceptor mIntentResolverInterceptor;
/**
* Invalidate the package info cache, which includes updating the cached computer.
@@ -1058,9 +1043,6 @@ public class PackageManagerService extends IPackageManager.Stub
// A lock-free cache for frequently called functions.
private volatile Computer mSnapshotComputer;
- // A trampoline that directs callers to either the live or snapshot computer.
- private final ComputerTracker mComputer = new ComputerTracker(this);
-
// If true, the snapshot is invalid (stale). The attribute is static since it may be
// set from outside classes. The attribute may be set to true anywhere, although it
// should only be set true while holding mLock. However, the attribute id guaranteed
@@ -1089,6 +1071,8 @@ public class PackageManagerService extends IPackageManager.Stub
* Return the cached computer. The method will rebuild the cached computer if necessary.
* The live computer will be returned if snapshots are disabled.
*/
+ @VisibleForTesting(visibility = Visibility.PACKAGE)
+ @NonNull
public Computer snapshotComputer() {
if (Thread.holdsLock(mLock)) {
// If the current thread holds mLock then it may have modified state but not
@@ -1167,15 +1151,6 @@ public class PackageManagerService extends IPackageManager.Stub
onChange(null);
}
- @Override
- public void notifyPackagesReplacedReceived(String[] packages) {
- Computer computer = snapshotComputer();
- ArraySet<String> packagesToNotify = computer.getNotifyPackagesForReplacedReceived(packages);
- for (int index = 0; index < packagesToNotify.size(); index++) {
- notifyInstallObserver(packagesToNotify.valueAt(index), false /* killApp */);
- }
- }
-
void notifyInstallObserver(String packageName, boolean killApp) {
final Pair<PackageInstalledInfo, IPackageInstallObserver2> pair =
killApp ? mPendingKillInstallObservers.remove(packageName)
@@ -1232,16 +1207,6 @@ public class PackageManagerService extends IPackageManager.Stub
PRUNE_UNUSED_SHARED_LIBRARIES_DELAY);
}
- @Override
- public void requestPackageChecksums(@NonNull String packageName, boolean includeSplits,
- @Checksum.TypeMask int optional, @Checksum.TypeMask int required,
- @Nullable List trustedInstallers,
- @NonNull IOnChecksumsReadyListener onChecksumsReadyListener, int userId) {
- requestChecksumsInternal(packageName, includeSplits, optional, required, trustedInstallers,
- onChecksumsReadyListener, userId, mInjector.getBackgroundExecutor(),
- mInjector.getBackgroundHandler());
- }
-
/**
* Requests checksums for the APK file.
* See {@link PackageInstaller.Session#requestChecksums} for details.
@@ -1267,15 +1232,15 @@ public class PackageManagerService extends IPackageManager.Stub
ApkChecksums.Injector injector = new ApkChecksums.Injector(
() -> mContext,
() -> handler,
- () -> mInjector.getIncrementalManager(),
- () -> mPmInternal);
+ mInjector::getIncrementalManager,
+ () -> mInjector.getLocalService(PackageManagerInternal.class));
ApkChecksums.getChecksums(filesToChecksum, optional, required, installerPackageName,
trustedCerts, onChecksumsReadyListener, injector);
});
}
- private void requestChecksumsInternal(@NonNull String packageName, boolean includeSplits,
- @Checksum.TypeMask int optional, @Checksum.TypeMask int required,
+ void requestChecksumsInternal(@NonNull Computer snapshot, @NonNull String packageName,
+ boolean includeSplits, @Checksum.TypeMask int optional, @Checksum.TypeMask int required,
@Nullable List trustedInstallers,
@NonNull IOnChecksumsReadyListener onChecksumsReadyListener, int userId,
@NonNull Executor executor, @NonNull Handler handler) {
@@ -1284,14 +1249,23 @@ public class PackageManagerService extends IPackageManager.Stub
Objects.requireNonNull(executor);
Objects.requireNonNull(handler);
- final ApplicationInfo applicationInfo = getApplicationInfoInternal(packageName, 0,
+ final ApplicationInfo applicationInfo = snapshot.getApplicationInfoInternal(packageName, 0,
Binder.getCallingUid(), userId);
if (applicationInfo == null) {
throw new ParcelableException(new PackageManager.NameNotFoundException(packageName));
}
- final InstallSourceInfo installSourceInfo = getInstallSourceInfo(packageName);
- final String installerPackageName =
- installSourceInfo != null ? installSourceInfo.getInitiatingPackageName() : null;
+
+ final InstallSourceInfo installSourceInfo = snapshot.getInstallSourceInfo(packageName);
+ final String installerPackageName;
+ if (installSourceInfo != null) {
+ if (!TextUtils.isEmpty(installSourceInfo.getInitiatingPackageName())) {
+ installerPackageName = installSourceInfo.getInitiatingPackageName();
+ } else {
+ installerPackageName = installSourceInfo.getInstallingPackageName();
+ }
+ } else {
+ installerPackageName = null;
+ }
List<Pair<String, File>> filesToChecksum = new ArrayList<>();
@@ -1313,8 +1287,8 @@ public class PackageManagerService extends IPackageManager.Stub
ApkChecksums.Injector injector = new ApkChecksums.Injector(
() -> mContext,
() -> handler,
- () -> mInjector.getIncrementalManager(),
- () -> mPmInternal);
+ mInjector::getIncrementalManager,
+ () -> mInjector.getLocalService(PackageManagerInternal.class));
ApkChecksums.getChecksums(filesToChecksum, optional, required, installerPackageName,
trustedCerts, onChecksumsReadyListener, injector);
});
@@ -1431,9 +1405,9 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- public static PackageManagerService main(Context context, Installer installer,
- @NonNull DomainVerificationService domainVerificationService, boolean factoryTest,
- boolean onlyCore) {
+ public static Pair<PackageManagerService, IPackageManager> main(Context context,
+ Installer installer, @NonNull DomainVerificationService domainVerificationService,
+ boolean factoryTest, boolean onlyCore) {
// Self-check for initial settings.
PackageManagerServiceCompilerMapping.checkProperties();
final TimingsTraceAndSlog t = new TimingsTraceAndSlog(TAG + "Timing",
@@ -1459,14 +1433,14 @@ public class PackageManagerService extends IPackageManager.Stub
RuntimePermissionsPersistence.createInstance(),
i.getPermissionManagerServiceInternal(),
domainVerificationService, lock),
- (i, pm) -> AppsFilter.create(pm.mPmInternal, i),
+ (i, pm) -> AppsFilter.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(),
i.getContext(), "*dexopt*"),
- (i, pm) -> new DexManager(i.getContext(), pm, i.getPackageDexOptimizer(),
+ (i, pm) -> new DexManager(i.getContext(), i.getPackageDexOptimizer(),
i.getInstaller(), i.getInstallLock()),
- (i, pm) -> new ArtManagerService(i.getContext(), pm, i.getInstaller(),
+ (i, pm) -> new ArtManagerService(i.getContext(), i.getInstaller(),
i.getInstallLock()),
(i, pm) -> ApexManager.getInstance(),
(i, pm) -> new ViewCompiler(i.getInstallLock(), i.getInstaller()),
@@ -1489,7 +1463,7 @@ public class PackageManagerService extends IPackageManager.Stub
i.getContext(), pm, i::getScanningPackageParser),
(i, pm, cn) -> new InstantAppResolverConnection(
i.getContext(), cn, Intent.ACTION_RESOLVE_INSTANT_APP_PACKAGE),
- (i, pm) -> new ModuleInfoProvider(i.getContext(), pm),
+ (i, pm) -> new ModuleInfoProvider(i.getContext()),
(i, pm) -> LegacyPermissionManagerService.create(i.getContext()),
(i, pm) -> domainVerificationService,
(i, pm) -> {
@@ -1517,13 +1491,15 @@ public class PackageManagerService extends IPackageManager.Stub
final CompatChange.ChangeListener selinuxChangeListener = packageName -> {
synchronized (m.mInstallLock) {
- final PackageStateInternal packageState = m.getPackageStateInternal(packageName);
+ final Computer snapshot = m.snapshotComputer();
+ final PackageStateInternal packageState =
+ snapshot.getPackageStateInternal(packageName);
if (packageState == null) {
Slog.e(TAG, "Failed to find package setting " + packageName);
return;
}
AndroidPackage pkg = packageState.getPkg();
- SharedUserApi sharedUser = m.mComputer.getSharedUser(
+ SharedUserApi sharedUser = snapshot.getSharedUser(
packageState.getSharedUserAppId());
String oldSeInfo = AndroidPackageUtils.getSeInfo(pkg, packageState);
@@ -1550,11 +1526,12 @@ public class PackageManagerService extends IPackageManager.Stub
selinuxChangeListener);
m.installAllowlistedSystemPackages();
- ServiceManager.addService("package", m);
+ IPackageManagerImpl iPackageManager = m.new IPackageManagerImpl();
+ ServiceManager.addService("package", iPackageManager);
final PackageManagerNative pmn = new PackageManagerNative(m);
ServiceManager.addService("package_native", pmn);
LocalManagerRegistry.addManager(PackageManagerLocal.class, m.new PackageManagerLocalImpl());
- return m;
+ return Pair.create(m, iPackageManager);
}
/** Install/uninstall system packages for all users based on their user-type, as applicable. */
@@ -1660,7 +1637,6 @@ public class PackageManagerService extends IPackageManager.Stub
mPackageDexOptimizer = testParams.packageDexOptimizer;
mPackageParserCallback = testParams.packageParserCallback;
mPendingBroadcasts = testParams.pendingPackageBroadcasts;
- mPmInternal = testParams.pmInternal;
mTestUtilityService = testParams.testUtilityService;
mProcessLoggingHandler = testParams.processLoggingHandler;
mProtectedPackages = testParams.protectedPackages;
@@ -1703,7 +1679,7 @@ public class PackageManagerService extends IPackageManager.Stub
mAppDataHelper = testParams.appDataHelper;
mInstallPackageHelper = testParams.installPackageHelper;
mRemovePackageHelper = testParams.removePackageHelper;
- mInitAndSystemPackageHelper = testParams.initAndSystemPackageHelper;
+ mInitAppsHelper = testParams.initAndSystemPackageHelper;
mDeletePackageHelper = testParams.deletePackageHelper;
mPreferredActivityHelper = testParams.preferredActivityHelper;
mResolveIntentHelper = testParams.resolveIntentHelper;
@@ -1712,6 +1688,8 @@ public class PackageManagerService extends IPackageManager.Stub
mSharedLibraries.setDeletePackageHelper(mDeletePackageHelper);
+ mIntentResolverInterceptor = null;
+
registerObservers(false);
invalidatePackageInfoCache();
}
@@ -1749,10 +1727,9 @@ public class PackageManagerService extends IPackageManager.Stub
t.traceBegin("createSubComponents");
// Expose private service for system components to use.
- mPmInternal = new PackageManagerInternalImpl();
+ LocalServices.addService(PackageManagerInternal.class, new PackageManagerInternalImpl());
LocalServices.addService(TestUtilityService.class, this);
mTestUtilityService = LocalServices.getService(TestUtilityService.class);
- LocalServices.addService(PackageManagerInternal.class, mPmInternal);
mUserManager = injector.getUserManagerService();
mUserNeedsBadging = new UserNeedsBadgingCache(mUserManager);
mComponentResolver = injector.getComponentResolver();
@@ -1852,7 +1829,8 @@ public class PackageManagerService extends IPackageManager.Stub
mAppDataHelper = new AppDataHelper(this);
mInstallPackageHelper = new InstallPackageHelper(this, mAppDataHelper);
mRemovePackageHelper = new RemovePackageHelper(this, mAppDataHelper);
- mInitAndSystemPackageHelper = new InitAndSystemPackageHelper(this);
+ mInitAppsHelper = new InitAppsHelper(this, mApexManager, mInstallPackageHelper,
+ mInjector.getSystemPartitions());
mDeletePackageHelper = new DeletePackageHelper(this, mRemovePackageHelper,
mAppDataHelper);
mSharedLibraries.setDeletePackageHelper(mDeletePackageHelper);
@@ -1900,9 +1878,10 @@ public class PackageManagerService extends IPackageManager.Stub
final int dependencyCount = entry.dependencies.length;
for (int j = 0; j < dependencyCount; j++) {
final SharedLibraryInfo dependency =
- getSharedLibraryInfo(entry.dependencies[j], undefinedVersion);
+ computer.getSharedLibraryInfo(entry.dependencies[j], undefinedVersion);
if (dependency != null) {
- getSharedLibraryInfo(name, undefinedVersion).addDependency(dependency);
+ computer.getSharedLibraryInfo(name, undefinedVersion)
+ .addDependency(dependency);
}
}
}
@@ -1914,7 +1893,7 @@ public class PackageManagerService extends IPackageManager.Stub
t.traceEnd();
t.traceBegin("read user settings");
- mFirstBoot = !mSettings.readLPw(mLiveComputer,
+ mFirstBoot = !mSettings.readLPw(computer,
mInjector.getUserManagerInternal().getUsers(
/* excludePartial= */ true,
/* excludeDying= */ false,
@@ -1986,8 +1965,11 @@ public class PackageManagerService extends IPackageManager.Stub
mIsEngBuild, mIsUserDebugBuild, mIncrementalVersion);
final int[] userIds = mUserManager.getUserIds();
- mOverlayConfig = mInitAndSystemPackageHelper.initPackages(packageSettings,
- userIds, startTime);
+ PackageParser2 packageParser = mInjector.getScanningCachingPackageParser();
+ mOverlayConfig = mInitAppsHelper.initSystemApps(packageParser, packageSettings, userIds,
+ startTime);
+ mInitAppsHelper.initNonSystemApps(packageParser, userIds, startTime);
+ packageParser.close();
// Resolve the storage manager.
mStorageManagerPackage = getStorageManagerPackageName(computer);
@@ -1995,17 +1977,26 @@ public class PackageManagerService extends IPackageManager.Stub
// Resolve protected action filters. Only the setup wizard is allowed to
// have a high priority filter for these actions.
mSetupWizardPackage = getSetupWizardPackageNameImpl(computer);
- mComponentResolver.fixProtectedFilterPriorities(mPmInternal.getSetupWizardPackageName());
-
- mDefaultTextClassifierPackage = getDefaultTextClassifierPackageName();
- mSystemTextClassifierPackageName = getSystemTextClassifierPackageName();
- mConfiguratorPackage = getDeviceConfiguratorPackageName();
- mAppPredictionServicePackage = getAppPredictionServicePackageName();
- mIncidentReportApproverPackage = getIncidentReportApproverPackageName();
+ mComponentResolver.fixProtectedFilterPriorities(mSetupWizardPackage);
+
+ mDefaultTextClassifierPackage = ensureSystemPackageName(computer,
+ mContext.getString(R.string.config_servicesExtensionPackage));
+ mSystemTextClassifierPackageName = ensureSystemPackageName(computer,
+ mContext.getString(R.string.config_defaultTextClassifierPackage));
+ mConfiguratorPackage = ensureSystemPackageName(computer,
+ mContext.getString(R.string.config_deviceConfiguratorPackageName));
+ mAppPredictionServicePackage = ensureSystemPackageName(computer,
+ getPackageFromComponentString(R.string.config_defaultAppPredictionService));
+ mIncidentReportApproverPackage = ensureSystemPackageName(computer,
+ mContext.getString(R.string.config_incidentReportApproverPackage));
mRetailDemoPackage = getRetailDemoPackageName();
- mOverlayConfigSignaturePackage = getOverlayConfigSignaturePackageName();
- mRecentsPackage = getRecentsPackageName();
- mAmbientContextDetectionPackage = getAmbientContextDetectionPackageName();
+ mOverlayConfigSignaturePackage = ensureSystemPackageName(computer,
+ mInjector.getSystemConfig().getOverlayConfigSignaturePackage());
+ mRecentsPackage = ensureSystemPackageName(computer,
+ getPackageFromComponentString(R.string.config_recentsComponentName));
+ mAmbientContextDetectionPackage = ensureSystemPackageName(computer,
+ getPackageFromComponentString(
+ R.string.config_defaultAmbientContextDetectionService));
// Now that we know all of the shared libraries, update all clients to have
// the correct library paths.
@@ -2139,8 +2130,8 @@ public class PackageManagerService extends IPackageManager.Stub
mDomainVerificationManager.setProxy(domainVerificationProxy);
- mServicesExtensionPackageName = getRequiredServicesExtensionPackageLPr();
- mSharedSystemSharedLibraryPackageName = getRequiredSharedLibrary(
+ mServicesExtensionPackageName = getRequiredServicesExtensionPackageLPr(computer);
+ mSharedSystemSharedLibraryPackageName = getRequiredSharedLibrary(computer,
PackageManager.SYSTEM_SHARED_LIBRARY_SHARED,
SharedLibraryInfo.VERSION_UNDEFINED);
} else {
@@ -2156,11 +2147,11 @@ public class PackageManagerService extends IPackageManager.Stub
mRequiredPermissionControllerPackage = getRequiredPermissionControllerLPr(computer);
mSettings.setPermissionControllerVersion(
- getPackageInfo(mRequiredPermissionControllerPackage, 0,
+ computer.getPackageInfo(mRequiredPermissionControllerPackage, 0,
UserHandle.USER_SYSTEM).getLongVersionCode());
// Resolve the sdk sandbox package
- mRequiredSdkSandboxPackage = getRequiredSdkSandboxPackageName();
+ mRequiredSdkSandboxPackage = getRequiredSdkSandboxPackageName(computer);
// Initialize InstantAppRegistry's Instant App list for all users.
for (AndroidPackage pkg : mPackages.values()) {
@@ -2168,7 +2159,8 @@ public class PackageManagerService extends IPackageManager.Stub
continue;
}
for (int userId : userIds) {
- final PackageStateInternal ps = getPackageStateInternal(pkg.getPackageName());
+ final PackageStateInternal ps =
+ computer.getPackageStateInternal(pkg.getPackageName());
if (ps == null || !ps.getUserStateOrDefault(userId).isInstantApp()
|| !ps.getUserStateOrDefault(userId).isInstalled()) {
continue;
@@ -2178,7 +2170,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
mInstallerService = mInjector.getPackageInstallerService();
- final ComponentName instantAppResolverComponent = getInstantAppResolver();
+ final ComponentName instantAppResolverComponent = getInstantAppResolver(computer);
if (instantAppResolverComponent != null) {
if (DEBUG_INSTANT) {
Slog.d(TAG, "Set ephemeral resolver: " + instantAppResolverComponent);
@@ -2204,7 +2196,8 @@ public class PackageManagerService extends IPackageManager.Stub
// scanning).
final Map<Integer, List<PackageInfo>> userPackages = new HashMap<>();
for (int userId : userIds) {
- userPackages.put(userId, getInstalledPackages(/*flags*/ 0, userId).getList());
+ userPackages.put(userId, computer.getInstalledPackages(/*flags*/ 0, userId)
+ .getList());
}
mDexManager.load(userPackages);
if (mIsUpgrade) {
@@ -2214,7 +2207,7 @@ public class PackageManagerService extends IPackageManager.Stub
SystemClock.uptimeMillis() - startTime);
}
- // Rebild the live computer since some attributes have been rebuilt.
+ // Rebuild the live computer since some attributes have been rebuilt.
mLiveComputer = createLiveComputer();
} // synchronized (mLock)
@@ -2222,6 +2215,7 @@ public class PackageManagerService extends IPackageManager.Stub
// CHECKSTYLE:ON IndentationCheck
mModuleInfoProvider = mInjector.getModuleInfoProvider();
+
mInjector.getSystemWrapper().enablePackageCaches();
// Now after opening every single application zip, make sure they
@@ -2240,6 +2234,8 @@ public class PackageManagerService extends IPackageManager.Stub
mServiceStartWithDelay = SystemClock.uptimeMillis() + (60 * 1000L);
+ mIntentResolverInterceptor = new IntentResolverInterceptor(mContext);
+
Slog.i(TAG, "Fix for b/169414761 is applied");
}
@@ -2255,19 +2251,16 @@ public class PackageManagerService extends IPackageManager.Stub
setUpInstantAppInstallerActivityLP(getInstantAppInstallerLPr());
}
- @Override
public boolean isFirstBoot() {
// allow instant applications
return mFirstBoot;
}
- @Override
public boolean isOnlyCoreApps() {
// allow instant applications
return mOnlyCore;
}
- @Override
public boolean isDeviceUpgrading() {
// allow instant applications
// The system property allows testing ota flow when upgraded to the same image.
@@ -2294,8 +2287,9 @@ public class PackageManagerService extends IPackageManager.Stub
}
@NonNull
- private String getRequiredSharedLibrary(@NonNull String name, int version) {
- SharedLibraryInfo libraryInfo = getSharedLibraryInfo(name, version);
+ private String getRequiredSharedLibrary(@NonNull Computer snapshot, @NonNull String name,
+ int version) {
+ SharedLibraryInfo libraryInfo = snapshot.getSharedLibraryInfo(name, version);
if (libraryInfo == null) {
throw new IllegalStateException("Missing required shared library:" + name);
}
@@ -2307,9 +2301,9 @@ public class PackageManagerService extends IPackageManager.Stub
}
@NonNull
- private String getRequiredServicesExtensionPackageLPr() {
+ private String getRequiredServicesExtensionPackageLPr(@NonNull Computer computer) {
String servicesExtensionPackage =
- ensureSystemPackageName(
+ ensureSystemPackageName(computer,
mContext.getString(R.string.config_servicesExtensionPackage));
if (TextUtils.isEmpty(servicesExtensionPackage)) {
throw new RuntimeException(
@@ -2388,8 +2382,9 @@ public class PackageManagerService extends IPackageManager.Stub
for (int i = 0; i < N; i++) {
final ResolveInfo cur = matches.get(i);
final String packageName = cur.getComponentInfo().packageName;
- if (checkPermission(android.Manifest.permission.INTENT_FILTER_VERIFICATION_AGENT,
- packageName, UserHandle.USER_SYSTEM) != PackageManager.PERMISSION_GRANTED) {
+ if (checkPermission(
+ android.Manifest.permission.INTENT_FILTER_VERIFICATION_AGENT, packageName,
+ UserHandle.USER_SYSTEM) != PackageManager.PERMISSION_GRANTED) {
continue;
}
@@ -2417,15 +2412,16 @@ public class PackageManagerService extends IPackageManager.Stub
for (int i = 0; i < N; i++) {
final ResolveInfo cur = matches.get(i);
final String packageName = cur.getComponentInfo().packageName;
- if (checkPermission(android.Manifest.permission.DOMAIN_VERIFICATION_AGENT,
- packageName, UserHandle.USER_SYSTEM) != PackageManager.PERMISSION_GRANTED) {
+ if (checkPermission(
+ android.Manifest.permission.DOMAIN_VERIFICATION_AGENT, packageName,
+ UserHandle.USER_SYSTEM) != PackageManager.PERMISSION_GRANTED) {
Slog.w(TAG, "Domain verification agent found but does not hold permission: "
+ packageName);
continue;
}
if (best == null || cur.priority > best.priority) {
- if (mComputer.isComponentEffectivelyEnabled(cur.getComponentInfo(),
+ if (computer.isComponentEffectivelyEnabled(cur.getComponentInfo(),
UserHandle.USER_SYSTEM)) {
best = cur;
} else {
@@ -2441,15 +2437,7 @@ public class PackageManagerService extends IPackageManager.Stub
return null;
}
- @Override
- public @Nullable ComponentName getInstantAppResolverComponent() {
- if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
- return null;
- }
- return getInstantAppResolver();
- }
-
- private @Nullable ComponentName getInstantAppResolver() {
+ @Nullable ComponentName getInstantAppResolver(@NonNull Computer snapshot) {
final String[] packageArray =
mContext.getResources().getStringArray(R.array.config_ephemeralResolverPackage);
if (packageArray.length == 0 && !Build.IS_DEBUGGABLE) {
@@ -2465,7 +2453,7 @@ public class PackageManagerService extends IPackageManager.Stub
| MATCH_DIRECT_BOOT_UNAWARE
| (!Build.IS_DEBUGGABLE ? MATCH_SYSTEM_ONLY : 0);
final Intent resolverIntent = new Intent(Intent.ACTION_RESOLVE_INSTANT_APP_PACKAGE);
- List<ResolveInfo> resolvers = queryIntentServicesInternal(resolverIntent, null,
+ List<ResolveInfo> resolvers = snapshot.queryIntentServicesInternal(resolverIntent, null,
resolveFlags, UserHandle.USER_SYSTEM, callingUid, false /*includeInstantApps*/);
final int N = resolvers.size();
if (N == 0) {
@@ -2569,155 +2557,6 @@ public class PackageManagerService extends IPackageManager.Stub
return matches.get(0).getComponentInfo().getComponentName();
}
- @Override
- public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
- throws RemoteException {
- try {
- return super.onTransact(code, data, reply, flags);
- } catch (RuntimeException e) {
- if (!(e instanceof SecurityException) && !(e instanceof IllegalArgumentException)
- && !(e instanceof ParcelableException)) {
- Slog.wtf(TAG, "Package Manager Unexpected Exception", e);
- }
- throw e;
- }
- }
-
- /**
- * Returns whether or not a full application can see an instant application.
- * <p>
- * Currently, there are four cases in which this can occur:
- * <ol>
- * <li>The calling application is a "special" process. Special processes
- * are those with a UID < {@link Process#FIRST_APPLICATION_UID}.</li>
- * <li>The calling application has the permission
- * {@link android.Manifest.permission#ACCESS_INSTANT_APPS}.</li>
- * <li>The calling application is the default launcher on the
- * system partition.</li>
- * <li>The calling application is the default app prediction service.</li>
- * </ol>
- */
- boolean canViewInstantApps(int callingUid, int userId) {
- return mComputer.canViewInstantApps(callingUid, userId);
- }
-
- private PackageInfo generatePackageInfo(@NonNull PackageStateInternal ps,
- @PackageManager.PackageInfoFlagsBits long flags, int userId) {
- return mComputer.generatePackageInfo(ps, flags, userId);
- }
-
- @Override
- public void checkPackageStartable(String packageName, int userId) {
- final int callingUid = Binder.getCallingUid();
- if (getInstantAppPackageName(callingUid) != null) {
- throw new SecurityException("Instant applications don't have access to this method");
- }
- if (!mUserManager.exists(userId)) {
- throw new SecurityException("User doesn't exist");
- }
- enforceCrossUserPermission(callingUid, userId, false, false, "checkPackageStartable");
- switch (getPackageStartability(packageName, callingUid, userId)) {
- case PACKAGE_STARTABILITY_NOT_FOUND:
- throw new SecurityException("Package " + packageName + " was not found!");
- case PACKAGE_STARTABILITY_NOT_SYSTEM:
- throw new SecurityException("Package " + packageName + " not a system app!");
- case PACKAGE_STARTABILITY_FROZEN:
- throw new SecurityException("Package " + packageName + " is currently frozen!");
- case PACKAGE_STARTABILITY_DIRECT_BOOT_UNSUPPORTED:
- throw new SecurityException("Package " + packageName + " is not encryption aware!");
- case PACKAGE_STARTABILITY_OK:
- default:
- }
- }
-
- private @PackageStartability int getPackageStartability(String packageName,
- int callingUid, int userId) {
- return mComputer.getPackageStartability(mSafeMode, packageName, callingUid, userId);
- }
-
- @Override
- public boolean isPackageAvailable(String packageName, int userId) {
- return mComputer.isPackageAvailable(packageName, userId);
- }
-
- @Override
- public PackageInfo getPackageInfo(String packageName,
- @PackageManager.PackageInfoFlagsBits long flags, int userId) {
- return mComputer.getPackageInfo(packageName, flags, userId);
- }
-
- @Override
- public PackageInfo getPackageInfoVersioned(VersionedPackage versionedPackage,
- @PackageManager.PackageInfoFlagsBits long flags, int userId) {
- return mComputer.getPackageInfoInternal(versionedPackage.getPackageName(),
- versionedPackage.getLongVersionCode(), flags, Binder.getCallingUid(), userId);
- }
-
- /**
- * Returns whether or not access to the application should be filtered.
- * <p>
- * Access may be limited based upon whether the calling or target applications
- * are instant applications.
- *
- * @see #canViewInstantApps(int, int)
- */
- private boolean shouldFilterApplication(@Nullable PackageStateInternal ps, int callingUid,
- @Nullable ComponentName component, @ComponentType int componentType, int userId) {
- return mComputer.shouldFilterApplication(ps, callingUid,
- component, componentType, userId);
- }
-
- /**
- * @see #shouldFilterApplication(PackageStateInternal, int, ComponentName, int, int)
- */
- boolean shouldFilterApplication(
- @Nullable PackageStateInternal ps, int callingUid, int userId) {
- return mComputer.shouldFilterApplication(
- ps, callingUid, userId);
- }
-
- /**
- * @see #shouldFilterApplication(PackageStateInternal, int, ComponentName, int, int)
- */
- private boolean shouldFilterApplication(@NonNull SharedUserSetting sus, int callingUid,
- int userId) {
- return mComputer.shouldFilterApplication(sus, callingUid, userId);
- }
-
- private boolean filterSharedLibPackage(@Nullable PackageStateInternal ps, int uid,
- int userId, @PackageManager.ComponentInfoFlagsBits long flags) {
- return mComputer.filterSharedLibPackage(ps, uid, userId, flags);
- }
-
- @Override
- public String[] currentToCanonicalPackageNames(String[] names) {
- return mComputer.currentToCanonicalPackageNames(names);
- }
-
- @Override
- public String[] canonicalToCurrentPackageNames(String[] names) {
- return mComputer.canonicalToCurrentPackageNames(names);
- }
-
- @Override
- public int getPackageUid(@NonNull String packageName,
- @PackageManager.PackageInfoFlagsBits long flags, @UserIdInt int userId) {
- return mComputer.getPackageUid(packageName, flags, userId);
- }
-
- int getPackageUidInternal(String packageName,
- @PackageManager.PackageInfoFlagsBits long flags, int userId, int callingUid) {
- return mComputer.getPackageUidInternal(packageName, flags, userId, callingUid);
- }
-
- @Override
- public int[] getPackageGids(String packageName, @PackageManager.PackageInfoFlagsBits long flags,
- int userId) {
- return mComputer.getPackageGids(packageName, flags, userId);
- }
-
- // NOTE: Can't remove due to unsupported app usage
- @Override
public PermissionGroupInfo getPermissionGroupInfo(String groupName, int flags) {
// Because this is accessed via the package manager service AIDL,
// go through the permission manager service AIDL
@@ -2725,86 +2564,6 @@ public class PackageManagerService extends IPackageManager.Stub
.getPermissionGroupInfo(groupName, flags);
}
- private ApplicationInfo generateApplicationInfoFromSettings(String packageName,
- @PackageManager.ApplicationInfoFlagsBits long flags, int filterCallingUid, int userId) {
- return mComputer.generateApplicationInfoFromSettings(packageName, flags, filterCallingUid,
- userId);
- }
-
- @Override
- public ApplicationInfo getApplicationInfo(String packageName,
- @PackageManager.ApplicationInfoFlagsBits long flags, int userId) {
- return mComputer.getApplicationInfo(packageName, flags, userId);
- }
-
- /**
- * Important: The provided filterCallingUid is used exclusively to filter out applications
- * that can be seen based on user state. It's typically the original caller uid prior
- * to clearing. Because it can only be provided by trusted code, its value can be
- * trusted and will be used as-is; unlike userId which will be validated by this method.
- */
- private ApplicationInfo getApplicationInfoInternal(String packageName,
- @PackageManager.ApplicationInfoFlagsBits long flags,
- int filterCallingUid, int userId) {
- return mComputer.getApplicationInfoInternal(packageName, flags,
- filterCallingUid, userId);
- }
-
- @Override
- public void deletePreloadsFileCache() {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CLEAR_APP_CACHE,
- "deletePreloadsFileCache");
- File dir = Environment.getDataPreloadsFileCacheDirectory();
- Slog.i(TAG, "Deleting preloaded file cache " + dir);
- FileUtils.deleteContents(dir);
- }
-
- @Override
- public void freeStorageAndNotify(final String volumeUuid, final long freeStorageSize,
- final @StorageManager.AllocateFlags int flags, final IPackageDataObserver observer) {
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.CLEAR_APP_CACHE, null);
- mHandler.post(() -> {
- boolean success = false;
- try {
- freeStorage(volumeUuid, freeStorageSize, flags);
- success = true;
- } catch (IOException e) {
- Slog.w(TAG, e);
- }
- if (observer != null) {
- try {
- observer.onRemoveCompleted(null, success);
- } catch (RemoteException e) {
- Slog.w(TAG, e);
- }
- }
- });
- }
-
- @Override
- public void freeStorage(final String volumeUuid, final long freeStorageSize,
- final @StorageManager.AllocateFlags int flags, final IntentSender pi) {
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.CLEAR_APP_CACHE, TAG);
- mHandler.post(() -> {
- boolean success = false;
- try {
- freeStorage(volumeUuid, freeStorageSize, flags);
- success = true;
- } catch (IOException e) {
- Slog.w(TAG, e);
- }
- if (pi != null) {
- try {
- pi.sendIntent(null, success ? 1 : 0, null, null, null);
- } catch (SendIntentException e) {
- Slog.w(TAG, e);
- }
- }
- });
- }
-
/**
* Blocking call to clear all cached app data above quota.
*/
@@ -2962,170 +2721,15 @@ public class PackageManagerService extends IPackageManager.Stub
return recommendedInstallLocation;
}
- /**
- * Update given flags when being used to request {@link ResolveInfo}.
- * <p>Instant apps are resolved specially, depending upon context. Minimally,
- * {@code}flags{@code} must have the {@link PackageManager#MATCH_INSTANT}
- * flag set. However, this flag is only honoured in three circumstances:
- * <ul>
- * <li>when called from a system process</li>
- * <li>when the caller holds the permission {@code android.permission.ACCESS_INSTANT_APPS}</li>
- * <li>when resolution occurs to start an activity with a {@code android.intent.action.VIEW}
- * action and a {@code android.intent.category.BROWSABLE} category</li>
- * </ul>
- */
- long updateFlagsForResolve(long flags, int userId, int callingUid,
- boolean wantInstantApps, boolean isImplicitImageCaptureIntentAndNotSetByDpc) {
- return mComputer.updateFlagsForResolve(flags, userId, callingUid,
- wantInstantApps, isImplicitImageCaptureIntentAndNotSetByDpc);
- }
-
- @Override
- public int getTargetSdkVersion(@NonNull String packageName) {
- return mComputer.getTargetSdkVersion(packageName);
- }
-
- @Override
- public ActivityInfo getActivityInfo(ComponentName component,
- @PackageManager.ComponentInfoFlagsBits long flags, int userId) {
- return mComputer.getActivityInfo(component, flags, userId);
- }
-
- /**
- * Important: The provided filterCallingUid is used exclusively to filter out activities
- * that can be seen based on user state. It's typically the original caller uid prior
- * to clearing. Because it can only be provided by trusted code, its value can be
- * trusted and will be used as-is; unlike userId which will be validated by this method.
- */
- private ActivityInfo getActivityInfoInternal(ComponentName component,
- @PackageManager.ComponentInfoFlagsBits long flags, int filterCallingUid, int userId) {
- return mComputer.getActivityInfoInternal(component, flags,
- filterCallingUid, userId);
- }
-
- @Override
- public boolean activitySupportsIntent(ComponentName component, Intent intent,
- String resolvedType) {
- return mComputer.activitySupportsIntent(mResolveComponentName, component, intent,
- resolvedType);
- }
-
- @Override
- public ActivityInfo getReceiverInfo(ComponentName component,
- @PackageManager.ComponentInfoFlagsBits long flags, int userId) {
- return mComputer.getReceiverInfo(component, flags, userId);
- }
-
- @Override
- public ParceledListSlice<SharedLibraryInfo> getSharedLibraries(String packageName,
- @PackageManager.PackageInfoFlagsBits long flags, int userId) {
- return mComputer.getSharedLibraries(packageName, flags, userId);
- }
-
- @Nullable
- @Override
- public ParceledListSlice<SharedLibraryInfo> getDeclaredSharedLibraries(
- @NonNull String packageName, @PackageManager.PackageInfoFlagsBits long flags,
- @NonNull int userId) {
- return mComputer.getDeclaredSharedLibraries(packageName, flags, userId);
- }
-
- @Nullable
- List<VersionedPackage> getPackagesUsingSharedLibrary(
- SharedLibraryInfo libInfo, @PackageManager.PackageInfoFlagsBits long flags,
- int callingUid, int userId) {
- return mComputer.getPackagesUsingSharedLibrary(libInfo, flags, callingUid, userId);
- }
-
- @Nullable
- @Override
- public ServiceInfo getServiceInfo(@NonNull ComponentName component,
- @PackageManager.ComponentInfoFlagsBits long flags, @UserIdInt int userId) {
- return mComputer.getServiceInfo(component, flags, userId);
- }
-
- @Nullable
- @Override
- public ProviderInfo getProviderInfo(@NonNull ComponentName component,
- @PackageManager.ComponentInfoFlagsBits long flags, @UserIdInt int userId) {
- return mComputer.getProviderInfo(component, flags, userId);
- }
-
- @Override
- public ModuleInfo getModuleInfo(String packageName, @ModuleInfoFlags int flags) {
+ public ModuleInfo getModuleInfo(String packageName, @PackageManager.ModuleInfoFlags int flags) {
return mModuleInfoProvider.getModuleInfo(packageName, flags);
}
- @Override
- public List<ModuleInfo> getInstalledModules(int flags) {
- return mModuleInfoProvider.getInstalledModules(flags);
- }
-
- @Nullable
- @Override
- public String[] getSystemSharedLibraryNames() {
- return mComputer.getSystemSharedLibraryNames();
- }
-
- @Override
- public @NonNull String getServicesSystemSharedLibraryPackageName() {
- return mServicesExtensionPackageName;
- }
-
- @Override
- public @NonNull String getSharedSystemSharedLibraryPackageName() {
- return mSharedSystemSharedLibraryPackageName;
- }
-
@GuardedBy("mLock")
void updateSequenceNumberLP(PackageSetting pkgSetting, int[] userList) {
mChangedPackagesTracker.updateSequenceNumber(pkgSetting.getPackageName(), userList);
}
- @Override
- public ChangedPackages getChangedPackages(int sequenceNumber, int userId) {
- final int callingUid = Binder.getCallingUid();
- if (getInstantAppPackageName(callingUid) != null) {
- return null;
- }
- if (!mUserManager.exists(userId)) {
- return null;
- }
- enforceCrossUserPermission(callingUid, userId, false, false, "getChangedPackages");
- final ChangedPackages changedPackages = mChangedPackagesTracker.getChangedPackages(
- sequenceNumber, userId);
-
- if (changedPackages != null) {
- final List<String> packageNames = changedPackages.getPackageNames();
- for (int index = packageNames.size() - 1; index >= 0; index--) {
- // Filter out the changes if the calling package should not be able to see it.
- final PackageSetting ps = mSettings.getPackageLPr(packageNames.get(index));
- if (shouldFilterApplication(ps, callingUid, userId)) {
- packageNames.remove(index);
- }
- }
- }
-
- return changedPackages;
- }
-
- @Override
- public @NonNull ParceledListSlice<FeatureInfo> getSystemAvailableFeatures() {
- // allow instant applications
- ArrayList<FeatureInfo> res;
- synchronized (mAvailableFeatures) {
- res = new ArrayList<>(mAvailableFeatures.size() + 1);
- res.addAll(mAvailableFeatures.values());
- }
- final FeatureInfo fi = new FeatureInfo();
- fi.reqGlEsVersion = SystemProperties.getInt("ro.opengles.version",
- FeatureInfo.GL_ES_VERSION_UNDEFINED);
- res.add(fi);
-
- return new ParceledListSlice<>(res);
- }
-
- @Override
public boolean hasSystemFeature(String name, int version) {
// allow instant applications
synchronized (mAvailableFeatures) {
@@ -3139,29 +2743,10 @@ public class PackageManagerService extends IPackageManager.Stub
}
// NOTE: Can't remove due to unsupported app usage
- @Override
public int checkPermission(String permName, String pkgName, int userId) {
return mPermissionManager.checkPermission(pkgName, permName, userId);
}
- // NOTE: Can't remove without a major refactor. Keep around for now.
- @Override
- public int checkUidPermission(String permName, int uid) {
- return mComputer.checkUidPermission(permName, uid);
- }
-
- @Override
- public String getPermissionControllerPackageName() {
- final int callingUid = Binder.getCallingUid();
- if (mComputer.getPackageStateFiltered(mRequiredPermissionControllerPackage,
- callingUid, UserHandle.getUserId(callingUid)) != null) {
- return mRequiredPermissionControllerPackage;
- }
-
- throw new IllegalStateException("PermissionController is not found");
- }
-
- @Override
public String getSdkSandboxPackageName() {
return mRequiredSdkSandboxPackage;
}
@@ -3170,172 +2755,7 @@ public class PackageManagerService extends IPackageManager.Stub
return mRequiredInstallerPackage;
}
- // NOTE: Can't remove due to unsupported app usage
- @Override
- public boolean addPermission(PermissionInfo info) {
- // Because this is accessed via the package manager service AIDL,
- // go through the permission manager service AIDL
- return mContext.getSystemService(PermissionManager.class).addPermission(info, false);
- }
-
- // NOTE: Can't remove due to unsupported app usage
- @Override
- public boolean addPermissionAsync(PermissionInfo info) {
- // Because this is accessed via the package manager service AIDL,
- // go through the permission manager service AIDL
- return mContext.getSystemService(PermissionManager.class).addPermission(info, true);
- }
-
- // NOTE: Can't remove due to unsupported app usage
- @Override
- public void removePermission(String permName) {
- // Because this is accessed via the package manager service AIDL,
- // go through the permission manager service AIDL
- mContext.getSystemService(PermissionManager.class).removePermission(permName);
- }
-
- // NOTE: Can't remove due to unsupported app usage
- @Override
- public void grantRuntimePermission(String packageName, String permName, final int userId) {
- // Because this is accessed via the package manager service AIDL,
- // go through the permission manager service AIDL
- mContext.getSystemService(PermissionManager.class)
- .grantRuntimePermission(packageName, permName, UserHandle.of(userId));
- }
-
- @Override
- public boolean isProtectedBroadcast(String actionName) {
- if (actionName != null) {
- // TODO: remove these terrible hacks
- if (actionName.startsWith("android.net.netmon.lingerExpired")
- || actionName.startsWith("com.android.server.sip.SipWakeupTimer")
- || actionName.startsWith("com.android.internal.telephony.data-reconnect")
- || actionName.startsWith("android.net.netmon.launchCaptivePortalApp")) {
- return true;
- }
- }
- // allow instant applications
- synchronized (mProtectedBroadcasts) {
- return mProtectedBroadcasts.contains(actionName);
- }
- }
-
- @Override
- public int checkSignatures(@NonNull String pkg1, @NonNull String pkg2) {
- return mComputer.checkSignatures(pkg1, pkg2);
- }
-
- @Override
- public int checkUidSignatures(int uid1, int uid2) {
- return mComputer.checkUidSignatures(uid1, uid2);
- }
-
- @Override
- public boolean hasSigningCertificate(@NonNull String packageName, @NonNull byte[] certificate,
- @PackageManager.CertificateInputType int type) {
- return mComputer.hasSigningCertificate(packageName, certificate, type);
- }
-
- @Override
- public boolean hasUidSigningCertificate(int uid, @NonNull byte[] certificate,
- @PackageManager.CertificateInputType int type) {
- return mComputer.hasUidSigningCertificate(uid, certificate, type);
- }
-
- @Override
- public List<String> getAllPackages() {
- return mComputer.getAllPackages();
- }
-
- /**
- * <em>IMPORTANT:</em> Not all packages returned by this method may be known
- * to the system. There are two conditions in which this may occur:
- * <ol>
- * <li>The package is on adoptable storage and the device has been removed</li>
- * <li>The package is being removed and the internal structures are partially updated</li>
- * </ol>
- * The second is an artifact of the current data structures and should be fixed. See
- * b/111075456 for one such instance.
- * This binder API is cached. If the algorithm in this method changes,
- * or if the underlying objecs (as returned by getSettingLPr()) change
- * then the logic that invalidates the cache must be revisited. See
- * calls to invalidateGetPackagesForUidCache() to locate the points at
- * which the cache is invalidated.
- */
- @Override
- public String[] getPackagesForUid(int uid) {
- final int callingUid = Binder.getCallingUid();
- final int userId = UserHandle.getUserId(uid);
- enforceCrossUserOrProfilePermission(callingUid, userId,
- /* requireFullPermission */ false,
- /* checkShell */ false, "getPackagesForUid");
- return mComputer.getPackagesForUid(uid);
- }
-
- @Nullable
- @Override
- public String getNameForUid(int uid) {
- return mComputer.getNameForUid(uid);
- }
-
- @Nullable
- @Override
- public String[] getNamesForUids(@NonNull int[] uids) {
- return mComputer.getNamesForUids(uids);
- }
-
- @Override
- public int getUidForSharedUser(@NonNull String sharedUserName) {
- return mComputer.getUidForSharedUser(sharedUserName);
- }
-
- @Override
- public int getFlagsForUid(int uid) {
- return mComputer.getFlagsForUid(uid);
- }
-
- @Override
- public int getPrivateFlagsForUid(int uid) {
- return mComputer.getPrivateFlagsForUid(uid);
- }
-
- @Override
- public boolean isUidPrivileged(int uid) {
- return mComputer.isUidPrivileged(uid);
- }
-
- // NOTE: Can't remove due to unsupported app usage
- @NonNull
- @Override
- public String[] getAppOpPermissionPackages(@NonNull String permissionName) {
- return mComputer.getAppOpPermissionPackages(permissionName);
- }
-
- @Override
- public ResolveInfo resolveIntent(Intent intent, String resolvedType,
- @PackageManager.ResolveInfoFlagsBits long flags, int userId) {
- return mResolveIntentHelper.resolveIntentInternal(snapshotComputer(), intent, resolvedType,
- flags, 0 /*privateResolveFlags*/, userId, false, Binder.getCallingUid());
- }
-
- @Override
- public ResolveInfo findPersistentPreferredActivity(Intent intent, int userId) {
- return mPreferredActivityHelper.findPersistentPreferredActivity(intent, userId);
- }
-
- @Override
- public void setLastChosenActivity(Intent intent, String resolvedType, int flags,
- IntentFilter filter, int match, ComponentName activity) {
- mPreferredActivityHelper.setLastChosenActivity(intent, resolvedType, flags,
- new WatchedIntentFilter(filter), match, activity);
- }
-
- @Override
- public ResolveInfo getLastChosenActivity(Intent intent, String resolvedType, int flags) {
- return mPreferredActivityHelper.getLastChosenActivity(intent, resolvedType, flags);
- }
-
- private void requestInstantAppResolutionPhaseTwo(AuxiliaryResolveInfo responseObj,
+ void requestInstantAppResolutionPhaseTwo(AuxiliaryResolveInfo responseObj,
Intent origIntent, String resolvedType, String callingPackage,
@Nullable String callingFeatureId, boolean isRequesterInstantApp,
Bundle verificationBundle, int userId) {
@@ -3347,31 +2767,6 @@ public class PackageManagerService extends IPackageManager.Stub
mHandler.sendMessage(msg);
}
- /**
- * From Android R, camera intents have to match system apps. The only exception to this is if
- * the DPC has set the camera persistent preferred activity. This case was introduced
- * because it is important that the DPC has the ability to set both system and non-system
- * camera persistent preferred activities.
- *
- * @return {@code true} if the intent is a camera intent and the persistent preferred
- * activity was not set by the DPC.
- */
- @GuardedBy("mLock")
- boolean isImplicitImageCaptureIntentAndNotSetByDpcLocked(Intent intent, int userId,
- String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags) {
- return mComputer.isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, userId,
- resolvedType, flags);
- }
-
- @GuardedBy("mLock")
- ResolveInfo findPersistentPreferredActivityLP(Intent intent,
- String resolvedType,
- @PackageManager.ResolveInfoFlagsBits long flags, List<ResolveInfo> query, boolean debug,
- int userId) {
- return mComputer.findPersistentPreferredActivityLP(intent,
- resolvedType, flags, query, debug, userId);
- }
-
// findPreferredActivityBody returns two items: a "things changed" flag and a
// ResolveInfo, which is the preferred activity itself.
static class FindPreferredActivityBodyResult {
@@ -3379,251 +2774,11 @@ public class PackageManagerService extends IPackageManager.Stub
ResolveInfo mPreferredResolveInfo;
}
- FindPreferredActivityBodyResult findPreferredActivityInternal(
+ public @NonNull ParceledListSlice<ResolveInfo> queryIntentReceivers(@NonNull Computer snapshot,
Intent intent, String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags,
- List<ResolveInfo> query, boolean always,
- boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered) {
- return mComputer.findPreferredActivityInternal(
- intent, resolvedType, flags,
- query, always,
- removeMatches, debug, userId, queryMayBeFiltered);
- }
-
- /*
- * Returns if intent can be forwarded from the sourceUserId to the targetUserId
- */
- @Override
- public boolean canForwardTo(@NonNull Intent intent, @Nullable String resolvedType,
- @UserIdInt int sourceUserId, @UserIdInt int targetUserId) {
- return mComputer.canForwardTo(intent, resolvedType, sourceUserId, targetUserId);
- }
-
- private UserInfo getProfileParent(int userId) {
- return mComputer.getProfileParent(userId);
- }
-
- private List<CrossProfileIntentFilter> getMatchingCrossProfileIntentFilters(Intent intent,
- String resolvedType, int userId) {
- return mComputer.getMatchingCrossProfileIntentFilters(intent,
- resolvedType, userId);
- }
-
- @Override
- public @NonNull ParceledListSlice<ResolveInfo> queryIntentActivities(Intent intent,
- String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, int userId) {
- try {
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "queryIntentActivities");
-
- return new ParceledListSlice<>(snapshotComputer().queryIntentActivitiesInternal(intent,
- resolvedType, flags, userId));
- } finally {
- Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
- }
- }
-
- /**
- * Returns the package name of the calling Uid if it's an instant app. If it isn't
- * instant, returns {@code null}.
- */
- String getInstantAppPackageName(int callingUid) {
- return mComputer.getInstantAppPackageName(callingUid);
- }
-
- @Override
- public @NonNull ParceledListSlice<ResolveInfo> queryIntentActivityOptions(ComponentName caller,
- Intent[] specifics, String[] specificTypes, Intent intent,
- String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, int userId) {
- return new ParceledListSlice<>(mResolveIntentHelper.queryIntentActivityOptionsInternal(
- snapshotComputer(), caller, specifics, specificTypes, intent, resolvedType, flags,
- userId));
- }
-
- @Override
- public @NonNull ParceledListSlice<ResolveInfo> queryIntentReceivers(Intent intent,
- String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, int userId) {
- return new ParceledListSlice<>(mResolveIntentHelper.queryIntentReceiversInternal(
- snapshotComputer(), intent, resolvedType, flags, userId, Binder.getCallingUid()));
- }
-
- @Override
- public ResolveInfo resolveService(Intent intent, String resolvedType,
- @PackageManager.ResolveInfoFlagsBits long flags, int userId) {
- final int callingUid = Binder.getCallingUid();
- return mResolveIntentHelper.resolveServiceInternal(snapshotComputer(), intent, resolvedType,
- flags, userId, callingUid);
- }
-
- @Override
- public @NonNull ParceledListSlice<ResolveInfo> queryIntentServices(Intent intent,
- String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, int userId) {
- final int callingUid = Binder.getCallingUid();
- return new ParceledListSlice<>(queryIntentServicesInternal(
- intent, resolvedType, flags, userId, callingUid, false /*includeInstantApps*/));
- }
-
- @NonNull List<ResolveInfo> queryIntentServicesInternal(Intent intent,
- String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, int userId,
- int callingUid, boolean includeInstantApps) {
- return mComputer.queryIntentServicesInternal(intent,
- resolvedType, flags, userId, callingUid,
- includeInstantApps);
- }
-
- @Override
- public @NonNull ParceledListSlice<ResolveInfo> queryIntentContentProviders(Intent intent,
- String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, int userId) {
- return new ParceledListSlice<>(mResolveIntentHelper.queryIntentContentProvidersInternal(
- snapshotComputer(), intent, resolvedType, flags, userId));
- }
-
- @Override
- public ParceledListSlice<PackageInfo> getInstalledPackages(
- @PackageManager.PackageInfoFlagsBits long flags, int userId) {
- return mComputer.getInstalledPackages(flags, userId);
- }
-
- @Override
- public ParceledListSlice<PackageInfo> getPackagesHoldingPermissions(
- @NonNull String[] permissions, @PackageManager.PackageInfoFlagsBits long flags,
@UserIdInt int userId) {
- return mComputer.getPackagesHoldingPermissions(permissions, flags, userId);
- }
-
- @Override
- public ParceledListSlice<ApplicationInfo> getInstalledApplications(
- @PackageManager.ApplicationInfoFlagsBits long flags, int userId) {
- final int callingUid = Binder.getCallingUid();
- return new ParceledListSlice<>(
- mComputer.getInstalledApplications(flags, userId, callingUid));
- }
-
- @Override
- public ParceledListSlice<InstantAppInfo> getInstantApps(int userId) {
- if (HIDE_EPHEMERAL_APIS) {
- return null;
- }
- if (!canViewInstantApps(Binder.getCallingUid(), userId)) {
- mContext.enforceCallingOrSelfPermission(Manifest.permission.ACCESS_INSTANT_APPS,
- "getEphemeralApplications");
- }
- enforceCrossUserPermission(Binder.getCallingUid(), userId, true /* requireFullPermission */,
- false /* checkShell */, "getEphemeralApplications");
-
- Computer computer = snapshotComputer();
- List<InstantAppInfo> instantApps = mInstantAppRegistry.getInstantApps(computer, userId);
- if (instantApps != null) {
- return new ParceledListSlice<>(instantApps);
- }
- return null;
- }
-
- @Override
- public boolean isInstantApp(String packageName, int userId) {
- return mComputer.isInstantApp(packageName, userId);
- }
-
- private boolean isInstantAppInternal(String packageName, @UserIdInt int userId,
- int callingUid) {
- return mComputer.isInstantAppInternal(packageName, userId,
- callingUid);
- }
-
- @Override
- public byte[] getInstantAppCookie(String packageName, int userId) {
- if (HIDE_EPHEMERAL_APIS) {
- return null;
- }
-
- enforceCrossUserPermission(Binder.getCallingUid(), userId, true /* requireFullPermission */,
- false /* checkShell */, "getInstantAppCookie");
- if (!isCallerSameApp(packageName, Binder.getCallingUid())) {
- return null;
- }
- PackageStateInternal packageState = getPackageStateInternal(packageName);
- if (packageState == null || packageState.getPkg() == null) {
- return null;
- }
- return mInstantAppRegistry.getInstantAppCookie(packageState.getPkg(), userId);
- }
-
- @Override
- public boolean setInstantAppCookie(String packageName, byte[] cookie, int userId) {
- if (HIDE_EPHEMERAL_APIS) {
- return true;
- }
-
- enforceCrossUserPermission(Binder.getCallingUid(), userId, true /* requireFullPermission */,
- true /* checkShell */, "setInstantAppCookie");
- if (!isCallerSameApp(packageName, Binder.getCallingUid())) {
- return false;
- }
-
- PackageStateInternal packageState = getPackageStateInternal(packageName);
- if (packageState == null || packageState.getPkg() == null) {
- return false;
- }
- return mInstantAppRegistry.setInstantAppCookie(packageState.getPkg(), cookie,
- mContext.getPackageManager().getInstantAppCookieMaxBytes(), userId);
- }
-
- @Override
- public Bitmap getInstantAppIcon(String packageName, int userId) {
- if (HIDE_EPHEMERAL_APIS) {
- return null;
- }
-
- if (!canViewInstantApps(Binder.getCallingUid(), userId)) {
- mContext.enforceCallingOrSelfPermission(Manifest.permission.ACCESS_INSTANT_APPS,
- "getInstantAppIcon");
- }
- enforceCrossUserPermission(Binder.getCallingUid(), userId, true /* requireFullPermission */,
- false /* checkShell */, "getInstantAppIcon");
-
- return mInstantAppRegistry.getInstantAppIcon(packageName, userId);
- }
-
- boolean isCallerSameApp(String packageName, int uid) {
- return mComputer.isCallerSameApp(packageName, uid);
- }
-
- @Override
- public @NonNull ParceledListSlice<ApplicationInfo> getPersistentApplications(int flags) {
- if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
- return ParceledListSlice.emptyList();
- }
- return new ParceledListSlice<>(mComputer.getPersistentApplications(mSafeMode, flags));
- }
-
- @Override
- public ProviderInfo resolveContentProvider(String name,
- @PackageManager.ResolveInfoFlagsBits long flags, int userId) {
- return mComputer.resolveContentProvider(name, flags, userId, Binder.getCallingUid());
- }
-
- @Deprecated
- public void querySyncProviders(List<String> outNames, List<ProviderInfo> outInfo) {
- mComputer.querySyncProviders(mSafeMode, outNames, outInfo);
- }
-
- @NonNull
- @Override
- public ParceledListSlice<ProviderInfo> queryContentProviders(@Nullable String processName,
- int uid, @PackageManager.ComponentInfoFlagsBits long flags,
- @Nullable String metaDataKey) {
- return mComputer.queryContentProviders(processName, uid, flags, metaDataKey);
- }
-
- @Nullable
- @Override
- public InstrumentationInfo getInstrumentationInfo(@NonNull ComponentName component, int flags) {
- return mComputer.getInstrumentationInfo(component, flags);
- }
-
- @NonNull
- @Override
- public ParceledListSlice<InstrumentationInfo> queryInstrumentation(
- @NonNull String targetPackage, int flags) {
- return mComputer.queryInstrumentation(targetPackage, flags);
+ return new ParceledListSlice<>(mResolveIntentHelper.queryIntentReceiversInternal(
+ snapshot, intent, resolvedType, flags, userId, Binder.getCallingUid()));
}
public static void reportSettingsProblem(int priority, String msg) {
@@ -3642,40 +2797,6 @@ public class PackageManagerService extends IPackageManager.Stub
return packageName + STATIC_SHARED_LIB_DELIMITER + libraryVersion;
}
- /**
- * Enforces the request is from the system or an app that has INTERACT_ACROSS_USERS
- * or INTERACT_ACROSS_USERS_FULL permissions, if the {@code userId} is not for the caller.
- *
- * @param checkShell whether to prevent shell from access if there's a debugging restriction
- * @param message the message to log on security exception
- */
- void enforceCrossUserPermission(int callingUid, @UserIdInt int userId,
- boolean requireFullPermission, boolean checkShell, String message) {
- mComputer.enforceCrossUserPermission(callingUid, userId,
- requireFullPermission, checkShell, message);
- }
-
- /**
- * Checks if the request is from the system or an app that has the appropriate cross-user
- * permissions defined as follows:
- * <ul>
- * <li>INTERACT_ACROSS_USERS_FULL if {@code requireFullPermission} is true.</li>
- * <li>INTERACT_ACROSS_USERS if the given {@code userId} is in a different profile group
- * to the caller.</li>
- * <li>Otherwise, INTERACT_ACROSS_PROFILES if the given {@code userId} is in the same profile
- * group as the caller.</li>
- * </ul>
- *
- * @param checkShell whether to prevent shell from access if there's a debugging restriction
- * @param message the message to log on security exception
- */
- private void enforceCrossUserOrProfilePermission(int callingUid, @UserIdInt int userId,
- boolean requireFullPermission, boolean checkShell, String message) {
- mComputer.enforceCrossUserOrProfilePermission(callingUid, userId,
- requireFullPermission, checkShell, message);
- }
-
- @Override
public void performFstrimIfNeeded() {
PackageManagerServiceUtils.enforceSystemOrRoot("Only the system can request fstrim");
@@ -3717,28 +2838,10 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- @Override
public void updatePackagesIfNeeded() {
mDexOptHelper.performPackageDexOptUpgradeIfNeeded();
}
- @Override
- public void notifyPackageUse(String packageName, int reason) {
- final int callingUid = Binder.getCallingUid();
- final int callingUserId = UserHandle.getUserId(callingUid);
- Computer computer = snapshotComputer();
- final boolean notify;
- if (getInstantAppPackageName(callingUid) != null) {
- notify = isCallerSameApp(packageName, callingUid);
- } else {
- notify = !isInstantAppInternal(packageName, callingUserId, Process.SYSTEM_UID);
- }
- if (!notify) {
- return;
- }
-
- notifyPackageUseInternal(packageName, reason);
- }
private void notifyPackageUseInternal(String packageName, int reason) {
long time = System.currentTimeMillis();
@@ -3747,118 +2850,10 @@ public class PackageManagerService extends IPackageManager.Stub
});
}
- @Override
- public void notifyDexLoad(String loadingPackageName, Map<String, String> classLoaderContextMap,
- String loaderIsa) {
- int callingUid = Binder.getCallingUid();
- if (PLATFORM_PACKAGE_NAME.equals(loadingPackageName) && callingUid != Process.SYSTEM_UID) {
- Slog.w(TAG, "Non System Server process reporting dex loads as system server. uid="
- + callingUid);
- // Do not record dex loads from processes pretending to be system server.
- // Only the system server should be assigned the package "android", so reject calls
- // that don't satisfy the constraint.
- //
- // notifyDexLoad is a PM API callable from the app process. So in theory, apps could
- // craft calls to this API and pretend to be system server. Doing so poses no particular
- // danger for dex load reporting or later dexopt, however it is a sensible check to do
- // in order to verify the expectations.
- return;
- }
-
- int userId = UserHandle.getCallingUserId();
- ApplicationInfo ai = getApplicationInfo(loadingPackageName, /*flags*/ 0, userId);
- if (ai == null) {
- Slog.w(TAG, "Loading a package that does not exist for the calling user. package="
- + loadingPackageName + ", user=" + userId);
- return;
- }
- mDexManager.notifyDexLoad(ai, classLoaderContextMap, loaderIsa, userId,
- Process.isIsolated(callingUid));
- }
-
- @Override
- public void registerDexModule(String packageName, String dexModulePath, boolean isSharedModule,
- IDexModuleRegisterCallback callback) {
- int userId = UserHandle.getCallingUserId();
- ApplicationInfo ai = getApplicationInfo(packageName, /*flags*/ 0, userId);
- DexManager.RegisterDexModuleResult result;
- if (ai == null) {
- Slog.w(TAG, "Registering a dex module for a package that does not exist for the" +
- " calling user. package=" + packageName + ", user=" + userId);
- result = new DexManager.RegisterDexModuleResult(false, "Package not installed");
- } else {
- result = mDexManager.registerDexModule(ai, dexModulePath, isSharedModule, userId);
- }
-
- if (callback != null) {
- mHandler.post(() -> {
- try {
- callback.onDexModuleRegistered(dexModulePath, result.success, result.message);
- } catch (RemoteException e) {
- Slog.w(TAG, "Failed to callback after module registration " + dexModulePath, e);
- }
- });
- }
- }
-
- /**
- * Ask the package manager to perform a dex-opt with the given compiler filter.
- *
- * Note: exposed only for the shell command to allow moving packages explicitly to a
- * definite state.
- */
- @Override
- public boolean performDexOptMode(String packageName,
- boolean checkProfiles, String targetCompilerFilter, boolean force,
- boolean bootComplete, String splitName) {
- return mDexOptHelper.performDexOptMode(packageName, checkProfiles, targetCompilerFilter,
- force, bootComplete, splitName);
- }
-
- /**
- * Ask the package manager to perform a dex-opt with the given compiler filter on the
- * secondary dex files belonging to the given package.
- *
- * Note: exposed only for the shell command to allow moving packages explicitly to a
- * definite state.
- */
- @Override
- public boolean performDexOptSecondary(String packageName, String compilerFilter,
- boolean force) {
- return mDexOptHelper.performDexOptSecondary(packageName, compilerFilter, force);
- }
-
- /**
- * Reconcile the information we have about the secondary dex files belonging to
- * {@code packageName} and the actual dex files. For all dex files that were
- * deleted, update the internal records and delete the generated oat files.
- */
- @Override
- public void reconcileSecondaryDexFiles(String packageName) {
- if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
- return;
- } else if (isInstantAppInternal(
- packageName, UserHandle.getCallingUserId(), Process.SYSTEM_UID)) {
- return;
- }
- mDexManager.reconcileSecondaryDexFiles(packageName);
- }
-
/*package*/ DexManager getDexManager() {
return mDexManager;
}
- @NonNull
- List<PackageStateInternal> findSharedNonSystemLibraries(
- @NonNull PackageStateInternal pkgSetting) {
- return mComputer.findSharedNonSystemLibraries(pkgSetting);
- }
-
- @Nullable
- SharedLibraryInfo getSharedLibraryInfo(String name, long version) {
- return mComputer.getSharedLibraryInfo(name, version);
- }
-
public void shutdown() {
mCompilerStats.writeNow();
mDexManager.writePackageDexUsageNow();
@@ -3874,67 +2869,10 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- @Override
- public void dumpProfiles(String packageName) {
- /* Only the shell, root, or the app user should be able to dump profiles. */
- final int callingUid = Binder.getCallingUid();
- final String[] callerPackageNames = getPackagesForUid(callingUid);
- if (callingUid != Process.SHELL_UID
- && callingUid != Process.ROOT_UID
- && !ArrayUtils.contains(callerPackageNames, packageName)) {
- throw new SecurityException("dumpProfiles");
- }
-
- AndroidPackage pkg = getPackage(packageName);
- if (pkg == null) {
- throw new IllegalArgumentException("Unknown package: " + packageName);
- }
-
- synchronized (mInstallLock) {
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dump profiles");
- mArtManagerService.dumpProfiles(pkg);
- Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
- }
- }
-
- @Override
- public void forceDexOpt(String packageName) {
- mDexOptHelper.forceDexOpt(packageName);
- }
-
int[] resolveUserIds(int userId) {
return (userId == UserHandle.USER_ALL) ? mUserManager.getUserIds() : new int[] { userId };
}
- @Override
- public Property getProperty(String propertyName, String packageName, String className) {
- Objects.requireNonNull(propertyName);
- Objects.requireNonNull(packageName);
- PackageStateInternal packageState = mComputer.getPackageStateFiltered(packageName,
- Binder.getCallingUid(), UserHandle.getCallingUserId());
- if (packageState == null) {
- return null;
- }
- return mPackageProperty.getProperty(propertyName, packageName, className);
- }
-
- @Override
- public ParceledListSlice<Property> queryProperty(
- String propertyName, @PropertyLocation int componentType) {
- Objects.requireNonNull(propertyName);
- final int callingUid = Binder.getCallingUid();
- final int callingUserId = UserHandle.getCallingUserId();
- final List<Property> result =
- mPackageProperty.queryProperty(propertyName, componentType, packageName -> {
- final PackageStateInternal ps = getPackageStateInternal(packageName);
- return shouldFilterApplication(ps, callingUid, callingUserId);
- });
- if (result == null) {
- return ParceledListSlice.emptyList();
- }
- return new ParceledListSlice<>(result);
- }
-
private void setUpInstantAppInstallerActivityLP(ActivityInfo installerActivity) {
if (installerActivity == null) {
if (DEBUG_INSTANT) {
@@ -4013,14 +2951,14 @@ public class PackageManagerService extends IPackageManager.Stub
mPackageObserverHelper.notifyRemoved(packageName, uid);
}
- void sendPackageAddedForUser(String packageName, @NonNull PackageStateInternal packageState,
- int userId, int dataLoaderType) {
+ void sendPackageAddedForUser(@NonNull Computer snapshot, String packageName,
+ @NonNull PackageStateInternal packageState, int userId, int dataLoaderType) {
final PackageUserStateInternal userState = packageState.getUserStateOrDefault(userId);
final boolean isSystem = packageState.isSystem();
final boolean isInstantApp = userState.isInstantApp();
final int[] userIds = isInstantApp ? EMPTY_INT_ARRAY : new int[] { userId };
final int[] instantUserIds = isInstantApp ? new int[] { userId } : EMPTY_INT_ARRAY;
- sendPackageAddedForNewUsers(packageName, isSystem /*sendBootCompleted*/,
+ sendPackageAddedForNewUsers(snapshot, packageName, isSystem /*sendBootCompleted*/,
false /*startReceiver*/, packageState.getAppId(), userIds, instantUserIds,
dataLoaderType);
@@ -4032,15 +2970,15 @@ public class PackageManagerService extends IPackageManager.Stub
}
@Override
- public void sendPackageAddedForNewUsers(String packageName, boolean sendBootCompleted,
- boolean includeStopped, @AppIdInt int appId, int[] userIds, int[] instantUserIds,
- int dataLoaderType) {
+ public void sendPackageAddedForNewUsers(@NonNull Computer snapshot, String packageName,
+ boolean sendBootCompleted, boolean includeStopped, @AppIdInt int appId, int[] userIds,
+ int[] instantUserIds, int dataLoaderType) {
if (ArrayUtils.isEmpty(userIds) && ArrayUtils.isEmpty(instantUserIds)) {
return;
}
SparseArray<int[]> broadcastAllowList = mAppsFilter.getVisibilityAllowList(
- getPackageStateInternal(packageName, Process.SYSTEM_UID),
- userIds, getPackageStates());
+ snapshot.getPackageStateInternal(packageName, Process.SYSTEM_UID),
+ userIds, snapshot.getPackageStates());
mHandler.post(() -> mBroadcastHelper.sendPackageAddedForNewUsers(
packageName, appId, userIds, instantUserIds, dataLoaderType, broadcastAllowList));
if (sendBootCompleted && !ArrayUtils.isEmpty(userIds)) {
@@ -4054,159 +2992,6 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- @Override
- public boolean setApplicationHiddenSettingAsUser(String packageName, boolean hidden,
- int userId) {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USERS, null);
- final int callingUid = Binder.getCallingUid();
- enforceCrossUserPermission(callingUid, userId, true /* requireFullPermission */,
- true /* checkShell */, "setApplicationHiddenSetting for user " + userId);
-
- if (hidden && isPackageDeviceAdmin(packageName, userId)) {
- Slog.w(TAG, "Not hiding package " + packageName + ": has active device admin");
- return false;
- }
-
- // Do not allow "android" is being disabled
- if ("android".equals(packageName)) {
- Slog.w(TAG, "Cannot hide package: android");
- return false;
- }
-
- final long callingId = Binder.clearCallingIdentity();
- try {
- final PackageStateInternal packageState =
- mComputer.getPackageStateFiltered(packageName, callingUid, userId);
- if (packageState == null) {
- return false;
- }
-
- // Cannot hide static shared libs as they are considered
- // a part of the using app (emulating static linking). Also
- // static libs are installed always on internal storage.
- AndroidPackage pkg = packageState.getPkg();
- if (pkg != null) {
- // Cannot hide SDK libs as they are controlled by SDK manager.
- if (pkg.getSdkLibName() != null) {
- Slog.w(TAG, "Cannot hide package: " + packageName
- + " providing SDK library: "
- + pkg.getSdkLibName());
- return false;
- }
- // Cannot hide static shared libs as they are considered
- // a part of the using app (emulating static linking). Also
- // static libs are installed always on internal storage.
- if (pkg.getStaticSharedLibName() != null) {
- Slog.w(TAG, "Cannot hide package: " + packageName
- + " providing static shared library: "
- + pkg.getStaticSharedLibName());
- return false;
- }
- }
- // Only allow protected packages to hide themselves.
- if (hidden && !UserHandle.isSameApp(callingUid, packageState.getAppId())
- && mProtectedPackages.isPackageStateProtected(userId, packageName)) {
- Slog.w(TAG, "Not hiding protected package: " + packageName);
- return false;
- }
-
- if (packageState.getUserStateOrDefault(userId).isHidden() == hidden) {
- return false;
- }
-
- commitPackageStateMutation(null, packageName, packageState1 ->
- packageState1.userState(userId).setHidden(hidden));
-
- final PackageStateInternal newPackageState = getPackageStateInternal(packageName);
-
- if (hidden) {
- killApplication(packageName, newPackageState.getAppId(), userId, "hiding pkg");
- sendApplicationHiddenForUser(packageName, newPackageState, userId);
- } else {
- sendPackageAddedForUser(packageName, newPackageState, userId, DataLoaderType.NONE);
- }
-
- scheduleWritePackageRestrictions(userId);
- return true;
- } finally {
- Binder.restoreCallingIdentity(callingId);
- }
- }
-
- @Override
- public void setSystemAppHiddenUntilInstalled(String packageName, boolean hidden) {
- final int callingUid = Binder.getCallingUid();
- final boolean calledFromSystemOrPhone = callingUid == Process.PHONE_UID
- || callingUid == Process.SYSTEM_UID;
- if (!calledFromSystemOrPhone) {
- mContext.enforceCallingOrSelfPermission(Manifest.permission.SUSPEND_APPS,
- "setSystemAppHiddenUntilInstalled");
- }
-
- final PackageStateInternal stateRead = getPackageStateInternal(packageName);
- if (stateRead == null || !stateRead.isSystem() || stateRead.getPkg() == null) {
- return;
- }
- if (stateRead.getPkg().isCoreApp() && !calledFromSystemOrPhone) {
- throw new SecurityException("Only system or phone callers can modify core apps");
- }
-
- commitPackageStateMutation(null, mutator -> {
- mutator.forPackage(packageName)
- .setHiddenUntilInstalled(hidden);
- mutator.forDisabledSystemPackage(packageName)
- .setHiddenUntilInstalled(hidden);
- });
- }
-
- @Override
- public boolean setSystemAppInstallState(String packageName, boolean installed, int userId) {
- final int callingUid = Binder.getCallingUid();
- final boolean calledFromSystemOrPhone = callingUid == Process.PHONE_UID
- || callingUid == Process.SYSTEM_UID;
- if (!calledFromSystemOrPhone) {
- mContext.enforceCallingOrSelfPermission(Manifest.permission.SUSPEND_APPS,
- "setSystemAppHiddenUntilInstalled");
- }
-
- final PackageStateInternal packageState = getPackageStateInternal(packageName);
- // The target app should always be in system
- if (packageState == null || !packageState.isSystem() || packageState.getPkg() == null) {
- return false;
- }
- if (packageState.getPkg().isCoreApp() && !calledFromSystemOrPhone) {
- throw new SecurityException("Only system or phone callers can modify core apps");
- }
- // Check if the install state is the same
- if (packageState.getUserStateOrDefault(userId).isInstalled() == installed) {
- return false;
- }
-
- final long callingId = Binder.clearCallingIdentity();
- try {
- if (installed) {
- // install the app from uninstalled state
- installExistingPackageAsUser(
- packageName,
- userId,
- PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS,
- PackageManager.INSTALL_REASON_DEVICE_SETUP,
- null);
- return true;
- }
-
- // uninstall the app from installed state
- deletePackageVersioned(
- new VersionedPackage(packageName, PackageManager.VERSION_CODE_HIGHEST),
- new LegacyPackageDeleteObserver(null).getBinder(),
- userId,
- PackageManager.DELETE_SYSTEM_APP);
- return true;
- } finally {
- Binder.restoreCallingIdentity(callingId);
- }
- }
-
private void sendApplicationHiddenForUser(String packageName, PackageStateInternal packageState,
int userId) {
final PackageRemovedInfo info = new PackageRemovedInfo(this);
@@ -4218,26 +3003,6 @@ public class PackageManagerService extends IPackageManager.Stub
info.sendPackageRemovedBroadcasts(true /*killApp*/, false /*removedBySystem*/);
}
- /**
- * Returns true if application is not found or there was an error. Otherwise it returns
- * the hidden state of the package for the given user.
- */
- @Override
- public boolean getApplicationHiddenSettingAsUser(@NonNull String packageName,
- @UserIdInt int userId) {
- return mComputer.getApplicationHiddenSettingAsUser(packageName, userId);
- }
-
- /**
- * @hide
- */
- @Override
- public int installExistingPackageAsUser(String packageName, int userId, int installFlags,
- int installReason, List<String> whiteListedPermissions) {
- return mInstallPackageHelper.installExistingPackageAsUser(packageName, userId, installFlags,
- installReason, whiteListedPermissions, null);
- }
-
boolean isUserRestricted(int userId, String restrictionKey) {
Bundle restrictions = mUserManager.getUserRestrictions(userId);
if (restrictions.getBoolean(restrictionKey, false)) {
@@ -4247,79 +3012,8 @@ public class PackageManagerService extends IPackageManager.Stub
return false;
}
- @Override
- public String[] setDistractingPackageRestrictionsAsUser(String[] packageNames,
- int restrictionFlags, int userId) {
- mContext.enforceCallingOrSelfPermission(android.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");
- if (restrictionFlags != 0
- && !mSuspendPackageHelper.isSuspendAllowedForUser(userId, callingUid)) {
- Slog.w(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<>();
- Computer computer = snapshotComputer();
- final boolean[] canRestrict = (restrictionFlags != 0)
- ? mSuspendPackageHelper.canSuspendPackageForUser(computer, packageNames, userId,
- callingUid) : null;
- for (int i = 0; i < packageNames.length; i++) {
- final String packageName = packageNames[i];
- final PackageStateInternal packageState =
- computer.getPackageStateInternal(packageName);
- if (packageState == null
- || computer.shouldFilterApplication(packageState, callingUid, userId)) {
- Slog.w(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]);
- }
-
- private void enforceCanSetPackagesSuspendedAsUser(String callingPackage, int callingUid,
- int userId, String callingMethod) {
+ private void enforceCanSetPackagesSuspendedAsUser(@NonNull Computer snapshot,
+ String callingPackage, int callingUid, int userId, String callingMethod) {
if (callingUid == Process.ROOT_UID
// Need to compare app-id to allow system dialogs access on secondary users
|| UserHandle.getAppId(callingUid) == Process.SYSTEM_UID) {
@@ -4328,7 +3022,7 @@ public class PackageManagerService extends IPackageManager.Stub
final String ownerPackage = mProtectedPackages.getDeviceOwnerOrProfileOwnerPackage(userId);
if (ownerPackage != null) {
- final int ownerUid = getPackageUid(ownerPackage, 0, userId);
+ final int ownerUid = snapshot.getPackageUid(ownerPackage, 0, userId);
if (ownerUid == callingUid) {
return;
}
@@ -4337,7 +3031,7 @@ public class PackageManagerService extends IPackageManager.Stub
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.SUSPEND_APPS,
callingMethod);
- final int packageUid = getPackageUid(callingPackage, 0, userId);
+ final int packageUid = snapshot.getPackageUid(callingPackage, 0, userId);
final boolean allowedPackageUid = packageUid == callingUid;
// TODO(b/139383163): remove special casing for shell and enforce INTERACT_ACROSS_USERS_FULL
final boolean allowedShell = callingUid == SHELL_UID
@@ -4349,34 +3043,6 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- @Override
- public String[] setPackagesSuspendedAsUser(String[] packageNames, boolean suspended,
- PersistableBundle appExtras, PersistableBundle launcherExtras,
- SuspendDialogInfo dialogInfo, String callingPackage, int userId) {
- final int callingUid = Binder.getCallingUid();
- enforceCanSetPackagesSuspendedAsUser(callingPackage, callingUid, userId,
- "setPackagesSuspendedAsUser");
- return mSuspendPackageHelper.setPackagesSuspended(snapshotComputer(), packageNames,
- suspended, appExtras, launcherExtras, dialogInfo, callingPackage, userId,
- callingUid);
- }
-
- @Override
- public Bundle getSuspendedPackageAppExtras(String packageName, int userId) {
- final int callingUid = Binder.getCallingUid();
- if (getPackageUid(packageName, 0, userId) != callingUid) {
- throw new SecurityException("Calling package " + packageName
- + " does not belong to calling uid " + callingUid);
- }
- return mSuspendPackageHelper.getSuspendedPackageAppExtras(
- packageName, userId, callingUid);
- }
-
- @Override
- public boolean isPackageSuspendedForUser(@NonNull String packageName, @UserIdInt int userId) {
- return mComputer.isPackageSuspendedForUser(packageName, userId);
- }
-
void unsuspendForSuspendingPackage(@NonNull Computer computer, String suspendingPackage,
@UserIdInt int userId) {
// TODO: This can be replaced by a special parameter to iterate all packages, rather than
@@ -4386,13 +3052,9 @@ public class PackageManagerService extends IPackageManager.Stub
allPackages, suspendingPackage::equals, userId);
}
- private boolean isSuspendingAnyPackages(String suspendingPackage, int userId) {
- return mComputer.isSuspendingAnyPackages(suspendingPackage, userId);
- }
-
- void removeAllDistractingPackageRestrictions(int userId) {
- final String[] allPackages = mComputer.getAllAvailablePackageNames();
- removeDistractingPackageRestrictions(allPackages, userId);
+ void removeAllDistractingPackageRestrictions(@NonNull Computer snapshot, int userId) {
+ final String[] allPackages = snapshot.getAllAvailablePackageNames();
+ removeDistractingPackageRestrictions(snapshot, allPackages, userId);
}
/**
@@ -4404,11 +3066,12 @@ public class PackageManagerService extends IPackageManager.Stub
* @param packagesToChange The packages on which restrictions are to be removed.
* @param userId the user for which changes are taking place.
*/
- private void removeDistractingPackageRestrictions(String[] packagesToChange, int userId) {
+ 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 = getPackageStateInternal(packageName);
+ 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()));
@@ -4431,291 +3094,13 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- @Override
- public String[] getUnsuspendablePackagesForUser(String[] packageNames, int userId) {
- Objects.requireNonNull(packageNames, "packageNames cannot be null");
- mContext.enforceCallingOrSelfPermission(Manifest.permission.SUSPEND_APPS,
- "getUnsuspendablePackagesForUser");
- final int callingUid = Binder.getCallingUid();
- if (UserHandle.getUserId(callingUid) != userId) {
- throw new SecurityException("Calling uid " + callingUid
- + " cannot query getUnsuspendablePackagesForUser for user " + userId);
- }
- return mSuspendPackageHelper.getUnsuspendablePackagesForUser(snapshotComputer(),
- packageNames, userId, callingUid);
- }
-
- @Override
- public void verifyPendingInstall(int id, int verificationCode) throws RemoteException {
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.PACKAGE_VERIFICATION_AGENT,
- "Only package verification agents can verify applications");
- final int callingUid = Binder.getCallingUid();
-
- final Message msg = mHandler.obtainMessage(PACKAGE_VERIFIED);
- final PackageVerificationResponse response = new PackageVerificationResponse(
- verificationCode, callingUid);
- msg.arg1 = id;
- msg.obj = response;
- mHandler.sendMessage(msg);
- }
-
- @Override
- public void extendVerificationTimeout(int id, int verificationCodeAtTimeout,
- long millisecondsToDelay) {
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.PACKAGE_VERIFICATION_AGENT,
- "Only package verification agents can extend verification timeouts");
- final int callingUid = Binder.getCallingUid();
-
- mHandler.post(() -> {
- final PackageVerificationState state = mPendingVerification.get(id);
- final PackageVerificationResponse response = new PackageVerificationResponse(
- verificationCodeAtTimeout, callingUid);
-
- long delay = millisecondsToDelay;
- if (delay > PackageManager.MAXIMUM_VERIFICATION_TIMEOUT) {
- delay = PackageManager.MAXIMUM_VERIFICATION_TIMEOUT;
- }
- if (delay < 0) {
- delay = 0;
- }
-
- if ((state != null) && !state.timeoutExtended()) {
- state.extendTimeout();
-
- final Message msg = mHandler.obtainMessage(PACKAGE_VERIFIED);
- msg.arg1 = id;
- msg.obj = response;
- mHandler.sendMessageDelayed(msg, delay);
- }
- });
- }
-
- private void setEnableRollbackCode(int token, int enableRollbackCode) {
+ void setEnableRollbackCode(int token, int enableRollbackCode) {
final Message msg = mHandler.obtainMessage(ENABLE_ROLLBACK_STATUS);
msg.arg1 = token;
msg.arg2 = enableRollbackCode;
mHandler.sendMessage(msg);
}
- @Override
- public void finishPackageInstall(int token, boolean didLaunch) {
- PackageManagerServiceUtils.enforceSystemOrRoot(
- "Only the system is allowed to finish installs");
-
- if (DEBUG_INSTALL) {
- Slog.v(TAG, "BM finishing package install for " + token);
- }
- Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "restore", token);
-
- final Message msg = mHandler.obtainMessage(POST_INSTALL, token, didLaunch ? 1 : 0);
- mHandler.sendMessage(msg);
- }
-
- @Deprecated
- @Override
- public void verifyIntentFilter(int id, int verificationCode, List<String> failedDomains) {
- DomainVerificationProxyV1.queueLegacyVerifyResult(mContext, mDomainVerificationConnection,
- id, verificationCode, failedDomains, Binder.getCallingUid());
- }
-
- @Deprecated
- @Override
- public int getIntentVerificationStatus(String packageName, int userId) {
- return mDomainVerificationManager.getLegacyState(packageName, userId);
- }
-
- @Deprecated
- @Override
- public boolean updateIntentVerificationStatus(String packageName, int status, int userId) {
- return mDomainVerificationManager.setLegacyUserState(packageName, userId, status);
- }
-
- @Deprecated
- @Override
- public @NonNull ParceledListSlice<IntentFilterVerificationInfo> getIntentFilterVerifications(
- String packageName) {
- return ParceledListSlice.emptyList();
- }
-
- @NonNull
- @Override
- public ParceledListSlice<IntentFilter> getAllIntentFilters(@NonNull String packageName) {
- return mComputer.getAllIntentFilters(packageName);
- }
-
- @Override
- public void setInstallerPackageName(String targetPackage, String installerPackageName) {
- final int callingUid = Binder.getCallingUid();
- final int callingUserId = UserHandle.getUserId(callingUid);
- final FunctionalUtils.ThrowingCheckedFunction<Computer, Boolean, RuntimeException>
- implementation = computer -> {
- if (computer.getInstantAppPackageName(callingUid) != null) {
- return false;
- }
-
- PackageStateInternal targetPackageState =
- computer.getPackageStateInternal(targetPackage);
- if (targetPackageState == null
- || computer.shouldFilterApplication(targetPackageState, callingUid,
- callingUserId)) {
- throw new IllegalArgumentException("Unknown target package: " + targetPackage);
- }
-
- PackageStateInternal installerPackageState = null;
- if (installerPackageName != null) {
- installerPackageState = computer.getPackageStateInternal(installerPackageName);
- if (installerPackageState == null
- || shouldFilterApplication(
- installerPackageState, callingUid, callingUserId)) {
- throw new IllegalArgumentException("Unknown installer package: "
- + installerPackageName);
- }
- }
-
- Signature[] callerSignature;
- final int appId = UserHandle.getAppId(callingUid);
- Pair<PackageStateInternal, SharedUserApi> either =
- computer.getPackageOrSharedUser(appId);
- if (either != null) {
- if (either.first != null) {
- callerSignature = either.first.getSigningDetails().getSignatures();
- } else {
- callerSignature = either.second.getSigningDetails().getSignatures();
- }
- } else {
- throw new SecurityException("Unknown calling UID: " + callingUid);
- }
-
- // Verify: can't set installerPackageName to a package that is
- // not signed with the same cert as the caller.
- if (installerPackageState != null) {
- if (compareSignatures(callerSignature,
- installerPackageState.getSigningDetails().getSignatures())
- != PackageManager.SIGNATURE_MATCH) {
- throw new SecurityException(
- "Caller does not have same cert as new installer package "
- + installerPackageName);
- }
- }
-
- // Verify: if target already has an installer package, it must
- // be signed with the same cert as the caller.
- String targetInstallerPackageName =
- targetPackageState.getInstallSource().installerPackageName;
- PackageStateInternal targetInstallerPkgSetting = targetInstallerPackageName == null
- ? null : computer.getPackageStateInternal(targetInstallerPackageName);
-
- if (targetInstallerPkgSetting != null) {
- if (compareSignatures(callerSignature,
- targetInstallerPkgSetting.getSigningDetails().getSignatures())
- != PackageManager.SIGNATURE_MATCH) {
- throw new SecurityException(
- "Caller does not have same cert as old installer package "
- + targetInstallerPackageName);
- }
- } else if (mContext.checkCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES)
- != PERMISSION_GRANTED) {
- // This is probably an attempt to exploit vulnerability b/150857253 of taking
- // privileged installer permissions when the installer has been uninstalled or
- // was never set.
- EventLog.writeEvent(0x534e4554, "150857253", callingUid, "");
-
- final long binderToken = Binder.clearCallingIdentity();
- try {
- if (mInjector.getCompatibility().isChangeEnabledByUid(
- THROW_EXCEPTION_ON_REQUIRE_INSTALL_PACKAGES_TO_ADD_INSTALLER_PACKAGE,
- callingUid)) {
- throw new SecurityException("Neither user " + callingUid
- + " nor current process has "
- + Manifest.permission.INSTALL_PACKAGES);
- } else {
- // If change disabled, fail silently for backwards compatibility
- return false;
- }
- } finally {
- Binder.restoreCallingIdentity(binderToken);
- }
- }
-
- return true;
- };
- PackageStateMutator.InitialState initialState = recordInitialState();
- boolean allowed = implementation.apply(snapshotComputer());
- if (allowed) {
- // TODO: Need to lock around here to handle mSettings.addInstallerPackageNames,
- // should find an alternative which avoids any race conditions
- PackageStateInternal targetPackageState;
- synchronized (mLock) {
- PackageStateMutator.Result result = commitPackageStateMutation(initialState,
- targetPackage, state -> state.setInstaller(installerPackageName));
- if (result.isPackagesChanged() || result.isStateChanged()) {
- synchronized (mPackageStateWriteLock) {
- allowed = implementation.apply(snapshotComputer());
- if (allowed) {
- commitPackageStateMutation(null, targetPackage,
- state -> state.setInstaller(installerPackageName));
- } else {
- return;
- }
- }
- }
- targetPackageState = getPackageStateInternal(targetPackage);
- mSettings.addInstallerPackageNames(targetPackageState.getInstallSource());
- }
- mAppsFilter.addPackage(targetPackageState);
- scheduleWriteSettings();
- }
- }
-
- @Override
- public void setApplicationCategoryHint(String packageName, int categoryHint,
- String callerPackageName) {
- if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
- throw new SecurityException("Instant applications don't have access to this method");
- }
- mInjector.getSystemService(AppOpsManager.class).checkPackage(Binder.getCallingUid(),
- callerPackageName);
-
- final PackageStateMutator.InitialState initialState = recordInitialState();
-
- final FunctionalUtils.ThrowingFunction<Computer, PackageStateMutator.Result>
- implementation = computer -> {
- PackageStateInternal packageState = computer.getPackageStateFiltered(packageName,
- Binder.getCallingUid(), UserHandle.getCallingUserId());
- if (packageState == null) {
- throw new IllegalArgumentException("Unknown target package " + packageName);
- }
-
- if (!Objects.equals(callerPackageName,
- packageState.getInstallSource().installerPackageName)) {
- throw new IllegalArgumentException("Calling package " + callerPackageName
- + " is not installer for " + packageName);
- }
-
- if (packageState.getCategoryOverride() != categoryHint) {
- return commitPackageStateMutation(initialState,
- packageName, state -> state.setCategoryOverride(categoryHint));
- } else {
- return null;
- }
- };
-
- PackageStateMutator.Result result = implementation.apply(snapshotComputer());
- if (result != null && result.isStateChanged() && !result.isSpecificPackageNull()) {
- // TODO: Specific return value of what state changed?
- // The installer on record might have changed, retry with lock
- synchronized (mPackageStateWriteLock) {
- result = implementation.apply(snapshotComputer());
- }
- }
-
- if (result != null && result.isCommitted()) {
- scheduleWriteSettings();
- }
- }
-
/**
* Callback from PackageSettings whenever an app is first transitioned out of the
* 'stopped' state. Normally we just issue the broadcast, but we can't do that if
@@ -4756,7 +3141,7 @@ public class PackageManagerService extends IPackageManager.Stub
if (DEBUG_BACKUP) {
Slog.i(TAG, "Package " + packageName + " sending normal FIRST_LAUNCH");
}
- final boolean isInstantApp = isInstantAppInternal(
+ final boolean isInstantApp = snapshotComputer().isInstantAppInternal(
packageName, userId, Process.SYSTEM_UID);
final int[] userIds = isInstantApp ? EMPTY_INT_ARRAY : new int[] { userId };
final int[] instantUserIds = isInstantApp ? new int[] { userId } : EMPTY_INT_ARRAY;
@@ -4794,52 +3179,34 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- @Override
- public void deletePackageAsUser(String packageName, int versionCode,
- IPackageDeleteObserver observer, int userId, int flags) {
- deletePackageVersioned(new VersionedPackage(packageName, versionCode),
- new LegacyPackageDeleteObserver(observer).getBinder(), userId, flags);
- }
-
- @Override
public void deleteExistingPackageAsUser(VersionedPackage versionedPackage,
final IPackageDeleteObserver2 observer, final int userId) {
mDeletePackageHelper.deleteExistingPackageAsUser(
versionedPackage, observer, userId);
}
- @Override
public void deletePackageVersioned(VersionedPackage versionedPackage,
final IPackageDeleteObserver2 observer, final int userId, final int deleteFlags) {
mDeletePackageHelper.deletePackageVersionedInternal(
versionedPackage, observer, userId, deleteFlags, false);
}
- private String resolveExternalPackageName(AndroidPackage pkg) {
- return mComputer.resolveExternalPackageName(pkg);
- }
-
- String resolveInternalPackageName(String packageName, long versionCode) {
- return mComputer.resolveInternalPackageName(packageName, versionCode);
- }
-
- boolean isCallerVerifier(int callingUid) {
+ boolean isCallerVerifier(@NonNull Computer snapshot, int callingUid) {
final int callingUserId = UserHandle.getUserId(callingUid);
- return mRequiredVerifierPackage != null &&
- callingUid == getPackageUid(mRequiredVerifierPackage, 0, callingUserId);
+ return mRequiredVerifierPackage != null && callingUid == snapshot.getPackageUid(
+ mRequiredVerifierPackage, 0, callingUserId);
}
- @Override
- public boolean isPackageDeviceAdminOnAnyUser(String packageName) {
+ public boolean isPackageDeviceAdminOnAnyUser(@NonNull Computer snapshot, String packageName) {
final int callingUid = Binder.getCallingUid();
- if (checkUidPermission(android.Manifest.permission.MANAGE_USERS, callingUid)
+ if (snapshot.checkUidPermission(android.Manifest.permission.MANAGE_USERS, callingUid)
!= PERMISSION_GRANTED) {
EventLog.writeEvent(0x534e4554, "128599183", -1, "");
throw new SecurityException(android.Manifest.permission.MANAGE_USERS
+ " permission is required to call this API");
}
- if (getInstantAppPackageName(callingUid) != null
- && !isCallerSameApp(packageName, callingUid)) {
+ if (snapshot.getInstantAppPackageName(callingUid) != null
+ && !snapshot.isCallerSameApp(packageName, callingUid)) {
return false;
}
return isPackageDeviceAdmin(packageName, UserHandle.USER_ALL);
@@ -4888,147 +3255,15 @@ public class PackageManagerService extends IPackageManager.Stub
return mDevicePolicyManager;
}
- @Override
- public boolean setBlockUninstallForUser(String packageName, boolean blockUninstall,
+ private boolean clearApplicationUserDataLIF(@NonNull Computer snapshot, String packageName,
int userId) {
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.DELETE_PACKAGES, null);
- PackageStateInternal packageState = getPackageStateInternal(packageName);
- if (packageState != null && packageState.getPkg() != null) {
- AndroidPackage pkg = packageState.getPkg();
- // Cannot block uninstall SDK libs as they are controlled by SDK manager.
- if (pkg.getSdkLibName() != null) {
- Slog.w(TAG, "Cannot block uninstall of package: " + packageName
- + " providing SDK library: " + pkg.getSdkLibName());
- return false;
- }
- // Cannot block uninstall of static shared libs as they are
- // considered a part of the using app (emulating static linking).
- // Also static libs are installed always on internal storage.
- if (pkg.getStaticSharedLibName() != null) {
- Slog.w(TAG, "Cannot block uninstall of package: " + packageName
- + " providing static shared library: " + pkg.getStaticSharedLibName());
- return false;
- }
- }
- synchronized (mLock) {
- mSettings.setBlockUninstallLPw(userId, packageName, blockUninstall);
- }
-
- scheduleWritePackageRestrictions(userId);
- return true;
- }
-
- @Override
- public boolean getBlockUninstallForUser(@NonNull String packageName, @UserIdInt int userId) {
- return mComputer.getBlockUninstallForUser(packageName, userId);
- }
-
- @Override
- public boolean setRequiredForSystemUser(String packageName, boolean requiredForSystemUser) {
- PackageManagerServiceUtils.enforceSystemOrRoot(
- "setRequiredForSystemUser can only be run by the system or root");
-
- PackageStateMutator.Result result = commitPackageStateMutation(null, packageName,
- packageState -> packageState.setRequiredForSystemUser(requiredForSystemUser));
- if (!result.isCommitted()) {
- return false;
- }
-
- scheduleWriteSettings();
- return true;
- }
-
- @Override
- public void clearApplicationProfileData(String packageName) {
- PackageManagerServiceUtils.enforceSystemOrRoot(
- "Only the system can clear all profile data");
-
- final AndroidPackage pkg = getPackage(packageName);
- try (PackageFreezer ignored = freezePackage(packageName, "clearApplicationProfileData")) {
- synchronized (mInstallLock) {
- mAppDataHelper.clearAppProfilesLIF(pkg);
- }
- }
- }
-
- @Override
- public void clearApplicationUserData(final String packageName,
- final IPackageDataObserver observer, final int userId) {
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.CLEAR_APP_USER_DATA, null);
-
- final int callingUid = Binder.getCallingUid();
- enforceCrossUserPermission(callingUid, userId, true /* requireFullPermission */,
- false /* checkShell */, "clear application data");
-
- if (mComputer.getPackageStateFiltered(packageName, callingUid, userId) == null) {
- if (observer != null) {
- mHandler.post(() -> {
- try {
- observer.onRemoveCompleted(packageName, false);
- } catch (RemoteException e) {
- Log.i(TAG, "Observer no longer exists.");
- }
- });
- }
- return;
- }
- if (mProtectedPackages.isPackageDataProtected(userId, packageName)) {
- throw new SecurityException("Cannot clear data for a protected package: "
- + packageName);
- }
-
- // Queue up an async operation since the package deletion may take a little while.
- mHandler.post(new Runnable() {
- public void run() {
- mHandler.removeCallbacks(this);
- final boolean succeeded;
- try (PackageFreezer freezer = freezePackage(packageName,
- "clearApplicationUserData")) {
- synchronized (mInstallLock) {
- succeeded = clearApplicationUserDataLIF(packageName, userId);
- }
- mInstantAppRegistry.deleteInstantApplicationMetadata(packageName, userId);
- synchronized (mLock) {
- if (succeeded) {
- resetComponentEnabledSettingsIfNeededLPw(packageName, userId);
- }
- }
- }
- if (succeeded) {
- // invoke DeviceStorageMonitor's update method to clear any notifications
- DeviceStorageMonitorInternal dsm = LocalServices
- .getService(DeviceStorageMonitorInternal.class);
- if (dsm != null) {
- dsm.checkMemory();
- }
- if (checkPermission(Manifest.permission.SUSPEND_APPS, packageName, userId)
- == PERMISSION_GRANTED) {
- unsuspendForSuspendingPackage(snapshotComputer(), packageName, userId);
- removeAllDistractingPackageRestrictions(userId);
- flushPackageRestrictionsAsUserInternalLocked(userId);
- }
- }
- if (observer != null) {
- try {
- observer.onRemoveCompleted(packageName, succeeded);
- } catch (RemoteException e) {
- Log.i(TAG, "Observer no longer exists.");
- }
- } //end if observer
- } //end run
- });
- }
-
- private boolean clearApplicationUserDataLIF(String packageName, int userId) {
if (packageName == null) {
Slog.w(TAG, "Attempt to delete null packageName.");
return false;
}
// Try finding details about the requested package
- AndroidPackage pkg = getPackage(packageName);
+ AndroidPackage pkg = snapshot.getPackage(packageName);
if (pkg == null) {
Slog.w(TAG, "Package named '" + packageName + "' doesn't exist.");
return false;
@@ -5051,8 +3286,8 @@ public class PackageManagerService extends IPackageManager.Stub
} else {
flags = 0;
}
- mAppDataHelper.prepareAppDataContentsLIF(pkg, getPackageStateInternal(packageName), userId,
- flags);
+ mAppDataHelper.prepareAppDataContentsLIF(pkg, snapshot.getPackageStateInternal(packageName),
+ userId, flags);
return true;
}
@@ -5103,106 +3338,10 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- @Override
- public void deleteApplicationCacheFiles(final String packageName,
- final IPackageDataObserver observer) {
- final int userId = UserHandle.getCallingUserId();
- deleteApplicationCacheFilesAsUser(packageName, userId, observer);
- }
-
- @Override
- public void deleteApplicationCacheFilesAsUser(final String packageName, final int userId,
- final IPackageDataObserver observer) {
- final int callingUid = Binder.getCallingUid();
- if (mContext.checkCallingOrSelfPermission(
- android.Manifest.permission.INTERNAL_DELETE_CACHE_FILES)
- != PackageManager.PERMISSION_GRANTED) {
- // If the caller has the old delete cache permission, silently ignore. Else throw.
- if (mContext.checkCallingOrSelfPermission(
- android.Manifest.permission.DELETE_CACHE_FILES)
- == PackageManager.PERMISSION_GRANTED) {
- Slog.w(TAG, "Calling uid " + callingUid + " does not have " +
- android.Manifest.permission.INTERNAL_DELETE_CACHE_FILES +
- ", silently ignoring");
- return;
- }
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.INTERNAL_DELETE_CACHE_FILES, null);
- }
- enforceCrossUserPermission(callingUid, userId, /* requireFullPermission= */ true,
- /* checkShell= */ false, "delete application cache files");
- final int hasAccessInstantApps = mContext.checkCallingOrSelfPermission(
- android.Manifest.permission.ACCESS_INSTANT_APPS);
-
- final AndroidPackage pkg = getPackage(packageName);
-
- // Queue up an async operation since the package deletion may take a little while.
- mHandler.post(() -> {
- final PackageStateInternal ps =
- pkg == null ? null : getPackageStateInternal(pkg.getPackageName());
- boolean doClearData = true;
- if (ps != null) {
- final boolean targetIsInstantApp =
- ps.getUserStateOrDefault(UserHandle.getUserId(callingUid)).isInstantApp();
- doClearData = !targetIsInstantApp
- || hasAccessInstantApps == PackageManager.PERMISSION_GRANTED;
- }
- if (doClearData) {
- synchronized (mInstallLock) {
- final int flags = FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL;
- // We're only clearing cache files, so we don't care if the
- // app is unfrozen and still able to run
- mAppDataHelper.clearAppDataLIF(pkg, userId,
- flags | Installer.FLAG_CLEAR_CACHE_ONLY);
- mAppDataHelper.clearAppDataLIF(pkg, userId,
- flags | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
- }
- }
- if (observer != null) {
- try {
- observer.onRemoveCompleted(packageName, true);
- } catch (RemoteException e) {
- Log.i(TAG, "Observer no longer exists.");
- }
- }
- });
- }
-
- @Override
- public void getPackageSizeInfo(final String packageName, int userId,
- final IPackageStatsObserver observer) {
- throw new UnsupportedOperationException(
- "Shame on you for calling the hidden API getPackageSizeInfo(). Shame!");
- }
-
- int getUidTargetSdkVersion(int uid) {
- return mComputer.getUidTargetSdkVersion(uid);
- }
-
- @Override
- public void addPreferredActivity(IntentFilter filter, int match,
- ComponentName[] set, ComponentName activity, int userId, boolean removeExisting) {
- mPreferredActivityHelper.addPreferredActivity(
- new WatchedIntentFilter(filter), match, set, activity, true, userId,
- "Adding preferred", removeExisting);
- }
-
void postPreferredActivityChangedBroadcast(int userId) {
mHandler.post(() -> mBroadcastHelper.sendPreferredActivityChangedBroadcast(userId));
}
- @Override
- public void replacePreferredActivity(IntentFilter filter, int match,
- ComponentName[] set, ComponentName activity, int userId) {
- mPreferredActivityHelper.replacePreferredActivity(new WatchedIntentFilter(filter), match,
- set, activity, userId);
- }
-
- @Override
- public void clearPackagePreferredActivities(String packageName) {
- mPreferredActivityHelper.clearPackagePreferredActivities(packageName);
- }
-
/** This method takes a specific user id as well as UserHandle.USER_ALL. */
@GuardedBy("mLock")
@@ -5219,121 +3358,19 @@ public class PackageManagerService extends IPackageManager.Stub
// Persistent preferred activity might have came into effect due to this
// install.
- mPreferredActivityHelper.updateDefaultHomeNotLocked(userId);
- }
-
- @Override
- public void resetApplicationPreferences(int userId) {
- mPreferredActivityHelper.resetApplicationPreferences(userId);
- }
-
- @Override
- public int getPreferredActivities(List<IntentFilter> outFilters,
- List<ComponentName> outActivities, String packageName) {
- return mPreferredActivityHelper.getPreferredActivities(outFilters, outActivities,
- packageName, mComputer);
- }
-
- @Override
- public void addPersistentPreferredActivity(IntentFilter filter, ComponentName activity,
- int userId) {
- mPreferredActivityHelper.addPersistentPreferredActivity(new WatchedIntentFilter(filter),
- activity, userId);
- }
-
- @Override
- public void clearPackagePersistentPreferredActivities(String packageName, int userId) {
- mPreferredActivityHelper.clearPackagePersistentPreferredActivities(packageName, userId);
- }
-
- /**
- * Non-Binder method, support for the backup/restore mechanism: write the
- * full set of preferred activities in its canonical XML format. Returns the
- * XML output as a byte array, or null if there is none.
- */
- @Override
- public byte[] getPreferredActivityBackup(int userId) {
- return mPreferredActivityHelper.getPreferredActivityBackup(userId);
- }
-
- @Override
- public void restorePreferredActivities(byte[] backup, int userId) {
- mPreferredActivityHelper.restorePreferredActivities(backup, userId);
- }
-
- /**
- * Non-Binder method, support for the backup/restore mechanism: write the
- * default browser (etc) settings in its canonical XML format. Returns the default
- * browser XML representation as a byte array, or null if there is none.
- */
- @Override
- public byte[] getDefaultAppsBackup(int userId) {
- return mPreferredActivityHelper.getDefaultAppsBackup(userId);
- }
-
- @Override
- public void restoreDefaultApps(byte[] backup, int userId) {
- mPreferredActivityHelper.restoreDefaultApps(backup, userId);
- }
-
- @Override
- public byte[] getDomainVerificationBackup(int userId) {
- if (Binder.getCallingUid() != Process.SYSTEM_UID) {
- throw new SecurityException("Only the system may call getDomainVerificationBackup()");
- }
-
- try {
- try (ByteArrayOutputStream output = new ByteArrayOutputStream()) {
- TypedXmlSerializer serializer = Xml.resolveSerializer(output);
- mDomainVerificationManager.writeSettings(snapshotComputer(), serializer, true,
- userId);
- return output.toByteArray();
- }
- } catch (Exception e) {
- if (DEBUG_BACKUP) {
- Slog.e(TAG, "Unable to write domain verification for backup", e);
- }
- return null;
- }
- }
-
- @Override
- public void restoreDomainVerification(byte[] backup, int userId) {
- if (Binder.getCallingUid() != Process.SYSTEM_UID) {
- throw new SecurityException("Only the system may call restorePreferredActivities()");
- }
-
- try {
- ByteArrayInputStream input = new ByteArrayInputStream(backup);
- TypedXmlPullParser parser = Xml.resolvePullParser(input);
-
- // User ID input isn't necessary here as it assumes the user integers match and that
- // the only states inside the backup XML are for the target user.
- mDomainVerificationManager.restoreSettings(snapshotComputer(), parser);
- input.close();
- } catch (Exception e) {
- if (DEBUG_BACKUP) {
- Slog.e(TAG, "Exception restoring domain verification: " + e.getMessage());
- }
- }
- }
-
- @Override
- public void addCrossProfileIntentFilter(IntentFilter intentFilter, String ownerPackage,
- int sourceUserId, int targetUserId, int flags) {
- addCrossProfileIntentFilter(new WatchedIntentFilter(intentFilter), ownerPackage,
- sourceUserId, targetUserId, flags);
+ mPreferredActivityHelper.updateDefaultHomeNotLocked(snapshotComputer(), userId);
}
/**
* Variant that takes a {@link WatchedIntentFilter}
*/
- public void addCrossProfileIntentFilter(WatchedIntentFilter intentFilter, String ownerPackage,
- int sourceUserId, int targetUserId, int flags) {
+ public void addCrossProfileIntentFilter(@NonNull Computer snapshot,
+ WatchedIntentFilter intentFilter, String ownerPackage, int sourceUserId,
+ int targetUserId, int flags) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
int callingUid = Binder.getCallingUid();
- enforceOwnerRights(ownerPackage, callingUid);
+ enforceOwnerRights(snapshot, ownerPackage, callingUid);
PackageManagerServiceUtils.enforceShellRestriction(mInjector.getUserManagerInternal(),
UserManager.DISALLOW_DEBUGGING_FEATURES, callingUid, sourceUserId);
if (intentFilter.countActions() == 0) {
@@ -5360,55 +3397,25 @@ public class PackageManagerService extends IPackageManager.Stub
scheduleWritePackageRestrictions(sourceUserId);
}
- @Override
- public void clearCrossProfileIntentFilters(int sourceUserId, String ownerPackage) {
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
- final int callingUid = Binder.getCallingUid();
- enforceOwnerRights(ownerPackage, callingUid);
- PackageManagerServiceUtils.enforceShellRestriction(mInjector.getUserManagerInternal(),
- UserManager.DISALLOW_DEBUGGING_FEATURES, callingUid, sourceUserId);
- synchronized (mLock) {
- CrossProfileIntentResolver resolver =
- mSettings.editCrossProfileIntentResolverLPw(sourceUserId);
- ArraySet<CrossProfileIntentFilter> set =
- new ArraySet<>(resolver.filterSet());
- for (CrossProfileIntentFilter filter : set) {
- if (filter.getOwnerPackage().equals(ownerPackage)) {
- resolver.removeFilter(filter);
- }
- }
- }
- scheduleWritePackageRestrictions(sourceUserId);
- }
-
// Enforcing that callingUid is owning pkg on userId
- private void enforceOwnerRights(String pkg, int callingUid) {
+ private void enforceOwnerRights(@NonNull Computer snapshot, String pkg, int callingUid) {
// The system owns everything.
if (UserHandle.getAppId(callingUid) == Process.SYSTEM_UID) {
return;
}
- final String[] callerPackageNames = getPackagesForUid(callingUid);
+ final String[] callerPackageNames = snapshot.getPackagesForUid(callingUid);
if (!ArrayUtils.contains(callerPackageNames, pkg)) {
throw new SecurityException("Calling uid " + callingUid
+ " does not own package " + pkg);
}
final int callingUserId = UserHandle.getUserId(callingUid);
- PackageInfo pi = getPackageInfo(pkg, 0, callingUserId);
+ PackageInfo pi = snapshot.getPackageInfo(pkg, 0, callingUserId);
if (pi == null) {
throw new IllegalArgumentException("Unknown package " + pkg + " on user "
+ callingUserId);
}
}
- @Override
- public ComponentName getHomeActivities(List<ResolveInfo> allHomeCandidates) {
- if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
- return null;
- }
- return getHomeActivitiesAsUser(allHomeCandidates, UserHandle.getCallingUserId());
- }
-
public void sendSessionCommitBroadcast(PackageInstaller.SessionInfo sessionInfo, int userId) {
UserManagerService ums = UserManagerService.getInstance();
if (ums == null || sessionInfo.isStaged()) {
@@ -5416,34 +3423,13 @@ public class PackageManagerService extends IPackageManager.Stub
}
final UserInfo parent = ums.getProfileParent(userId);
final int launcherUid = (parent != null) ? parent.id : userId;
- final ComponentName launcherComponent = getDefaultHomeActivity(launcherUid);
+ // TODO: Should this snapshot be moved further up?
+ final ComponentName launcherComponent = snapshotComputer()
+ .getDefaultHomeActivity(launcherUid);
mBroadcastHelper.sendSessionCommitBroadcast(sessionInfo, userId, launcherUid,
launcherComponent, mAppPredictionServicePackage);
}
- /**
- * Report the 'Home' activity which is currently set as "always use this one". If non is set
- * then reports the most likely home activity or null if there are more than one.
- */
- private ComponentName getDefaultHomeActivity(int userId) {
- return mComputer.getDefaultHomeActivity(userId);
- }
-
- Intent getHomeIntent() {
- return mComputer.getHomeIntent();
- }
-
- ComponentName getHomeActivitiesAsUser(List<ResolveInfo> allHomeCandidates,
- int userId) {
- return mComputer.getHomeActivitiesAsUser(allHomeCandidates,
- userId);
- }
-
- @Override
- public void setHomeActivity(ComponentName comp, int userId) {
- mPreferredActivityHelper.setHomeActivity(comp, userId);
- }
-
private @Nullable String getSetupWizardPackageNameImpl(@NonNull Computer computer) {
final Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_SETUP_WIZARD);
@@ -5477,10 +3463,11 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- private @NonNull String getRequiredSdkSandboxPackageName() {
+ @NonNull
+ private static String getRequiredSdkSandboxPackageName(@NonNull Computer computer) {
final Intent intent = new Intent(SdkSandboxManagerLocal.SERVICE_INTERFACE);
- final List<ResolveInfo> matches = queryIntentServicesInternal(
+ final List<ResolveInfo> matches = computer.queryIntentServicesInternal(
intent,
/* resolvedType= */ null,
MATCH_SYSTEM_ONLY | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE,
@@ -5495,89 +3482,6 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- @Override
- public String getDefaultTextClassifierPackageName() {
- return ensureSystemPackageName(
- mContext.getString(R.string.config_servicesExtensionPackage));
- }
-
- @Override
- public String getSystemTextClassifierPackageName() {
- return ensureSystemPackageName(
- mContext.getString(R.string.config_defaultTextClassifierPackage));
- }
-
- @Override
- public @Nullable String getAttentionServicePackageName() {
- return ensureSystemPackageName(
- getPackageFromComponentString(R.string.config_defaultAttentionService));
- }
-
- @Override
- public @Nullable String getRotationResolverPackageName() {
- return ensureSystemPackageName(
- getPackageFromComponentString(R.string.config_defaultRotationResolverService));
- }
-
- @Nullable
- private String getDeviceConfiguratorPackageName() {
- return ensureSystemPackageName(mContext.getString(
- R.string.config_deviceConfiguratorPackageName));
- }
-
- @Override
- public String getWellbeingPackageName() {
- final long identity = Binder.clearCallingIdentity();
- try {
- return CollectionUtils.firstOrNull(
- mContext.getSystemService(RoleManager.class).getRoleHolders(
- RoleManager.ROLE_SYSTEM_WELLBEING));
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- }
-
- @Override
- public String getAppPredictionServicePackageName() {
- return ensureSystemPackageName(
- getPackageFromComponentString(R.string.config_defaultAppPredictionService));
- }
-
- @Override
- public String getSystemCaptionsServicePackageName() {
- return ensureSystemPackageName(
- getPackageFromComponentString(R.string.config_defaultSystemCaptionsService));
- }
-
- @Override
- public String getSetupWizardPackageName() {
- if (Binder.getCallingUid() != Process.SYSTEM_UID) {
- throw new SecurityException("Non-system caller");
- }
- return mPmInternal.getSetupWizardPackageName();
- }
-
- public @Nullable String getAmbientContextDetectionPackageName() {
- return ensureSystemPackageName(getPackageFromComponentString(
- R.string.config_defaultAmbientContextDetectionService));
- }
-
- public String getIncidentReportApproverPackageName() {
- return ensureSystemPackageName(mContext.getString(
- R.string.config_incidentReportApproverPackage));
- }
-
- @Override
- public String getContentCaptureServicePackageName() {
- return ensureSystemPackageName(
- getPackageFromComponentString(R.string.config_defaultContentCaptureService));
- }
-
- public String getOverlayConfigSignaturePackageName() {
- return ensureSystemPackageName(mInjector.getSystemConfig()
- .getOverlayConfigSignaturePackage());
- }
-
@Nullable
private String getRetailDemoPackageName() {
final String predefinedPkgName = mContext.getString(R.string.config_retailDemoPackage);
@@ -5614,14 +3518,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
@Nullable
- private String getRecentsPackageName() {
- return ensureSystemPackageName(
- getPackageFromComponentString(R.string.config_recentsComponentName));
-
- }
-
- @Nullable
- private String getPackageFromComponentString(@StringRes int stringResId) {
+ String getPackageFromComponentString(@StringRes int stringResId) {
final String componentString = mContext.getString(stringResId);
if (TextUtils.isEmpty(componentString)) {
return null;
@@ -5634,14 +3531,17 @@ public class PackageManagerService extends IPackageManager.Stub
}
@Nullable
- private String ensureSystemPackageName(@Nullable String packageName) {
+ String ensureSystemPackageName(@NonNull Computer snapshot,
+ @Nullable String packageName) {
if (packageName == null) {
return null;
}
final long token = Binder.clearCallingIdentity();
try {
- if (getPackageInfo(packageName, MATCH_FACTORY_ONLY, UserHandle.USER_SYSTEM) == null) {
- PackageInfo packageInfo = getPackageInfo(packageName, 0, UserHandle.USER_SYSTEM);
+ if (snapshot.getPackageInfo(packageName, MATCH_FACTORY_ONLY,
+ UserHandle.USER_SYSTEM) == null) {
+ PackageInfo packageInfo =
+ snapshot.getPackageInfo(packageName, 0, UserHandle.USER_SYSTEM);
if (packageInfo != null) {
EventLog.writeEvent(0x534e4554, "145981139", packageInfo.applicationInfo.uid,
"");
@@ -5654,39 +3554,6 @@ public class PackageManagerService extends IPackageManager.Stub
return packageName;
}
- @Override
- public void setApplicationEnabledSetting(String appPackageName,
- int newState, int flags, int userId, String callingPackage) {
- if (!mUserManager.exists(userId)) return;
- if (callingPackage == null) {
- callingPackage = Integer.toString(Binder.getCallingUid());
- }
-
- setEnabledSettings(List.of(new ComponentEnabledSetting(appPackageName, newState, flags)),
- userId, callingPackage);
- }
-
- @Override
- public void setUpdateAvailable(String packageName, boolean updateAvailable) {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES, null);
- commitPackageStateMutation(null, packageName, state ->
- state.setUpdateAvailable(updateAvailable));
- }
-
- @Override
- public void overrideLabelAndIcon(@NonNull ComponentName componentName,
- @NonNull String nonLocalizedLabel, int icon, int userId) {
- if (TextUtils.isEmpty(nonLocalizedLabel)) {
- throw new IllegalArgumentException("Override label should be a valid String");
- }
- updateComponentLabelIcon(componentName, nonLocalizedLabel, icon, userId);
- }
-
- @Override
- public void restoreLabelAndIcon(@NonNull ComponentName componentName, int userId) {
- updateComponentLabelIcon(componentName, null, null, userId);
- }
-
@VisibleForTesting(visibility = Visibility.PRIVATE)
public void updateComponentLabelIcon(/*@NonNull*/ ComponentName componentName,
@Nullable String nonLocalizedLabel, @Nullable Integer icon, int userId) {
@@ -5753,30 +3620,13 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- @Override
- public void setComponentEnabledSetting(ComponentName componentName,
- int newState, int flags, int userId) {
- if (!mUserManager.exists(userId)) return;
-
- setEnabledSettings(List.of(new ComponentEnabledSetting(componentName, newState, flags)),
- userId, null /* callingPackage */);
- }
-
- @Override
- public void setComponentEnabledSettings(List<ComponentEnabledSetting> settings, int userId) {
- if (!mUserManager.exists(userId)) return;
- if (settings == null || settings.isEmpty()) {
- throw new IllegalArgumentException("The list of enabled settings is empty");
- }
-
- setEnabledSettings(settings, userId, null /* callingPackage */);
- }
-
private void setEnabledSettings(List<ComponentEnabledSetting> settings, int userId,
String callingPackage) {
final int callingUid = Binder.getCallingUid();
- enforceCrossUserPermission(callingUid, userId, false /* requireFullPermission */,
- true /* checkShell */, "set enabled");
+ // TODO: This method is not properly snapshotified beyond this call
+ final Computer preLockSnapshot = snapshotComputer();
+ preLockSnapshot.enforceCrossUserPermission(callingUid, userId,
+ false /* requireFullPermission */, true /* checkShell */, "set enabled");
final int targetSize = settings.size();
for (int i = 0; i < targetSize; i++) {
@@ -5832,6 +3682,7 @@ public class PackageManagerService extends IPackageManager.Stub
final Map<String, PackageSetting> pkgSettings = new ArrayMap<>(targetSize);
// reader
synchronized (mLock) {
+ final Computer snapshot = snapshotComputer();
// Checks for target packages
for (int i = 0; i < targetSize; i++) {
final ComponentEnabledSetting setting = settings.get(i);
@@ -5841,13 +3692,13 @@ public class PackageManagerService extends IPackageManager.Stub
continue;
}
final boolean isCallerTargetApp = ArrayUtils.contains(
- getPackagesForUid(callingUid), packageName);
+ snapshot.getPackagesForUid(callingUid), packageName);
final PackageSetting pkgSetting = mSettings.getPackageLPr(packageName);
// Limit who can change which apps
if (!isCallerTargetApp) {
// Don't allow apps that don't have permission to modify other apps
if (!allowedByPermission
- || shouldFilterApplication(pkgSetting, callingUid, userId)) {
+ || snapshot.shouldFilterApplication(pkgSetting, callingUid, userId)) {
throw new SecurityException("Attempt to change component state; "
+ "pid=" + Binder.getCallingPid()
+ ", uid=" + callingUid
@@ -6020,12 +3871,13 @@ public class PackageManagerService extends IPackageManager.Stub
final long callingId = Binder.clearCallingIdentity();
try {
+ final Computer newSnapshot = snapshotComputer();
for (int i = 0; i < sendNowBroadcasts.size(); i++) {
final String packageName = sendNowBroadcasts.keyAt(i);
final ArrayList<String> components = sendNowBroadcasts.valueAt(i);
final int packageUid = UserHandle.getUid(
userId, pkgSettings.get(packageName).getAppId());
- sendPackageChangedBroadcast(packageName, false /* dontKillApp */,
+ sendPackageChangedBroadcast(newSnapshot, packageName, false /* dontKillApp */,
components, packageUid, null /* reason */);
}
} finally {
@@ -6055,7 +3907,7 @@ public class PackageManagerService extends IPackageManager.Stub
// if it ever does, we don't want to end up with some of the user's apps
// permanently suspended.
unsuspendForSuspendingPackage(computer, packageName, userId);
- removeAllDistractingPackageRestrictions(userId);
+ removeAllDistractingPackageRestrictions(computer, userId);
}
success = true;
} else {
@@ -6093,22 +3945,6 @@ public class PackageManagerService extends IPackageManager.Stub
return true;
}
- @WorkerThread
- @Override
- public void flushPackageRestrictionsAsUser(int userId) {
- if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
- return;
- }
- if (!mUserManager.exists(userId)) {
- return;
- }
- enforceCrossUserPermission(Binder.getCallingUid(), userId, false /* requireFullPermission*/,
- false /* checkShell */, "flushPackageRestrictions");
- synchronized (mLock) {
- flushPackageRestrictionsAsUserInternalLocked(userId);
- }
- }
-
@GuardedBy("mLock")
private void flushPackageRestrictionsAsUserInternalLocked(int userId) {
// NOTE: this invokes synchronous disk access, so callers using this
@@ -6122,119 +3958,31 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- void sendPackageChangedBroadcast(String packageName,
+ void sendPackageChangedBroadcast(@NonNull Computer snapshot, String packageName,
boolean dontKillApp, ArrayList<String> componentNames, int packageUid, String reason) {
final int userId = UserHandle.getUserId(packageUid);
- final boolean isInstantApp = isInstantAppInternal(packageName, userId, Process.SYSTEM_UID);
+ final boolean isInstantApp =
+ snapshot.isInstantAppInternal(packageName, userId, Process.SYSTEM_UID);
final int[] userIds = isInstantApp ? EMPTY_INT_ARRAY : new int[] { userId };
final int[] instantUserIds = isInstantApp ? new int[] { userId } : EMPTY_INT_ARRAY;
- final SparseArray<int[]> broadcastAllowList = getBroadcastAllowList(
+ final SparseArray<int[]> broadcastAllowList = snapshot.getBroadcastAllowList(
packageName, userIds, isInstantApp);
mHandler.post(() -> mBroadcastHelper.sendPackageChangedBroadcast(
packageName, dontKillApp, componentNames, packageUid, reason, userIds,
instantUserIds, broadcastAllowList));
}
- @Nullable
- private SparseArray<int[]> getBroadcastAllowList(@NonNull String packageName,
- @UserIdInt int[] userIds, boolean isInstantApp) {
- return mComputer.getBroadcastAllowList(packageName, userIds, isInstantApp);
- }
-
- @Override
- public void setPackageStoppedState(String packageName, boolean stopped, int userId) {
- if (!mUserManager.exists(userId)) return;
- final int callingUid = Binder.getCallingUid();
- final Computer computer = snapshotComputer();
- if (computer.getInstantAppPackageName(callingUid) == null) {
- final int permission = mContext.checkCallingOrSelfPermission(
- android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE);
- final boolean allowedByPermission = (permission == PackageManager.PERMISSION_GRANTED);
- if (!allowedByPermission
- && !ArrayUtils.contains(computer.getPackagesForUid(callingUid), packageName)) {
- throw new SecurityException(
- "Permission Denial: attempt to change stopped state from pid="
- + Binder.getCallingPid()
- + ", uid=" + callingUid + ", package=" + packageName);
- }
- computer.enforceCrossUserPermission(callingUid, userId,
- true /* requireFullPermission */, true /* checkShell */, "stop package");
-
- final PackageStateInternal packageState = computer.getPackageStateInternal(packageName);
- final PackageUserState packageUserState = packageState == null
- ? null : packageState.getUserStateOrDefault(userId);
- if (packageState != null
- && !computer.shouldFilterApplication(packageState, callingUid, userId)
- && packageUserState.isStopped() != stopped) {
- boolean wasNotLaunched = packageUserState.isNotLaunched();
- commitPackageStateMutation(null, packageName, state -> {
- PackageUserStateWrite userState = state.userState(userId);
- userState.setStopped(stopped);
- if (wasNotLaunched) {
- userState.setNotLaunched(false);
- }
- });
-
- if (wasNotLaunched) {
- final String installerPackageName =
- packageState.getInstallSource().installerPackageName;
- if (installerPackageName != null) {
- notifyFirstLaunch(packageName, installerPackageName, userId);
- }
- }
-
- scheduleWritePackageRestrictions(userId);
- }
- }
-
- // If this would cause the app to leave force-stop, then also make sure to unhibernate the
- // app if needed.
- if (!stopped) {
- mHandler.post(() -> {
- AppHibernationManagerInternal ah =
- mInjector.getLocalService(AppHibernationManagerInternal.class);
- if (ah != null && ah.isHibernatingForUser(packageName, userId)) {
- ah.setHibernatingForUser(packageName, userId, false);
- ah.setHibernatingGlobally(packageName, false);
- }
- });
- }
- }
-
- @Nullable
- @Override
- public String getInstallerPackageName(@NonNull String packageName) {
- return mComputer.getInstallerPackageName(packageName);
- }
-
- @Override
- @Nullable
- public InstallSourceInfo getInstallSourceInfo(@NonNull String packageName) {
- return mComputer.getInstallSourceInfo(packageName);
- }
-
- @PackageManager.EnabledState
- @Override
- public int getApplicationEnabledSetting(@NonNull String packageName, @UserIdInt int userId) {
- return mComputer.getApplicationEnabledSetting(packageName, userId);
- }
-
- @Override
- public int getComponentEnabledSetting(@NonNull ComponentName component, int userId) {
- return mComputer.getComponentEnabledSetting(component, Binder.getCallingUid(), userId);
- }
-
- @Override
- public void enterSafeMode() {
- PackageManagerServiceUtils.enforceSystemOrRoot(
- "Only the system can request entering safe mode");
-
- if (!mSystemReady) {
- mSafeMode = true;
+ /**
+ * Used by SystemServer
+ */
+ public void waitForAppDataPrepared() {
+ if (mPrepareAppDataFuture == null) {
+ return;
}
+ ConcurrentUtils.waitForFutureNoInterrupt(mPrepareAppDataFuture, "wait for prepareAppData");
+ mPrepareAppDataFuture = null;
}
- @Override
public void systemReady() {
PackageManagerServiceUtils.enforceSystemOrRoot(
"Only the system can claim the system is ready");
@@ -6265,7 +4013,7 @@ public class PackageManagerService extends IPackageManager.Stub
.getUriFor(Global.ENABLE_EPHEMERAL_FEATURE),
false, co, UserHandle.USER_ALL);
mContext.getContentResolver().registerContentObserver(android.provider.Settings.Secure
- .getUriFor(Secure.INSTANT_APPS_ENABLED), false, co, UserHandle.USER_ALL);
+ .getUriFor(Secure.INSTANT_APPS_ENABLED), false, co, UserHandle.USER_ALL);
co.onChange(true);
mAppsFilter.onSystemReady();
@@ -6307,7 +4055,7 @@ public class PackageManagerService extends IPackageManager.Stub
// Now that we're mostly running, clean up stale users and apps
mUserManager.reconcileUsers(StorageManager.UUID_PRIVATE_INTERNAL);
- storageEventHelper.reconcileApps(StorageManager.UUID_PRIVATE_INTERNAL);
+ storageEventHelper.reconcileApps(snapshotComputer(), StorageManager.UUID_PRIVATE_INTERNAL);
mPermissionManager.onSystemReady();
@@ -6319,7 +4067,7 @@ public class PackageManagerService extends IPackageManager.Stub
final int livingUserCount = livingUsers.size();
for (int i = 0; i < livingUserCount; i++) {
final int userId = livingUsers.get(i).id;
- if (mPmInternal.isPermissionUpgradeNeeded(userId)) {
+ if (mSettings.isPermissionUpgradeNeeded(userId)) {
grantPermissionsUserIds = ArrayUtils.appendInt(
grantPermissionsUserIds, userId);
}
@@ -6361,11 +4109,12 @@ public class PackageManagerService extends IPackageManager.Stub
if (packageName == null) {
return;
}
- AndroidPackage pkg = mPackages.get(packageName);
+ final Computer snapshot = snapshotComputer();
+ AndroidPackage pkg = snapshot.getPackage(packageName);
if (pkg == null) {
return;
}
- sendPackageChangedBroadcast(pkg.getPackageName(),
+ sendPackageChangedBroadcast(snapshot, pkg.getPackageName(),
true /* dontKillApp */,
new ArrayList<>(Collections.singletonList(pkg.getPackageName())),
pkg.getUid(),
@@ -6397,44 +4146,11 @@ public class PackageManagerService extends IPackageManager.Stub
// Prune unused static shared libraries which have been cached a period of time
schedulePruneUnusedStaticSharedLibraries(false /* delay */);
- }
- /**
- * Used by SystemServer
- */
- public void waitForAppDataPrepared() {
- if (mPrepareAppDataFuture == null) {
- return;
+ // TODO(b/222706900): Remove this intent interceptor before T launch
+ if (mIntentResolverInterceptor != null) {
+ mIntentResolverInterceptor.registerListeners();
}
- ConcurrentUtils.waitForFutureNoInterrupt(mPrepareAppDataFuture, "wait for prepareAppData");
- mPrepareAppDataFuture = null;
- }
-
- @Override
- public boolean isSafeMode() {
- // allow instant applications
- return mSafeMode;
- }
-
- @Override
- public boolean hasSystemUidErrors() {
- // allow instant applications
- return false;
- }
-
- @Override
- public void onShellCommand(FileDescriptor in, FileDescriptor out,
- FileDescriptor err, String[] args, ShellCallback callback,
- ResultReceiver resultReceiver) {
- (new PackageManagerShellCommand(this, mContext,mDomainVerificationManager.getShell()))
- .exec(this, in, out, err, args, callback, resultReceiver);
- }
-
- @SuppressWarnings("resource")
- @Override
- protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw)) return;
- new DumpHelper(this).doDump(fd, pw, args);
}
void dumpSnapshotStats(PrintWriter pw, boolean isBrief) {
@@ -6451,14 +4167,6 @@ public class PackageManagerService extends IPackageManager.Stub
mSnapshotStatistics.dump(pw, " ", now, hits, -1, isBrief);
}
- /**
- * Dump package manager states to the file according to a given dumping type of
- * {@link DumpState}.
- */
- void dumpComputer(int type, FileDescriptor fd, PrintWriter pw, DumpState dumpState) {
- mComputer.dump(type, fd, pw, dumpState);
- }
-
//TODO: b/111402650
private void disableSkuSpecificApps() {
String[] apkList = mContext.getResources().getStringArray(
@@ -6472,10 +4180,11 @@ public class PackageManagerService extends IPackageManager.Stub
if (!TextUtils.isEmpty(sku) && ArrayUtils.contains(skuArray, sku)) {
return;
}
+ final Computer snapshot = snapshotComputer();
for (String packageName : apkList) {
- setSystemAppHiddenUntilInstalled(packageName, true);
+ setSystemAppHiddenUntilInstalled(snapshot, packageName, true);
for (UserInfo user : mInjector.getUserManagerInternal().getUsers(false)) {
- setSystemAppInstallState(packageName, false, user.id);
+ setSystemAppInstallState(snapshot, packageName, false, user.id);
}
}
}
@@ -6513,98 +4222,6 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- @Override
- public int movePackage(final String packageName, final String volumeUuid) {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MOVE_PACKAGE, null);
-
- final int callingUid = Binder.getCallingUid();
- final UserHandle user = new UserHandle(UserHandle.getUserId(callingUid));
- final int moveId = mNextMoveId.getAndIncrement();
- mHandler.post(() -> {
- try {
- MovePackageHelper movePackageHelper = new MovePackageHelper(this);
- movePackageHelper.movePackageInternal(
- packageName, volumeUuid, moveId, callingUid, user);
- } catch (PackageManagerException e) {
- Slog.w(TAG, "Failed to move " + packageName, e);
- mMoveCallbacks.notifyStatusChanged(moveId, e.error);
- }
- });
- return moveId;
- }
-
- @Override
- public int movePrimaryStorage(String volumeUuid) throws RemoteException {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MOVE_PACKAGE, null);
-
- final int realMoveId = mNextMoveId.getAndIncrement();
- final Bundle extras = new Bundle();
- extras.putString(VolumeRecord.EXTRA_FS_UUID, volumeUuid);
- mMoveCallbacks.notifyCreated(realMoveId, extras);
-
- final IPackageMoveObserver callback = new IPackageMoveObserver.Stub() {
- @Override
- public void onCreated(int moveId, Bundle extras) {
- // Ignored
- }
-
- @Override
- public void onStatusChanged(int moveId, int status, long estMillis) {
- mMoveCallbacks.notifyStatusChanged(realMoveId, status, estMillis);
- }
- };
-
- final StorageManager storage = mInjector.getSystemService(StorageManager.class);
- storage.setPrimaryStorageUuid(volumeUuid, callback);
- return realMoveId;
- }
-
- @Override
- public int getMoveStatus(int moveId) {
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS, null);
- return mMoveCallbacks.mLastStatus.get(moveId);
- }
-
- @Override
- public void registerMoveCallback(IPackageMoveObserver callback) {
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS, null);
- mMoveCallbacks.register(callback);
- }
-
- @Override
- public void unregisterMoveCallback(IPackageMoveObserver callback) {
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS, null);
- mMoveCallbacks.unregister(callback);
- }
-
- @Override
- public boolean setInstallLocation(int loc) {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS,
- null);
- if (getInstallLocation() == loc) {
- return true;
- }
- if (loc == InstallLocationUtils.APP_INSTALL_AUTO
- || loc == InstallLocationUtils.APP_INSTALL_INTERNAL
- || loc == InstallLocationUtils.APP_INSTALL_EXTERNAL) {
- android.provider.Settings.Global.putInt(mContext.getContentResolver(),
- android.provider.Settings.Global.DEFAULT_INSTALL_LOCATION, loc);
- return true;
- }
- return false;
- }
-
- @Override
- public int getInstallLocation() {
- // allow instant app access
- return android.provider.Settings.Global.getInt(mContext.getContentResolver(),
- android.provider.Settings.Global.DEFAULT_INSTALL_LOCATION,
- InstallLocationUtils.APP_INSTALL_AUTO);
- }
-
/** Called by UserManagerService */
void cleanUpUser(UserManagerService userManager, @UserIdInt int userId) {
synchronized (mLock) {
@@ -6660,22 +4277,10 @@ public class PackageManagerService extends IPackageManager.Stub
mPermissionManager.writeLegacyPermissionStateTEMP();
mSettings.readPermissionStateForUserSyncLPr(userId);
mPermissionManager.readLegacyPermissionStateTEMP();
- return mPmInternal.isPermissionUpgradeNeeded(userId);
- }
- }
-
- @Override
- public VerifierDeviceIdentity getVerifierDeviceIdentity() throws RemoteException {
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.PACKAGE_VERIFICATION_AGENT,
- "Only package verification agents can read the verifier device identity");
-
- synchronized (mLock) {
- return mSettings.getVerifierDeviceIdentityLPw(mLiveComputer);
+ return mSettings.isPermissionUpgradeNeeded(userId);
}
}
- @Override
public boolean isStorageLow() {
// allow instant applications
final long token = Binder.clearCallingIdentity();
@@ -6692,52 +4297,8 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- @Override
- public IPackageInstaller getPackageInstaller() {
- // Return installer service for internal calls.
- if (PackageManagerServiceUtils.isSystemOrRoot()) {
- return mInstallerService;
- }
- // Return null for InstantApps.
- if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
- return null;
- }
- return mInstallerService;
- }
-
- @Override
- public IArtManager getArtManager() {
- return mArtManagerService;
- }
-
- boolean userNeedsBadging(int userId) {
- return mUserNeedsBadging.get(userId);
- }
-
- @Nullable
- @Override
- public KeySet getKeySetByAlias(@NonNull String packageName, @NonNull String alias) {
- return mComputer.getKeySetByAlias(packageName, alias);
- }
-
- @Nullable
- @Override
- public KeySet getSigningKeySet(@NonNull String packageName) {
- return mComputer.getSigningKeySet(packageName);
- }
-
- @Override
- public boolean isPackageSignedByKeySet(@NonNull String packageName, @NonNull KeySet ks) {
- return mComputer.isPackageSignedByKeySet(packageName, ks);
- }
-
- @Override
- public boolean isPackageSignedByKeySetExactly(@NonNull String packageName, @NonNull KeySet ks) {
- return mComputer.isPackageSignedByKeySetExactly(packageName, ks);
- }
-
- private void deletePackageIfUnused(final String packageName) {
- PackageStateInternal ps = getPackageStateInternal(packageName);
+ private void deletePackageIfUnused(@NonNull Computer snapshot, final String packageName) {
+ PackageStateInternal ps = snapshot.getPackageStateInternal(packageName);
if (ps == null) {
return;
}
@@ -6755,780 +4316,2044 @@ public class PackageManagerService extends IPackageManager.Stub
0, PackageManager.DELETE_ALL_USERS, true /*removedBySystem*/));
}
- private AndroidPackage getPackage(String packageName) {
- return mComputer.getPackage(packageName);
+ void deletePreloadsFileCache() {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CLEAR_APP_CACHE,
+ "deletePreloadsFileCache");
+ File dir = Environment.getDataPreloadsFileCacheDirectory();
+ Slog.i(PackageManagerService.TAG, "Deleting preloaded file cache " + dir);
+ FileUtils.deleteContents(dir);
}
- private AndroidPackage getPackage(int uid) {
- return mComputer.getPackage(uid);
- }
+ void setSystemAppHiddenUntilInstalled(@NonNull Computer snapshot, String packageName,
+ boolean hidden) {
+ final int callingUid = Binder.getCallingUid();
+ final boolean calledFromSystemOrPhone = callingUid == Process.PHONE_UID
+ || callingUid == Process.SYSTEM_UID;
+ if (!calledFromSystemOrPhone) {
+ mContext.enforceCallingOrSelfPermission(Manifest.permission.SUSPEND_APPS,
+ "setSystemAppHiddenUntilInstalled");
+ }
- private SigningDetails getSigningDetails(@NonNull String packageName) {
- return mComputer.getSigningDetails(packageName);
- }
+ final PackageStateInternal stateRead = snapshot.getPackageStateInternal(packageName);
+ if (stateRead == null || !stateRead.isSystem() || stateRead.getPkg() == null) {
+ return;
+ }
+ if (stateRead.getPkg().isCoreApp() && !calledFromSystemOrPhone) {
+ throw new SecurityException("Only system or phone callers can modify core apps");
+ }
- private SigningDetails getSigningDetails(int uid) {
- return mComputer.getSigningDetails(uid);
+ commitPackageStateMutation(null, mutator -> {
+ mutator.forPackage(packageName)
+ .setHiddenUntilInstalled(hidden);
+ mutator.forDisabledSystemPackage(packageName)
+ .setHiddenUntilInstalled(hidden);
+ });
}
- private boolean filterAppAccess(AndroidPackage pkg, int callingUid, int userId) {
- return mComputer.filterAppAccess(pkg, callingUid, userId);
- }
+ boolean setSystemAppInstallState(@NonNull Computer snapshot, String packageName,
+ boolean installed, int userId) {
+ final int callingUid = Binder.getCallingUid();
+ final boolean calledFromSystemOrPhone = callingUid == Process.PHONE_UID
+ || callingUid == Process.SYSTEM_UID;
+ if (!calledFromSystemOrPhone) {
+ mContext.enforceCallingOrSelfPermission(Manifest.permission.SUSPEND_APPS,
+ "setSystemAppHiddenUntilInstalled");
+ }
- private boolean filterAppAccess(String packageName, int callingUid, int userId) {
- return mComputer.filterAppAccess(packageName, callingUid, userId);
- }
+ final PackageStateInternal packageState = snapshot.getPackageStateInternal(packageName);
+ // The target app should always be in system
+ if (packageState == null || !packageState.isSystem() || packageState.getPkg() == null) {
+ return false;
+ }
+ if (packageState.getPkg().isCoreApp() && !calledFromSystemOrPhone) {
+ throw new SecurityException("Only system or phone callers can modify core apps");
+ }
+ // Check if the install state is the same
+ if (packageState.getUserStateOrDefault(userId).isInstalled() == installed) {
+ return false;
+ }
+
+ final long callingId = Binder.clearCallingIdentity();
+ try {
+ if (installed) {
+ // install the app from uninstalled state
+ mInstallPackageHelper.installExistingPackageAsUser(
+ packageName,
+ userId,
+ PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS,
+ PackageManager.INSTALL_REASON_DEVICE_SETUP,
+ null,
+ null);
+ return true;
+ }
- private boolean filterAppAccess(int uid, int callingUid) {
- return mComputer.filterAppAccess(uid, callingUid);
+ // uninstall the app from installed state
+ deletePackageVersioned(
+ new VersionedPackage(packageName, PackageManager.VERSION_CODE_HIGHEST),
+ new PackageManager.LegacyPackageDeleteObserver(null).getBinder(),
+ userId,
+ PackageManager.DELETE_SYSTEM_APP);
+ return true;
+ } finally {
+ Binder.restoreCallingIdentity(callingId);
+ }
}
- @Nullable
- private int[] getVisibilityAllowList(@NonNull String packageName, @UserIdInt int userId) {
- return mComputer.getVisibilityAllowList(packageName, userId);
+ void finishPackageInstall(int token, boolean didLaunch) {
+ PackageManagerServiceUtils.enforceSystemOrRoot(
+ "Only the system is allowed to finish installs");
+
+ if (PackageManagerService.DEBUG_INSTALL) {
+ Slog.v(PackageManagerService.TAG, "BM finishing package install for " + token);
+ }
+ Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "restore", token);
+
+ final Message msg = mHandler.obtainMessage(PackageManagerService.POST_INSTALL, token,
+ didLaunch ? 1 : 0);
+ mHandler.sendMessage(msg);
}
- boolean canQueryPackage(int callingUid, @Nullable String targetPackageName) {
- return mComputer.canQueryPackage(callingUid, targetPackageName);
+ void checkPackageStartable(@NonNull Computer snapshot, @NonNull String packageName,
+ @UserIdInt int userId) {
+ final int callingUid = Binder.getCallingUid();
+ if (snapshot.getInstantAppPackageName(callingUid) != null) {
+ throw new SecurityException("Instant applications don't have access to this method");
+ }
+ if (!mUserManager.exists(userId)) {
+ throw new SecurityException("User doesn't exist");
+ }
+ snapshot.enforceCrossUserPermission(callingUid, userId, false, false,
+ "checkPackageStartable");
+ switch (snapshot.getPackageStartability(mSafeMode, packageName, callingUid, userId)) {
+ case PACKAGE_STARTABILITY_NOT_FOUND:
+ throw new SecurityException("Package " + packageName + " was not found!");
+ case PACKAGE_STARTABILITY_NOT_SYSTEM:
+ throw new SecurityException("Package " + packageName + " not a system app!");
+ case PACKAGE_STARTABILITY_FROZEN:
+ throw new SecurityException("Package " + packageName + " is currently frozen!");
+ case PACKAGE_STARTABILITY_DIRECT_BOOT_UNSUPPORTED:
+ throw new SecurityException("Package " + packageName + " is not encryption aware!");
+ case PACKAGE_STARTABILITY_OK:
+ default:
+ }
}
- private class PackageManagerLocalImpl implements PackageManagerLocal {
+ void setPackageStoppedState(@NonNull Computer snapshot, @NonNull String packageName,
+ boolean stopped, @UserIdInt int userId) {
+ if (!mUserManager.exists(userId)) return;
+ final int callingUid = Binder.getCallingUid();
+ if (snapshot.getInstantAppPackageName(callingUid) == null) {
+ final int permission = mContext.checkCallingOrSelfPermission(
+ Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE);
+ final boolean allowedByPermission = (permission == PackageManager.PERMISSION_GRANTED);
+ if (!allowedByPermission
+ && !ArrayUtils.contains(snapshot.getPackagesForUid(callingUid), packageName)) {
+ throw new SecurityException(
+ "Permission Denial: attempt to change stopped state from pid="
+ + Binder.getCallingPid()
+ + ", uid=" + callingUid + ", package=" + packageName);
+ }
+ snapshot.enforceCrossUserPermission(callingUid, userId,
+ true /* requireFullPermission */, true /* checkShell */, "stop package");
+
+ final PackageStateInternal packageState =
+ snapshot.getPackageStateInternal(packageName);
+ final PackageUserState packageUserState = packageState == null
+ ? null : packageState.getUserStateOrDefault(userId);
+ if (packageState != null
+ && !snapshot.shouldFilterApplication(packageState, callingUid, userId)
+ && packageUserState.isStopped() != stopped) {
+ boolean wasNotLaunched = packageUserState.isNotLaunched();
+ commitPackageStateMutation(null, packageName, state -> {
+ PackageUserStateWrite userState = state.userState(userId);
+ userState.setStopped(stopped);
+ if (wasNotLaunched) {
+ userState.setNotLaunched(false);
+ }
+ });
+
+ if (wasNotLaunched) {
+ final String installerPackageName =
+ packageState.getInstallSource().installerPackageName;
+ if (installerPackageName != null) {
+ notifyFirstLaunch(packageName, installerPackageName, userId);
+ }
+ }
+
+ scheduleWritePackageRestrictions(userId);
+ }
+ }
+
+ // If this would cause the app to leave force-stop, then also make sure to unhibernate the
+ // app if needed.
+ if (!stopped) {
+ mHandler.post(() -> {
+ AppHibernationManagerInternal ah =
+ mInjector.getLocalService(AppHibernationManagerInternal.class);
+ if (ah != null && ah.isHibernatingForUser(packageName, userId)) {
+ ah.setHibernatingForUser(packageName, userId, false);
+ ah.setHibernatingGlobally(packageName, false);
+ }
+ });
+ }
}
- private class PackageManagerInternalImpl extends PackageManagerInternal {
+ public class IPackageManagerImpl extends IPackageManagerBase {
+
+ public IPackageManagerImpl() {
+ super(PackageManagerService.this, mContext, mDexOptHelper, mModuleInfoProvider,
+ mPreferredActivityHelper, mResolveIntentHelper, mDomainVerificationManager,
+ mDomainVerificationConnection, mInstallerService, mPackageProperty,
+ mResolveComponentName, mInstantAppResolverSettingsComponent,
+ mRequiredSdkSandboxPackage, mServicesExtensionPackageName,
+ mSharedSystemSharedLibraryPackageName);
+ }
+
@Override
- public List<ApplicationInfo> getInstalledApplications(
- @PackageManager.ApplicationInfoFlagsBits long flags, int userId, int callingUid) {
- return PackageManagerService.this.mComputer.getInstalledApplications(flags, userId,
- callingUid);
+ public void checkPackageStartable(String packageName, int userId) {
+ PackageManagerService.this
+ .checkPackageStartable(snapshotComputer(), packageName, userId);
}
@Override
- public boolean isPlatformSigned(String packageName) {
- PackageStateInternal packageState = getPackageStateInternal(packageName);
- if (packageState == null) {
- return false;
+ public void clearApplicationProfileData(String packageName) {
+ PackageManagerServiceUtils.enforceSystemOrRoot(
+ "Only the system can clear all profile data");
+
+ final Computer snapshot = snapshotComputer();
+ final AndroidPackage pkg = snapshot.getPackage(packageName);
+ try (PackageFreezer ignored = freezePackage(packageName, "clearApplicationProfileData")) {
+ synchronized (mInstallLock) {
+ mAppDataHelper.clearAppProfilesLIF(pkg);
+ }
}
- SigningDetails signingDetails = packageState.getSigningDetails();
- return signingDetails.hasAncestorOrSelf(mPlatformPackage.getSigningDetails())
- || mPlatformPackage.getSigningDetails().checkCapability(signingDetails,
- SigningDetails.CertCapabilities.PERMISSION);
}
@Override
- public boolean isDataRestoreSafe(byte[] restoringFromSigHash, String packageName) {
- SigningDetails sd = getSigningDetails(packageName);
- if (sd == null) {
- return false;
+ public void clearApplicationUserData(final String packageName,
+ final IPackageDataObserver observer, final int userId) {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.CLEAR_APP_USER_DATA, null);
+
+ final int callingUid = Binder.getCallingUid();
+ final Computer snapshot = snapshotComputer();
+ snapshot.enforceCrossUserPermission(callingUid, userId, true /* requireFullPermission */,
+ false /* checkShell */, "clear application data");
+
+ if (snapshot.getPackageStateFiltered(packageName, callingUid, userId) == null) {
+ if (observer != null) {
+ mHandler.post(() -> {
+ try {
+ observer.onRemoveCompleted(packageName, false);
+ } catch (RemoteException e) {
+ Log.i(TAG, "Observer no longer exists.");
+ }
+ });
+ }
+ return;
}
- return sd.hasSha256Certificate(restoringFromSigHash,
- SigningDetails.CertCapabilities.INSTALLED_DATA);
+ if (mProtectedPackages.isPackageDataProtected(userId, packageName)) {
+ throw new SecurityException("Cannot clear data for a protected package: "
+ + packageName);
+ }
+
+ // Queue up an async operation since the package deletion may take a little while.
+ mHandler.post(new Runnable() {
+ public void run() {
+ mHandler.removeCallbacks(this);
+ final boolean succeeded;
+ try (PackageFreezer freezer = freezePackage(packageName,
+ "clearApplicationUserData")) {
+ synchronized (mInstallLock) {
+ succeeded = clearApplicationUserDataLIF(snapshotComputer(), packageName,
+ userId);
+ }
+ mInstantAppRegistry.deleteInstantApplicationMetadata(packageName, userId);
+ synchronized (mLock) {
+ if (succeeded) {
+ resetComponentEnabledSettingsIfNeededLPw(packageName, userId);
+ }
+ }
+ }
+ if (succeeded) {
+ // invoke DeviceStorageMonitor's update method to clear any notifications
+ DeviceStorageMonitorInternal dsm = LocalServices
+ .getService(DeviceStorageMonitorInternal.class);
+ if (dsm != null) {
+ dsm.checkMemory();
+ }
+ if (checkPermission(Manifest.permission.SUSPEND_APPS, packageName, userId)
+ == PERMISSION_GRANTED) {
+ final Computer snapshot = snapshotComputer();
+ unsuspendForSuspendingPackage(snapshot, packageName, userId);
+ removeAllDistractingPackageRestrictions(snapshot, userId);
+ flushPackageRestrictionsAsUserInternalLocked(userId);
+ }
+ }
+ if (observer != null) {
+ try {
+ observer.onRemoveCompleted(packageName, succeeded);
+ } catch (RemoteException e) {
+ Log.i(TAG, "Observer no longer exists.");
+ }
+ } //end if observer
+ } //end run
+ });
}
@Override
- public boolean isDataRestoreSafe(Signature restoringFromSig, String packageName) {
- SigningDetails sd = getSigningDetails(packageName);
- if (sd == null) {
- return false;
+ public void clearCrossProfileIntentFilters(int sourceUserId, String ownerPackage) {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
+ final int callingUid = Binder.getCallingUid();
+ final Computer snapshot = snapshotComputer();
+ enforceOwnerRights(snapshot, ownerPackage, callingUid);
+ PackageManagerServiceUtils.enforceShellRestriction(mInjector.getUserManagerInternal(),
+ UserManager.DISALLOW_DEBUGGING_FEATURES, callingUid, sourceUserId);
+ synchronized (mLock) {
+ CrossProfileIntentResolver resolver =
+ mSettings.editCrossProfileIntentResolverLPw(sourceUserId);
+ ArraySet<CrossProfileIntentFilter> set =
+ new ArraySet<>(resolver.filterSet());
+ for (CrossProfileIntentFilter filter : set) {
+ if (filter.getOwnerPackage().equals(ownerPackage)) {
+ resolver.removeFilter(filter);
+ }
+ }
}
- return sd.hasCertificate(restoringFromSig,
- SigningDetails.CertCapabilities.INSTALLED_DATA);
+ scheduleWritePackageRestrictions(sourceUserId);
}
@Override
- public boolean hasSignatureCapability(int serverUid, int clientUid,
- @SigningDetails.CertCapabilities int capability) {
- SigningDetails serverSigningDetails = getSigningDetails(serverUid);
- SigningDetails clientSigningDetails = getSigningDetails(clientUid);
- return serverSigningDetails.checkCapability(clientSigningDetails, capability)
- || clientSigningDetails.hasAncestorOrSelf(serverSigningDetails);
+ public final void deleteApplicationCacheFiles(final String packageName,
+ final IPackageDataObserver observer) {
+ final int userId = UserHandle.getCallingUserId();
+ deleteApplicationCacheFilesAsUser(packageName, userId, observer);
+ }
+
+ @Override
+ public void deleteApplicationCacheFilesAsUser(final String packageName, final int userId,
+ final IPackageDataObserver observer) {
+ final int callingUid = Binder.getCallingUid();
+ if (mContext.checkCallingOrSelfPermission(
+ android.Manifest.permission.INTERNAL_DELETE_CACHE_FILES)
+ != PackageManager.PERMISSION_GRANTED) {
+ // If the caller has the old delete cache permission, silently ignore. Else throw.
+ if (mContext.checkCallingOrSelfPermission(
+ android.Manifest.permission.DELETE_CACHE_FILES)
+ == PackageManager.PERMISSION_GRANTED) {
+ Slog.w(TAG, "Calling uid " + callingUid + " does not have " +
+ android.Manifest.permission.INTERNAL_DELETE_CACHE_FILES +
+ ", silently ignoring");
+ return;
+ }
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.INTERNAL_DELETE_CACHE_FILES, null);
+ }
+ final Computer snapshot = snapshotComputer();
+ snapshot.enforceCrossUserPermission(callingUid, userId, /* requireFullPermission= */ true,
+ /* checkShell= */ false, "delete application cache files");
+ final int hasAccessInstantApps = mContext.checkCallingOrSelfPermission(
+ android.Manifest.permission.ACCESS_INSTANT_APPS);
+ // Queue up an async operation since the package deletion may take a little while.
+ mHandler.post(() -> {
+ // Snapshot in the Handler Runnable since this may be deferred quite a bit
+ // TODO: Is this and the later mInstallLock re-snapshot necessary?
+ final Computer newSnapshot = snapshotComputer();
+ final PackageStateInternal ps = newSnapshot.getPackageStateInternal(packageName);
+ boolean doClearData = true;
+ if (ps != null) {
+ final boolean targetIsInstantApp =
+ ps.getUserStateOrDefault(UserHandle.getUserId(callingUid)).isInstantApp();
+ doClearData = !targetIsInstantApp
+ || hasAccessInstantApps == PackageManager.PERMISSION_GRANTED;
+ }
+ if (doClearData) {
+ synchronized (mInstallLock) {
+ final int flags = FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL;
+ // Snapshot again after mInstallLock?
+ final AndroidPackage pkg = snapshotComputer().getPackage(packageName);
+ // We're only clearing cache files, so we don't care if the
+ // app is unfrozen and still able to run
+ mAppDataHelper.clearAppDataLIF(pkg, userId,
+ flags | Installer.FLAG_CLEAR_CACHE_ONLY);
+ mAppDataHelper.clearAppDataLIF(pkg, userId,
+ flags | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
+ }
+ }
+ if (observer != null) {
+ try {
+ observer.onRemoveCompleted(packageName, true);
+ } catch (RemoteException e) {
+ Log.i(TAG, "Observer no longer exists.");
+ }
+ }
+ });
}
- private SigningDetails getSigningDetails(@NonNull String packageName) {
- return PackageManagerService.this.getSigningDetails(packageName);
+ @Override
+ public void dumpProfiles(String packageName) {
+ /* Only the shell, root, or the app user should be able to dump profiles. */
+ final int callingUid = Binder.getCallingUid();
+ final Computer snapshot = snapshotComputer();
+ final String[] callerPackageNames = snapshot.getPackagesForUid(callingUid);
+ if (callingUid != Process.SHELL_UID
+ && callingUid != Process.ROOT_UID
+ && !ArrayUtils.contains(callerPackageNames, packageName)) {
+ throw new SecurityException("dumpProfiles");
+ }
+
+ AndroidPackage pkg = snapshot.getPackage(packageName);
+ if (pkg == null) {
+ throw new IllegalArgumentException("Unknown package: " + packageName);
+ }
+
+ synchronized (mInstallLock) {
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dump profiles");
+ mArtManagerService.dumpProfiles(pkg);
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+ }
}
- private SigningDetails getSigningDetails(int uid) {
- return PackageManagerService.this.getSigningDetails(uid);
+ @Override
+ public void enterSafeMode() {
+ PackageManagerServiceUtils.enforceSystemOrRoot(
+ "Only the system can request entering safe mode");
+
+ if (!mSystemReady) {
+ mSafeMode = true;
+ }
}
@Override
- public boolean isInstantApp(String packageName, int userId) {
- return PackageManagerService.this.isInstantApp(packageName, userId);
+ public void extendVerificationTimeout(int id, int verificationCodeAtTimeout,
+ long millisecondsToDelay) {
+ mContext.enforceCallingOrSelfPermission(
+ Manifest.permission.PACKAGE_VERIFICATION_AGENT,
+ "Only package verification agents can extend verification timeouts");
+ final int callingUid = Binder.getCallingUid();
+
+ mHandler.post(() -> {
+ final PackageVerificationState state = mPendingVerification.get(id);
+ final PackageVerificationResponse response = new PackageVerificationResponse(
+ verificationCodeAtTimeout, callingUid);
+
+ long delay = millisecondsToDelay;
+ if (delay > PackageManager.MAXIMUM_VERIFICATION_TIMEOUT) {
+ delay = PackageManager.MAXIMUM_VERIFICATION_TIMEOUT;
+ }
+ if (delay < 0) {
+ delay = 0;
+ }
+
+ if ((state != null) && !state.timeoutExtended()) {
+ state.extendTimeout();
+
+ final Message msg = mHandler.obtainMessage(PackageManagerService.PACKAGE_VERIFIED);
+ msg.arg1 = id;
+ msg.obj = response;
+ mHandler.sendMessageDelayed(msg, delay);
+ }
+ });
}
+ @WorkerThread
@Override
- public String getInstantAppPackageName(int uid) {
- return PackageManagerService.this.getInstantAppPackageName(uid);
+ public void flushPackageRestrictionsAsUser(int userId) {
+ final Computer snapshot = snapshotComputer();
+ final int callingUid = Binder.getCallingUid();
+ if (snapshot.getInstantAppPackageName(callingUid) != null) {
+ return;
+ }
+ if (!mUserManager.exists(userId)) {
+ return;
+ }
+ snapshot.enforceCrossUserPermission(callingUid, userId,
+ false /* requireFullPermission*/, false /* checkShell */,
+ "flushPackageRestrictions");
+ synchronized (mLock) {
+ flushPackageRestrictionsAsUserInternalLocked(userId);
+ }
+ }
+
+
+ @Override
+ public void freeStorage(final String volumeUuid, final long freeStorageSize,
+ final @StorageManager.AllocateFlags int flags, final IntentSender pi) {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.CLEAR_APP_CACHE, TAG);
+ mHandler.post(() -> {
+ boolean success = false;
+ try {
+ PackageManagerService.this.freeStorage(volumeUuid, freeStorageSize, flags);
+ success = true;
+ } catch (IOException e) {
+ Slog.w(TAG, e);
+ }
+ if (pi != null) {
+ try {
+ pi.sendIntent(null, success ? 1 : 0, null, null, null);
+ } catch (SendIntentException e) {
+ Slog.w(TAG, e);
+ }
+ }
+ });
}
@Override
- public boolean filterAppAccess(AndroidPackage pkg, int callingUid, int userId) {
- return PackageManagerService.this.filterAppAccess(pkg, callingUid, userId);
+ public void freeStorageAndNotify(final String volumeUuid, final long freeStorageSize,
+ final @StorageManager.AllocateFlags int flags, final IPackageDataObserver observer) {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.CLEAR_APP_CACHE, null);
+ mHandler.post(() -> {
+ boolean success = false;
+ try {
+ PackageManagerService.this.freeStorage(volumeUuid, freeStorageSize, flags);
+ success = true;
+ } catch (IOException e) {
+ Slog.w(PackageManagerService.TAG, e);
+ }
+ if (observer != null) {
+ try {
+ observer.onRemoveCompleted(null, success);
+ } catch (RemoteException e) {
+ Slog.w(PackageManagerService.TAG, e);
+ }
+ }
+ });
}
@Override
- public boolean filterAppAccess(String packageName, int callingUid, int userId) {
- return PackageManagerService.this.filterAppAccess(packageName, callingUid, userId);
+ public ChangedPackages getChangedPackages(int sequenceNumber, int userId) {
+ final int callingUid = Binder.getCallingUid();
+ final Computer snapshot = snapshotComputer();
+ if (snapshot.getInstantAppPackageName(callingUid) != null) {
+ return null;
+ }
+ if (!mUserManager.exists(userId)) {
+ return null;
+ }
+ snapshot.enforceCrossUserPermission(callingUid, userId, false, false,
+ "getChangedPackages");
+ final ChangedPackages changedPackages = mChangedPackagesTracker.getChangedPackages(
+ sequenceNumber, userId);
+
+ if (changedPackages != null) {
+ final List<String> packageNames = changedPackages.getPackageNames();
+ for (int index = packageNames.size() - 1; index >= 0; index--) {
+ // Filter out the changes if the calling package should not be able to see it.
+ final PackageStateInternal packageState =
+ snapshot.getPackageStateInternal(packageNames.get(index));
+ if (snapshot.shouldFilterApplication(packageState, callingUid, userId)) {
+ packageNames.remove(index);
+ }
+ }
+ }
+
+ return changedPackages;
}
@Override
- public boolean filterAppAccess(int uid, int callingUid) {
- return PackageManagerService.this.filterAppAccess(uid, callingUid);
+ public byte[] getDomainVerificationBackup(int userId) {
+ if (Binder.getCallingUid() != Process.SYSTEM_UID) {
+ throw new SecurityException("Only the system may call getDomainVerificationBackup()");
+ }
+
+ try {
+ try (ByteArrayOutputStream output = new ByteArrayOutputStream()) {
+ TypedXmlSerializer serializer = Xml.resolveSerializer(output);
+ mDomainVerificationManager.writeSettings(snapshotComputer(), serializer, true,
+ userId);
+ return output.toByteArray();
+ }
+ } catch (Exception e) {
+ if (PackageManagerService.DEBUG_BACKUP) {
+ Slog.e(PackageManagerService.TAG, "Unable to write domain verification for backup", e);
+ }
+ return null;
+ }
}
- @Nullable
@Override
- public int[] getVisibilityAllowList(@NonNull String packageName, int userId) {
- return PackageManagerService.this.getVisibilityAllowList(packageName, userId);
+ public IBinder getHoldLockToken() {
+ if (!Build.IS_DEBUGGABLE) {
+ throw new SecurityException("getHoldLockToken requires a debuggable build");
+ }
+
+ mContext.enforceCallingPermission(
+ Manifest.permission.INJECT_EVENTS,
+ "getHoldLockToken requires INJECT_EVENTS permission");
+
+ final Binder token = new Binder();
+ token.attachInterface(this, "holdLock:" + Binder.getCallingUid());
+ return token;
}
@Override
- public boolean canQueryPackage(int callingUid, @Nullable String packageName) {
- return PackageManagerService.this.canQueryPackage(callingUid, packageName);
+ public String getInstantAppAndroidId(String packageName, int userId) {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.ACCESS_INSTANT_APPS, "getInstantAppAndroidId");
+ final Computer snapshot = snapshotComputer();
+ snapshot.enforceCrossUserPermission(Binder.getCallingUid(), userId,
+ true /* requireFullPermission */, false /* checkShell */,
+ "getInstantAppAndroidId");
+ // Make sure the target is an Instant App.
+ if (!snapshot.isInstantApp(packageName, userId)) {
+ return null;
+ }
+ return mInstantAppRegistry.getInstantAppAndroidId(packageName, userId);
}
@Override
- public AndroidPackage getPackage(String packageName) {
- return PackageManagerService.this.getPackage(packageName);
+ public byte[] getInstantAppCookie(String packageName, int userId) {
+ if (HIDE_EPHEMERAL_APIS) {
+ return null;
+ }
+
+ final Computer snapshot = snapshotComputer();
+ snapshot.enforceCrossUserPermission(Binder.getCallingUid(), userId,
+ true /* requireFullPermission */, false /* checkShell */,
+ "getInstantAppCookie");
+ if (!snapshot.isCallerSameApp(packageName, Binder.getCallingUid())) {
+ return null;
+ }
+ PackageStateInternal packageState = snapshot.getPackageStateInternal(packageName);
+ if (packageState == null || packageState.getPkg() == null) {
+ return null;
+ }
+ return mInstantAppRegistry.getInstantAppCookie(packageState.getPkg(), userId);
}
- @Nullable
@Override
- public AndroidPackageApi getAndroidPackage(@NonNull String packageName) {
- return PackageManagerService.this.getPackage(packageName);
+ public Bitmap getInstantAppIcon(String packageName, int userId) {
+ if (HIDE_EPHEMERAL_APIS) {
+ return null;
+ }
+
+ final Computer snapshot = snapshotComputer();
+ if (!snapshot.canViewInstantApps(Binder.getCallingUid(), userId)) {
+ mContext.enforceCallingOrSelfPermission(Manifest.permission.ACCESS_INSTANT_APPS,
+ "getInstantAppIcon");
+ }
+ snapshot.enforceCrossUserPermission(Binder.getCallingUid(), userId,
+ true /* requireFullPermission */, false /* checkShell */,
+ "getInstantAppIcon");
+
+ return mInstantAppRegistry.getInstantAppIcon(packageName, userId);
}
@Override
- public AndroidPackage getPackage(int uid) {
- return PackageManagerService.this.getPackage(uid);
+ public ParceledListSlice<InstantAppInfo> getInstantApps(int userId) {
+ if (HIDE_EPHEMERAL_APIS) {
+ return null;
+ }
+
+ final Computer snapshot = snapshotComputer();
+ if (!snapshot.canViewInstantApps(Binder.getCallingUid(), userId)) {
+ mContext.enforceCallingOrSelfPermission(Manifest.permission.ACCESS_INSTANT_APPS,
+ "getEphemeralApplications");
+ }
+ snapshot.enforceCrossUserPermission(Binder.getCallingUid(), userId,
+ true /* requireFullPermission */, false /* checkShell */,
+ "getEphemeralApplications");
+
+ List<InstantAppInfo> instantApps = mInstantAppRegistry.getInstantApps(snapshot, userId);
+ if (instantApps != null) {
+ return new ParceledListSlice<>(instantApps);
+ }
+ return null;
}
@Override
- public List<AndroidPackage> getPackagesForAppId(int appId) {
- return mComputer.getPackagesForAppId(appId);
+ public ResolveInfo getLastChosenActivity(Intent intent, String resolvedType, int flags) {
+ return mPreferredActivityHelper.getLastChosenActivity(snapshotComputer(), intent,
+ resolvedType, flags);
}
- @Nullable
@Override
- public PackageStateInternal getPackageStateInternal(String packageName) {
- return PackageManagerService.this.getPackageStateInternal(packageName);
+ public IntentSender getLaunchIntentSenderForPackage(String packageName, String callingPackage,
+ String featureId, int userId) throws RemoteException {
+ return mResolveIntentHelper.getLaunchIntentSenderForPackage(snapshotComputer(),
+ packageName, callingPackage, featureId, userId);
}
- @Nullable
@Override
- public PackageState getPackageState(@NonNull String packageName) {
- return PackageManagerService.this.getPackageState(packageName);
+ public List<String> getMimeGroup(String packageName, String mimeGroup) {
+ final Computer snapshot = snapshotComputer();
+ enforceOwnerRights(snapshot, packageName, Binder.getCallingUid());
+ return getMimeGroupInternal(snapshot, packageName, mimeGroup);
}
- @NonNull
@Override
- public ArrayMap<String, ? extends PackageStateInternal> getPackageStates() {
- return PackageManagerService.this.getPackageStates();
+ public int getMoveStatus(int moveId) {
+ mContext.enforceCallingOrSelfPermission(
+ Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS, null);
+ return mMoveCallbacks.mLastStatus.get(moveId);
}
@Override
- public PackageList getPackageList(@Nullable PackageListObserver observer) {
- final ArrayList<String> list = new ArrayList<>();
- forEachPackageState(packageState -> {
- AndroidPackage pkg = packageState.getPkg();
- if (pkg != null) {
- list.add(pkg.getPackageName());
- }
- });
- final PackageList packageList = new PackageList(list, observer);
- if (observer != null) {
- mPackageObserverHelper.addObserver(packageList);
+ public String getPermissionControllerPackageName() {
+ final int callingUid = Binder.getCallingUid();
+ final Computer snapshot = snapshotComputer();
+ if (snapshot.getPackageStateFiltered(mRequiredPermissionControllerPackage,
+ callingUid, UserHandle.getUserId(callingUid)) != null) {
+ return mRequiredPermissionControllerPackage;
}
- return packageList;
+
+ throw new IllegalStateException("PermissionController is not found");
}
@Override
- public void removePackageListObserver(PackageListObserver observer) {
- mPackageObserverHelper.removeObserver(observer);
+ public int getRuntimePermissionsVersion(@UserIdInt int userId) {
+ Preconditions.checkArgumentNonnegative(userId);
+ enforceAdjustRuntimePermissionsPolicyOrUpgradeRuntimePermissions(
+ "getRuntimePermissionVersion");
+ return mSettings.getDefaultRuntimePermissionsVersion(userId);
}
@Override
- public PackageStateInternal getDisabledSystemPackage(@NonNull String packageName) {
- return snapshotComputer().getDisabledSystemPackage(packageName);
+ public String getSplashScreenTheme(@NonNull String packageName, int userId) {
+ final Computer snapshot = snapshotComputer();
+ PackageStateInternal packageState = filterPackageStateForInstalledAndFiltered(snapshot,
+ packageName, Binder.getCallingUid(), userId);
+ return packageState == null ? null
+ : packageState.getUserStateOrDefault(userId).getSplashScreenTheme();
}
@Override
- public @Nullable
- String getDisabledSystemPackageName(@NonNull String packageName) {
- PackageStateInternal disabledPkgSetting = getDisabledSystemPackage(
- packageName);
- AndroidPackage disabledPkg = disabledPkgSetting == null
- ? null : disabledPkgSetting.getPkg();
- return disabledPkg == null ? null : disabledPkg.getPackageName();
+ public Bundle getSuspendedPackageAppExtras(String packageName, int userId) {
+ final int callingUid = Binder.getCallingUid();
+ final Computer snapshot = snapshot();
+ if (snapshot.getPackageUid(packageName, 0, userId) != callingUid) {
+ throw new SecurityException("Calling package " + packageName
+ + " does not belong to calling uid " + callingUid);
+ }
+ return mSuspendPackageHelper
+ .getSuspendedPackageAppExtras(snapshot, packageName, userId, callingUid);
}
@Override
- public @NonNull String[] getKnownPackageNames(int knownPackage, int userId) {
- return PackageManagerService.this.getKnownPackageNamesInternal(knownPackage, userId);
+ public @NonNull ParceledListSlice<FeatureInfo> getSystemAvailableFeatures() {
+ // allow instant applications
+ ArrayList<FeatureInfo> res;
+ synchronized (mAvailableFeatures) {
+ res = new ArrayList<>(mAvailableFeatures.size() + 1);
+ res.addAll(mAvailableFeatures.values());
+ }
+ final FeatureInfo fi = new FeatureInfo();
+ fi.reqGlEsVersion = SystemProperties.getInt("ro.opengles.version",
+ FeatureInfo.GL_ES_VERSION_UNDEFINED);
+ res.add(fi);
+
+ return new ParceledListSlice<>(res);
}
@Override
- public boolean isSameApp(@Nullable String packageName, int callingUid, int userId) {
- if (packageName == null) {
- return false;
+ public String[] getUnsuspendablePackagesForUser(String[] packageNames, int userId) {
+ Objects.requireNonNull(packageNames, "packageNames cannot be null");
+ mContext.enforceCallingOrSelfPermission(Manifest.permission.SUSPEND_APPS,
+ "getUnsuspendablePackagesForUser");
+ final int callingUid = Binder.getCallingUid();
+ if (UserHandle.getUserId(callingUid) != userId) {
+ throw new SecurityException("Calling uid " + callingUid
+ + " cannot query getUnsuspendablePackagesForUser for user " + userId);
}
+ return mSuspendPackageHelper.getUnsuspendablePackagesForUser(snapshotComputer(),
+ packageNames, userId, callingUid);
+ }
- if (Process.isSdkSandboxUid(callingUid)) {
- return packageName.equals(getSdkSandboxPackageName());
+ @Override
+ public VerifierDeviceIdentity getVerifierDeviceIdentity() throws RemoteException {
+ mContext.enforceCallingOrSelfPermission(
+ Manifest.permission.PACKAGE_VERIFICATION_AGENT,
+ "Only package verification agents can read the verifier device identity");
+
+ synchronized (mLock) {
+ return mSettings.getVerifierDeviceIdentityLPw(mLiveComputer);
}
- int uid = getPackageUid(packageName, 0, userId);
- return UserHandle.isSameApp(uid, callingUid);
}
@Override
- public boolean isResolveActivityComponent(ComponentInfo component) {
- return mResolveActivity.packageName.equals(component.packageName)
- && mResolveActivity.name.equals(component.name);
+ public void makeProviderVisible(int recipientUid, @NonNull String visibleAuthority) {
+ final Computer snapshot = snapshotComputer();
+ final int recipientUserId = UserHandle.getUserId(recipientUid);
+ final ProviderInfo providerInfo =
+ snapshot.getGrantImplicitAccessProviderInfo(recipientUid, visibleAuthority);
+ if (providerInfo == null) {
+ return;
+ }
+ int visibleUid = providerInfo.applicationInfo.uid;
+ PackageManagerService.this.grantImplicitAccess(snapshot, recipientUserId,
+ null /*Intent*/, UserHandle.getAppId(recipientUid), visibleUid,
+ false /*direct*/, false /* retainOnUpdate */);
}
@Override
- public void setKeepUninstalledPackages(final List<String> packageList) {
- PackageManagerService.this.setKeepUninstalledPackagesInternal(packageList);
+ public void makeUidVisible(int recipientUid, int visibleUid) {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.MAKE_UID_VISIBLE, "makeUidVisible");
+ final int callingUid = Binder.getCallingUid();
+ final int recipientUserId = UserHandle.getUserId(recipientUid);
+ final int visibleUserId = UserHandle.getUserId(visibleUid);
+ final Computer snapshot = snapshotComputer();
+ snapshot.enforceCrossUserPermission(callingUid, recipientUserId,
+ false /* requireFullPermission */, false /* checkShell */, "makeUidVisible");
+ snapshot.enforceCrossUserPermission(callingUid, visibleUserId,
+ false /* requireFullPermission */, false /* checkShell */, "makeUidVisible");
+ snapshot.enforceCrossUserPermission(recipientUid, visibleUserId,
+ false /* requireFullPermission */, false /* checkShell */, "makeUidVisible");
+
+ PackageManagerService.this.grantImplicitAccess(snapshot, recipientUserId,
+ null /*Intent*/, UserHandle.getAppId(recipientUid), visibleUid,
+ false /*direct*/, false /* retainOnUpdate */);
}
@Override
- public boolean isPermissionsReviewRequired(String packageName, int userId) {
- return mPermissionManager.isPermissionsReviewRequired(packageName, userId);
+ public void holdLock(IBinder token, int durationMs) {
+ mTestUtilityService.verifyHoldLockToken(token);
+
+ synchronized (mLock) {
+ SystemClock.sleep(durationMs);
+ }
}
+ /**
+ * @hide
+ */
@Override
- public PackageInfo getPackageInfo(
- String packageName, @PackageManager.PackageInfoFlagsBits long flags,
- int filterCallingUid, int userId) {
- return PackageManagerService.this.mComputer
- .getPackageInfoInternal(packageName, PackageManager.VERSION_CODE_HIGHEST,
- flags, filterCallingUid, userId);
+ public int installExistingPackageAsUser(String packageName, int userId, int installFlags,
+ int installReason, List<String> whiteListedPermissions) {
+ return mInstallPackageHelper.installExistingPackageAsUser(packageName, userId, installFlags,
+ installReason, whiteListedPermissions, null);
}
@Override
- public long getCeDataInode(String packageName, int userId) {
- final PackageStateInternal packageState = getPackageStateInternal(packageName);
- if (packageState == null) {
- return 0;
- } else {
- return packageState.getUserStateOrDefault(userId).getCeDataInode();
+ public boolean isAutoRevokeWhitelisted(String packageName) {
+ int mode = mInjector.getSystemService(AppOpsManager.class).checkOpNoThrow(
+ AppOpsManager.OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED,
+ Binder.getCallingUid(), packageName);
+ return mode == MODE_IGNORED;
+ }
+
+ @Override
+ public boolean isPackageStateProtected(@NonNull String packageName, @UserIdInt int userId) {
+ final int callingUid = Binder.getCallingUid();
+ final int callingAppId = UserHandle.getAppId(callingUid);
+
+ final Computer snapshot = snapshotComputer();
+ snapshot.enforceCrossUserPermission(callingUid, userId, false /*requireFullPermission*/,
+ true /*checkShell*/, "isPackageStateProtected");
+
+ if (callingAppId != Process.SYSTEM_UID && callingAppId != Process.ROOT_UID
+ && snapshot.checkUidPermission(MANAGE_DEVICE_ADMINS, callingUid)
+ != PERMISSION_GRANTED) {
+ throw new SecurityException("Caller must have the "
+ + MANAGE_DEVICE_ADMINS + " permission.");
}
+
+ return mProtectedPackages.isPackageStateProtected(userId, packageName);
}
@Override
- public Bundle getSuspendedPackageLauncherExtras(String packageName, int userId) {
- return mSuspendPackageHelper.getSuspendedPackageLauncherExtras(
- packageName, userId, Binder.getCallingUid());
+ public boolean isProtectedBroadcast(String actionName) {
+ if (actionName != null) {
+ // TODO: remove these terrible hacks
+ if (actionName.startsWith("android.net.netmon.lingerExpired")
+ || actionName.startsWith("com.android.server.sip.SipWakeupTimer")
+ || actionName.startsWith("com.android.internal.telephony.data-reconnect")
+ || actionName.startsWith("android.net.netmon.launchCaptivePortalApp")) {
+ return true;
+ }
+ }
+ // allow instant applications
+ synchronized (mProtectedBroadcasts) {
+ return mProtectedBroadcasts.contains(actionName);
+ }
}
+ /**
+ * Logs process start information (including base APK hash) to the security log.
+ * @hide
+ */
@Override
- public boolean isPackageSuspended(String packageName, int userId) {
- return mSuspendPackageHelper.isPackageSuspended(
- packageName, userId, Binder.getCallingUid());
+ public void logAppProcessStartIfNeeded(String packageName, String processName, int uid,
+ String seinfo, String apkFile, int pid) {
+ final Computer snapshot = snapshotComputer();
+ if (snapshot.getInstantAppPackageName(Binder.getCallingUid()) != null) {
+ return;
+ }
+ if (!SecurityLog.isLoggingEnabled()) {
+ return;
+ }
+ mProcessLoggingHandler.logAppProcessStart(mContext,
+ LocalServices.getService(PackageManagerInternal.class), apkFile, packageName,
+ processName, uid, seinfo, pid);
}
@Override
- public void removeAllNonSystemPackageSuspensions(int userId) {
- final Computer computer = snapshotComputer();
- final String[] allPackages = computer.getAllAvailablePackageNames();
- mSuspendPackageHelper.removeSuspensionsBySuspendingPackage(computer, allPackages,
- (suspendingPackage) -> !PLATFORM_PACKAGE_NAME.equals(suspendingPackage),
- userId);
+ public int movePackage(final String packageName, final String volumeUuid) {
+ mContext.enforceCallingOrSelfPermission(Manifest.permission.MOVE_PACKAGE, null);
+
+ final int callingUid = Binder.getCallingUid();
+ final UserHandle user = new UserHandle(UserHandle.getUserId(callingUid));
+ final int moveId = mNextMoveId.getAndIncrement();
+ mHandler.post(() -> {
+ try {
+ MovePackageHelper movePackageHelper =
+ new MovePackageHelper(PackageManagerService.this);
+ movePackageHelper.movePackageInternal(
+ packageName, volumeUuid, moveId, callingUid, user);
+ } catch (PackageManagerException e) {
+ Slog.w(PackageManagerService.TAG, "Failed to move " + packageName, e);
+ mMoveCallbacks.notifyStatusChanged(moveId, e.error);
+ }
+ });
+ return moveId;
}
@Override
- public void removeNonSystemPackageSuspensions(String packageName, int userId) {
- mSuspendPackageHelper.removeSuspensionsBySuspendingPackage(snapshotComputer(),
- new String[]{packageName},
- (suspendingPackage) -> !PLATFORM_PACKAGE_NAME.equals(suspendingPackage),
+ public int movePrimaryStorage(String volumeUuid) throws RemoteException {
+ mContext.enforceCallingOrSelfPermission(Manifest.permission.MOVE_PACKAGE, null);
+
+ final int realMoveId = mNextMoveId.getAndIncrement();
+ final Bundle extras = new Bundle();
+ extras.putString(VolumeRecord.EXTRA_FS_UUID, volumeUuid);
+ mMoveCallbacks.notifyCreated(realMoveId, extras);
+
+ final IPackageMoveObserver callback = new IPackageMoveObserver.Stub() {
+ @Override
+ public void onCreated(int moveId, Bundle extras) {
+ // Ignored
+ }
+
+ @Override
+ public void onStatusChanged(int moveId, int status, long estMillis) {
+ mMoveCallbacks.notifyStatusChanged(realMoveId, status, estMillis);
+ }
+ };
+
+ final StorageManager storage = mInjector.getSystemService(StorageManager.class);
+ storage.setPrimaryStorageUuid(volumeUuid, callback);
+ return realMoveId;
+ }
+
+ @Override
+ public void notifyDexLoad(String loadingPackageName,
+ Map<String, String> classLoaderContextMap,
+ String loaderIsa) {
+ int callingUid = Binder.getCallingUid();
+ if (PackageManagerService.PLATFORM_PACKAGE_NAME.equals(loadingPackageName)
+ && callingUid != Process.SYSTEM_UID) {
+ Slog.w(PackageManagerService.TAG,
+ "Non System Server process reporting dex loads as system server. uid="
+ + callingUid);
+ // Do not record dex loads from processes pretending to be system server.
+ // Only the system server should be assigned the package "android", so reject calls
+ // that don't satisfy the constraint.
+ //
+ // notifyDexLoad is a PM API callable from the app process. So in theory, apps could
+ // craft calls to this API and pretend to be system server. Doing so poses no
+ // particular danger for dex load reporting or later dexopt, however it is a
+ // sensible check to do in order to verify the expectations.
+ return;
+ }
+
+ int userId = UserHandle.getCallingUserId();
+ ApplicationInfo ai = snapshot().getApplicationInfo(loadingPackageName, /*flags*/ 0,
userId);
+ if (ai == null) {
+ Slog.w(PackageManagerService.TAG, "Loading a package that does not exist for the calling user. package="
+ + loadingPackageName + ", user=" + userId);
+ return;
+ }
+ mDexManager.notifyDexLoad(ai, classLoaderContextMap, loaderIsa, userId,
+ Process.isIsolated(callingUid));
}
@Override
- public void flushPackageRestrictions(int userId) {
- synchronized (mLock) {
- PackageManagerService.this.flushPackageRestrictionsAsUserInternalLocked(userId);
+ public void notifyPackageUse(String packageName, int reason) {
+ final int callingUid = Binder.getCallingUid();
+ final int callingUserId = UserHandle.getUserId(callingUid);
+ Computer snapshot = snapshotComputer();
+ final boolean notify;
+ if (snapshot.getInstantAppPackageName(callingUid) != null) {
+ notify = snapshot.isCallerSameApp(packageName, callingUid);
+ } else {
+ notify = !snapshot.isInstantAppInternal(packageName, callingUserId,
+ Process.SYSTEM_UID);
}
+ if (!notify) {
+ return;
+ }
+
+ notifyPackageUseInternal(packageName, reason);
}
@Override
- public void removeDistractingPackageRestrictions(String packageName, int userId) {
- PackageManagerService.this.removeDistractingPackageRestrictions(
- new String[]{packageName}, userId);
+ public void overrideLabelAndIcon(@NonNull ComponentName componentName,
+ @NonNull String nonLocalizedLabel, int icon, int userId) {
+ if (TextUtils.isEmpty(nonLocalizedLabel)) {
+ throw new IllegalArgumentException("Override label should be a valid String");
+ }
+ updateComponentLabelIcon(componentName, nonLocalizedLabel, icon, userId);
}
@Override
- public void removeAllDistractingPackageRestrictions(int userId) {
- PackageManagerService.this.removeAllDistractingPackageRestrictions(userId);
+ public ParceledListSlice<PackageManager.Property> queryProperty(
+ String propertyName, @PackageManager.PropertyLocation int componentType) {
+ Objects.requireNonNull(propertyName);
+ final int callingUid = Binder.getCallingUid();
+ final int callingUserId = UserHandle.getCallingUserId();
+ final Computer snapshot = snapshotComputer();
+ final List<PackageManager.Property> result =
+ mPackageProperty.queryProperty(propertyName, componentType, packageName -> {
+ final PackageStateInternal ps =
+ snapshot.getPackageStateInternal(packageName);
+ return snapshot.shouldFilterApplication(ps, callingUid, callingUserId);
+ });
+ if (result == null) {
+ return ParceledListSlice.emptyList();
+ }
+ return new ParceledListSlice<>(result);
}
+ /**
+ * Reconcile the information we have about the secondary dex files belonging to
+ * {@code packageName} and the actual dex files. For all dex files that were
+ * deleted, update the internal records and delete the generated oat files.
+ */
@Override
- public String getSuspendingPackage(String suspendedPackage, int userId) {
- return mSuspendPackageHelper.getSuspendingPackage(
- suspendedPackage, userId, Binder.getCallingUid());
+ public void reconcileSecondaryDexFiles(String packageName) {
+ final Computer snapshot = snapshotComputer();
+ if (snapshot.getInstantAppPackageName(Binder.getCallingUid()) != null) {
+ return;
+ } else if (snapshot.isInstantAppInternal(
+ packageName, UserHandle.getCallingUserId(), Process.SYSTEM_UID)) {
+ return;
+ }
+ mDexManager.reconcileSecondaryDexFiles(packageName);
}
@Override
- public SuspendDialogInfo getSuspendedDialogInfo(String suspendedPackage,
- String suspendingPackage, int userId) {
- return mSuspendPackageHelper.getSuspendedDialogInfo(
- suspendedPackage, suspendingPackage, userId, Binder.getCallingUid());
+ public void registerDexModule(String packageName, String dexModulePath,
+ boolean isSharedModule,
+ IDexModuleRegisterCallback callback) {
+ int userId = UserHandle.getCallingUserId();
+ ApplicationInfo ai = snapshot().getApplicationInfo(packageName, /*flags*/ 0, userId);
+ DexManager.RegisterDexModuleResult result;
+ if (ai == null) {
+ Slog.w(PackageManagerService.TAG,
+ "Registering a dex module for a package that does not exist for the" +
+ " calling user. package=" + packageName + ", user=" + userId);
+ result = new DexManager.RegisterDexModuleResult(false, "Package not installed");
+ } else {
+ result = mDexManager.registerDexModule(ai, dexModulePath, isSharedModule, userId);
+ }
+
+ if (callback != null) {
+ mHandler.post(() -> {
+ try {
+ callback.onDexModuleRegistered(dexModulePath, result.success,
+ result.message);
+ } catch (RemoteException e) {
+ Slog.w(PackageManagerService.TAG,
+ "Failed to callback after module registration " + dexModulePath, e);
+ }
+ });
+ }
}
@Override
- public int getDistractingPackageRestrictions(String packageName, int userId) {
- final PackageStateInternal packageState = getPackageStateInternal(packageName);
- return (packageState == null) ? RESTRICTION_NONE
- : packageState.getUserStateOrDefault(userId).getDistractionFlags();
+ public void registerMoveCallback(IPackageMoveObserver callback) {
+ mContext.enforceCallingOrSelfPermission(
+ Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS, null);
+ mMoveCallbacks.register(callback);
}
@Override
- public int getPackageUid(String packageName,
- @PackageManager.PackageInfoFlagsBits long flags, int userId) {
- return PackageManagerService.this
- .getPackageUidInternal(packageName, flags, userId, Process.SYSTEM_UID);
+ public void restoreDomainVerification(byte[] backup, int userId) {
+ if (Binder.getCallingUid() != Process.SYSTEM_UID) {
+ throw new SecurityException("Only the system may call restorePreferredActivities()");
+ }
+
+ try {
+ ByteArrayInputStream input = new ByteArrayInputStream(backup);
+ TypedXmlPullParser parser = Xml.resolvePullParser(input);
+
+ // User ID input isn't necessary here as it assumes the user integers match and that
+ // the only states inside the backup XML are for the target user.
+ mDomainVerificationManager.restoreSettings(snapshotComputer(), parser);
+ input.close();
+ } catch (Exception e) {
+ if (PackageManagerService.DEBUG_BACKUP) {
+ Slog.e(PackageManagerService.TAG, "Exception restoring domain verification: " + e.getMessage());
+ }
+ }
}
@Override
- public ApplicationInfo getApplicationInfo(
- String packageName, @PackageManager.ApplicationInfoFlagsBits long flags,
- int filterCallingUid, int userId) {
- return PackageManagerService.this
- .getApplicationInfoInternal(packageName, flags, filterCallingUid, userId);
+ public void restoreLabelAndIcon(@NonNull ComponentName componentName, int userId) {
+ updateComponentLabelIcon(componentName, null, null, userId);
}
@Override
- public ActivityInfo getActivityInfo(
- ComponentName component, @PackageManager.ComponentInfoFlagsBits long flags,
- int filterCallingUid, int userId) {
- return PackageManagerService.this
- .getActivityInfoInternal(component, flags, filterCallingUid, userId);
+ public void sendDeviceCustomizationReadyBroadcast() {
+ mContext.enforceCallingPermission(Manifest.permission.SEND_DEVICE_CUSTOMIZATION_READY,
+ "sendDeviceCustomizationReadyBroadcast");
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ BroadcastHelper.sendDeviceCustomizationReadyBroadcast();
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
}
@Override
- public List<ResolveInfo> queryIntentActivities(
- Intent intent, String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags,
- int filterCallingUid, int userId) {
- return snapshotComputer().queryIntentActivitiesInternal(intent, resolvedType, flags,
- userId);
+ public void setApplicationCategoryHint(String packageName, int categoryHint,
+ String callerPackageName) {
+ final PackageStateMutator.InitialState initialState = recordInitialState();
+
+ final FunctionalUtils.ThrowingFunction<Computer, PackageStateMutator.Result>
+ implementation = computer -> {
+ if (computer.getInstantAppPackageName(Binder.getCallingUid()) != null) {
+ throw new SecurityException(
+ "Instant applications don't have access to this method");
+ }
+ mInjector.getSystemService(AppOpsManager.class)
+ .checkPackage(Binder.getCallingUid(), callerPackageName);
+
+ PackageStateInternal packageState = computer.getPackageStateFiltered(packageName,
+ Binder.getCallingUid(), UserHandle.getCallingUserId());
+ if (packageState == null) {
+ throw new IllegalArgumentException("Unknown target package " + packageName);
+ }
+
+ if (!Objects.equals(callerPackageName,
+ packageState.getInstallSource().installerPackageName)) {
+ throw new IllegalArgumentException("Calling package " + callerPackageName
+ + " is not installer for " + packageName);
+ }
+
+ if (packageState.getCategoryOverride() != categoryHint) {
+ return commitPackageStateMutation(initialState,
+ packageName, state -> state.setCategoryOverride(categoryHint));
+ } else {
+ return null;
+ }
+ };
+
+ PackageStateMutator.Result result = implementation.apply(snapshotComputer());
+ if (result != null && result.isStateChanged() && !result.isSpecificPackageNull()) {
+ // TODO: Specific return value of what state changed?
+ // The installer on record might have changed, retry with lock
+ synchronized (mPackageStateWriteLock) {
+ result = implementation.apply(snapshotComputer());
+ }
+ }
+
+ if (result != null && result.isCommitted()) {
+ scheduleWriteSettings();
+ }
}
@Override
- public List<ResolveInfo> queryIntentReceivers(Intent intent,
- String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags,
- int filterCallingUid, int userId) {
- return PackageManagerService.this.mResolveIntentHelper.queryIntentReceiversInternal(
- snapshotComputer(), intent, resolvedType, flags, userId, filterCallingUid);
+ public void setApplicationEnabledSetting(String appPackageName,
+ int newState, int flags, int userId, String callingPackage) {
+ if (!mUserManager.exists(userId)) return;
+ if (callingPackage == null) {
+ callingPackage = Integer.toString(Binder.getCallingUid());
+ }
+
+ setEnabledSettings(List.of(new PackageManager.ComponentEnabledSetting(appPackageName, newState, flags)),
+ userId, callingPackage);
}
@Override
- public List<ResolveInfo> queryIntentServices(
- Intent intent, @PackageManager.ResolveInfoFlagsBits long flags, int callingUid,
+ public boolean setApplicationHiddenSettingAsUser(String packageName, boolean hidden,
int userId) {
- final String resolvedType = intent.resolveTypeIfNeeded(mContext.getContentResolver());
- return PackageManagerService.this
- .queryIntentServicesInternal(intent, resolvedType, flags, userId, callingUid,
- false);
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USERS, null);
+ final int callingUid = Binder.getCallingUid();
+ final Computer snapshot = snapshotComputer();
+ snapshot.enforceCrossUserPermission(callingUid, userId, true /* requireFullPermission */,
+ true /* checkShell */, "setApplicationHiddenSetting for user " + userId);
+
+ if (hidden && isPackageDeviceAdmin(packageName, userId)) {
+ Slog.w(TAG, "Not hiding package " + packageName + ": has active device admin");
+ return false;
+ }
+
+ // Do not allow "android" is being disabled
+ if ("android".equals(packageName)) {
+ Slog.w(TAG, "Cannot hide package: android");
+ return false;
+ }
+
+ final long callingId = Binder.clearCallingIdentity();
+ try {
+ final PackageStateInternal packageState =
+ snapshot.getPackageStateFiltered(packageName, callingUid, userId);
+ if (packageState == null) {
+ return false;
+ }
+
+ // Cannot hide static shared libs as they are considered
+ // a part of the using app (emulating static linking). Also
+ // static libs are installed always on internal storage.
+ AndroidPackage pkg = packageState.getPkg();
+ if (pkg != null) {
+ // Cannot hide SDK libs as they are controlled by SDK manager.
+ if (pkg.getSdkLibName() != null) {
+ Slog.w(TAG, "Cannot hide package: " + packageName
+ + " providing SDK library: "
+ + pkg.getSdkLibName());
+ return false;
+ }
+ // Cannot hide static shared libs as they are considered
+ // a part of the using app (emulating static linking). Also
+ // static libs are installed always on internal storage.
+ if (pkg.getStaticSharedLibName() != null) {
+ Slog.w(TAG, "Cannot hide package: " + packageName
+ + " providing static shared library: "
+ + pkg.getStaticSharedLibName());
+ return false;
+ }
+ }
+ // Only allow protected packages to hide themselves.
+ if (hidden && !UserHandle.isSameApp(callingUid, packageState.getAppId())
+ && mProtectedPackages.isPackageStateProtected(userId, packageName)) {
+ Slog.w(TAG, "Not hiding protected package: " + packageName);
+ return false;
+ }
+
+ if (packageState.getUserStateOrDefault(userId).isHidden() == hidden) {
+ return false;
+ }
+
+ commitPackageStateMutation(null, packageName, packageState1 ->
+ packageState1.userState(userId).setHidden(hidden));
+
+ final Computer newSnapshot = snapshotComputer();
+ final PackageStateInternal newPackageState =
+ newSnapshot.getPackageStateInternal(packageName);
+
+ if (hidden) {
+ killApplication(packageName, newPackageState.getAppId(), userId, "hiding pkg");
+ sendApplicationHiddenForUser(packageName, newPackageState, userId);
+ } else {
+ sendPackageAddedForUser(newSnapshot, packageName, newPackageState, userId,
+ DataLoaderType.NONE);
+ }
+
+ scheduleWritePackageRestrictions(userId);
+ return true;
+ } finally {
+ Binder.restoreCallingIdentity(callingId);
+ }
}
@Override
- public ComponentName getHomeActivitiesAsUser(List<ResolveInfo> allHomeCandidates,
+ public boolean setBlockUninstallForUser(String packageName, boolean blockUninstall,
int userId) {
- return PackageManagerService.this.getHomeActivitiesAsUser(allHomeCandidates, userId);
+ mContext.enforceCallingOrSelfPermission(
+ Manifest.permission.DELETE_PACKAGES, null);
+ final Computer snapshot = snapshotComputer();
+ PackageStateInternal packageState = snapshot.getPackageStateInternal(packageName);
+ if (packageState != null && packageState.getPkg() != null) {
+ AndroidPackage pkg = packageState.getPkg();
+ // Cannot block uninstall SDK libs as they are controlled by SDK manager.
+ if (pkg.getSdkLibName() != null) {
+ Slog.w(PackageManagerService.TAG, "Cannot block uninstall of package: " + packageName
+ + " providing SDK library: " + pkg.getSdkLibName());
+ return false;
+ }
+ // Cannot block uninstall of static shared libs as they are
+ // considered a part of the using app (emulating static linking).
+ // Also static libs are installed always on internal storage.
+ if (pkg.getStaticSharedLibName() != null) {
+ Slog.w(PackageManagerService.TAG, "Cannot block uninstall of package: " + packageName
+ + " providing static shared library: " + pkg.getStaticSharedLibName());
+ return false;
+ }
+ }
+ synchronized (mLock) {
+ mSettings.setBlockUninstallLPw(userId, packageName, blockUninstall);
+ }
+
+ scheduleWritePackageRestrictions(userId);
+ return true;
}
@Override
- public ComponentName getDefaultHomeActivity(int userId) {
- return PackageManagerService.this.getDefaultHomeActivity(userId);
+ public void setComponentEnabledSetting(ComponentName componentName,
+ int newState, int flags, int userId) {
+ if (!mUserManager.exists(userId)) return;
+
+ setEnabledSettings(List.of(new PackageManager.ComponentEnabledSetting(componentName, newState, flags)),
+ userId, null /* callingPackage */);
}
@Override
- public ComponentName getSystemUiServiceComponent() {
- return ComponentName.unflattenFromString(mContext.getResources().getString(
- com.android.internal.R.string.config_systemUIServiceComponent));
+ public void setComponentEnabledSettings(List<PackageManager.ComponentEnabledSetting> settings, int userId) {
+ if (!mUserManager.exists(userId)) return;
+ if (settings == null || settings.isEmpty()) {
+ throw new IllegalArgumentException("The list of enabled settings is empty");
+ }
+
+ setEnabledSettings(settings, userId, null /* callingPackage */);
}
@Override
- public void setDeviceAndProfileOwnerPackages(
- int deviceOwnerUserId, String deviceOwnerPackage,
- SparseArray<String> profileOwnerPackages) {
- mProtectedPackages.setDeviceAndProfileOwnerPackages(
- deviceOwnerUserId, deviceOwnerPackage, profileOwnerPackages);
- final ArraySet<Integer> usersWithPoOrDo = new ArraySet<>();
- if (deviceOwnerPackage != null) {
- usersWithPoOrDo.add(deviceOwnerUserId);
+ 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);
+ }
}
- final int sz = profileOwnerPackages.size();
- for (int i = 0; i < sz; i++) {
- if (profileOwnerPackages.valueAt(i) != null) {
- removeAllNonSystemPackageSuspensions(profileOwnerPackages.keyAt(i));
+
+ 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]);
}
@Override
- public void setDeviceOwnerProtectedPackages(
- String deviceOwnerPackageName, List<String> packageNames) {
- mProtectedPackages.setDeviceOwnerProtectedPackages(
- deviceOwnerPackageName, packageNames);
- }
+ public void setHarmfulAppWarning(@NonNull String packageName, @Nullable CharSequence warning,
+ int userId) {
+ final int callingUid = Binder.getCallingUid();
+ final int callingAppId = UserHandle.getAppId(callingUid);
- @Override
- public boolean isPackageDataProtected(int userId, String packageName) {
- return mProtectedPackages.isPackageDataProtected(userId, packageName);
+ final Computer snapshot = snapshotComputer();
+ snapshot.enforceCrossUserPermission(callingUid, userId, true /*requireFullPermission*/,
+ true /*checkShell*/, "setHarmfulAppInfo");
+
+ if (callingAppId != Process.SYSTEM_UID && callingAppId != Process.ROOT_UID &&
+ snapshot.checkUidPermission(SET_HARMFUL_APP_WARNINGS, callingUid)
+ != PERMISSION_GRANTED) {
+ throw new SecurityException("Caller must have the "
+ + SET_HARMFUL_APP_WARNINGS + " permission.");
+ }
+
+ PackageStateMutator.Result result = commitPackageStateMutation(null, packageName,
+ packageState -> packageState.userState(userId)
+ .setHarmfulAppWarning(warning == null ? null : warning.toString()));
+ if (result.isSpecificPackageNull()) {
+ throw new IllegalArgumentException("Unknown package: " + packageName);
+ }
+ scheduleWritePackageRestrictions(userId);
}
@Override
- public boolean isPackageStateProtected(String packageName, int userId) {
- return mProtectedPackages.isPackageStateProtected(userId, packageName);
+ public boolean setInstallLocation(int loc) {
+ mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SECURE_SETTINGS,
+ null);
+ if (getInstallLocation() == loc) {
+ return true;
+ }
+ if (loc == InstallLocationUtils.APP_INSTALL_AUTO
+ || loc == InstallLocationUtils.APP_INSTALL_INTERNAL
+ || loc == InstallLocationUtils.APP_INSTALL_EXTERNAL) {
+ android.provider.Settings.Global.putInt(mContext.getContentResolver(),
+ android.provider.Settings.Global.DEFAULT_INSTALL_LOCATION, loc);
+ return true;
+ }
+ return false;
}
@Override
- public boolean isPackageEphemeral(int userId, String packageName) {
- final PackageStateInternal packageState = getPackageStateInternal(packageName);
- return packageState != null
- && packageState.getUserStateOrDefault(userId).isInstantApp();
+ public void setInstallerPackageName(String targetPackage, String installerPackageName) {
+ final int callingUid = Binder.getCallingUid();
+ final int callingUserId = UserHandle.getUserId(callingUid);
+ final FunctionalUtils.ThrowingCheckedFunction<Computer, Boolean, RuntimeException>
+ implementation = snapshot -> {
+ if (snapshot.getInstantAppPackageName(callingUid) != null) {
+ return false;
+ }
+
+ PackageStateInternal targetPackageState =
+ snapshot.getPackageStateInternal(targetPackage);
+ if (targetPackageState == null
+ || snapshot.shouldFilterApplication(targetPackageState, callingUid,
+ callingUserId)) {
+ throw new IllegalArgumentException("Unknown target package: " + targetPackage);
+ }
+
+ PackageStateInternal installerPackageState = null;
+ if (installerPackageName != null) {
+ installerPackageState = snapshot.getPackageStateInternal(installerPackageName);
+ if (installerPackageState == null
+ || snapshot.shouldFilterApplication(
+ installerPackageState, callingUid, callingUserId)) {
+ throw new IllegalArgumentException("Unknown installer package: "
+ + installerPackageName);
+ }
+ }
+
+ Signature[] callerSignature;
+ final int appId = UserHandle.getAppId(callingUid);
+ Pair<PackageStateInternal, SharedUserApi> either =
+ snapshot.getPackageOrSharedUser(appId);
+ if (either != null) {
+ if (either.first != null) {
+ callerSignature = either.first.getSigningDetails().getSignatures();
+ } else {
+ callerSignature = either.second.getSigningDetails().getSignatures();
+ }
+ } else {
+ throw new SecurityException("Unknown calling UID: " + callingUid);
+ }
+
+ // Verify: can't set installerPackageName to a package that is
+ // not signed with the same cert as the caller.
+ if (installerPackageState != null) {
+ if (compareSignatures(callerSignature,
+ installerPackageState.getSigningDetails().getSignatures())
+ != PackageManager.SIGNATURE_MATCH) {
+ throw new SecurityException(
+ "Caller does not have same cert as new installer package "
+ + installerPackageName);
+ }
+ }
+
+ // Verify: if target already has an installer package, it must
+ // be signed with the same cert as the caller.
+ String targetInstallerPackageName =
+ targetPackageState.getInstallSource().installerPackageName;
+ PackageStateInternal targetInstallerPkgSetting = targetInstallerPackageName == null
+ ? null : snapshot.getPackageStateInternal(targetInstallerPackageName);
+
+ if (targetInstallerPkgSetting != null) {
+ if (compareSignatures(callerSignature,
+ targetInstallerPkgSetting.getSigningDetails().getSignatures())
+ != PackageManager.SIGNATURE_MATCH) {
+ throw new SecurityException(
+ "Caller does not have same cert as old installer package "
+ + targetInstallerPackageName);
+ }
+ } else if (mContext.checkCallingOrSelfPermission(
+ Manifest.permission.INSTALL_PACKAGES) != PERMISSION_GRANTED) {
+ // This is probably an attempt to exploit vulnerability b/150857253 of taking
+ // privileged installer permissions when the installer has been uninstalled or
+ // was never set.
+ EventLog.writeEvent(0x534e4554, "150857253", callingUid, "");
+
+ final long binderToken = Binder.clearCallingIdentity();
+ try {
+ if (mInjector.getCompatibility().isChangeEnabledByUid(
+ PackageManagerService.THROW_EXCEPTION_ON_REQUIRE_INSTALL_PACKAGES_TO_ADD_INSTALLER_PACKAGE,
+ callingUid)) {
+ throw new SecurityException("Neither user " + callingUid
+ + " nor current process has "
+ + Manifest.permission.INSTALL_PACKAGES);
+ } else {
+ // If change disabled, fail silently for backwards compatibility
+ return false;
+ }
+ } finally {
+ Binder.restoreCallingIdentity(binderToken);
+ }
+ }
+
+ return true;
+ };
+ PackageStateMutator.InitialState initialState = recordInitialState();
+ boolean allowed = implementation.apply(snapshotComputer());
+ if (allowed) {
+ // TODO: Need to lock around here to handle mSettings.addInstallerPackageNames,
+ // should find an alternative which avoids any race conditions
+ PackageStateInternal targetPackageState;
+ synchronized (mLock) {
+ PackageStateMutator.Result result = commitPackageStateMutation(initialState,
+ targetPackage, state -> state.setInstaller(installerPackageName));
+ if (result.isPackagesChanged() || result.isStateChanged()) {
+ synchronized (mPackageStateWriteLock) {
+ allowed = implementation.apply(snapshotComputer());
+ if (allowed) {
+ commitPackageStateMutation(null, targetPackage,
+ state -> state.setInstaller(installerPackageName));
+ } else {
+ return;
+ }
+ }
+ }
+ targetPackageState = snapshotComputer().getPackageStateInternal(targetPackage);
+ mSettings.addInstallerPackageNames(targetPackageState.getInstallSource());
+ }
+ mAppsFilter.addPackage(targetPackageState);
+ scheduleWriteSettings();
+ }
}
@Override
- public boolean wasPackageEverLaunched(String packageName, int userId) {
- final PackageStateInternal packageState = getPackageStateInternal(packageName);
- if (packageState == null) {
- throw new IllegalArgumentException("Unknown package: " + packageName);
+ public boolean setInstantAppCookie(String packageName, byte[] cookie, int userId) {
+ if (HIDE_EPHEMERAL_APIS) {
+ return true;
+ }
+
+ final Computer snapshot = snapshotComputer();
+ snapshot.enforceCrossUserPermission(Binder.getCallingUid(), userId,
+ true /* requireFullPermission */, true /* checkShell */,
+ "setInstantAppCookie");
+ if (!snapshot.isCallerSameApp(packageName, Binder.getCallingUid())) {
+ return false;
+ }
+
+ PackageStateInternal packageState = snapshot.getPackageStateInternal(packageName);
+ if (packageState == null || packageState.getPkg() == null) {
+ return false;
}
- return !packageState.getUserStateOrDefault(userId).isNotLaunched();
+ return mInstantAppRegistry.setInstantAppCookie(packageState.getPkg(), cookie,
+ mContext.getPackageManager().getInstantAppCookieMaxBytes(), userId);
}
@Override
- public boolean isEnabledAndMatches(ParsedMainComponent component, long flags, int userId) {
- return PackageStateUtils.isEnabledAndMatches(
- getPackageStateInternal(component.getPackageName()), component, flags, userId);
+ public void setKeepUninstalledPackages(List<String> packageList) {
+ mContext.enforceCallingPermission(
+ Manifest.permission.KEEP_UNINSTALLED_PACKAGES,
+ "setKeepUninstalledPackages requires KEEP_UNINSTALLED_PACKAGES permission");
+ Objects.requireNonNull(packageList);
+
+ setKeepUninstalledPackagesInternal(snapshot(), packageList);
}
@Override
- public boolean userNeedsBadging(int userId) {
- synchronized (mLock) {
- return PackageManagerService.this.userNeedsBadging(userId);
+ public void setMimeGroup(String packageName, String mimeGroup, List<String> mimeTypes) {
+ final Computer snapshot = snapshotComputer();
+ enforceOwnerRights(snapshot, packageName, Binder.getCallingUid());
+ mimeTypes = CollectionUtils.emptyIfNull(mimeTypes);
+ final PackageStateInternal packageState = snapshot.getPackageStateInternal(packageName);
+ Set<String> existingMimeTypes = packageState.getMimeGroups().get(mimeGroup);
+ if (existingMimeTypes == null) {
+ throw new IllegalArgumentException("Unknown MIME group " + mimeGroup
+ + " for package " + packageName);
+ }
+ if (existingMimeTypes.size() == mimeTypes.size()
+ && existingMimeTypes.containsAll(mimeTypes)) {
+ return;
+ }
+
+ ArraySet<String> mimeTypesSet = new ArraySet<>(mimeTypes);
+ commitPackageStateMutation(null, packageName, packageStateWrite -> {
+ packageStateWrite.setMimeGroup(mimeGroup, mimeTypesSet);
+ });
+ if (mComponentResolver.updateMimeGroup(snapshotComputer(), packageName, mimeGroup)) {
+ Binder.withCleanCallingIdentity(() ->
+ mPreferredActivityHelper.clearPackagePreferredActivities(packageName,
+ UserHandle.USER_ALL));
}
+
+ scheduleWriteSettings();
}
@Override
- public String getNameForUid(int uid) {
- return PackageManagerService.this.getNameForUid(uid);
+ public void setPackageStoppedState(String packageName, boolean stopped, int userId) {
+ PackageManagerService.this
+ .setPackageStoppedState(snapshotComputer(), packageName, stopped, userId);
}
@Override
- public void requestInstantAppResolutionPhaseTwo(AuxiliaryResolveInfo responseObj,
- Intent origIntent, String resolvedType, String callingPackage,
- @Nullable String callingFeatureId, boolean isRequesterInstantApp,
- Bundle verificationBundle, int userId) {
- PackageManagerService.this.requestInstantAppResolutionPhaseTwo(responseObj, origIntent,
- resolvedType, callingPackage, callingFeatureId, isRequesterInstantApp,
- verificationBundle, userId);
+ public String[] setPackagesSuspendedAsUser(String[] packageNames, boolean suspended,
+ PersistableBundle appExtras, PersistableBundle launcherExtras,
+ SuspendDialogInfo dialogInfo, String callingPackage, int userId) {
+ final int callingUid = Binder.getCallingUid();
+ final Computer snapshot = snapshotComputer();
+ enforceCanSetPackagesSuspendedAsUser(snapshot, callingPackage, callingUid, userId,
+ "setPackagesSuspendedAsUser");
+ return mSuspendPackageHelper.setPackagesSuspended(snapshot, packageNames, suspended,
+ appExtras, launcherExtras, dialogInfo, callingPackage, userId, callingUid);
}
@Override
- public void grantImplicitAccess(int userId, Intent intent,
- int recipientAppId, int visibleUid, boolean direct) {
- grantImplicitAccess(userId, intent, recipientAppId, visibleUid, direct,
- false /* retainOnUpdate */);
+ public boolean setRequiredForSystemUser(String packageName, boolean requiredForSystemUser) {
+ PackageManagerServiceUtils.enforceSystemOrRoot(
+ "setRequiredForSystemUser can only be run by the system or root");
+
+ PackageStateMutator.Result result = commitPackageStateMutation(null, packageName,
+ packageState -> packageState.setRequiredForSystemUser(requiredForSystemUser));
+ if (!result.isCommitted()) {
+ return false;
+ }
+
+ scheduleWriteSettings();
+ return true;
}
@Override
- public void grantImplicitAccess(int userId, Intent intent,
- int recipientAppId, int visibleUid, boolean direct, boolean retainOnUpdate) {
- Computer computer = snapshotComputer();
- final AndroidPackage visiblePackage = computer.getPackage(visibleUid);
- final int recipientUid = UserHandle.getUid(userId, recipientAppId);
- if (visiblePackage == null || computer.getPackage(recipientUid) == null) {
- return;
- }
+ public void setRuntimePermissionsVersion(int version, @UserIdInt int userId) {
+ Preconditions.checkArgumentNonnegative(version);
+ Preconditions.checkArgumentNonnegative(userId);
+ enforceAdjustRuntimePermissionsPolicyOrUpgradeRuntimePermissions(
+ "setRuntimePermissionVersion");
+ mSettings.setDefaultRuntimePermissionsVersion(version, userId);
+ }
- final boolean instantApp = computer.isInstantAppInternal(
- visiblePackage.getPackageName(), userId, visibleUid);
- final boolean accessGranted;
- if (instantApp) {
- if (!direct) {
- // if the interaction that lead to this granting access to an instant app
- // was indirect (i.e.: URI permission grant), do not actually execute the
- // grant.
- return;
- }
- accessGranted = mInstantAppRegistry.grantInstantAccess(userId, intent,
- recipientAppId, UserHandle.getAppId(visibleUid) /*instantAppId*/);
- } else {
- accessGranted = mAppsFilter.grantImplicitAccess(recipientUid, visibleUid,
- retainOnUpdate);
+ @Override
+ public void setSplashScreenTheme(@NonNull String packageName, @Nullable String themeId,
+ int userId) {
+ final int callingUid = Binder.getCallingUid();
+ final Computer snapshot = snapshotComputer();
+ snapshot.enforceCrossUserPermission(callingUid, userId, false /* requireFullPermission */,
+ false /* checkShell */, "setSplashScreenTheme");
+ enforceOwnerRights(snapshot, packageName, callingUid);
+
+ PackageStateInternal packageState = filterPackageStateForInstalledAndFiltered(snapshot,
+ packageName, callingUid, userId);
+ if (packageState == null) {
+ return;
}
- if (accessGranted) {
- ApplicationPackageManager.invalidateGetPackagesForUidCache();
- }
+ commitPackageStateMutation(null, packageName, state ->
+ state.userState(userId).setSplashScreenTheme(themeId));
}
@Override
- public boolean isInstantAppInstallerComponent(ComponentName component) {
- final ActivityInfo instantAppInstallerActivity = mInstantAppInstallerActivity;
- return instantAppInstallerActivity != null
- && instantAppInstallerActivity.getComponentName().equals(component);
+ public void setUpdateAvailable(String packageName, boolean updateAvailable) {
+ mContext.enforceCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES, null);
+ commitPackageStateMutation(null, packageName, state ->
+ state.setUpdateAvailable(updateAvailable));
}
@Override
- public void pruneInstantApps() {
- mInstantAppRegistry.pruneInstantApps(snapshotComputer());
+ public void unregisterMoveCallback(IPackageMoveObserver callback) {
+ mContext.enforceCallingOrSelfPermission(
+ Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS, null);
+ mMoveCallbacks.unregister(callback);
}
@Override
- public void pruneCachedApksInApex(@NonNull List<PackageInfo> apexPackages) {
- if (mCacheDir == null) {
- return;
- }
+ public void verifyPendingInstall(int id, int verificationCode) throws RemoteException {
+ mContext.enforceCallingOrSelfPermission(
+ Manifest.permission.PACKAGE_VERIFICATION_AGENT,
+ "Only package verification agents can verify applications");
+ final int callingUid = Binder.getCallingUid();
- final PackageCacher cacher = new PackageCacher(mCacheDir);
- synchronized (mLock) {
- for (int i = 0, size = apexPackages.size(); i < size; i++) {
- final List<String> apkNames =
- mApexManager.getApksInApex(apexPackages.get(i).packageName);
- for (int j = 0, apksInApex = apkNames.size(); j < apksInApex; j++) {
- final AndroidPackage pkg = getPackage(apkNames.get(j));
- cacher.cleanCachedResult(new File(pkg.getPath()));
- }
- }
- }
+ final Message msg = mHandler.obtainMessage(PackageManagerService.PACKAGE_VERIFIED);
+ final PackageVerificationResponse response = new PackageVerificationResponse(
+ verificationCode, callingUid);
+ msg.arg1 = id;
+ msg.obj = response;
+ mHandler.sendMessage(msg);
}
@Override
- public String getSetupWizardPackageName() {
- return mSetupWizardPackage;
+ public void requestPackageChecksums(@NonNull String packageName, boolean includeSplits,
+ @Checksum.TypeMask int optional, @Checksum.TypeMask int required,
+ @Nullable List trustedInstallers,
+ @NonNull IOnChecksumsReadyListener onChecksumsReadyListener, int userId) {
+ requestChecksumsInternal(snapshotComputer(), packageName, includeSplits, optional,
+ required, trustedInstallers, onChecksumsReadyListener, userId,
+ mInjector.getBackgroundExecutor(), mInjector.getBackgroundHandler());
}
- public void setExternalSourcesPolicy(ExternalSourcesPolicy policy) {
- if (policy != null) {
- mExternalSourcesPolicy = policy;
+ @Override
+ public void notifyPackagesReplacedReceived(String[] packages) {
+ Computer computer = snapshotComputer();
+ ArraySet<String> packagesToNotify = computer.getNotifyPackagesForReplacedReceived(packages);
+ for (int index = 0; index < packagesToNotify.size(); index++) {
+ notifyInstallObserver(packagesToNotify.valueAt(index), false /* killApp */);
}
}
@Override
- public boolean isPackagePersistent(String packageName) {
- final PackageStateInternal packageState = getPackageStateInternal(packageName);
- if (packageState == null) {
- return false;
+ public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
+ throws RemoteException {
+ try {
+ return super.onTransact(code, data, reply, flags);
+ } catch (RuntimeException e) {
+ if (!(e instanceof SecurityException) && !(e instanceof IllegalArgumentException)
+ && !(e instanceof ParcelableException)) {
+ Slog.wtf(TAG, "Package Manager Unexpected Exception", e);
+ }
+ throw e;
}
+ }
- AndroidPackage pkg = packageState.getPkg();
- return pkg != null && pkg.isSystem() && pkg.isPersistent();
+ @Override
+ public void onShellCommand(FileDescriptor in, FileDescriptor out,
+ FileDescriptor err, String[] args, ShellCallback callback,
+ ResultReceiver resultReceiver) {
+ (new PackageManagerShellCommand(this, mContext,
+ mDomainVerificationManager.getShell()))
+ .exec(this, in, out, err, args, callback, resultReceiver);
}
+ @SuppressWarnings("resource")
@Override
- public List<PackageInfo> getOverlayPackages(int userId) {
- final ArrayList<PackageInfo> overlayPackages = new ArrayList<>();
- forEachPackageState(packageState -> {
- final AndroidPackage pkg = packageState.getPkg();
- if (pkg != null && pkg.getOverlayTarget() != null) {
- PackageInfo pkgInfo = generatePackageInfo(packageState, 0, userId);
- if (pkgInfo != null) {
- overlayPackages.add(pkgInfo);
- }
+ protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw)) return;
+ new DumpHelper(PackageManagerService.this).doDump(fd, pw, args);
+ }
+ }
+
+ private class PackageManagerLocalImpl implements PackageManagerLocal {
+ @Override
+ public void reconcileSdkData(@Nullable String volumeUuid, @NonNull String packageName,
+ @NonNull List<String> subDirNames, int userId, int appId, int previousAppId,
+ @NonNull String seInfo, int flags) throws IOException {
+ synchronized (mInstallLock) {
+ ReconcileSdkDataArgs args = mInstaller.buildReconcileSdkDataArgs(volumeUuid,
+ packageName, subDirNames, userId, appId, seInfo,
+ flags);
+ args.previousAppId = previousAppId;
+ try {
+ mInstaller.reconcileSdkData(args);
+ } catch (InstallerException e) {
+ throw new IOException(e.getMessage());
}
- });
+ }
+ }
+ }
- return overlayPackages;
+ private class PackageManagerInternalImpl extends PackageManagerInternalBase {
+
+ public PackageManagerInternalImpl() {
+ super(PackageManagerService.this);
}
+ @NonNull
@Override
- public List<String> getTargetPackageNames(int userId) {
- List<String> targetPackages = new ArrayList<>();
- forEachPackageState(packageState -> {
- final AndroidPackage pkg = packageState.getPkg();
- if (pkg != null && !pkg.isOverlay()) {
- targetPackages.add(pkg.getPackageName());
- }
- });
- return targetPackages;
+ protected Context getContext() {
+ return mContext;
}
+ @NonNull
@Override
- public boolean setEnabledOverlayPackages(int userId, @NonNull String targetPackageName,
- @Nullable OverlayPaths overlayPaths,
- @NonNull Set<String> outUpdatedPackageNames) {
- return PackageManagerService.this.setEnabledOverlayPackages(userId, targetPackageName,
- overlayPaths, outUpdatedPackageNames);
+ protected PermissionManagerServiceInternal getPermissionManager() {
+ return mPermissionManager;
}
+ @NonNull
@Override
- public ResolveInfo resolveIntent(Intent intent, String resolvedType,
- @PackageManager.ResolveInfoFlagsBits long flags,
- @PackageManagerInternal.PrivateResolveFlags long privateResolveFlags, int userId,
- boolean resolveForStart, int filterCallingUid) {
- return mResolveIntentHelper.resolveIntentInternal(snapshotComputer(),
- intent, resolvedType, flags, privateResolveFlags, userId, resolveForStart,
- filterCallingUid);
+ protected AppDataHelper getAppDataHelper() {
+ return mAppDataHelper;
}
+ @NonNull
@Override
- public ResolveInfo resolveService(Intent intent, String resolvedType,
- @PackageManager.ResolveInfoFlagsBits long flags, int userId, int callingUid) {
- return mResolveIntentHelper.resolveServiceInternal(snapshotComputer(), intent,
- resolvedType, flags, userId, callingUid);
+ protected PackageObserverHelper getPackageObserverHelper() {
+ return mPackageObserverHelper;
}
+ @NonNull
@Override
- public ProviderInfo resolveContentProvider(String name,
- @PackageManager.ResolveInfoFlagsBits long flags, int userId, int callingUid) {
- return PackageManagerService.this.mComputer
- .resolveContentProvider(name, flags, userId,callingUid);
+ protected ResolveIntentHelper getResolveIntentHelper() {
+ return mResolveIntentHelper;
}
+ @NonNull
@Override
- public void addIsolatedUid(int isolatedUid, int ownerUid) {
- synchronized (mLock) {
- mIsolatedOwners.put(isolatedUid, ownerUid);
- }
+ protected SuspendPackageHelper getSuspendPackageHelper() {
+ return mSuspendPackageHelper;
}
+ @NonNull
@Override
- public void removeIsolatedUid(int isolatedUid) {
- synchronized (mLock) {
- mIsolatedOwners.delete(isolatedUid);
- }
+ protected ProtectedPackages getProtectedPackages() {
+ return mProtectedPackages;
}
+ @NonNull
@Override
- public int getUidTargetSdkVersion(int uid) {
- return PackageManagerService.this.getUidTargetSdkVersion(uid);
+ protected UserNeedsBadgingCache getUserNeedsBadging() {
+ return mUserNeedsBadging;
}
+ @NonNull
@Override
- public int getPackageTargetSdkVersion(String packageName) {
- final PackageStateInternal packageState = getPackageStateInternal(packageName);
- if (packageState != null && packageState.getPkg() != null) {
- return packageState.getPkg().getTargetSdkVersion();
- }
- return Build.VERSION_CODES.CUR_DEVELOPMENT;
+ protected InstantAppRegistry getInstantAppRegistry() {
+ return mInstantAppRegistry;
}
+ @NonNull
@Override
- public boolean canAccessInstantApps(int callingUid, int userId) {
- return PackageManagerService.this.canViewInstantApps(callingUid, userId);
+ protected ApexManager getApexManager() {
+ return mApexManager;
}
+ @NonNull
@Override
- public boolean canAccessComponent(int callingUid, @NonNull ComponentName component,
- @UserIdInt int userId) {
- return mComputer.canAccessComponent(callingUid, component, userId);
+ protected DexManager getDexManager() {
+ return mDexManager;
}
@Override
- public boolean hasInstantApplicationMetadata(String packageName, int userId) {
- return mInstantAppRegistry.hasInstantApplicationMetadata(packageName, userId);
+ public boolean isPlatformSigned(String packageName) {
+ PackageStateInternal packageState = snapshot().getPackageStateInternal(packageName);
+ if (packageState == null) {
+ return false;
+ }
+ SigningDetails signingDetails = packageState.getSigningDetails();
+ return signingDetails.hasAncestorOrSelf(mPlatformPackage.getSigningDetails())
+ || mPlatformPackage.getSigningDetails().checkCapability(signingDetails,
+ SigningDetails.CertCapabilities.PERMISSION);
}
@Override
- public void notifyPackageUse(String packageName, int reason) {
- synchronized (mLock) {
- PackageManagerService.this.notifyPackageUseInternal(packageName, reason);
+ public boolean isDataRestoreSafe(byte[] restoringFromSigHash, String packageName) {
+ final Computer snapshot = snapshot();
+ SigningDetails sd = snapshot.getSigningDetails(packageName);
+ if (sd == null) {
+ return false;
}
+ return sd.hasSha256Certificate(restoringFromSigHash,
+ SigningDetails.CertCapabilities.INSTALLED_DATA);
}
@Override
- public void onPackageProcessKilledForUninstall(String packageName) {
- mHandler.post(() -> PackageManagerService.this.notifyInstallObserver(packageName,
- true /* killApp */));
+ public boolean isDataRestoreSafe(Signature restoringFromSig, String packageName) {
+ final Computer snapshot = snapshot();
+ SigningDetails sd = snapshot.getSigningDetails(packageName);
+ if (sd == null) {
+ return false;
+ }
+ return sd.hasCertificate(restoringFromSig,
+ SigningDetails.CertCapabilities.INSTALLED_DATA);
}
@Override
- public SparseArray<String> getAppsWithSharedUserIds() {
- return mComputer.getAppsWithSharedUserIds();
+ public boolean hasSignatureCapability(int serverUid, int clientUid,
+ @SigningDetails.CertCapabilities int capability) {
+ final Computer snapshot = snapshot();
+ SigningDetails serverSigningDetails = snapshot.getSigningDetails(serverUid);
+ SigningDetails clientSigningDetails = snapshot.getSigningDetails(clientUid);
+ return serverSigningDetails.checkCapability(clientSigningDetails, capability)
+ || clientSigningDetails.hasAncestorOrSelf(serverSigningDetails);
}
@Override
- @NonNull
- public String[] getSharedUserPackagesForPackage(String packageName, int userId) {
- return mComputer.getSharedUserPackagesForPackage(packageName, userId);
+ public PackageList getPackageList(@Nullable PackageListObserver observer) {
+ final ArrayList<String> list = new ArrayList<>();
+ PackageManagerService.this.forEachPackageState(snapshot(), packageState -> {
+ AndroidPackage pkg = packageState.getPkg();
+ if (pkg != null) {
+ list.add(pkg.getPackageName());
+ }
+ });
+ final PackageList packageList = new PackageList(list, observer);
+ if (observer != null) {
+ mPackageObserverHelper.addObserver(packageList);
+ }
+ return packageList;
}
@Override
- public ArrayMap<String, ProcessInfo> getProcessesForUid(int uid) {
- return mComputer.getProcessesForUid(uid);
+ public @Nullable
+ String getDisabledSystemPackageName(@NonNull String packageName) {
+ PackageStateInternal disabledPkgSetting = snapshot().getDisabledSystemPackage(
+ packageName);
+ AndroidPackage disabledPkg = disabledPkgSetting == null
+ ? null : disabledPkgSetting.getPkg();
+ return disabledPkg == null ? null : disabledPkg.getPackageName();
}
@Override
- public int[] getPermissionGids(String permissionName, int userId) {
- return mPermissionManager.getPermissionGids(permissionName, userId);
+ public boolean isResolveActivityComponent(ComponentInfo component) {
+ return mResolveActivity.packageName.equals(component.packageName)
+ && mResolveActivity.name.equals(component.name);
}
@Override
- public boolean isOnlyCoreApps() {
- return PackageManagerService.this.isOnlyCoreApps();
+ public long getCeDataInode(String packageName, int userId) {
+ final PackageStateInternal packageState =
+ snapshot().getPackageStateInternal(packageName);
+ if (packageState == null) {
+ return 0;
+ } else {
+ return packageState.getUserStateOrDefault(userId).getCeDataInode();
+ }
}
@Override
- public void freeStorage(String volumeUuid, long bytes,
- @StorageManager.AllocateFlags int flags) throws IOException {
- PackageManagerService.this.freeStorage(volumeUuid, bytes, flags);
+ public void removeAllNonSystemPackageSuspensions(int userId) {
+ final Computer computer = snapshotComputer();
+ final String[] allPackages = computer.getAllAvailablePackageNames();
+ mSuspendPackageHelper.removeSuspensionsBySuspendingPackage(computer, allPackages,
+ (suspendingPackage) -> !PLATFORM_PACKAGE_NAME.equals(suspendingPackage),
+ userId);
}
@Override
- public void forEachPackageSetting(Consumer<PackageSetting> actionLocked) {
- PackageManagerService.this.forEachPackageSetting(actionLocked);
+ public void flushPackageRestrictions(int userId) {
+ synchronized (mLock) {
+ PackageManagerService.this.flushPackageRestrictionsAsUserInternalLocked(userId);
+ }
}
@Override
- public void forEachPackageState(Consumer<PackageStateInternal> action) {
- PackageManagerService.this.forEachPackageState(action);
+ public void setDeviceAndProfileOwnerPackages(
+ int deviceOwnerUserId, String deviceOwnerPackage,
+ SparseArray<String> profileOwnerPackages) {
+ mProtectedPackages.setDeviceAndProfileOwnerPackages(
+ deviceOwnerUserId, deviceOwnerPackage, profileOwnerPackages);
+ final ArraySet<Integer> usersWithPoOrDo = new ArraySet<>();
+ if (deviceOwnerPackage != null) {
+ usersWithPoOrDo.add(deviceOwnerUserId);
+ }
+ final int sz = profileOwnerPackages.size();
+ for (int i = 0; i < sz; i++) {
+ if (profileOwnerPackages.valueAt(i) != null) {
+ removeAllNonSystemPackageSuspensions(profileOwnerPackages.keyAt(i));
+ }
+ }
}
@Override
- public void forEachPackage(Consumer<AndroidPackage> action) {
- PackageManagerService.this.forEachPackage(action);
+ public void pruneCachedApksInApex(@NonNull List<PackageInfo> apexPackages) {
+ if (mCacheDir == null) {
+ return;
+ }
+
+ final PackageCacher cacher = new PackageCacher(mCacheDir);
+ synchronized (mLock) {
+ final Computer snapshot = snapshot();
+ for (int i = 0, size = apexPackages.size(); i < size; i++) {
+ final List<String> apkNames =
+ mApexManager.getApksInApex(apexPackages.get(i).packageName);
+ for (int j = 0, apksInApex = apkNames.size(); j < apksInApex; j++) {
+ final AndroidPackage pkg = snapshot.getPackage(apkNames.get(j));
+ cacher.cleanCachedResult(new File(pkg.getPath()));
+ }
+ }
+ }
}
@Override
- public void forEachInstalledPackage(@NonNull Consumer<AndroidPackage> action,
- @UserIdInt int userId) {
- PackageManagerService.this.forEachInstalledPackage(action, userId);
+ public void setExternalSourcesPolicy(ExternalSourcesPolicy policy) {
+ if (policy != null) {
+ mExternalSourcesPolicy = policy;
+ }
}
@Override
- public ArraySet<String> getEnabledComponents(String packageName, int userId) {
- final PackageStateInternal packageState = getPackageStateInternal(packageName);
+ public boolean isPackagePersistent(String packageName) {
+ final PackageStateInternal packageState =
+ snapshot().getPackageStateInternal(packageName);
if (packageState == null) {
- return new ArraySet<>();
+ return false;
}
- return packageState.getUserStateOrDefault(userId).getEnabledComponents();
+
+ AndroidPackage pkg = packageState.getPkg();
+ return pkg != null && pkg.isSystem() && pkg.isPersistent();
}
@Override
- public ArraySet<String> getDisabledComponents(String packageName, int userId) {
- final PackageStateInternal packageState = getPackageStateInternal(packageName);
- if (packageState == null) {
- return new ArraySet<>();
+ public List<PackageInfo> getOverlayPackages(int userId) {
+ final Computer snapshot = snapshotComputer();
+ final ArrayList<PackageInfo> overlayPackages = new ArrayList<>();
+ final ArrayMap<String, ? extends PackageStateInternal> packageStates =
+ snapshot.getPackageStates();
+ for (int index = 0; index < packageStates.size(); index++) {
+ final PackageStateInternal packageState = packageStates.valueAt(index);
+ final AndroidPackage pkg = packageState.getPkg();
+ if (pkg != null && pkg.getOverlayTarget() != null) {
+ PackageInfo pkgInfo = snapshot.generatePackageInfo(packageState, 0, userId);
+ if (pkgInfo != null) {
+ overlayPackages.add(pkgInfo);
+ }
+ }
}
- return packageState.getUserStateOrDefault(userId).getDisabledComponents();
+
+ return overlayPackages;
}
@Override
- public @PackageManager.EnabledState int getApplicationEnabledState(
- String packageName, int userId) {
- final PackageStateInternal packageState = getPackageStateInternal(packageName);
- if (packageState == null) {
- return COMPONENT_ENABLED_STATE_DEFAULT;
+ public List<String> getTargetPackageNames(int userId) {
+ List<String> targetPackages = new ArrayList<>();
+ PackageManagerService.this.forEachPackageState(snapshot(), packageState -> {
+ final AndroidPackage pkg = packageState.getPkg();
+ if (pkg != null && !pkg.isOverlay()) {
+ targetPackages.add(pkg.getPackageName());
+ }
+ });
+ return targetPackages;
+ }
+
+ @Override
+ public boolean setEnabledOverlayPackages(int userId, @NonNull String targetPackageName,
+ @Nullable OverlayPaths overlayPaths,
+ @NonNull Set<String> outUpdatedPackageNames) {
+ return PackageManagerService.this.setEnabledOverlayPackages(userId, targetPackageName,
+ overlayPaths, outUpdatedPackageNames);
+ }
+
+ @Override
+ public void addIsolatedUid(int isolatedUid, int ownerUid) {
+ synchronized (mLock) {
+ mIsolatedOwners.put(isolatedUid, ownerUid);
}
- return packageState.getUserStateOrDefault(userId).getEnabledState();
}
@Override
- public @PackageManager.EnabledState int getComponentEnabledSetting(
- @NonNull ComponentName componentName, int callingUid, int userId) {
- return PackageManagerService.this.mComputer.getComponentEnabledSettingInternal(
- componentName, callingUid, userId);
+ public void removeIsolatedUid(int isolatedUid) {
+ synchronized (mLock) {
+ mIsolatedOwners.delete(isolatedUid);
+ }
}
@Override
- public void setEnableRollbackCode(int token, int enableRollbackCode) {
- PackageManagerService.this.setEnableRollbackCode(token, enableRollbackCode);
+ public void notifyPackageUse(String packageName, int reason) {
+ synchronized (mLock) {
+ PackageManagerService.this.notifyPackageUseInternal(packageName, reason);
+ }
}
/**
@@ -7546,11 +6371,6 @@ public class PackageManagerService extends IPackageManager.Stub
return mArtManagerService.compileLayouts(pkg);
}
- @Override
- public void finishPackageInstall(int token, boolean didLaunch) {
- PackageManagerService.this.finishPackageInstall(token, didLaunch);
- }
-
@Nullable
@Override
public String removeLegacyDefaultBrowserPackageName(int userId) {
@@ -7560,16 +6380,6 @@ public class PackageManagerService extends IPackageManager.Stub
}
@Override
- public boolean isApexPackage(String packageName) {
- return PackageManagerService.this.mApexManager.isApexPackage(packageName);
- }
-
- @Override
- public List<String> getApksInApex(String apexPackageName) {
- return PackageManagerService.this.mApexManager.getApksInApex(apexPackageName);
- }
-
- @Override
public void uninstallApex(String packageName, long versionCode, int userId,
IntentSender intentSender, int flags) {
final int callerUid = Binder.getCallingUid();
@@ -7644,11 +6454,6 @@ public class PackageManagerService extends IPackageManager.Stub
}
@Override
- public boolean isCallerInstallerOfRecord(@NonNull AndroidPackage pkg, int callingUid) {
- return mComputer.isCallerInstallerOfRecord(pkg, callingUid);
- }
-
- @Override
public boolean isPermissionUpgradeNeeded(int userId) {
return mSettings.isPermissionUpgradeNeeded(userId);
}
@@ -7662,13 +6467,9 @@ public class PackageManagerService extends IPackageManager.Stub
}
@Override
- public List<String> getMimeGroup(String packageName, String mimeGroup) {
- return PackageManagerService.this.getMimeGroupInternal(packageName, mimeGroup);
- }
-
- @Override
public void setVisibilityLogging(String packageName, boolean enable) {
- final PackageStateInternal packageState = getPackageStateInternal(packageName);
+ final PackageStateInternal packageState =
+ snapshot().getPackageStateInternal(packageName);
if (packageState == null) {
throw new IllegalStateException("No package found for " + packageName);
}
@@ -7676,12 +6477,6 @@ public class PackageManagerService extends IPackageManager.Stub
}
@Override
- public boolean isSystemPackage(@NonNull String packageName) {
- return packageName.equals(
- PackageManagerService.this.ensureSystemPackageName(packageName));
- }
-
- @Override
public void clearBlockUninstallForUser(@UserIdInt int userId) {
synchronized (mLock) {
mSettings.clearBlockUninstallLPw(userId);
@@ -7690,21 +6485,11 @@ public class PackageManagerService extends IPackageManager.Stub
}
@Override
- public void unsuspendForSuspendingPackage(final String packageName, int affectedUser) {
- PackageManagerService.this.unsuspendForSuspendingPackage(snapshotComputer(),
- packageName, affectedUser);
- }
-
- @Override
- public boolean isSuspendingAnyPackages(String suspendingPackage, int userId) {
- return PackageManagerService.this.isSuspendingAnyPackages(suspendingPackage, userId);
- }
-
- @Override
public boolean registerInstalledLoadingProgressCallback(String packageName,
PackageManagerInternal.InstalledLoadingProgressCallback callback, int userId) {
- final PackageStateInternal ps =
- getPackageStateInstalledFiltered(packageName, Binder.getCallingUid(), userId);
+ final Computer snapshot = snapshotComputer();
+ final PackageStateInternal ps = filterPackageStateForInstalledAndFiltered(snapshot,
+ packageName, Binder.getCallingUid(), userId);
if (ps == null) {
return false;
}
@@ -7725,8 +6510,9 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public IncrementalStatesInfo getIncrementalStatesInfo(
@NonNull String packageName, int filterCallingUid, int userId) {
- final PackageStateInternal ps =
- getPackageStateInstalledFiltered(packageName, filterCallingUid, userId);
+ final Computer snapshot = snapshotComputer();
+ final PackageStateInternal ps = filterPackageStateForInstalledAndFiltered(snapshot,
+ packageName, filterCallingUid, userId);
if (ps == null) {
return null;
}
@@ -7734,64 +6520,23 @@ public class PackageManagerService extends IPackageManager.Stub
}
@Override
- public void requestChecksums(@NonNull String packageName, boolean includeSplits,
- @Checksum.TypeMask int optional, @Checksum.TypeMask int required,
- @Nullable List trustedInstallers,
- @NonNull IOnChecksumsReadyListener onChecksumsReadyListener, int userId,
- @NonNull Executor executor, @NonNull Handler handler) {
- requestChecksumsInternal(packageName, includeSplits, optional, required,
- trustedInstallers, onChecksumsReadyListener, userId, executor, handler);
- }
-
- @Override
- public boolean isPackageFrozen(@NonNull String packageName,
- int callingUid, int userId) {
- return PackageManagerService.this.getPackageStartability(
- packageName, callingUid, userId) == PACKAGE_STARTABILITY_FROZEN;
- }
-
- @Override
- public long deleteOatArtifactsOfPackage(String packageName) {
- return PackageManagerService.this.deleteOatArtifactsOfPackage(packageName);
- }
-
- @Override
- public void reconcileAppsData(int userId, @StorageManager.StorageFlags int flags,
- boolean migrateAppsData) {
- PackageManagerService.this.mAppDataHelper.reconcileAppsData(userId, flags,
- migrateAppsData);
- }
-
- @Override
- @NonNull
- public ArraySet<PackageStateInternal> getSharedUserPackages(int sharedUserAppId) {
- return PackageManagerService.this.mComputer.getSharedUserPackages(sharedUserAppId);
- }
-
- @Override
- @Nullable
- public SharedUserApi getSharedUserApi(int sharedUserAppId) {
- return mComputer.getSharedUser(sharedUserAppId);
- }
-
- @NonNull
- @Override
- public PackageStateMutator.InitialState recordInitialState() {
- return PackageManagerService.this.recordInitialState();
- }
+ public boolean isSameApp(@Nullable String packageName, int callingUid, int userId) {
+ if (packageName == null) {
+ return false;
+ }
- @Nullable
- @Override
- public PackageStateMutator.Result commitPackageStateMutation(
- @Nullable PackageStateMutator.InitialState state,
- @NonNull Consumer<PackageStateMutator> consumer) {
- return PackageManagerService.this.commitPackageStateMutation(state, consumer);
+ if (Process.isSdkSandboxUid(callingUid)) {
+ return packageName.equals(mRequiredSdkSandboxPackage);
+ }
+ Computer snapshot = snapshot();
+ int uid = snapshot.getPackageUid(packageName, 0, userId);
+ return UserHandle.isSameApp(uid, callingUid);
}
- @NonNull
@Override
- public Computer snapshot() {
- return snapshotComputer();
+ public void onPackageProcessKilledForUninstall(String packageName) {
+ mHandler.post(() -> PackageManagerService.this.notifyInstallObserver(packageName,
+ true /* killApp */));
}
}
@@ -7876,23 +6621,6 @@ public class PackageManagerService extends IPackageManager.Stub
return true;
}
- @Override
- public int getRuntimePermissionsVersion(@UserIdInt int userId) {
- Preconditions.checkArgumentNonnegative(userId);
- enforceAdjustRuntimePermissionsPolicyOrUpgradeRuntimePermissions(
- "getRuntimePermissionVersion");
- return mSettings.getDefaultRuntimePermissionsVersion(userId);
- }
-
- @Override
- public void setRuntimePermissionsVersion(int version, @UserIdInt int userId) {
- Preconditions.checkArgumentNonnegative(version);
- Preconditions.checkArgumentNonnegative(userId);
- enforceAdjustRuntimePermissionsPolicyOrUpgradeRuntimePermissions(
- "setRuntimePermissionVersion");
- mSettings.setDefaultRuntimePermissionsVersion(version, userId);
- }
-
private void enforceAdjustRuntimePermissionsPolicyOrUpgradeRuntimePermissions(
@NonNull String message) {
if (mContext.checkCallingOrSelfPermission(
@@ -7923,24 +6651,6 @@ public class PackageManagerService extends IPackageManager.Stub
return mSettings.getDisabledSystemPkgLPr(packageName);
}
- @VisibleForTesting(visibility = Visibility.PRIVATE)
- @Nullable
- PackageStateInternal getPackageStateInternal(String packageName) {
- return mComputer.getPackageStateInternal(packageName);
- }
-
- @Nullable
- PackageStateInternal getPackageStateInternal(String packageName, int callingUid) {
- return mComputer.getPackageStateInternal(packageName, callingUid);
- }
-
- @Nullable
- PackageStateInternal getPackageStateInstalledFiltered(@NonNull String packageName,
- int callingUid, @UserIdInt int userId) {
- return filterPackageStateForInstalledAndFiltered(mComputer, packageName, callingUid,
- userId);
- }
-
@Nullable
private PackageStateInternal filterPackageStateForInstalledAndFiltered(
@NonNull Computer computer, @NonNull String packageName, int callingUid,
@@ -7956,22 +6666,8 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- @Nullable
- private PackageState getPackageState(String packageName) {
- return mComputer.getPackageStateCopied(packageName);
- }
-
- @NonNull
- ArrayMap<String, ? extends PackageStateInternal> getPackageStates() {
- Computer computer = snapshotComputer();
- if (computer == mLiveComputer) {
- return new ArrayMap<>(computer.getPackageStates());
- } else {
- return computer.getPackageStates();
- }
- }
-
- private void forEachPackageSetting(Consumer<PackageSetting> actionLocked) {
+ @Deprecated
+ void forEachPackageSetting(Consumer<PackageSetting> actionLocked) {
synchronized (mLock) {
int size = mSettings.getPackagesLocked().size();
for (int index = 0; index < size; index++) {
@@ -7980,13 +6676,13 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- void forEachPackageState(Consumer<PackageStateInternal> consumer) {
- forEachPackageState(mComputer.getPackageStates(), consumer);
+ void forEachPackageState(@NonNull Computer snapshot, Consumer<PackageStateInternal> consumer) {
+ forEachPackageState(snapshot.getPackageStates(), consumer);
}
- void forEachPackage(Consumer<AndroidPackage> consumer) {
+ void forEachPackage(@NonNull Computer snapshot, Consumer<AndroidPackage> consumer) {
final ArrayMap<String, ? extends PackageStateInternal> packageStates =
- mComputer.getPackageStates();
+ snapshot.getPackageStates();
int size = packageStates.size();
for (int index = 0; index < size; index++) {
PackageStateInternal packageState = packageStates.valueAt(index);
@@ -8006,7 +6702,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- void forEachInstalledPackage(@NonNull Consumer<AndroidPackage> action,
+ void forEachInstalledPackage(@NonNull Computer snapshot, @NonNull Consumer<AndroidPackage> action,
@UserIdInt int userId) {
Consumer<PackageStateInternal> actionWrapped = packageState -> {
if (packageState.getPkg() != null
@@ -8014,30 +6710,13 @@ public class PackageManagerService extends IPackageManager.Stub
action.accept(packageState.getPkg());
}
};
- forEachPackageState(mComputer.getPackageStates(), actionWrapped);
+ forEachPackageState(snapshot.getPackageStates(), actionWrapped);
}
boolean isHistoricalPackageUsageAvailable() {
return mPackageUsage.isHistoricalPackageUsageAvailable();
}
- /**
- * Logs process start information (including base APK hash) to the security log.
- * @hide
- */
- @Override
- public void logAppProcessStartIfNeeded(String packageName, String processName, int uid,
- String seinfo, String apkFile, int pid) {
- if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
- return;
- }
- if (!SecurityLog.isLoggingEnabled()) {
- return;
- }
- mProcessLoggingHandler.logAppProcessStart(mContext, mPmInternal, apkFile, packageName,
- processName, uid, seinfo, pid);
- }
-
public CompilerStats.PackageStats getOrCreateCompilerPackageStats(AndroidPackage pkg) {
return getOrCreateCompilerPackageStats(pkg.getPackageName());
}
@@ -8046,77 +6725,39 @@ public class PackageManagerService extends IPackageManager.Stub
return mCompilerStats.getOrCreatePackageStats(pkgName);
}
- @Override
- public boolean isAutoRevokeWhitelisted(String packageName) {
- int mode = mInjector.getSystemService(AppOpsManager.class).checkOpNoThrow(
- AppOpsManager.OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED,
- Binder.getCallingUid(), packageName);
- return mode == MODE_IGNORED;
- }
-
- @PackageManager.InstallReason
- @Override
- public int getInstallReason(@NonNull String packageName, @UserIdInt int userId) {
- return mComputer.getInstallReason(packageName, userId);
- }
-
- @Override
- public boolean canRequestPackageInstalls(String packageName, int userId) {
- return mComputer.canRequestPackageInstalls(packageName, Binder.getCallingUid(), userId,
- true /* throwIfPermNotDeclared*/);
- }
-
- /**
- * Returns true if the system or user is explicitly preventing an otherwise valid installer to
- * complete an install. This includes checks like unknown sources and user restrictions.
- */
- public boolean isInstallDisabledForPackage(String packageName, int uid, int userId) {
- return mComputer.isInstallDisabledForPackage(packageName, uid, userId);
- }
-
- @Override
- public ComponentName getInstantAppResolverSettingsComponent() {
- return mInstantAppResolverSettingsComponent;
- }
-
- @Override
- public ComponentName getInstantAppInstallerComponent() {
- if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
- return null;
+ void grantImplicitAccess(@NonNull Computer snapshot, @UserIdInt int userId,
+ Intent intent, @AppIdInt int recipientAppId, int visibleUid, boolean direct,
+ boolean retainOnUpdate) {
+ final AndroidPackage visiblePackage = snapshot.getPackage(visibleUid);
+ final int recipientUid = UserHandle.getUid(userId, recipientAppId);
+ if (visiblePackage == null || snapshot.getPackage(recipientUid) == null) {
+ return;
}
- return mInstantAppInstallerActivity == null
- ? null : mInstantAppInstallerActivity.getComponentName();
- }
- @Override
- public String getInstantAppAndroidId(String packageName, int userId) {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_INSTANT_APPS,
- "getInstantAppAndroidId");
- enforceCrossUserPermission(Binder.getCallingUid(), userId, true /* requireFullPermission */,
- false /* checkShell */, "getInstantAppAndroidId");
- // Make sure the target is an Instant App.
- if (!isInstantApp(packageName, userId)) {
- return null;
+ final boolean instantApp = snapshot.isInstantAppInternal(
+ visiblePackage.getPackageName(), userId, visibleUid);
+ final boolean accessGranted;
+ if (instantApp) {
+ if (!direct) {
+ // if the interaction that lead to this granting access to an instant app
+ // was indirect (i.e.: URI permission grant), do not actually execute the
+ // grant.
+ return;
+ }
+ accessGranted = mInstantAppRegistry.grantInstantAccess(userId, intent,
+ recipientAppId, UserHandle.getAppId(visibleUid) /*instantAppId*/);
+ } else {
+ accessGranted = mAppsFilter.grantImplicitAccess(recipientUid, visibleUid,
+ retainOnUpdate);
}
- return mInstantAppRegistry.getInstantAppAndroidId(packageName, userId);
- }
- @Override
- public void grantImplicitAccess(int recipientUid, @NonNull String visibleAuthority) {
- final int callingUid = Binder.getCallingUid();
- final int recipientUserId = UserHandle.getUserId(recipientUid);
- final ProviderInfo providerInfo =
- mComputer.getGrantImplicitAccessProviderInfo(recipientUid, visibleAuthority);
- if (providerInfo == null) {
- return;
+ if (accessGranted) {
+ ApplicationPackageManager.invalidateGetPackagesForUidCache();
}
- int visibleUid = providerInfo.applicationInfo.uid;
- mPmInternal.grantImplicitAccess(recipientUserId, null /*Intent*/,
- UserHandle.getAppId(recipientUid), visibleUid, false /*direct*/);
}
- boolean canHaveOatDir(String packageName) {
- final PackageStateInternal packageState = getPackageStateInternal(packageName);
+ boolean canHaveOatDir(@NonNull Computer snapshot, String packageName) {
+ final PackageStateInternal packageState = snapshot.getPackageStateInternal(packageName);
if (packageState == null || packageState.getPkg() == null) {
return false;
}
@@ -8124,8 +6765,8 @@ public class PackageManagerService extends IPackageManager.Stub
packageState.getTransientState().isUpdatedSystemApp());
}
- long deleteOatArtifactsOfPackage(String packageName) {
- PackageStateInternal packageState = getPackageStateInternal(packageName);
+ long deleteOatArtifactsOfPackage(@NonNull Computer snapshot, String packageName) {
+ PackageStateInternal packageState = snapshot.getPackageStateInternal(packageName);
if (packageState == null || packageState.getPkg() == null) {
return -1; // error code of deleteOptimizedFiles
}
@@ -8133,107 +6774,9 @@ public class PackageManagerService extends IPackageManager.Stub
ArtUtils.createArtPackageInfo(packageState.getPkg(), packageState));
}
- @NonNull
- Set<String> getUnusedPackages(long downgradeTimeThresholdMillis) {
- return mComputer.getUnusedPackages(downgradeTimeThresholdMillis);
- }
-
- @Override
- public void setHarmfulAppWarning(@NonNull String packageName, @Nullable CharSequence warning,
- int userId) {
- final int callingUid = Binder.getCallingUid();
- final int callingAppId = UserHandle.getAppId(callingUid);
-
- enforceCrossUserPermission(callingUid, userId, true /*requireFullPermission*/,
- true /*checkShell*/, "setHarmfulAppInfo");
-
- if (callingAppId != Process.SYSTEM_UID && callingAppId != Process.ROOT_UID &&
- checkUidPermission(SET_HARMFUL_APP_WARNINGS, callingUid) != PERMISSION_GRANTED) {
- throw new SecurityException("Caller must have the "
- + SET_HARMFUL_APP_WARNINGS + " permission.");
- }
-
- PackageStateMutator.Result result = commitPackageStateMutation(null, packageName,
- packageState -> packageState.userState(userId)
- .setHarmfulAppWarning(warning == null ? null : warning.toString()));
- if (result.isSpecificPackageNull()) {
- throw new IllegalArgumentException("Unknown package: " + packageName);
- }
- scheduleWritePackageRestrictions(userId);
- }
-
- @Nullable
- @Override
- public CharSequence getHarmfulAppWarning(@NonNull String packageName, @UserIdInt int userId) {
- return mComputer.getHarmfulAppWarning(packageName, userId);
- }
-
- @Override
- public boolean isPackageStateProtected(@NonNull String packageName, @UserIdInt int userId) {
- final int callingUid = Binder.getCallingUid();
- final int callingAppId = UserHandle.getAppId(callingUid);
-
- enforceCrossUserPermission(callingUid, userId, false /*requireFullPermission*/,
- true /*checkShell*/, "isPackageStateProtected");
-
- if (callingAppId != Process.SYSTEM_UID && callingAppId != Process.ROOT_UID
- && checkUidPermission(MANAGE_DEVICE_ADMINS, callingUid) != PERMISSION_GRANTED) {
- throw new SecurityException("Caller must have the "
- + MANAGE_DEVICE_ADMINS + " permission.");
- }
-
- return mProtectedPackages.isPackageStateProtected(userId, packageName);
- }
-
- @Override
- public void sendDeviceCustomizationReadyBroadcast() {
- mContext.enforceCallingPermission(Manifest.permission.SEND_DEVICE_CUSTOMIZATION_READY,
- "sendDeviceCustomizationReadyBroadcast");
-
- final long ident = Binder.clearCallingIdentity();
- try {
- BroadcastHelper.sendDeviceCustomizationReadyBroadcast();
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
-
- @Override
- public void setMimeGroup(String packageName, String mimeGroup, List<String> mimeTypes) {
- enforceOwnerRights(packageName, Binder.getCallingUid());
- mimeTypes = CollectionUtils.emptyIfNull(mimeTypes);
- final PackageStateInternal packageState = getPackageStateInternal(packageName);
- Set<String> existingMimeTypes = packageState.getMimeGroups().get(mimeGroup);
- if (existingMimeTypes == null) {
- throw new IllegalArgumentException("Unknown MIME group " + mimeGroup
- + " for package " + packageName);
- }
- if (existingMimeTypes.size() == mimeTypes.size()
- && existingMimeTypes.containsAll(mimeTypes)) {
- return;
- }
-
- ArraySet<String> mimeTypesSet = new ArraySet<>(mimeTypes);
- commitPackageStateMutation(null, packageName, packageStateWrite -> {
- packageStateWrite.setMimeGroup(mimeGroup, mimeTypesSet);
- });
- if (mComponentResolver.updateMimeGroup(snapshotComputer(), packageName, mimeGroup)) {
- Binder.withCleanCallingIdentity(() ->
- mPreferredActivityHelper.clearPackagePreferredActivities(packageName,
- UserHandle.USER_ALL));
- }
-
- scheduleWriteSettings();
- }
-
- @Override
- public List<String> getMimeGroup(String packageName, String mimeGroup) {
- enforceOwnerRights(packageName, Binder.getCallingUid());
- return getMimeGroupInternal(packageName, mimeGroup);
- }
-
- private List<String> getMimeGroupInternal(String packageName, String mimeGroup) {
- final PackageStateInternal packageState = getPackageStateInternal(packageName);
+ List<String> getMimeGroupInternal(@NonNull Computer snapshot, String packageName,
+ String mimeGroup) {
+ final PackageStateInternal packageState = snapshot.getPackageStateInternal(packageName);
if (packageState == null) {
return Collections.emptyList();
}
@@ -8247,32 +6790,6 @@ public class PackageManagerService extends IPackageManager.Stub
return new ArrayList<>(mimeTypes);
}
- @Override
- public void setSplashScreenTheme(@NonNull String packageName, @Nullable String themeId,
- int userId) {
- final int callingUid = Binder.getCallingUid();
- enforceCrossUserPermission(callingUid, userId, false /* requireFullPermission */,
- false /* checkShell */, "setSplashScreenTheme");
- enforceOwnerRights(packageName, callingUid);
-
- PackageStateInternal packageState = getPackageStateInstalledFiltered(packageName,
- callingUid, userId);
- if (packageState == null) {
- return;
- }
-
- commitPackageStateMutation(null, packageName, state ->
- state.userState(userId).setSplashScreenTheme(themeId));
- }
-
- @Override
- public String getSplashScreenTheme(@NonNull String packageName, int userId) {
- PackageStateInternal packageState =
- getPackageStateInstalledFiltered(packageName, Binder.getCallingUid(), userId);
- return packageState == null ? null
- : packageState.getUserStateOrDefault(userId).getSplashScreenTheme();
- }
-
/**
* Temporary method that wraps mSettings.writeLPr() and calls mPermissionManager's
* writeLegacyPermissionsTEMP() beforehand.
@@ -8286,21 +6803,6 @@ public class PackageManagerService extends IPackageManager.Stub
}
@Override
- public IBinder getHoldLockToken() {
- if (!Build.IS_DEBUGGABLE) {
- throw new SecurityException("getHoldLockToken requires a debuggable build");
- }
-
- mContext.enforceCallingPermission(
- Manifest.permission.INJECT_EVENTS,
- "getHoldLockToken requires INJECT_EVENTS permission");
-
- final Binder token = new Binder();
- token.attachInterface(this, "holdLock:" + Binder.getCallingUid());
- return token;
- }
-
- @Override
public void verifyHoldLockToken(IBinder token) {
if (!Build.IS_DEBUGGABLE) {
throw new SecurityException("holdLock requires a debuggable build");
@@ -8315,15 +6817,6 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- @Override
- public void holdLock(IBinder token, int durationMs) {
- mTestUtilityService.verifyHoldLockToken(token);
-
- synchronized (mLock) {
- SystemClock.sleep(durationMs);
- }
- }
-
static String getDefaultTimeouts() {
final long token = Binder.clearCallingIdentity();
try {
@@ -8348,16 +6841,16 @@ public class PackageManagerService extends IPackageManager.Stub
* Returns the array containing per-uid timeout configuration.
* This is derived from DeviceConfig flags.
*/
- public @NonNull PerUidReadTimeouts[] getPerUidReadTimeouts() {
+ public @NonNull PerUidReadTimeouts[] getPerUidReadTimeouts(@NonNull Computer snapshot) {
PerUidReadTimeouts[] result = mPerUidReadTimeoutsCache;
if (result == null) {
- result = parsePerUidReadTimeouts();
+ result = parsePerUidReadTimeouts(snapshot);
mPerUidReadTimeoutsCache = result;
}
return result;
}
- private @NonNull PerUidReadTimeouts[] parsePerUidReadTimeouts() {
+ private @NonNull PerUidReadTimeouts[] parsePerUidReadTimeouts(@NonNull Computer snapshot) {
final String defaultTimeouts = getDefaultTimeouts();
final String knownDigestersList = getKnownDigestersList();
final List<PerPackageReadTimeouts> perPackageReadTimeouts =
@@ -8371,7 +6864,8 @@ public class PackageManagerService extends IPackageManager.Stub
final List<PerUidReadTimeouts> result = new ArrayList<>(perPackageReadTimeouts.size());
for (int i = 0, size = perPackageReadTimeouts.size(); i < size; ++i) {
final PerPackageReadTimeouts perPackage = perPackageReadTimeouts.get(i);
- final PackageStateInternal ps = getPackageStateInternal(perPackage.packageName);
+ final PackageStateInternal ps =
+ snapshot.getPackageStateInternal(perPackage.packageName);
if (ps == null) {
if (DEBUG_PER_UID_READ_TIMEOUTS) {
Slog.i(TAG, "PerUidReadTimeouts: package not found = "
@@ -8421,17 +6915,7 @@ public class PackageManagerService extends IPackageManager.Stub
return result.toArray(new PerUidReadTimeouts[result.size()]);
}
- @Override
- public void setKeepUninstalledPackages(List<String> packageList) {
- mContext.enforceCallingPermission(
- Manifest.permission.KEEP_UNINSTALLED_PACKAGES,
- "setKeepUninstalledPackages requires KEEP_UNINSTALLED_PACKAGES permission");
- Objects.requireNonNull(packageList);
-
- setKeepUninstalledPackagesInternal(packageList);
- }
-
- private void setKeepUninstalledPackagesInternal(List<String> packageList) {
+ void setKeepUninstalledPackagesInternal(@NonNull Computer snapshot, List<String> packageList) {
Preconditions.checkNotNull(packageList);
synchronized (mKeepUninstalledPackages) {
List<String> toRemove = new ArrayList<>(mKeepUninstalledPackages);
@@ -8441,7 +6925,7 @@ public class PackageManagerService extends IPackageManager.Stub
mKeepUninstalledPackages.addAll(packageList);
for (int i = 0; i < toRemove.size(); i++) {
- deletePackageIfUnused(toRemove.get(i));
+ deletePackageIfUnused(snapshot, toRemove.get(i));
}
}
}
@@ -8452,19 +6936,6 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- @Override
- public IntentSender getLaunchIntentSenderForPackage(String packageName, String callingPackage,
- String featureId, int userId) throws RemoteException {
- return mResolveIntentHelper.getLaunchIntentSenderForPackage(snapshotComputer(),
- packageName, callingPackage, featureId, userId);
- }
-
- @Override
- public boolean canPackageQuery(@NonNull String sourcePackageName,
- @NonNull String targetPackageName, @UserIdInt int userId) {
- return mComputer.canPackageQuery(sourcePackageName, targetPackageName, userId);
- }
-
boolean getSafeMode() {
return mSafeMode;
}
@@ -8501,43 +6972,44 @@ public class PackageManagerService extends IPackageManager.Stub
mInstrumentation.put(name, instrumentation);
}
- String[] getKnownPackageNamesInternal(int knownPackage, int userId) {
+ 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 mComputer.filterOnlySystemPackages(mRequiredInstallerPackage);
+ return snapshot.filterOnlySystemPackages(mRequiredInstallerPackage);
case PackageManagerInternal.PACKAGE_UNINSTALLER:
- return mComputer.filterOnlySystemPackages(mRequiredUninstallerPackage);
+ return snapshot.filterOnlySystemPackages(mRequiredUninstallerPackage);
case PackageManagerInternal.PACKAGE_SETUP_WIZARD:
- return mComputer.filterOnlySystemPackages(mSetupWizardPackage);
+ return snapshot.filterOnlySystemPackages(mSetupWizardPackage);
case PackageManagerInternal.PACKAGE_SYSTEM:
return new String[]{"android"};
case PackageManagerInternal.PACKAGE_VERIFIER:
- return mComputer.filterOnlySystemPackages(mRequiredVerifierPackage);
+ return snapshot.filterOnlySystemPackages(mRequiredVerifierPackage);
case PackageManagerInternal.PACKAGE_SYSTEM_TEXT_CLASSIFIER:
- return mComputer.filterOnlySystemPackages(
+ return snapshot.filterOnlySystemPackages(
mDefaultTextClassifierPackage, mSystemTextClassifierPackageName);
case PackageManagerInternal.PACKAGE_PERMISSION_CONTROLLER:
- return mComputer.filterOnlySystemPackages(mRequiredPermissionControllerPackage);
+ return snapshot.filterOnlySystemPackages(mRequiredPermissionControllerPackage);
case PackageManagerInternal.PACKAGE_CONFIGURATOR:
- return mComputer.filterOnlySystemPackages(mConfiguratorPackage);
+ return snapshot.filterOnlySystemPackages(mConfiguratorPackage);
case PackageManagerInternal.PACKAGE_INCIDENT_REPORT_APPROVER:
- return mComputer.filterOnlySystemPackages(mIncidentReportApproverPackage);
+ return snapshot.filterOnlySystemPackages(mIncidentReportApproverPackage);
case PackageManagerInternal.PACKAGE_AMBIENT_CONTEXT_DETECTION:
- return mComputer.filterOnlySystemPackages(mAmbientContextDetectionPackage);
+ return snapshot.filterOnlySystemPackages(mAmbientContextDetectionPackage);
case PackageManagerInternal.PACKAGE_APP_PREDICTOR:
- return mComputer.filterOnlySystemPackages(mAppPredictionServicePackage);
+ return snapshot.filterOnlySystemPackages(mAppPredictionServicePackage);
case PackageManagerInternal.PACKAGE_COMPANION:
- return mComputer.filterOnlySystemPackages(COMPANION_PACKAGE_NAME);
+ 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 mComputer.filterOnlySystemPackages(getOverlayConfigSignaturePackageName());
+ return snapshot.filterOnlySystemPackages(mOverlayConfigSignaturePackage);
case PackageManagerInternal.PACKAGE_RECENTS:
- return mComputer.filterOnlySystemPackages(mRecentsPackage);
+ return snapshot.filterOnlySystemPackages(mRecentsPackage);
default:
return ArrayUtils.emptyArray(String.class);
}
@@ -8557,10 +7029,6 @@ public class PackageManagerService extends IPackageManager.Stub
mDefaultAppProvider.setDefaultBrowser(packageName, async, userId);
}
- ResolveInfo getInstantAppInstallerInfo() {
- return mInstantAppInstallerInfo;
- }
-
PackageUsage getPackageUsage() {
return mPackageUsage;
}
@@ -8574,7 +7042,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
boolean isExpectingBetter(String packageName) {
- return mInitAndSystemPackageHelper.isExpectingBetter(packageName);
+ return mInitAppsHelper.isExpectingBetter(packageName);
}
int getDefParseFlags() {
@@ -8652,10 +7120,6 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- ResolveInfo getResolveInfo() {
- return mResolveInfo;
- }
-
ApplicationInfo getCoreAndroidApplication() {
return mAndroidApplication;
}
@@ -8677,13 +7141,12 @@ public class PackageManagerService extends IPackageManager.Stub
}
boolean isOverlayMutable(String packageName) {
- return (mOverlayConfig != null ? mOverlayConfig
- : OverlayConfig.getSystemInstance()).isMutable(packageName);
+ return mOverlayConfig.isMutable(packageName);
}
@ScanFlags int getSystemPackageScanFlags(File codePath) {
List<ScanPartition> dirsToScanAsSystem =
- mInitAndSystemPackageHelper.getDirsToScanAsSystem();
+ mInitAppsHelper.getDirsToScanAsSystem();
@PackageManagerService.ScanFlags int scanFlags = SCAN_AS_SYSTEM;
for (int i = dirsToScanAsSystem.size() - 1; i >= 0; i--) {
ScanPartition partition = dirsToScanAsSystem.get(i);
@@ -8701,7 +7164,7 @@ public class PackageManagerService extends IPackageManager.Stub
Pair<Integer, Integer> getSystemPackageRescanFlagsAndReparseFlags(File scanFile,
int systemScanFlags, int systemParseFlags) {
List<ScanPartition> dirsToScanAsSystem =
- mInitAndSystemPackageHelper.getDirsToScanAsSystem();
+ mInitAppsHelper.getDirsToScanAsSystem();
@ParsingPackageUtils.ParseFlags int reparseFlags = 0;
@PackageManagerService.ScanFlags int rescanFlags = 0;
for (int i1 = dirsToScanAsSystem.size() - 1; i1 >= 0; i1--) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java b/services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java
index 5bdda0b3c1d8..e466fe2c0e31 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java
@@ -109,7 +109,7 @@ public final class PackageManagerServiceTestParams {
public AppDataHelper appDataHelper;
public InstallPackageHelper installPackageHelper;
public RemovePackageHelper removePackageHelper;
- public InitAndSystemPackageHelper initAndSystemPackageHelper;
+ public InitAppsHelper initAndSystemPackageHelper;
public DeletePackageHelper deletePackageHelper;
public PreferredActivityHelper preferredActivityHelper;
public ResolveIntentHelper resolveIntentHelper;
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index 8d3fbf7fc679..2a1a99068d45 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -850,6 +850,8 @@ public class PackageManagerServiceUtils {
ret.recommendedInstallLocation = recommendedInstallLocation;
ret.multiArch = pkg.isMultiArch();
ret.debuggable = pkg.isDebuggable();
+ ret.isSdkLibrary = pkg.isIsSdkLibrary();
+
return ret;
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 500b4ec70c44..15753cd24e85 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -131,6 +131,7 @@ import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
+import java.util.Set;
import java.util.WeakHashMap;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CountDownLatch;
@@ -144,6 +145,10 @@ class PackageManagerShellCommand extends ShellCommand {
private final static String ART_PROFILE_SNAPSHOT_DEBUG_LOCATION = "/data/misc/profman/";
private static final int DEFAULT_STAGED_READY_TIMEOUT_MS = 60 * 1000;
private static final String TAG = "PackageManagerShellCommand";
+ private static final Set<String> UNSUPPORTED_INSTALL_CMD_OPTS = Set.of(
+ "--multi-package"
+ );
+ private static final Set<String> UNSUPPORTED_SESSION_CREATE_OPTS = Collections.emptySet();
final IPackageManager mInterface;
final LegacyPermissionManagerInternal mLegacyPermissionManager;
@@ -159,9 +164,9 @@ class PackageManagerShellCommand extends ShellCommand {
private static final SecureRandom RANDOM = new SecureRandom();
- PackageManagerShellCommand(@NonNull PackageManagerService service,
+ PackageManagerShellCommand(@NonNull IPackageManager packageManager,
@NonNull Context context, @NonNull DomainVerificationShell domainVerificationShell) {
- mInterface = service;
+ mInterface = packageManager;
mLegacyPermissionManager = LocalServices.getService(LegacyPermissionManagerInternal.class);
mPermissionManager = context.getSystemService(PermissionManager.class);
mContext = context;
@@ -1330,7 +1335,7 @@ class PackageManagerShellCommand extends ShellCommand {
}
private int runStreamingInstall() throws RemoteException {
- final InstallParams params = makeInstallParams();
+ final InstallParams params = makeInstallParams(UNSUPPORTED_INSTALL_CMD_OPTS);
if (params.sessionParams.dataLoaderParams == null) {
params.sessionParams.setDataLoaderParams(
PackageManagerShellCommandDataLoader.getStreamingDataLoaderParams(this));
@@ -1339,7 +1344,7 @@ class PackageManagerShellCommand extends ShellCommand {
}
private int runIncrementalInstall() throws RemoteException {
- final InstallParams params = makeInstallParams();
+ final InstallParams params = makeInstallParams(UNSUPPORTED_INSTALL_CMD_OPTS);
if (params.sessionParams.dataLoaderParams == null) {
params.sessionParams.setDataLoaderParams(
PackageManagerShellCommandDataLoader.getIncrementalDataLoaderParams(this));
@@ -1348,7 +1353,7 @@ class PackageManagerShellCommand extends ShellCommand {
}
private int runInstall() throws RemoteException {
- return doRunInstall(makeInstallParams());
+ return doRunInstall(makeInstallParams(UNSUPPORTED_INSTALL_CMD_OPTS));
}
private int doRunInstall(final InstallParams params) throws RemoteException {
@@ -1500,7 +1505,7 @@ class PackageManagerShellCommand extends ShellCommand {
private int runInstallCreate() throws RemoteException {
final PrintWriter pw = getOutPrintWriter();
- final InstallParams installParams = makeInstallParams();
+ final InstallParams installParams = makeInstallParams(UNSUPPORTED_SESSION_CREATE_OPTS);
final int sessionId = doCreateSession(installParams.sessionParams,
installParams.installerPackageName, installParams.userId);
@@ -2535,8 +2540,10 @@ class PackageManagerShellCommand extends ShellCommand {
privAppPermissions = SystemConfig.getInstance()
.getSystemExtPrivAppPermissions(pkg);
} else if (isApexApp(pkg)) {
+ final String apexName = ApexManager.getInstance().getApexModuleNameForPackageName(
+ getApexPackageNameContainingPackage(pkg));
privAppPermissions = SystemConfig.getInstance()
- .getApexPrivAppPermissions(getApexPackageNameContainingPackage(pkg), pkg);
+ .getApexPrivAppPermissions(apexName, pkg);
} else {
privAppPermissions = SystemConfig.getInstance().getPrivAppPermissions(pkg);
}
@@ -2562,8 +2569,10 @@ class PackageManagerShellCommand extends ShellCommand {
privAppPermissions = SystemConfig.getInstance()
.getSystemExtPrivAppDenyPermissions(pkg);
} else if (isApexApp(pkg)) {
+ final String apexName = ApexManager.getInstance().getApexModuleNameForPackageName(
+ getApexPackageNameContainingPackage(pkg));
privAppPermissions = SystemConfig.getInstance()
- .getApexPrivAppDenyPermissions(getApexPackageNameContainingPackage(pkg), pkg);
+ .getApexPrivAppDenyPermissions(apexName, pkg);
} else {
privAppPermissions = SystemConfig.getInstance().getPrivAppDenyPermissions(pkg);
}
@@ -2896,7 +2905,7 @@ class PackageManagerShellCommand extends ShellCommand {
long stagedReadyTimeoutMs = DEFAULT_STAGED_READY_TIMEOUT_MS;
}
- private InstallParams makeInstallParams() {
+ private InstallParams makeInstallParams(Set<String> unsupportedOptions) {
final SessionParams sessionParams = new SessionParams(SessionParams.MODE_FULL_INSTALL);
final InstallParams params = new InstallParams();
@@ -2910,6 +2919,9 @@ class PackageManagerShellCommand extends ShellCommand {
boolean replaceExisting = true;
boolean forceNonStaged = false;
while ((opt = getNextOption()) != null) {
+ if (unsupportedOptions.contains(opt)) {
+ throw new IllegalArgumentException("Unsupported option " + opt);
+ }
switch (opt) {
case "-r": // ignore
break;
@@ -3817,7 +3829,7 @@ class PackageManagerShellCommand extends ShellCommand {
pw.println(" [--user USER_ID] INTENT");
pw.println(" Prints all broadcast receivers that can handle the given INTENT.");
pw.println("");
- pw.println(" install [-rtfdgw] [-i PACKAGE] [--user USER_ID|all|current]");
+ pw.println(" install [-rtfdg] [-i PACKAGE] [--user USER_ID|all|current]");
pw.println(" [-p INHERIT_PACKAGE] [--install-location 0/1/2]");
pw.println(" [--install-reason 0/1/2/3/4] [--originating-uri URI]");
pw.println(" [--referrer URI] [--abi ABI_NAME] [--force-sdk]");
diff --git a/services/core/java/com/android/server/pm/PackageRemovedInfo.java b/services/core/java/com/android/server/pm/PackageRemovedInfo.java
index fdad83347f24..28ad4b61d8c7 100644
--- a/services/core/java/com/android/server/pm/PackageRemovedInfo.java
+++ b/services/core/java/com/android/server/pm/PackageRemovedInfo.java
@@ -38,8 +38,6 @@ final class PackageRemovedInfo {
String mInstallerPackageName;
int mUid = -1;
int mRemovedAppId = -1;
- // If not -1, the app is going through an appId change
- int mNewAppId = -1;
int[] mOrigUsers;
int[] mRemovedUsers = null;
int[] mBroadcastUsers = null;
@@ -67,22 +65,16 @@ final class PackageRemovedInfo {
sendPackageRemovedBroadcastInternal(killApp, removedBySystem);
}
- void sendSystemPackageUpdatedBroadcasts(int newAppId) {
+ void sendSystemPackageUpdatedBroadcasts() {
if (mIsRemovedPackageSystemUpdate) {
- sendSystemPackageUpdatedBroadcastsInternal(newAppId);
+ sendSystemPackageUpdatedBroadcastsInternal();
}
}
- private void sendSystemPackageUpdatedBroadcastsInternal(int newAppId) {
+ private void sendSystemPackageUpdatedBroadcastsInternal() {
Bundle extras = new Bundle(2);
- extras.putInt(Intent.EXTRA_UID, newAppId);
- // When appId changes, do not set the replacing extra
- if (mNewAppId >= 0) {
- extras.putBoolean(Intent.EXTRA_UID_CHANGING, true);
- extras.putInt(Intent.EXTRA_PREVIOUS_UID, mRemovedAppId >= 0 ? mRemovedAppId : mUid);
- } else {
- extras.putBoolean(Intent.EXTRA_REPLACING, true);
- }
+ extras.putInt(Intent.EXTRA_UID, mRemovedAppId >= 0 ? mRemovedAppId : mUid);
+ extras.putBoolean(Intent.EXTRA_REPLACING, true);
mPackageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, mRemovedPackage, extras,
0, null /*targetPackage*/, null, null, null, mBroadcastAllowList, null);
if (mInstallerPackageName != null) {
@@ -90,17 +82,13 @@ final class PackageRemovedInfo {
mRemovedPackage, extras, 0 /*flags*/,
mInstallerPackageName, null, null, null, null /* broadcastAllowList */,
null);
+ mPackageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED,
+ mRemovedPackage, extras, 0 /*flags*/,
+ mInstallerPackageName, null, null, null, null /* broadcastAllowList */,
+ null);
}
- if (mNewAppId < 0) {
- mPackageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, mRemovedPackage,
- extras, 0, null /*targetPackage*/, null, null, null, mBroadcastAllowList, null);
- if (mInstallerPackageName != null) {
- mPackageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED,
- mRemovedPackage, extras, 0 /*flags*/,
- mInstallerPackageName, null, null, null, null /* broadcastAllowList */,
- null);
- }
- }
+ mPackageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, mRemovedPackage,
+ extras, 0, null /*targetPackage*/, null, null, null, mBroadcastAllowList, null);
mPackageSender.sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED, null, null, 0,
mRemovedPackage, null, null, null, null /* broadcastAllowList */,
getTemporaryAppAllowlistBroadcastOptions(REASON_PACKAGE_REPLACED).toBundle());
@@ -134,15 +122,10 @@ final class PackageRemovedInfo {
extras.putBoolean(Intent.EXTRA_DATA_REMOVED, mDataRemoved);
extras.putBoolean(Intent.EXTRA_DONT_KILL_APP, !killApp);
extras.putBoolean(Intent.EXTRA_USER_INITIATED, !removedBySystem);
-
- // When appId changes, do not set the replacing extra
- if (mNewAppId >= 0) {
- extras.putBoolean(Intent.EXTRA_UID_CHANGING, true);
- extras.putInt(Intent.EXTRA_NEW_UID, mNewAppId);
- } else if (mIsUpdate || mIsRemovedPackageSystemUpdate) {
+ final boolean isReplace = mIsUpdate || mIsRemovedPackageSystemUpdate;
+ if (isReplace) {
extras.putBoolean(Intent.EXTRA_REPLACING, true);
}
-
extras.putBoolean(Intent.EXTRA_REMOVED_FOR_ALL_USERS, mRemovedForAllUsers);
if (mRemovedPackage != null) {
mPackageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED,
@@ -165,9 +148,9 @@ final class PackageRemovedInfo {
}
}
if (mRemovedAppId >= 0) {
- // If the package is not actually removed, some services need to know the
- // package name affected.
- if (mNewAppId >= 0 || mIsUpdate || mIsRemovedPackageSystemUpdate) {
+ // If a system app's updates are uninstalled the UID is not actually removed. Some
+ // services need to know the package name affected.
+ if (isReplace) {
extras.putString(Intent.EXTRA_PACKAGE_NAME, mRemovedPackage);
}
diff --git a/services/core/java/com/android/server/pm/PackageSender.java b/services/core/java/com/android/server/pm/PackageSender.java
index d380098d44b3..656d5962e1a9 100644
--- a/services/core/java/com/android/server/pm/PackageSender.java
+++ b/services/core/java/com/android/server/pm/PackageSender.java
@@ -16,6 +16,7 @@
package com.android.server.pm;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.IIntentReceiver;
import android.os.Bundle;
@@ -30,9 +31,9 @@ interface PackageSender {
Bundle extras, int flags, String targetPkg,
IIntentReceiver finishedReceiver, int[] userIds, int[] instantUserIds,
@Nullable SparseArray<int[]> broadcastAllowList, @Nullable Bundle bOptions);
- void sendPackageAddedForNewUsers(String packageName, boolean sendBootCompleted,
- boolean includeStopped, int appId, int[] userIds, int[] instantUserIds,
- int dataLoaderType);
+ void sendPackageAddedForNewUsers(@NonNull Computer snapshot, String packageName,
+ boolean sendBootCompleted, boolean includeStopped, int appId, int[] userIds,
+ int[] instantUserIds, int dataLoaderType);
void notifyPackageAdded(String packageName, int uid);
void notifyPackageChanged(String packageName, int uid);
void notifyPackageRemoved(String packageName, int uid);
diff --git a/services/core/java/com/android/server/pm/PackageSessionVerifier.java b/services/core/java/com/android/server/pm/PackageSessionVerifier.java
index 6b57deba56b5..2016fc3093b3 100644
--- a/services/core/java/com/android/server/pm/PackageSessionVerifier.java
+++ b/services/core/java/com/android/server/pm/PackageSessionVerifier.java
@@ -24,7 +24,6 @@ import android.content.Context;
import android.content.Intent;
import android.content.pm.IPackageInstallObserver2;
import android.content.pm.PackageInfo;
-import android.content.pm.PackageInstaller.SessionInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.content.pm.SigningDetails;
@@ -110,7 +109,7 @@ final class PackageSessionVerifier {
verifyAPK(session, callback);
} catch (PackageManagerException e) {
String errorMessage = PackageManager.installStatusToString(e.error, e.getMessage());
- session.setSessionFailed(SessionInfo.SESSION_VERIFICATION_FAILED, errorMessage);
+ session.setSessionFailed(e.error, errorMessage);
callback.onResult(e.error, e.getMessage());
}
});
@@ -137,7 +136,7 @@ final class PackageSessionVerifier {
}
if (returnCode != PackageManager.INSTALL_SUCCEEDED) {
String errorMessage = PackageManager.installStatusToString(returnCode, msg);
- session.setSessionFailed(SessionInfo.SESSION_VERIFICATION_FAILED, errorMessage);
+ session.setSessionFailed(returnCode, errorMessage);
callback.onResult(returnCode, msg);
} else {
session.setSessionReady();
@@ -220,7 +219,7 @@ final class PackageSessionVerifier {
}
private void onVerificationFailure(StagingManager.StagedSession session, Callback callback,
- @SessionInfo.SessionErrorCode int errorCode, String errorMessage) {
+ int errorCode, String errorMessage) {
if (!ensureActiveApexSessionIsAborted(session)) {
Slog.e(TAG, "Failed to abort apex session " + session.sessionId());
// Safe to ignore active apex session abortion failure since session will be marked
@@ -312,7 +311,7 @@ final class PackageSessionVerifier {
// Failed to get hold of StorageManager
Slog.e(TAG, "Failed to get hold of StorageManager", e);
throw new PackageManagerException(
- SessionInfo.SESSION_UNKNOWN_ERROR,
+ PackageManager.INSTALL_FAILED_INTERNAL_ERROR,
"Failed to get hold of StorageManager");
}
// Proactively mark session as ready before calling apexd. Although this call order
@@ -350,7 +349,7 @@ final class PackageSessionVerifier {
final ParseResult<SigningDetails> newResult = ApkSignatureVerifier.verify(
input.reset(), apexPath, minSignatureScheme);
if (newResult.isError()) {
- throw new PackageManagerException(SessionInfo.SESSION_VERIFICATION_FAILED,
+ throw new PackageManagerException(PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE,
"Failed to parse APEX package " + apexPath + " : "
+ newResult.getException(), newResult.getException());
}
@@ -369,7 +368,7 @@ final class PackageSessionVerifier {
input.reset(), existingApexPkg.applicationInfo.sourceDir,
SigningDetails.SignatureSchemeVersion.JAR);
if (existingResult.isError()) {
- throw new PackageManagerException(SessionInfo.SESSION_VERIFICATION_FAILED,
+ throw new PackageManagerException(PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE,
"Failed to parse APEX package " + existingApexPkg.applicationInfo.sourceDir
+ " : " + existingResult.getException(), existingResult.getException());
}
@@ -383,7 +382,7 @@ final class PackageSessionVerifier {
return;
}
- throw new PackageManagerException(SessionInfo.SESSION_VERIFICATION_FAILED,
+ throw new PackageManagerException(PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE,
"APK-container signature of APEX package " + packageName + " with version "
+ newApexPkg.versionCodeMajor + " and path " + apexPath + " is not"
+ " compatible with the one currently installed on device");
@@ -426,11 +425,12 @@ final class PackageSessionVerifier {
packageInfo = PackageInfoWithoutStateUtils.generate(parsedPackage, apexInfo, flags);
if (packageInfo == null) {
throw new PackageManagerException(
- SessionInfo.SESSION_VERIFICATION_FAILED,
+ PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE,
"Unable to generate package info: " + apexInfo.modulePath);
}
} catch (PackageManagerException e) {
- throw new PackageManagerException(SessionInfo.SESSION_VERIFICATION_FAILED,
+ throw new PackageManagerException(
+ PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE,
"Failed to parse APEX package " + apexInfo.modulePath + " : " + e, e);
}
result.add(packageInfo);
@@ -452,7 +452,7 @@ final class PackageSessionVerifier {
}
}
throw new PackageManagerException(
- SessionInfo.SESSION_VERIFICATION_FAILED,
+ PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE,
"Could not find rollback id for commit session: " + sessionId);
}
@@ -560,7 +560,7 @@ final class PackageSessionVerifier {
try {
checkActiveSessions(InstallLocationUtils.getStorageManager().supportsCheckpoint());
} catch (RemoteException e) {
- throw new PackageManagerException(SessionInfo.SESSION_VERIFICATION_FAILED,
+ throw new PackageManagerException(PackageManager.INSTALL_FAILED_INTERNAL_ERROR,
"Can't query fs-checkpoint status : " + e);
}
}
@@ -576,7 +576,7 @@ final class PackageSessionVerifier {
}
if (!supportsCheckpoint && activeSessions > 1) {
throw new PackageManagerException(
- SessionInfo.SESSION_VERIFICATION_FAILED,
+ PackageManager.INSTALL_FAILED_OTHER_STAGED_SESSION_IN_PROGRESS,
"Cannot stage multiple sessions without checkpoint support");
}
}
@@ -607,13 +607,13 @@ final class PackageSessionVerifier {
// will be deleted.
}
stagedSession.setSessionFailed(
- SessionInfo.SESSION_CONFLICT,
+ PackageManager.INSTALL_FAILED_OTHER_STAGED_SESSION_IN_PROGRESS,
"Session was failed by rollback session: " + session.sessionId());
Slog.i(TAG, "Session " + stagedSession.sessionId() + " is marked failed due to "
+ "rollback session: " + session.sessionId());
} else if (!isRollback(session) && isRollback(stagedSession)) {
throw new PackageManagerException(
- SessionInfo.SESSION_CONFLICT,
+ PackageManager.INSTALL_FAILED_OTHER_STAGED_SESSION_IN_PROGRESS,
"Session was failed by rollback session: " + stagedSession.sessionId());
}
@@ -636,7 +636,7 @@ final class PackageSessionVerifier {
final String packageName = child.getPackageName();
if (packageName == null) {
throw new PackageManagerException(
- SessionInfo.SESSION_VERIFICATION_FAILED,
+ PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE,
"Cannot stage session " + child.sessionId() + " with package name null");
}
for (StagingManager.StagedSession stagedSession : mStagedSessions) {
@@ -648,14 +648,14 @@ final class PackageSessionVerifier {
if (stagedSession.getCommittedMillis() < parent.getCommittedMillis()) {
// Fail the session committed later when there are overlapping packages
throw new PackageManagerException(
- SessionInfo.SESSION_VERIFICATION_FAILED,
+ PackageManager.INSTALL_FAILED_OTHER_STAGED_SESSION_IN_PROGRESS,
"Package: " + packageName + " in session: "
+ child.sessionId()
+ " has been staged already by session: "
+ stagedSession.sessionId());
} else {
stagedSession.setSessionFailed(
- SessionInfo.SESSION_VERIFICATION_FAILED,
+ PackageManager.INSTALL_FAILED_OTHER_STAGED_SESSION_IN_PROGRESS,
"Package: " + packageName + " in session: "
+ stagedSession.sessionId()
+ " has been staged already by session: "
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index f06ae1e06187..2bae00f91b82 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -477,6 +477,7 @@ public class PackageSetting extends SettingBase implements PackageStateInternal
public void setSharedUserAppId(int sharedUserAppId) {
mSharedUserAppId = sharedUserAppId;
+ onChanged();
}
@Override
diff --git a/services/core/java/com/android/server/pm/PreferredActivityHelper.java b/services/core/java/com/android/server/pm/PreferredActivityHelper.java
index 8c49bafa06a8..9befd6e09eb4 100644
--- a/services/core/java/com/android/server/pm/PreferredActivityHelper.java
+++ b/services/core/java/com/android/server/pm/PreferredActivityHelper.java
@@ -25,6 +25,7 @@ import static com.android.server.pm.PackageManagerService.DEBUG_PREFERRED;
import static com.android.server.pm.PackageManagerService.TAG;
import android.annotation.NonNull;
+import android.annotation.UserIdInt;
import android.content.ComponentName;
import android.content.Intent;
import android.content.IntentFilter;
@@ -74,17 +75,18 @@ final class PreferredActivityHelper {
mPm = pm;
}
- private ResolveInfo findPreferredActivityNotLocked(Intent intent, String resolvedType,
- @PackageManager.ResolveInfoFlagsBits long flags, List<ResolveInfo> query,
- boolean always, boolean removeMatches, boolean debug, int userId) {
- return findPreferredActivityNotLocked(
- intent, resolvedType, flags, query, always, removeMatches, debug, userId,
+ private ResolveInfo findPreferredActivityNotLocked(@NonNull Computer snapshot, Intent intent,
+ String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags,
+ List<ResolveInfo> query, boolean always, boolean removeMatches, boolean debug,
+ @UserIdInt int userId) {
+ return findPreferredActivityNotLocked(snapshot, intent, resolvedType, flags, query, always,
+ removeMatches, debug, userId,
UserHandle.getAppId(Binder.getCallingUid()) >= Process.FIRST_APPLICATION_UID);
}
// TODO: handle preferred activities missing while user has amnesia
/** <b>must not hold {@link PackageManagerService.mLock}</b> */
- public ResolveInfo findPreferredActivityNotLocked(
+ public ResolveInfo findPreferredActivityNotLocked(@NonNull Computer snapshot,
Intent intent, String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags,
List<ResolveInfo> query, boolean always, boolean removeMatches, boolean debug,
int userId, boolean queryMayBeFiltered) {
@@ -95,7 +97,7 @@ final class PreferredActivityHelper {
if (!mPm.mUserManager.exists(userId)) return null;
PackageManagerService.FindPreferredActivityBodyResult body =
- mPm.findPreferredActivityInternal(
+ snapshot.findPreferredActivityInternal(
intent, resolvedType, flags, query, always,
removeMatches, debug, userId, queryMayBeFiltered);
if (body.mChanged) {
@@ -117,7 +119,7 @@ final class PreferredActivityHelper {
mPm.clearPackagePreferredActivitiesLPw(packageName, changedUsers, userId);
}
if (changedUsers.size() > 0) {
- updateDefaultHomeNotLocked(changedUsers);
+ updateDefaultHomeNotLocked(mPm.snapshotComputer(), changedUsers);
mPm.postPreferredActivityChangedBroadcast(userId);
mPm.scheduleWritePackageRestrictions(userId);
}
@@ -128,7 +130,7 @@ final class PreferredActivityHelper {
*
* @return Whether the ACTION_PREFERRED_ACTIVITY_CHANGED broadcast has been scheduled.
*/
- public boolean updateDefaultHomeNotLocked(int userId) {
+ public boolean updateDefaultHomeNotLocked(@NonNull Computer snapshot, @UserIdInt int userId) {
if (Thread.holdsLock(mPm.mLock)) {
Slog.wtf(TAG, "Calling thread " + Thread.currentThread().getName()
+ " is holding mLock", new Throwable());
@@ -139,10 +141,10 @@ final class PreferredActivityHelper {
// before that.
return false;
}
- final Intent intent = mPm.getHomeIntent();
- final List<ResolveInfo> resolveInfos = mPm.snapshotComputer().queryIntentActivitiesInternal(
+ final Intent intent = snapshot.getHomeIntent();
+ final List<ResolveInfo> resolveInfos = snapshot.queryIntentActivitiesInternal(
intent, null, MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE, userId);
- final ResolveInfo preferredResolveInfo = findPreferredActivityNotLocked(
+ final ResolveInfo preferredResolveInfo = findPreferredActivityNotLocked(snapshot,
intent, null, 0, resolveInfos, true, false, false, userId);
final String packageName = preferredResolveInfo != null
&& preferredResolveInfo.activityInfo != null
@@ -151,7 +153,7 @@ final class PreferredActivityHelper {
if (TextUtils.equals(currentPackageName, packageName)) {
return false;
}
- final String[] callingPackages = mPm.getPackagesForUid(Binder.getCallingUid());
+ final String[] callingPackages = snapshot.getPackagesForUid(Binder.getCallingUid());
if (callingPackages != null && ArrayUtils.contains(callingPackages,
mPm.mRequiredPermissionControllerPackage)) {
// PermissionController manages default home directly.
@@ -173,23 +175,21 @@ final class PreferredActivityHelper {
/**
* Variant that takes a {@link WatchedIntentFilter}
*/
- public void addPreferredActivity(WatchedIntentFilter filter, int match,
- ComponentName[] set, ComponentName activity, boolean always, int userId,
+ public void addPreferredActivity(@NonNull Computer snapshot, WatchedIntentFilter filter,
+ int match, ComponentName[] set, ComponentName activity, boolean always, int userId,
String opname, boolean removeExisting) {
// writer
int callingUid = Binder.getCallingUid();
- mPm.enforceCrossUserPermission(callingUid, userId, true /* requireFullPermission */,
+ snapshot.enforceCrossUserPermission(callingUid, userId, true /* requireFullPermission */,
false /* checkShell */, "add preferred activity");
if (mPm.mContext.checkCallingOrSelfPermission(
android.Manifest.permission.SET_PREFERRED_APPLICATIONS)
!= PackageManager.PERMISSION_GRANTED) {
- synchronized (mPm.mLock) {
- if (mPm.getUidTargetSdkVersion(callingUid)
- < Build.VERSION_CODES.FROYO) {
- Slog.w(TAG, "Ignoring addPreferredActivity() from uid "
- + callingUid);
- return;
- }
+ if (snapshot.getUidTargetSdkVersion(callingUid)
+ < Build.VERSION_CODES.FROYO) {
+ Slog.w(TAG, "Ignoring addPreferredActivity() from uid "
+ + callingUid);
+ return;
}
mPm.mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null);
@@ -213,7 +213,8 @@ final class PreferredActivityHelper {
new PreferredActivity(filter, match, set, activity, always));
mPm.scheduleWritePackageRestrictions(userId);
}
- if (!(isHomeFilter(filter) && updateDefaultHomeNotLocked(userId))) {
+ // Re-snapshot after mLock
+ if (!(isHomeFilter(filter) && updateDefaultHomeNotLocked(mPm.snapshotComputer(), userId))) {
mPm.postPreferredActivityChangedBroadcast(userId);
}
}
@@ -221,8 +222,8 @@ final class PreferredActivityHelper {
/**
* Variant that takes a {@link WatchedIntentFilter}
*/
- public void replacePreferredActivity(WatchedIntentFilter filter, int match,
- ComponentName[] set, ComponentName activity, int userId) {
+ public void replacePreferredActivity(@NonNull Computer snapshot, WatchedIntentFilter filter,
+ int match, ComponentName[] set, ComponentName activity, int userId) {
if (filter.countActions() != 1) {
throw new IllegalArgumentException(
"replacePreferredActivity expects filter to have only 1 action.");
@@ -237,13 +238,14 @@ final class PreferredActivityHelper {
}
final int callingUid = Binder.getCallingUid();
- mPm.enforceCrossUserPermission(callingUid, userId, true /* requireFullPermission */,
+ snapshot.enforceCrossUserPermission(callingUid, userId, true /* requireFullPermission */,
false /* checkShell */, "replace preferred activity");
if (mPm.mContext.checkCallingOrSelfPermission(
android.Manifest.permission.SET_PREFERRED_APPLICATIONS)
!= PackageManager.PERMISSION_GRANTED) {
synchronized (mPm.mLock) {
- if (mPm.getUidTargetSdkVersion(callingUid)
+ // TODO: Remove lock?
+ if (mPm.snapshotComputer().getUidTargetSdkVersion(callingUid)
< Build.VERSION_CODES.FROYO) {
Slog.w(TAG, "Ignoring replacePreferredActivity() from uid "
+ Binder.getCallingUid());
@@ -295,21 +297,23 @@ final class PreferredActivityHelper {
}
}
}
- addPreferredActivity(filter, match, set, activity, true, userId,
+
+ // Retake a snapshot after editing with lock held
+ addPreferredActivity(mPm.snapshotComputer(), filter, match, set, activity, true, userId,
"Replacing preferred", false);
}
- public void clearPackagePreferredActivities(String packageName) {
+ public void clearPackagePreferredActivities(@NonNull Computer snapshot, String packageName) {
final int callingUid = Binder.getCallingUid();
- if (mPm.getInstantAppPackageName(callingUid) != null) {
+ if (snapshot.getInstantAppPackageName(callingUid) != null) {
return;
}
- final PackageStateInternal packageState = mPm.getPackageStateInternal(packageName);
- if (packageState == null || !mPm.isCallerSameApp(packageName, callingUid)) {
+ final PackageStateInternal packageState = snapshot.getPackageStateInternal(packageName);
+ if (packageState == null || !snapshot.isCallerSameApp(packageName, callingUid)) {
if (mPm.mContext.checkCallingOrSelfPermission(
android.Manifest.permission.SET_PREFERRED_APPLICATIONS)
!= PackageManager.PERMISSION_GRANTED) {
- if (mPm.getUidTargetSdkVersion(callingUid)
+ if (snapshot.getUidTargetSdkVersion(callingUid)
< Build.VERSION_CODES.FROYO) {
Slog.w(TAG, "Ignoring clearPackagePreferredActivities() from uid "
+ callingUid);
@@ -319,7 +323,7 @@ final class PreferredActivityHelper {
android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null);
}
}
- if (packageState != null && mPm.shouldFilterApplication(packageState, callingUid,
+ if (packageState != null && snapshot.shouldFilterApplication(packageState, callingUid,
UserHandle.getUserId(callingUid))) {
return;
}
@@ -328,23 +332,23 @@ final class PreferredActivityHelper {
}
/** <b>must not hold {@link #PackageManagerService.mLock}</b> */
- void updateDefaultHomeNotLocked(SparseBooleanArray userIds) {
+ void updateDefaultHomeNotLocked(@NonNull Computer snapshot, SparseBooleanArray userIds) {
if (Thread.holdsLock(mPm.mLock)) {
Slog.wtf(TAG, "Calling thread " + Thread.currentThread().getName()
+ " is holding mLock", new Throwable());
}
for (int i = userIds.size() - 1; i >= 0; --i) {
final int userId = userIds.keyAt(i);
- updateDefaultHomeNotLocked(userId);
+ updateDefaultHomeNotLocked(snapshot, userId);
}
}
- public void setHomeActivity(ComponentName comp, int userId) {
- if (mPm.getInstantAppPackageName(Binder.getCallingUid()) != null) {
+ public void setHomeActivity(@NonNull Computer snapshot, ComponentName comp, int userId) {
+ if (snapshot.getInstantAppPackageName(Binder.getCallingUid()) != null) {
return;
}
ArrayList<ResolveInfo> homeActivities = new ArrayList<>();
- mPm.getHomeActivitiesAsUser(homeActivities, userId);
+ snapshot.getHomeActivitiesAsUser(homeActivities, userId);
boolean found = false;
@@ -363,7 +367,7 @@ final class PreferredActivityHelper {
throw new IllegalArgumentException("Component " + comp + " cannot be home on user "
+ userId);
}
- replacePreferredActivity(getHomeFilter(), IntentFilter.MATCH_CATEGORY_EMPTY,
+ replacePreferredActivity(snapshot, getHomeFilter(), IntentFilter.MATCH_CATEGORY_EMPTY,
set, comp, userId);
}
@@ -400,7 +404,7 @@ final class PreferredActivityHelper {
mPm.scheduleWritePackageRestrictions(userId);
}
if (isHomeFilter(filter)) {
- updateDefaultHomeNotLocked(userId);
+ updateDefaultHomeNotLocked(mPm.snapshotComputer(), userId);
}
mPm.postPreferredActivityChangedBroadcast(userId);
}
@@ -416,7 +420,7 @@ final class PreferredActivityHelper {
changed = mPm.mSettings.clearPackagePersistentPreferredActivities(packageName, userId);
}
if (changed) {
- updateDefaultHomeNotLocked(userId);
+ updateDefaultHomeNotLocked(mPm.snapshotComputer(), userId);
mPm.postPreferredActivityChangedBroadcast(userId);
mPm.scheduleWritePackageRestrictions(userId);
}
@@ -505,7 +509,7 @@ final class PreferredActivityHelper {
synchronized (mPm.mLock) {
mPm.mSettings.readPreferredActivitiesLPw(readParser, readUserId);
}
- updateDefaultHomeNotLocked(readUserId);
+ updateDefaultHomeNotLocked(mPm.snapshotComputer(), readUserId);
});
} catch (Exception e) {
if (DEBUG_BACKUP) {
@@ -597,7 +601,7 @@ final class PreferredActivityHelper {
mPm.mPermissionManager.resetRuntimePermissions(pkg, userId);
}
}
- updateDefaultHomeNotLocked(userId);
+ updateDefaultHomeNotLocked(mPm.snapshotComputer(), userId);
resetNetworkPolicies(userId);
mPm.scheduleWritePackageRestrictions(userId);
} finally {
@@ -609,12 +613,11 @@ final class PreferredActivityHelper {
mPm.mInjector.getLocalService(NetworkPolicyManagerInternal.class).resetUserState(userId);
}
- // TODO: This method should not touch the Computer directly
- public int getPreferredActivities(List<IntentFilter> outFilters,
- List<ComponentName> outActivities, String packageName, Computer computer) {
+ public int getPreferredActivities(@NonNull Computer snapshot, List<IntentFilter> outFilters,
+ List<ComponentName> outActivities, String packageName) {
List<WatchedIntentFilter> temp =
WatchedIntentFilter.toWatchedIntentFilterList(outFilters);
- int result = getPreferredActivitiesInternal(temp, outActivities, packageName, computer);
+ int result = getPreferredActivitiesInternal(snapshot, temp, outActivities, packageName);
outFilters.clear();
for (int i = 0; i < temp.size(); i++) {
outFilters.add(temp.get(i).getIntentFilter());
@@ -625,16 +628,17 @@ final class PreferredActivityHelper {
/**
* Variant that takes a {@link WatchedIntentFilter}
*/
- private int getPreferredActivitiesInternal(List<WatchedIntentFilter> outFilters,
- List<ComponentName> outActivities, String packageName, Computer computer) {
+ private int getPreferredActivitiesInternal(@NonNull Computer snapshot,
+ List<WatchedIntentFilter> outFilters, List<ComponentName> outActivities,
+ String packageName) {
final int callingUid = Binder.getCallingUid();
- if (mPm.getInstantAppPackageName(callingUid) != null) {
+ if (snapshot.getInstantAppPackageName(callingUid) != null) {
return 0;
}
int num = 0;
final int userId = UserHandle.getCallingUserId();
- PreferredIntentResolver pir = computer.getPreferredActivities(userId);
+ PreferredIntentResolver pir = snapshot.getPreferredActivities(userId);
if (pir != null) {
final Iterator<PreferredActivity> it = pir.filterIterator();
while (it.hasNext()) {
@@ -642,8 +646,9 @@ final class PreferredActivityHelper {
final String prefPackageName = pa.mPref.mComponent.getPackageName();
if (packageName == null
|| (prefPackageName.equals(packageName) && pa.mPref.mAlways)) {
- if (mPm.shouldFilterApplication(
- mPm.getPackageStateInternal(prefPackageName), callingUid, userId)) {
+ if (snapshot.shouldFilterApplication(
+ snapshot.getPackageStateInternal(prefPackageName), callingUid,
+ userId)) {
continue;
}
if (outFilters != null) {
@@ -659,7 +664,8 @@ final class PreferredActivityHelper {
return num;
}
- public ResolveInfo findPersistentPreferredActivity(Intent intent, int userId) {
+ public ResolveInfo findPersistentPreferredActivity(@NonNull Computer snapshot, Intent intent,
+ int userId) {
if (!UserHandle.isSameApp(Binder.getCallingUid(), Process.SYSTEM_UID)) {
throw new SecurityException(
"findPersistentPreferredActivity can only be run by the system");
@@ -670,24 +676,23 @@ final class PreferredActivityHelper {
final int callingUid = Binder.getCallingUid();
intent = PackageManagerServiceUtils.updateIntentForResolve(intent);
final String resolvedType = intent.resolveTypeIfNeeded(mPm.mContext.getContentResolver());
- final long flags = mPm.updateFlagsForResolve(
+ final long flags = snapshot.updateFlagsForResolve(
0, userId, callingUid, false /*includeInstantApps*/,
- mPm.isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, userId, resolvedType,
+ snapshot.isImplicitImageCaptureIntentAndNotSetByDpc(intent, userId, resolvedType,
0));
- final List<ResolveInfo> query = mPm.snapshotComputer().queryIntentActivitiesInternal(intent,
+ final List<ResolveInfo> query = snapshot.queryIntentActivitiesInternal(intent,
resolvedType, flags, userId);
- synchronized (mPm.mLock) {
- return mPm.findPersistentPreferredActivityLP(intent, resolvedType, flags, query, false,
- userId);
- }
+ return snapshot.findPersistentPreferredActivity(intent, resolvedType, flags, query, false,
+ userId);
}
/**
* Variant that takes a {@link WatchedIntentFilter}
*/
- public void setLastChosenActivity(Intent intent, String resolvedType, int flags,
- WatchedIntentFilter filter, int match, ComponentName activity) {
- if (mPm.getInstantAppPackageName(Binder.getCallingUid()) != null) {
+ public void setLastChosenActivity(@NonNull Computer snapshot, Intent intent,
+ String resolvedType, int flags, WatchedIntentFilter filter, int match,
+ ComponentName activity) {
+ if (snapshot.getInstantAppPackageName(Binder.getCallingUid()) != null) {
return;
}
final int userId = UserHandle.getCallingUserId();
@@ -701,25 +706,26 @@ final class PreferredActivityHelper {
filter.dump(new PrintStreamPrinter(System.out), " ");
}
intent.setComponent(null);
- final List<ResolveInfo> query = mPm.snapshotComputer().queryIntentActivitiesInternal(intent,
+ final List<ResolveInfo> query = snapshot.queryIntentActivitiesInternal(intent,
resolvedType, flags, userId);
// Find any earlier preferred or last chosen entries and nuke them
- findPreferredActivityNotLocked(
- intent, resolvedType, flags, query, false, true, false, userId);
+ findPreferredActivityNotLocked(snapshot, intent, resolvedType, flags, query, false, true,
+ false, userId);
// Add the new activity as the last chosen for this filter
- addPreferredActivity(filter, match, null, activity, false, userId,
+ addPreferredActivity(snapshot, filter, match, null, activity, false, userId,
"Setting last chosen", false);
}
- public ResolveInfo getLastChosenActivity(Intent intent, String resolvedType, int flags) {
- if (mPm.getInstantAppPackageName(Binder.getCallingUid()) != null) {
+ public ResolveInfo getLastChosenActivity(@NonNull Computer snapshot, Intent intent,
+ String resolvedType, int flags) {
+ if (snapshot.getInstantAppPackageName(Binder.getCallingUid()) != null) {
return null;
}
final int userId = UserHandle.getCallingUserId();
if (DEBUG_PREFERRED) Log.v(TAG, "Querying last chosen activity for " + intent);
- final List<ResolveInfo> query = mPm.snapshotComputer().queryIntentActivitiesInternal(intent,
+ final List<ResolveInfo> query = snapshot.queryIntentActivitiesInternal(intent,
resolvedType, flags, userId);
- return findPreferredActivityNotLocked(
- intent, resolvedType, flags, query, false, false, false, userId);
+ return findPreferredActivityNotLocked(snapshot, intent, resolvedType, flags, query, false,
+ false, false, userId);
}
}
diff --git a/services/core/java/com/android/server/pm/PreferredComponent.java b/services/core/java/com/android/server/pm/PreferredComponent.java
index 4ec042f79052..2a1ca2c41e64 100644
--- a/services/core/java/com/android/server/pm/PreferredComponent.java
+++ b/services/core/java/com/android/server/pm/PreferredComponent.java
@@ -57,7 +57,6 @@ public class PreferredComponent {
private String mParseError;
private final Callbacks mCallbacks;
- private final String mSetupWizardPackageName;
public interface Callbacks {
public boolean onReadTag(String tagName, TypedXmlPullParser parser)
@@ -72,7 +71,6 @@ public class PreferredComponent {
mAlways = always;
mShortComponent = component.flattenToShortString();
mParseError = null;
- mSetupWizardPackageName = null;
if (set != null) {
final int N = set.length;
String[] myPackages = new String[N];
@@ -174,8 +172,6 @@ public class PreferredComponent {
mSetPackages = myPackages;
mSetClasses = myClasses;
mSetComponents = myComponents;
- final PackageManagerInternal packageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
- mSetupWizardPackageName = packageManagerInternal.getSetupWizardPackageName();
}
public String getParseError() {
@@ -209,6 +205,7 @@ public class PreferredComponent {
final int NQ = query.size();
final int NS = mSetPackages.length;
final PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
+ String setupWizardPackageName = pmi.getSetupWizardPackageName();
int numMatch = 0;
for (int i=0; i<NQ; i++) {
ResolveInfo ri = query.get(i);
@@ -217,7 +214,7 @@ public class PreferredComponent {
// ignore SetupWizard package's launcher capability because it is only existed
// during SetupWizard is running
- if (excludeSetupWizardPackage && ai.packageName.equals(mSetupWizardPackageName)) {
+ if (excludeSetupWizardPackage && ai.packageName.equals(setupWizardPackageName)) {
continue;
}
@@ -307,6 +304,8 @@ public class PreferredComponent {
if (!excludeSetupWizardPackage && NS < NQ) {
return false;
}
+ final PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
+ String setupWizardPackageName = pmi.getSetupWizardPackageName();
for (int i=0; i<NQ; i++) {
ResolveInfo ri = query.get(i);
ActivityInfo ai = ri.activityInfo;
@@ -314,7 +313,7 @@ public class PreferredComponent {
// ignore SetupWizard package's launcher capability because it is only existed
// during SetupWizard is running
- if (excludeSetupWizardPackage && ai.packageName.equals(mSetupWizardPackageName)) {
+ if (excludeSetupWizardPackage && ai.packageName.equals(setupWizardPackageName)) {
continue;
}
diff --git a/services/core/java/com/android/server/pm/RemovePackageHelper.java b/services/core/java/com/android/server/pm/RemovePackageHelper.java
index 4d1519c361c9..b181cdd92379 100644
--- a/services/core/java/com/android/server/pm/RemovePackageHelper.java
+++ b/services/core/java/com/android/server/pm/RemovePackageHelper.java
@@ -118,7 +118,8 @@ final class RemovePackageHelper {
public void removePackageLI(AndroidPackage pkg, boolean chatty) {
// Remove the parent package setting
- PackageStateInternal ps = mPm.getPackageStateInternal(pkg.getPackageName());
+ PackageStateInternal ps = mPm.snapshotComputer()
+ .getPackageStateInternal(pkg.getPackageName());
if (ps != null) {
removePackageLI(ps.getPackageName(), chatty);
} else if (DEBUG_REMOVE && chatty) {
@@ -271,8 +272,8 @@ final class RemovePackageHelper {
synchronized (mPm.mLock) {
mPm.mDomainVerificationManager.clearPackage(deletedPs.getPackageName());
mPm.mSettings.getKeySetManagerService().removeAppKeySetDataLPw(packageName);
- mPm.mAppsFilter.removePackage(mPm.getPackageStateInternal(packageName),
- false /* isReplace */);
+ mPm.mAppsFilter.removePackage(mPm.snapshotComputer()
+ .getPackageStateInternal(packageName), false /* isReplace */);
removedAppId = mPm.mSettings.removePackageLPw(packageName);
if (outInfo != null) {
outInfo.mRemovedAppId = removedAppId;
@@ -284,7 +285,11 @@ final class RemovePackageHelper {
List<AndroidPackage> sharedUserPkgs =
sus != null ? sus.getPackages() : Collections.emptyList();
mPermissionManager.onPackageUninstalled(packageName, deletedPs.getAppId(),
- deletedPs.getPkg(), sharedUserPkgs, UserHandle.USER_ALL);
+ deletedPkg, sharedUserPkgs, UserHandle.USER_ALL);
+ // After permissions are handled, check if the shared user can be migrated
+ if (sus != null) {
+ mPm.mSettings.checkAndConvertSharedUserSettingsLPw(sus);
+ }
}
mPm.clearPackagePreferredActivitiesLPw(
deletedPs.getPackageName(), changedUsers, UserHandle.USER_ALL);
@@ -294,7 +299,8 @@ final class RemovePackageHelper {
if (changedUsers.size() > 0) {
final PreferredActivityHelper preferredActivityHelper =
new PreferredActivityHelper(mPm);
- preferredActivityHelper.updateDefaultHomeNotLocked(changedUsers);
+ preferredActivityHelper.updateDefaultHomeNotLocked(mPm.snapshotComputer(),
+ changedUsers);
mPm.postPreferredActivityChangedBroadcast(UserHandle.USER_ALL);
}
}
diff --git a/services/core/java/com/android/server/pm/ResolveIntentHelper.java b/services/core/java/com/android/server/pm/ResolveIntentHelper.java
index 25356a489217..b74670b77a11 100644
--- a/services/core/java/com/android/server/pm/ResolveIntentHelper.java
+++ b/services/core/java/com/android/server/pm/ResolveIntentHelper.java
@@ -115,7 +115,7 @@ final class ResolveIntentHelper {
if (!mUserManager.exists(userId)) return null;
final int callingUid = Binder.getCallingUid();
flags = computer.updateFlagsForResolve(flags, userId, filterCallingUid, resolveForStart,
- computer.isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, userId,
+ computer.isImplicitImageCaptureIntentAndNotSetByDpc(intent, userId,
resolvedType, flags));
computer.enforceCrossUserPermission(callingUid, userId, false /*requireFullPermission*/,
false /*checkShell*/, "resolve intent");
@@ -170,9 +170,9 @@ final class ResolveIntentHelper {
}
// If we have saved a preference for a preferred activity for
// this Intent, use that.
- ResolveInfo ri = mPreferredActivityHelper.findPreferredActivityNotLocked(intent,
- resolvedType, flags, query, true, false, debug, userId,
- queryMayBeFiltered);
+ ResolveInfo ri = mPreferredActivityHelper.findPreferredActivityNotLocked(computer,
+ intent, resolvedType, flags, query, true, false, debug,
+ userId, queryMayBeFiltered);
if (ri != null) {
return ri;
}
@@ -317,7 +317,7 @@ final class ResolveIntentHelper {
final String instantAppPkgName = computer.getInstantAppPackageName(filterCallingUid);
flags = computer.updateFlagsForResolve(flags, userId, filterCallingUid,
false /*includeInstantApps*/,
- computer.isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, userId,
+ computer.isImplicitImageCaptureIntentAndNotSetByDpc(intent, userId,
resolvedType, flags));
Intent originalIntent = null;
ComponentName comp = intent.getComponent();
@@ -562,7 +562,7 @@ final class ResolveIntentHelper {
final int callingUid = Binder.getCallingUid();
flags = computer.updateFlagsForResolve(flags, userId, callingUid,
false /*includeInstantApps*/,
- computer.isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, userId,
+ computer.isImplicitImageCaptureIntentAndNotSetByDpc(intent, userId,
resolvedType, flags));
computer.enforceCrossUserPermission(callingUid, userId, false /*requireFullPermission*/,
false /*checkShell*/, "query intent activity options");
diff --git a/services/core/java/com/android/server/pm/ScanPackageUtils.java b/services/core/java/com/android/server/pm/ScanPackageUtils.java
index 33f0b54fb2de..4e8313bf1891 100644
--- a/services/core/java/com/android/server/pm/ScanPackageUtils.java
+++ b/services/core/java/com/android/server/pm/ScanPackageUtils.java
@@ -165,25 +165,15 @@ final class ScanPackageUtils {
}
}
- int previousAppId = Process.INVALID_UID;
-
if (pkgSetting != null && oldSharedUserSetting != sharedUserSetting) {
- if (oldSharedUserSetting != null && sharedUserSetting == null) {
- previousAppId = pkgSetting.getAppId();
- // Log that something is leaving shareduid and keep going
- Slog.i(TAG,
- "Package " + parsedPackage.getPackageName() + " shared user changed from "
- + oldSharedUserSetting.name + " to " + "<nothing>.");
- } else {
- PackageManagerService.reportSettingsProblem(Log.WARN,
- "Package " + parsedPackage.getPackageName() + " shared user changed from "
- + (oldSharedUserSetting != null
- ? oldSharedUserSetting.name : "<nothing>")
- + " to "
- + (sharedUserSetting != null ? sharedUserSetting.name : "<nothing>")
- + "; replacing with new");
- pkgSetting = null;
- }
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Package " + parsedPackage.getPackageName() + " shared user changed from "
+ + (oldSharedUserSetting != null
+ ? oldSharedUserSetting.name : "<nothing>")
+ + " to "
+ + (sharedUserSetting != null ? sharedUserSetting.name : "<nothing>")
+ + "; replacing with new");
+ pkgSetting = null;
}
String[] usesSdkLibraries = null;
@@ -474,8 +464,8 @@ final class ScanPackageUtils {
return new ScanResult(request, true, pkgSetting, changedAbiCodePath,
!createNewPackage /* existingSettingCopied */,
- previousAppId, sdkLibraryInfo, staticSharedLibraryInfo,
- dynamicSharedLibraryInfos);
+ Process.INVALID_UID /* previousAppId */ , sdkLibraryInfo,
+ staticSharedLibraryInfo, dynamicSharedLibraryInfos);
}
/**
diff --git a/services/core/java/com/android/server/pm/ScanResult.java b/services/core/java/com/android/server/pm/ScanResult.java
index f77be1f9b2d3..e2860ca327e7 100644
--- a/services/core/java/com/android/server/pm/ScanResult.java
+++ b/services/core/java/com/android/server/pm/ScanResult.java
@@ -70,7 +70,9 @@ final class ScanResult {
mPkgSetting = pkgSetting;
mChangedAbiCodePath = changedAbiCodePath;
mExistingSettingCopied = existingSettingCopied;
- mPreviousAppId = previousAppId;
+ // Hardcode mPreviousAppId to INVALID_UID (http://b/221088088)
+ // This will disable all migration code paths in PMS and PermMS
+ mPreviousAppId = Process.INVALID_UID;
mSdkSharedLibraryInfo = sdkSharedLibraryInfo;
mStaticSharedLibraryInfo = staticSharedLibraryInfo;
mDynamicSharedLibraryInfos = dynamicSharedLibraryInfos;
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index d3665749a7f8..698dbe945e6f 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -29,6 +29,7 @@ import static android.os.Process.PACKAGE_INFO_GID;
import static android.os.Process.SYSTEM_UID;
import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
+import static com.android.server.pm.SharedUidMigration.BEST_EFFORT;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -39,7 +40,6 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
-import android.content.pm.ComponentInfo;
import android.content.pm.IntentFilterVerificationInfo;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
@@ -62,7 +62,6 @@ import android.os.Handler;
import android.os.Message;
import android.os.PatternMatcher;
import android.os.PersistableBundle;
-import android.os.Process;
import android.os.SELinux;
import android.os.SystemClock;
import android.os.Trace;
@@ -112,11 +111,9 @@ import com.android.server.pm.permission.LegacyPermissionState.PermissionState;
import com.android.server.pm.pkg.PackageStateInternal;
import com.android.server.pm.pkg.PackageUserState;
import com.android.server.pm.pkg.PackageUserStateInternal;
-import com.android.server.pm.pkg.PackageUserStateUtils;
import com.android.server.pm.pkg.SuspendParams;
import com.android.server.pm.pkg.component.ParsedComponent;
import com.android.server.pm.pkg.component.ParsedIntentInfo;
-import com.android.server.pm.pkg.component.ParsedMainComponent;
import com.android.server.pm.pkg.component.ParsedPermission;
import com.android.server.pm.pkg.component.ParsedProcess;
import com.android.server.pm.pkg.parsing.PackageInfoWithoutStateUtils;
@@ -410,8 +407,6 @@ public final class Settings implements Watchable, Snappable {
int[] excludedUserIds;
}
- private static int mFirstAvailableUid = Process.FIRST_APPLICATION_UID;
-
/** Map from volume UUID to {@link VersionInfo} */
@Watched
private final WatchedArrayMap<String, VersionInfo> mVersion = new WatchedArrayMap<>();
@@ -474,10 +469,8 @@ public final class Settings implements Watchable, Snappable {
@Watched
final WatchedArrayMap<String, SharedUserSetting> mSharedUsers = new WatchedArrayMap<>();
- @Watched
- private final WatchedArrayList<SettingBase> mAppIds;
- @Watched
- private final WatchedSparseArray<SettingBase> mOtherAppIds;
+ @Watched(manual = true)
+ private final AppIdSettingMap mAppIds;
// For reading/writing settings file.
@Watched
@@ -567,7 +560,6 @@ public final class Settings implements Watchable, Snappable {
mCrossProfileIntentResolvers.registerObserver(mObserver);
mSharedUsers.registerObserver(mObserver);
mAppIds.registerObserver(mObserver);
- mOtherAppIds.registerObserver(mObserver);
mRenamedPackages.registerObserver(mObserver);
mNextAppLinkGeneration.registerObserver(mObserver);
mDefaultBrowserApp.registerObserver(mObserver);
@@ -593,8 +585,7 @@ public final class Settings implements Watchable, Snappable {
mLock = new PackageManagerTracedLock();
mPackages.putAll(pkgSettings);
- mAppIds = new WatchedArrayList<>();
- mOtherAppIds = new WatchedSparseArray<>();
+ mAppIds = new AppIdSettingMap();
mSystemDir = null;
mPermissions = null;
mRuntimePermissionsPersistence = null;
@@ -630,8 +621,7 @@ public final class Settings implements Watchable, Snappable {
mKeySetManagerService = new KeySetManagerService(mPackages);
mLock = lock;
- mAppIds = new WatchedArrayList<>();
- mOtherAppIds = new WatchedSparseArray<>();
+ mAppIds = new AppIdSettingMap();
mPermissions = new LegacyPermissionSettings(lock);
mRuntimePermissionsPersistence = new RuntimePermissionPersistence(
runtimePermissionsPersistence, new Consumer<Integer>() {
@@ -712,7 +702,6 @@ public final class Settings implements Watchable, Snappable {
mCrossProfileIntentResolvers, r.mCrossProfileIntentResolvers);
mSharedUsers.snapshot(r.mSharedUsers);
mAppIds = r.mAppIds.snapshot();
- mOtherAppIds = r.mOtherAppIds.snapshot();
WatchedArrayList.snapshot(
mPastSignatures, r.mPastSignatures);
WatchedArrayMap.snapshot(
@@ -784,7 +773,7 @@ public final class Settings implements Watchable, Snappable {
SharedUserSetting s = mSharedUsers.get(name);
if (s == null && create) {
s = new SharedUserSetting(name, pkgFlags, pkgPrivateFlags);
- s.mAppId = acquireAndRegisterNewAppIdLPw(s);
+ s.mAppId = mAppIds.acquireAndRegisterNewAppId(s);
if (s.mAppId < 0) {
// < 0 means we couldn't assign a userid; throw exception
throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE,
@@ -892,7 +881,7 @@ public final class Settings implements Watchable, Snappable {
pkgPrivateFlags, 0 /*userId*/, usesSdkLibraries, usesSdkLibrariesVersions,
usesStaticLibraries, usesStaticLibrariesVersions, mimeGroups, domainSetId);
p.setAppId(uid);
- if (registerExistingAppIdLPw(uid, p, name)) {
+ if (mAppIds.registerExistingAppId(uid, p, name)) {
mPackages.put(name, p);
return p;
}
@@ -911,7 +900,7 @@ public final class Settings implements Watchable, Snappable {
}
s = new SharedUserSetting(name, pkgFlags, pkgPrivateFlags);
s.mAppId = uid;
- if (registerExistingAppIdLPw(uid, s, name)) {
+ if (mAppIds.registerExistingAppId(uid, s, name)) {
mSharedUsers.put(name, s);
return s;
}
@@ -1212,11 +1201,11 @@ public final class Settings implements Watchable, Snappable {
final boolean createdNew;
if (p.getAppId() == 0 || forceNew) {
// Assign new user ID
- p.setAppId(acquireAndRegisterNewAppIdLPw(p));
+ p.setAppId(mAppIds.acquireAndRegisterNewAppId(p));
createdNew = true;
} else {
// Add new setting to list of user IDs
- createdNew = registerExistingAppIdLPw(p.getAppId(), p, p.getPackageName());
+ createdNew = mAppIds.registerExistingAppId(p.getAppId(), p, p.getPackageName());
}
if (p.getAppId() < 0) {
PackageManagerService.reportSettingsProblem(Log.WARN,
@@ -1277,7 +1266,8 @@ public final class Settings implements Watchable, Snappable {
// Utility method that adds a PackageSetting to mPackages and
// completes updating the shared user attributes and any restored
// app link verification state
- private void addPackageSettingLPw(PackageSetting p, SharedUserSetting sharedUser) {
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
+ void addPackageSettingLPw(PackageSetting p, SharedUserSetting sharedUser) {
mPackages.put(p.getPackageName(), p);
if (sharedUser != null) {
SharedUserSetting existingSharedUserSetting = getSharedUserSettingLPr(p);
@@ -1300,16 +1290,16 @@ public final class Settings implements Watchable, Snappable {
p.setAppId(sharedUser.mAppId);
}
- // If the we know about this user id, we have to update it as it
+ // If we know about this user id, we have to update it as it
// has to point to the same PackageSetting instance as the package.
Object userIdPs = getSettingLPr(p.getAppId());
if (sharedUser == null) {
if (userIdPs != null && userIdPs != p) {
- replaceAppIdLPw(p.getAppId(), p);
+ mAppIds.replaceSetting(p.getAppId(), p);
}
} else {
if (userIdPs != null && userIdPs != sharedUser) {
- replaceAppIdLPw(p.getAppId(), sharedUser);
+ mAppIds.replaceSetting(p.getAppId(), sharedUser);
}
}
}
@@ -1358,69 +1348,41 @@ public final class Settings implements Watchable, Snappable {
mInstallerPackages.remove(packageName);
}
- /** Returns true if the requested AppID was valid and not already registered. */
- private boolean registerExistingAppIdLPw(int appId, SettingBase obj, Object name) {
- if (appId > Process.LAST_APPLICATION_UID) {
- return false;
- }
-
- if (appId >= Process.FIRST_APPLICATION_UID) {
- int size = mAppIds.size();
- final int index = appId - Process.FIRST_APPLICATION_UID;
- // fill the array until our index becomes valid
- while (index >= size) {
- mAppIds.add(null);
- size++;
- }
- if (mAppIds.get(index) != null) {
- PackageManagerService.reportSettingsProblem(Log.WARN,
- "Adding duplicate app id: " + appId
- + " name=" + name);
- return false;
- }
- mAppIds.set(index, obj);
- } else {
- if (mOtherAppIds.get(appId) != null) {
- PackageManagerService.reportSettingsProblem(Log.WARN,
- "Adding duplicate shared id: " + appId
- + " name=" + name);
- return false;
- }
- mOtherAppIds.put(appId, obj);
- }
- return true;
- }
-
/** Gets the setting associated with the provided App ID */
public SettingBase getSettingLPr(int appId) {
- if (appId >= Process.FIRST_APPLICATION_UID) {
- final int size = mAppIds.size();
- final int index = appId - Process.FIRST_APPLICATION_UID;
- return index < size ? mAppIds.get(index) : null;
- } else {
- return mOtherAppIds.get(appId);
- }
+ return mAppIds.getSetting(appId);
}
/** Unregisters the provided app ID. */
void removeAppIdLPw(int appId) {
- if (appId >= Process.FIRST_APPLICATION_UID) {
- final int size = mAppIds.size();
- final int index = appId - Process.FIRST_APPLICATION_UID;
- if (index < size) mAppIds.set(index, null);
- } else {
- mOtherAppIds.remove(appId);
+ mAppIds.removeSetting(appId);
+ }
+ /**
+ * Transparently convert a SharedUserSetting into PackageSettings without changing appId.
+ * The sharedUser passed to this method has to be {@link SharedUserSetting#isSingleUser()}.
+ */
+ void convertSharedUserSettingsLPw(SharedUserSetting sharedUser) {
+ final PackageSetting ps = sharedUser.getPackageSettings().valueAt(0);
+ mAppIds.replaceSetting(sharedUser.getAppId(), ps);
+
+ // Unlink the SharedUserSetting
+ ps.setSharedUserAppId(INVALID_UID);
+ if (!sharedUser.getDisabledPackageSettings().isEmpty()) {
+ final PackageSetting disabledPs = sharedUser.getDisabledPackageSettings().valueAt(0);
+ disabledPs.setSharedUserAppId(INVALID_UID);
}
- setFirstAvailableUid(appId + 1);
+ mSharedUsers.remove(sharedUser.getName());
}
- private void replaceAppIdLPw(int appId, SettingBase obj) {
- if (appId >= Process.FIRST_APPLICATION_UID) {
- final int size = mAppIds.size();
- final int index = appId - Process.FIRST_APPLICATION_UID;
- if (index < size) mAppIds.set(index, obj);
- } else {
- mOtherAppIds.put(appId, obj);
+ /**
+ * Check and convert eligible SharedUserSettings to PackageSettings.
+ */
+ void checkAndConvertSharedUserSettingsLPw(SharedUserSetting sharedUser) {
+ if (!sharedUser.isSingleUser()) return;
+ final AndroidPackage pkg = sharedUser.getPackageSettings().valueAt(0).getPkg();
+ if (pkg != null && pkg.isLeavingSharedUid()
+ && SharedUidMigration.applyStrategy(BEST_EFFORT)) {
+ convertSharedUserSettingsLPw(sharedUser);
}
}
@@ -4190,10 +4152,11 @@ public final class Settings implements Watchable, Snappable {
// Accumulate all required args and call the installer after mPackages lock
// has been released
final String seInfo = AndroidPackageUtils.getSeInfo(ps.getPkg(), ps);
+ final boolean usesSdk = !ps.getPkg().getUsesSdkLibraries().isEmpty();
final CreateAppDataArgs args = Installer.buildCreateAppDataArgs(
ps.getVolumeUuid(), ps.getPackageName(), userHandle,
StorageManager.FLAG_STORAGE_CE | StorageManager.FLAG_STORAGE_DE,
- ps.getAppId(), seInfo, ps.getPkg().getTargetSdkVersion());
+ ps.getAppId(), seInfo, ps.getPkg().getTargetSdkVersion(), usesSdk);
batch.createAppData(args);
} else {
// Make sure the app is excluded from storage mapping for this user
@@ -4264,33 +4227,6 @@ public final class Settings implements Watchable, Snappable {
}
}
- // This should be called (at least) whenever an application is removed
- private void setFirstAvailableUid(int uid) {
- if (uid > mFirstAvailableUid) {
- mFirstAvailableUid = uid;
- }
- }
-
- /** Returns a new AppID or -1 if we could not find an available AppID to assign */
- private int acquireAndRegisterNewAppIdLPw(SettingBase obj) {
- // Let's be stupidly inefficient for now...
- final int size = mAppIds.size();
- for (int i = mFirstAvailableUid - Process.FIRST_APPLICATION_UID; i < size; i++) {
- if (mAppIds.get(i) == null) {
- mAppIds.set(i, obj);
- return Process.FIRST_APPLICATION_UID + i;
- }
- }
-
- // None left?
- if (size > (Process.LAST_APPLICATION_UID - Process.FIRST_APPLICATION_UID)) {
- return -1;
- }
-
- mAppIds.add(obj);
- return Process.FIRST_APPLICATION_UID + size;
- }
-
public VerifierDeviceIdentity getVerifierDeviceIdentityLPw(@NonNull Computer computer) {
if (mVerifierDeviceIdentity == null) {
mVerifierDeviceIdentity = VerifierDeviceIdentity.generate();
@@ -4323,33 +4259,6 @@ public final class Settings implements Watchable, Snappable {
return getDisabledSystemPkgLPr(enabledPackageSetting.getPackageName());
}
- boolean isEnabledAndMatchLPr(ComponentInfo componentInfo, long flags, int userId) {
- final PackageSetting ps = mPackages.get(componentInfo.packageName);
- if (ps == null) return false;
-
- final PackageUserStateInternal userState = ps.readUserState(userId);
- return PackageUserStateUtils.isMatch(userState, componentInfo, flags);
- }
-
- @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
- public boolean isEnabledAndMatchLPr(AndroidPackage pkg, ParsedMainComponent component,
- long flags, int userId) {
- final PackageSetting ps = mPackages.get(component.getPackageName());
- if (ps == null) return false;
-
- final PackageUserStateInternal userState = ps.readUserState(userId);
- return PackageUserStateUtils.isMatch(userState, pkg.isSystem(), pkg.isEnabled(), component,
- flags);
- }
-
- boolean isOrphaned(String packageName) {
- final PackageSetting pkg = mPackages.get(packageName);
- if (pkg == null) {
- throw new IllegalArgumentException("Unknown package: " + packageName);
- }
- return pkg.getInstallSource().isOrphaned;
- }
-
int getApplicationEnabledSettingLPr(String packageName, int userId)
throws PackageManager.NameNotFoundException {
final PackageSetting pkg = mPackages.get(packageName);
diff --git a/services/core/java/com/android/server/pm/SharedLibrariesImpl.java b/services/core/java/com/android/server/pm/SharedLibrariesImpl.java
index 3fe079034cf2..479a404c88bf 100644
--- a/services/core/java/com/android/server/pm/SharedLibrariesImpl.java
+++ b/services/core/java/com/android/server/pm/SharedLibrariesImpl.java
@@ -741,9 +741,11 @@ public final class SharedLibrariesImpl implements SharedLibrariesRead, Watchable
}
SharedLibraryInfo libraryInfo = versionedLib.valueAt(libIdx);
+ final Computer snapshot = mPm.snapshotComputer();
+
// Remove the shared library overlays from its dependent packages.
for (int currentUserId : mPm.mUserManager.getUserIds()) {
- final List<VersionedPackage> dependents = mPm.getPackagesUsingSharedLibrary(
+ final List<VersionedPackage> dependents = snapshot.getPackagesUsingSharedLibrary(
libraryInfo, 0, Process.SYSTEM_UID, currentUserId);
if (dependents == null) {
continue;
diff --git a/services/core/java/com/android/server/pm/SharedUidMigration.java b/services/core/java/com/android/server/pm/SharedUidMigration.java
new file mode 100644
index 000000000000..e44ef662efff
--- /dev/null
+++ b/services/core/java/com/android/server/pm/SharedUidMigration.java
@@ -0,0 +1,99 @@
+/*
+ * 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.content.pm.PackageManager;
+import android.os.Build;
+import android.os.SystemProperties;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * A utility class hosting code configuring shared UID migration behavior.
+ */
+public final class SharedUidMigration {
+
+ /**
+ * The system property key used to configure the shared UID migration strategy.
+ */
+ public static final String PROPERTY_KEY = "persist.debug.pm.shared_uid_migration_strategy";
+
+ /**
+ * Only leave shared UID for newly installed packages.
+ */
+ public static final int NEW_INSTALL_ONLY = 1;
+ /**
+ * Opportunistically migrate any single-package shared UID group.
+ */
+ public static final int BEST_EFFORT = 2;
+ /**
+ * Run appId transitions when the device reboots.
+ */
+ public static final int TRANSITION_AT_BOOT = 3;
+ /**
+ * Run appId transitions as soon as the upgrade is installed.
+ */
+ public static final int LIVE_TRANSITION = 4;
+
+ @IntDef({
+ NEW_INSTALL_ONLY,
+ BEST_EFFORT,
+ TRANSITION_AT_BOOT,
+ LIVE_TRANSITION,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Strategy {}
+
+ @Strategy
+ private static final int DEFAULT = BEST_EFFORT;
+
+ /**
+ * Whether shared UID migration is fully disabled. Disabled means the sharedUserMaxSdkVersion
+ * attribute will be directly ignored in the parsing phase.
+ */
+ public static boolean isDisabled() {
+ return !PackageManager.ENABLE_SHARED_UID_MIGRATION;
+ }
+
+ /**
+ * If the system is userdebug, returns the strategy to use by getting the system property
+ * {@link #PROPERTY_KEY}, or else returns the default strategy enabled in the build.
+ */
+ public static int getCurrentStrategy() {
+ if (!Build.IS_USERDEBUG) {
+ return DEFAULT;
+ }
+
+ final int s = SystemProperties.getInt(PROPERTY_KEY, DEFAULT);
+ // No transition strategies can be used (http://b/221088088)
+ if (s > BEST_EFFORT || s < NEW_INSTALL_ONLY) {
+ return DEFAULT;
+ }
+ return s;
+ }
+
+ /**
+ * Should the strategy be used based on the current active strategy.
+ */
+ public static boolean applyStrategy(@Strategy int strategy) {
+ return !isDisabled() && getCurrentStrategy() >= strategy;
+ }
+
+ private SharedUidMigration() {}
+}
diff --git a/services/core/java/com/android/server/pm/SharedUserSetting.java b/services/core/java/com/android/server/pm/SharedUserSetting.java
index 4d0bbc6fe437..23f0de8a5f71 100644
--- a/services/core/java/com/android/server/pm/SharedUserSetting.java
+++ b/services/core/java/com/android/server/pm/SharedUserSetting.java
@@ -221,6 +221,25 @@ public final class SharedUserSetting extends SettingBase implements SharedUserAp
}
/**
+ * A shared user is considered "single user" if there is exactly one single package
+ * currently using it. In the case when that package is also a system app, the APK on
+ * the system partition has to also leave shared UID.
+ */
+ public boolean isSingleUser() {
+ if (mPackages.size() != 1) {
+ return false;
+ }
+ if (mDisabledPackages.size() > 1) {
+ return false;
+ }
+ if (mDisabledPackages.size() == 1) {
+ final AndroidPackage pkg = mDisabledPackages.valueAt(0).getPkg();
+ return pkg != null && pkg.isLeavingSharedUid();
+ }
+ return true;
+ }
+
+ /**
* Determine the targetSdkVersion for a sharedUser and update pkg.applicationInfo.seInfo
* to ensure that all apps within the sharedUser share an SELinux domain. Use the lowest
* targetSdkVersion of all apps within the shared user, which corresponds to the least
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
index 8921fee6c8e0..7a73412c9b9f 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
@@ -19,9 +19,12 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.Person;
+import android.app.appsearch.AppSearchBatchResult;
import android.app.appsearch.AppSearchManager;
import android.app.appsearch.AppSearchResult;
import android.app.appsearch.AppSearchSession;
+import android.app.appsearch.BatchResultCallback;
+import android.app.appsearch.GenericDocument;
import android.app.appsearch.GetByDocumentIdRequest;
import android.app.appsearch.PackageIdentifier;
import android.app.appsearch.PutDocumentsRequest;
@@ -1827,9 +1830,9 @@ class ShortcutPackage extends ShortcutPackageItem {
ShortcutService.writeTagExtra(out, TAG_EXTRAS, si.getExtras());
final Map<String, Map<String, List<String>>> capabilityBindings =
- si.getCapabilityBindings();
+ si.getCapabilityBindingsInternal();
if (capabilityBindings != null && !capabilityBindings.isEmpty()) {
- XmlUtils.writeMapXml(si.getCapabilityBindings(), NAME_CAPABILITY, out);
+ XmlUtils.writeMapXml(capabilityBindings, NAME_CAPABILITY, out);
}
}
@@ -2384,14 +2387,24 @@ class ShortcutPackage extends ShortcutPackageItem {
}
runAsSystem(() -> fromAppSearch().thenAccept(session -> {
session.getByDocumentId(new GetByDocumentIdRequest.Builder(getPackageName())
- .addIds(ids).build(), mShortcutUser.mExecutor, result -> {
- final List<ShortcutInfo> ret = result.getSuccesses().values()
- .stream().map(doc ->
- ShortcutInfo.createFromGenericDocument(
- mShortcutUser.getUserId(), doc))
- .collect(Collectors.toList());
- cb.accept(ret);
- });
+ .addIds(ids).build(), mShortcutUser.mExecutor,
+ new BatchResultCallback<String, GenericDocument>() {
+ @Override
+ public void onResult(
+ @NonNull AppSearchBatchResult<String, GenericDocument> result) {
+ final List<ShortcutInfo> ret = result.getSuccesses().values()
+ .stream().map(doc ->
+ ShortcutInfo.createFromGenericDocument(
+ mShortcutUser.getUserId(), doc))
+ .collect(Collectors.toList());
+ cb.accept(ret);
+ }
+ @Override
+ public void onSystemError(
+ @Nullable Throwable throwable) {
+ Slog.d(TAG, "Error retrieving shortcuts", throwable);
+ }
+ });
}));
}
@@ -2407,15 +2420,24 @@ class ShortcutPackage extends ShortcutPackageItem {
runAsSystem(() -> fromAppSearch().thenAccept(session ->
session.remove(
new RemoveByDocumentIdRequest.Builder(getPackageName()).addIds(ids).build(),
- mShortcutUser.mExecutor, result -> {
- if (!result.isSuccess()) {
- final Map<String, AppSearchResult<Void>> failures =
- result.getFailures();
- for (String key : failures.keySet()) {
- Slog.e(TAG, "Failed deleting " + key + ", error message:"
- + failures.get(key).getErrorMessage());
+ mShortcutUser.mExecutor,
+ new BatchResultCallback<String, Void>() {
+ @Override
+ public void onResult(
+ @NonNull AppSearchBatchResult<String, Void> result) {
+ if (!result.isSuccess()) {
+ final Map<String, AppSearchResult<Void>> failures =
+ result.getFailures();
+ for (String key : failures.keySet()) {
+ Slog.e(TAG, "Failed deleting " + key + ", error message:"
+ + failures.get(key).getErrorMessage());
+ }
}
}
+ @Override
+ public void onSystemError(@Nullable Throwable throwable) {
+ Slog.e(TAG, "Error removing shortcuts", throwable);
+ }
})));
}
@@ -2452,12 +2474,20 @@ class ShortcutPackage extends ShortcutPackageItem {
AppSearchShortcutInfo.toGenericDocuments(shortcuts))
.build(),
mShortcutUser.mExecutor,
- result -> {
- if (!result.isSuccess()) {
- for (AppSearchResult<Void> k : result.getFailures().values()) {
- Slog.e(TAG, k.getErrorMessage());
+ new BatchResultCallback<String, Void>() {
+ @Override
+ public void onResult(
+ @NonNull AppSearchBatchResult<String, Void> result) {
+ if (!result.isSuccess()) {
+ for (AppSearchResult<Void> k : result.getFailures().values()) {
+ Slog.e(TAG, k.getErrorMessage());
+ }
}
}
+ @Override
+ public void onSystemError(@Nullable Throwable throwable) {
+ Slog.d(TAG, "Error persisting shortcuts", throwable);
+ }
});
}));
}
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 1cf2dc52e430..25fe0007ec4b 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -488,7 +488,8 @@ public class ShortcutService extends IShortcutService.Stub {
mShortcutBitmapSaver = new ShortcutBitmapSaver(this);
mShortcutDumpFiles = new ShortcutDumpFiles(this);
mIsAppSearchEnabled = DeviceConfig.getBoolean(NAMESPACE_SYSTEMUI,
- SystemUiDeviceConfigFlags.SHORTCUT_APPSEARCH_INTEGRATION, true);
+ SystemUiDeviceConfigFlags.SHORTCUT_APPSEARCH_INTEGRATION, true)
+ && !injectIsLowRamDevice();
if (onlyForPackageManagerApis) {
return; // Don't do anything further. For unit tests only.
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index 52a7beda43fb..43dde5cce2d6 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -28,8 +28,6 @@ import android.content.IntentFilter;
import android.content.pm.ApexStagedEvent;
import android.content.pm.IStagedApexObserver;
import android.content.pm.PackageInstaller;
-import android.content.pm.PackageInstaller.SessionInfo;
-import android.content.pm.PackageInstaller.SessionInfo.SessionErrorCode;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.content.pm.StagedApexInfo;
@@ -124,7 +122,7 @@ public class StagingManager {
boolean containsApkSession();
boolean containsApexSession();
void setSessionReady();
- void setSessionFailed(@SessionErrorCode int errorCode, String errorMessage);
+ void setSessionFailed(int errorCode, String errorMessage);
void setSessionApplied();
CompletableFuture<Void> installSession();
boolean hasParentSessionId();
@@ -279,7 +277,7 @@ public class StagingManager {
String packageName = apexSession.getPackageName();
String errorMsg = mApexManager.getApkInApexInstallError(packageName);
if (errorMsg != null) {
- throw new PackageManagerException(SessionInfo.SESSION_ACTIVATION_FAILED,
+ throw new PackageManagerException(PackageManager.INSTALL_ACTIVATION_FAILED,
"Failed to install apk-in-apex of " + packageName + " : " + errorMsg);
}
}
@@ -392,7 +390,7 @@ public class StagingManager {
revertMsg += " Reason for revert: " + reasonForRevert;
}
Slog.d(TAG, revertMsg);
- session.setSessionFailed(SessionInfo.SESSION_UNKNOWN_ERROR, revertMsg);
+ session.setSessionFailed(PackageManager.INSTALL_FAILED_INTERNAL_ERROR, revertMsg);
return;
}
@@ -477,7 +475,7 @@ public class StagingManager {
for (String apkInApex : mApexManager.getApksInApex(packageName)) {
if (!apkNames.add(apkInApex)) {
throw new PackageManagerException(
- SessionInfo.SESSION_ACTIVATION_FAILED,
+ PackageManager.INSTALL_ACTIVATION_FAILED,
"Package: " + packageName + " in session: "
+ apexSession.sessionId() + " has duplicate apk-in-apex: "
+ apkInApex, null);
@@ -495,9 +493,7 @@ public class StagingManager {
// Should be impossible
throw new RuntimeException(e);
} catch (ExecutionException ee) {
- PackageManagerException e = (PackageManagerException) ee.getCause();
- final String errorMsg = PackageManager.installStatusToString(e.error, e.getMessage());
- throw new PackageManagerException(SessionInfo.SESSION_ACTIVATION_FAILED, errorMsg);
+ throw (PackageManagerException) ee.getCause();
}
}
@@ -651,7 +647,7 @@ public class StagingManager {
// is upgrading. Fail all the sessions and exit early.
for (int i = 0; i < sessions.size(); i++) {
StagedSession session = sessions.get(i);
- session.setSessionFailed(SessionInfo.SESSION_ACTIVATION_FAILED,
+ session.setSessionFailed(PackageManager.INSTALL_ACTIVATION_FAILED,
"Build fingerprint has changed");
}
return;
@@ -691,7 +687,7 @@ public class StagingManager {
final ApexSessionInfo apexSession = apexSessions.get(session.sessionId());
if (apexSession == null || apexSession.isUnknown) {
hasFailedApexSession = true;
- session.setSessionFailed(SessionInfo.SESSION_ACTIVATION_FAILED, "apexd did "
+ session.setSessionFailed(PackageManager.INSTALL_ACTIVATION_FAILED, "apexd did "
+ "not know anything about a staged session supposed to be activated");
continue;
} else if (isApexSessionFailed(apexSession)) {
@@ -707,7 +703,7 @@ public class StagingManager {
errorMsg += " Error: " + apexSession.errorMessage;
}
Slog.d(TAG, errorMsg);
- session.setSessionFailed(SessionInfo.SESSION_ACTIVATION_FAILED, errorMsg);
+ session.setSessionFailed(PackageManager.INSTALL_ACTIVATION_FAILED, errorMsg);
continue;
} else if (apexSession.isActivated || apexSession.isSuccess) {
hasAppliedApexSession = true;
@@ -716,13 +712,13 @@ public class StagingManager {
// Apexd did not apply the session for some unknown reason. There is no guarantee
// that apexd will install it next time. Safer to proactively mark it as failed.
hasFailedApexSession = true;
- session.setSessionFailed(SessionInfo.SESSION_ACTIVATION_FAILED,
+ session.setSessionFailed(PackageManager.INSTALL_ACTIVATION_FAILED,
"Staged session " + session.sessionId() + " at boot didn't activate nor "
+ "fail. Marking it as failed anyway.");
} else {
Slog.w(TAG, "Apex session " + session.sessionId() + " is in impossible state");
hasFailedApexSession = true;
- session.setSessionFailed(SessionInfo.SESSION_ACTIVATION_FAILED,
+ session.setSessionFailed(PackageManager.INSTALL_ACTIVATION_FAILED,
"Impossible state");
}
}
@@ -742,7 +738,7 @@ public class StagingManager {
// Session has been already failed in the loop above.
continue;
}
- session.setSessionFailed(SessionInfo.SESSION_ACTIVATION_FAILED,
+ session.setSessionFailed(PackageManager.INSTALL_ACTIVATION_FAILED,
"Another apex session failed");
}
return;
@@ -758,7 +754,7 @@ public class StagingManager {
} catch (Exception e) {
Slog.e(TAG, "Staged install failed due to unhandled exception", e);
onInstallationFailure(session, new PackageManagerException(
- SessionInfo.SESSION_ACTIVATION_FAILED,
+ PackageManager.INSTALL_FAILED_INTERNAL_ERROR,
"Staged install failed due to unhandled exception: " + e),
supportsCheckpoint, needsCheckpoint);
}
diff --git a/services/core/java/com/android/server/pm/StorageEventHelper.java b/services/core/java/com/android/server/pm/StorageEventHelper.java
index bb7e55a4bf40..a991ed3c4792 100644
--- a/services/core/java/com/android/server/pm/StorageEventHelper.java
+++ b/services/core/java/com/android/server/pm/StorageEventHelper.java
@@ -26,13 +26,13 @@ import static com.android.server.pm.PackageManagerService.SCAN_INITIAL;
import static com.android.server.pm.PackageManagerService.TAG;
import static com.android.server.pm.PackageManagerServiceUtils.logCriticalInfo;
+import android.annotation.NonNull;
import android.app.ResourcesManager;
import android.content.IIntentReceiver;
import android.content.pm.PackageManager;
import android.content.pm.PackagePartitions;
import android.content.pm.UserInfo;
import android.content.pm.VersionedPackage;
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
import android.os.Environment;
import android.os.FileUtils;
import android.os.UserHandle;
@@ -48,6 +48,7 @@ import android.util.Slog;
import com.android.internal.policy.AttributeCache;
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.util.ArrayList;
@@ -78,7 +79,7 @@ public final class StorageEventHelper extends StorageEventListener {
// Clean up any users or apps that were removed or recreated
// while this volume was missing
mPm.mUserManager.reconcileUsers(volumeUuid);
- reconcileApps(volumeUuid);
+ reconcileApps(mPm.snapshotComputer(), volumeUuid);
// Clean up any install sessions that expired or were
// cancelled while this volume was missing
@@ -150,7 +151,7 @@ public final class StorageEventHelper extends StorageEventListener {
final AndroidPackage pkg;
try {
pkg = installPackageHelper.scanSystemPackageTracedLI(
- ps.getPath(), parseFlags, SCAN_INITIAL, 0, null);
+ ps.getPath(), parseFlags, SCAN_INITIAL, null);
loaded.add(pkg);
} catch (PackageManagerException e) {
@@ -299,8 +300,8 @@ public final class StorageEventHelper extends StorageEventListener {
* aren't expected, either due to uninstallation or reinstallation on
* another volume.
*/
- public void reconcileApps(String volumeUuid) {
- List<String> absoluteCodePaths = collectAbsoluteCodePaths();
+ public void reconcileApps(@NonNull Computer snapshot, String volumeUuid) {
+ List<String> absoluteCodePaths = collectAbsoluteCodePaths(snapshot);
List<File> filesToDelete = null;
final File[] files = FileUtils.listFilesOrEmpty(
@@ -345,10 +346,10 @@ public final class StorageEventHelper extends StorageEventListener {
}
}
- private List<String> collectAbsoluteCodePaths() {
+ private List<String> collectAbsoluteCodePaths(@NonNull Computer snapshot) {
List<String> codePaths = new ArrayList<>();
final ArrayMap<String, ? extends PackageStateInternal> packageStates =
- mPm.getPackageStates();
+ snapshot.getPackageStates();
final int packageCount = packageStates.size();
for (int i = 0; i < packageCount; i++) {
final PackageStateInternal ps = packageStates.valueAt(i);
diff --git a/services/core/java/com/android/server/pm/SuspendPackageHelper.java b/services/core/java/com/android/server/pm/SuspendPackageHelper.java
index 3ef5599385ce..588dfaf6db78 100644
--- a/services/core/java/com/android/server/pm/SuspendPackageHelper.java
+++ b/services/core/java/com/android/server/pm/SuspendPackageHelper.java
@@ -100,14 +100,14 @@ public final class SuspendPackageHelper {
* @return The names of failed packages.
*/
@Nullable
- String[] setPackagesSuspended(@NonNull Computer computer, @Nullable String[] packageNames,
+ String[] setPackagesSuspended(@NonNull Computer snapshot, @Nullable String[] packageNames,
boolean suspended, @Nullable PersistableBundle appExtras,
@Nullable PersistableBundle launcherExtras, @Nullable SuspendDialogInfo dialogInfo,
@NonNull String callingPackage, @UserIdInt int userId, int callingUid) {
if (ArrayUtils.isEmpty(packageNames)) {
return packageNames;
}
- if (suspended && !isSuspendAllowedForUser(userId, callingUid)) {
+ if (suspended && !isSuspendAllowedForUser(snapshot, userId, callingUid)) {
Slog.w(TAG, "Cannot suspend due to restrictions on user " + userId);
return packageNames;
}
@@ -123,7 +123,7 @@ public final class SuspendPackageHelper {
ArraySet<String> modifiedPackages = new ArraySet<>();
final boolean[] canSuspend = suspended
- ? canSuspendPackageForUser(computer, packageNames, userId, callingUid) : null;
+ ? canSuspendPackageForUser(snapshot, packageNames, userId, callingUid) : null;
for (int i = 0; i < packageNames.length; i++) {
final String packageName = packageNames[i];
if (callingPackage.equals(packageName)) {
@@ -133,9 +133,9 @@ public final class SuspendPackageHelper {
continue;
}
final PackageStateInternal packageState =
- computer.getPackageStateInternal(packageName);
+ snapshot.getPackageStateInternal(packageName);
if (packageState == null
- || computer.shouldFilterApplication(packageState, callingUid, userId)) {
+ || snapshot.shouldFilterApplication(packageState, callingUid, userId)) {
Slog.w(TAG, "Could not find package setting for package: " + packageName
+ ". Skipping suspending/un-suspending.");
unmodifiablePackages.add(packageName);
@@ -191,9 +191,11 @@ public final class SuspendPackageHelper {
}
});
+ final Computer newSnapshot = mPm.snapshotComputer();
+
if (!changedPackagesList.isEmpty()) {
final String[] changedPackages = changedPackagesList.toArray(new String[0]);
- sendPackagesSuspendedForUser(
+ sendPackagesSuspendedForUser(newSnapshot,
suspended ? Intent.ACTION_PACKAGES_SUSPENDED
: Intent.ACTION_PACKAGES_UNSUSPENDED,
changedPackages, changedUids.toArray(), userId);
@@ -202,7 +204,7 @@ public final class SuspendPackageHelper {
}
// Send the suspension changed broadcast to ensure suspension state is not stale.
if (!modifiedPackages.isEmpty()) {
- sendPackagesSuspendedForUser(Intent.ACTION_PACKAGES_SUSPENSION_CHANGED,
+ sendPackagesSuspendedForUser(newSnapshot, Intent.ACTION_PACKAGES_SUSPENSION_CHANGED,
modifiedPackages.toArray(new String[0]), modifiedUids.toArray(), userId);
}
return unmodifiablePackages.toArray(new String[0]);
@@ -217,14 +219,14 @@ public final class SuspendPackageHelper {
* @return The names of packages which are Unsuspendable.
*/
@NonNull
- String[] getUnsuspendablePackagesForUser(@NonNull Computer computer,
+ String[] getUnsuspendablePackagesForUser(@NonNull Computer snapshot,
@NonNull String[] packageNames, @UserIdInt int userId, int callingUid) {
- if (!isSuspendAllowedForUser(userId, callingUid)) {
+ if (!isSuspendAllowedForUser(snapshot, userId, callingUid)) {
Slog.w(TAG, "Cannot suspend due to restrictions on user " + userId);
return packageNames;
}
final ArraySet<String> unactionablePackages = new ArraySet<>();
- final boolean[] canSuspend = canSuspendPackageForUser(computer, packageNames, userId,
+ final boolean[] canSuspend = canSuspendPackageForUser(snapshot, packageNames, userId,
callingUid);
for (int i = 0; i < packageNames.length; i++) {
if (!canSuspend[i]) {
@@ -232,7 +234,7 @@ public final class SuspendPackageHelper {
continue;
}
final PackageStateInternal packageState =
- computer.getPackageStateFiltered(packageNames[i], callingUid, userId);
+ snapshot.getPackageStateFiltered(packageNames[i], callingUid, userId);
if (packageState == null) {
Slog.w(TAG, "Could not find package setting for package: " + packageNames[i]);
unactionablePackages.add(packageNames[i]);
@@ -250,8 +252,9 @@ public final class SuspendPackageHelper {
* @return The app extras of the suspended package.
*/
@Nullable
- Bundle getSuspendedPackageAppExtras(@NonNull String packageName, int userId, int callingUid) {
- final PackageStateInternal ps = mPm.getPackageStateInternal(packageName, callingUid);
+ Bundle getSuspendedPackageAppExtras(@NonNull Computer snapshot, @NonNull String packageName,
+ int userId, int callingUid) {
+ final PackageStateInternal ps = snapshot.getPackageStateInternal(packageName, callingUid);
if (ps == null) {
return null;
}
@@ -329,12 +332,14 @@ public final class SuspendPackageHelper {
}
});
+ final Computer newSnapshot = mPm.snapshotComputer();
+
mPm.scheduleWritePackageRestrictions(userId);
if (!unsuspendedPackages.isEmpty()) {
final String[] packageArray = unsuspendedPackages.toArray(
new String[unsuspendedPackages.size()]);
sendMyPackageSuspendedOrUnsuspended(packageArray, false, userId);
- sendPackagesSuspendedForUser(Intent.ACTION_PACKAGES_UNSUSPENDED,
+ sendPackagesSuspendedForUser(newSnapshot, Intent.ACTION_PACKAGES_UNSUSPENDED,
packageArray, unsuspendedUids.toArray(), userId);
}
}
@@ -348,10 +353,10 @@ public final class SuspendPackageHelper {
* @return The launcher extras.
*/
@Nullable
- Bundle getSuspendedPackageLauncherExtras(@NonNull String packageName, int userId,
- int callingUid) {
- final PackageStateInternal packageState = mPm.getPackageStateInternal(
- packageName, callingUid);
+ Bundle getSuspendedPackageLauncherExtras(@NonNull Computer snapshot,
+ @NonNull String packageName, int userId, int callingUid) {
+ final PackageStateInternal packageState =
+ snapshot.getPackageStateInternal(packageName, callingUid);
if (packageState == null) {
return null;
}
@@ -376,9 +381,10 @@ public final class SuspendPackageHelper {
* @param callingUid The caller's uid.
* @return {@code true}, if the given package is suspended.
*/
- boolean isPackageSuspended(@NonNull String packageName, int userId, int callingUid) {
- final PackageStateInternal packageState = mPm.getPackageStateInternal(
- packageName, callingUid);
+ boolean isPackageSuspended(@NonNull Computer snapshot, @NonNull String packageName, int userId,
+ int callingUid) {
+ final PackageStateInternal packageState =
+ snapshot.getPackageStateInternal(packageName, callingUid);
return packageState != null && packageState.getUserStateOrDefault(userId)
.isSuspended();
}
@@ -392,8 +398,9 @@ public final class SuspendPackageHelper {
* @return The name of suspending package.
*/
@Nullable
- String getSuspendingPackage(@NonNull String suspendedPackage, int userId, int callingUid) {
- final PackageStateInternal packageState = mPm.getPackageStateInternal(
+ String getSuspendingPackage(@NonNull Computer snapshot, @NonNull String suspendedPackage,
+ int userId, int callingUid) {
+ final PackageStateInternal packageState = snapshot.getPackageStateInternal(
suspendedPackage, callingUid);
if (packageState == null) {
return null;
@@ -424,9 +431,10 @@ public final class SuspendPackageHelper {
* @return The dialog info.
*/
@Nullable
- SuspendDialogInfo getSuspendedDialogInfo(@NonNull String suspendedPackage,
- @NonNull String suspendingPackage, int userId, int callingUid) {
- final PackageStateInternal packageState = mPm.getPackageStateInternal(
+ SuspendDialogInfo getSuspendedDialogInfo(@NonNull Computer snapshot,
+ @NonNull String suspendedPackage, @NonNull String suspendingPackage, int userId,
+ int callingUid) {
+ final PackageStateInternal packageState = snapshot.getPackageStateInternal(
suspendedPackage, callingUid);
if (packageState == null) {
return null;
@@ -454,9 +462,9 @@ public final class SuspendPackageHelper {
* @param callingUid The caller's uid.
* @return {@code true} if the user is allowed to suspend packages by the caller.
*/
- boolean isSuspendAllowedForUser(int userId, int callingUid) {
+ boolean isSuspendAllowedForUser(@NonNull Computer snapshot, int userId, int callingUid) {
final UserManagerService userManager = mInjector.getUserManagerService();
- return isCallerDeviceOrProfileOwner(userId, callingUid)
+ return isCallerDeviceOrProfileOwner(snapshot, userId, callingUid)
|| (!userManager.hasUserRestriction(UserManager.DISALLOW_APPS_CONTROL, userId)
&& !userManager.hasUserRestriction(UserManager.DISALLOW_UNINSTALL_APPS, userId));
}
@@ -471,21 +479,23 @@ public final class SuspendPackageHelper {
* @return An array containing results of the checks
*/
@NonNull
- boolean[] canSuspendPackageForUser(@NonNull Computer computer, @NonNull String[] packageNames,
+ boolean[] canSuspendPackageForUser(@NonNull Computer snapshot, @NonNull String[] packageNames,
int userId, int callingUid) {
final boolean[] canSuspend = new boolean[packageNames.length];
- final boolean isCallerOwner = isCallerDeviceOrProfileOwner(userId, callingUid);
+ final boolean isCallerOwner = isCallerDeviceOrProfileOwner(snapshot, userId, callingUid);
final long token = Binder.clearCallingIdentity();
try {
final DefaultAppProvider defaultAppProvider = mInjector.getDefaultAppProvider();
final String activeLauncherPackageName = defaultAppProvider.getDefaultHome(userId);
final String dialerPackageName = defaultAppProvider.getDefaultDialer(userId);
- final String requiredInstallerPackage = getKnownPackageName(PACKAGE_INSTALLER, userId);
+ final String requiredInstallerPackage =
+ getKnownPackageName(snapshot, PACKAGE_INSTALLER, userId);
final String requiredUninstallerPackage =
- getKnownPackageName(PACKAGE_UNINSTALLER, userId);
- final String requiredVerifierPackage = getKnownPackageName(PACKAGE_VERIFIER, userId);
+ getKnownPackageName(snapshot, PACKAGE_UNINSTALLER, userId);
+ final String requiredVerifierPackage =
+ getKnownPackageName(snapshot, PACKAGE_VERIFIER, userId);
final String requiredPermissionControllerPackage =
- getKnownPackageName(PACKAGE_PERMISSION_CONTROLLER, userId);
+ getKnownPackageName(snapshot, PACKAGE_PERMISSION_CONTROLLER, userId);
for (int i = 0; i < packageNames.length; i++) {
canSuspend[i] = false;
final String packageName = packageNames[i];
@@ -530,7 +540,7 @@ public final class SuspendPackageHelper {
+ "\": protected package");
continue;
}
- if (!isCallerOwner && computer.getBlockUninstall(userId, packageName)) {
+ if (!isCallerOwner && snapshot.getBlockUninstall(userId, packageName)) {
Slog.w(TAG, "Cannot suspend package \"" + packageName
+ "\": blocked by admin");
continue;
@@ -539,7 +549,7 @@ public final class SuspendPackageHelper {
// Cannot suspend static shared libs as they are considered
// a part of the using app (emulating static linking). Also
// static libs are installed always on internal storage.
- PackageStateInternal packageState = computer.getPackageStateInternal(packageName);
+ PackageStateInternal packageState = snapshot.getPackageStateInternal(packageName);
AndroidPackage pkg = packageState == null ? null : packageState.getPkg();
if (pkg != null) {
// Cannot suspend SDK libs as they are controlled by SDK manager.
@@ -580,8 +590,8 @@ public final class SuspendPackageHelper {
* @param userId The user where packages reside.
*/
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
- void sendPackagesSuspendedForUser(@NonNull String intent, @NonNull String[] pkgList,
- @NonNull int[] uidList, int userId) {
+ void sendPackagesSuspendedForUser(@NonNull Computer snapshot, @NonNull String intent,
+ @NonNull String[] pkgList, @NonNull int[] uidList, int userId) {
final List<List<String>> pkgsToSend = new ArrayList(pkgList.length);
final List<IntArray> uidsToSend = new ArrayList(pkgList.length);
final List<SparseArray<int[]>> allowListsToSend = new ArrayList(pkgList.length);
@@ -592,8 +602,8 @@ public final class SuspendPackageHelper {
final String pkgName = pkgList[i];
final int uid = uidList[i];
SparseArray<int[]> allowList = mInjector.getAppsFilter().getVisibilityAllowList(
- mPm.getPackageStateInternal(pkgName, SYSTEM_UID),
- userIds, mPm.getPackageStates());
+ snapshot.getPackageStateInternal(pkgName, SYSTEM_UID),
+ userIds, snapshot.getPackageStates());
if (allowList == null) {
allowList = new SparseArray<>(0);
}
@@ -628,19 +638,22 @@ public final class SuspendPackageHelper {
}
}
- private String getKnownPackageName(@KnownPackage int knownPackage, int userId) {
- final String[] knownPackages = mPm.getKnownPackageNamesInternal(knownPackage, userId);
+ private String getKnownPackageName(@NonNull Computer snapshot, @KnownPackage int knownPackage,
+ int userId) {
+ final String[] knownPackages =
+ mPm.getKnownPackageNamesInternal(snapshot, knownPackage, userId);
return knownPackages.length > 0 ? knownPackages[0] : null;
}
- private boolean isCallerDeviceOrProfileOwner(int userId, int callingUid) {
+ private boolean isCallerDeviceOrProfileOwner(@NonNull Computer snapshot, int userId,
+ int callingUid) {
if (callingUid == SYSTEM_UID) {
return true;
}
final String ownerPackage = mProtectedPackages.getDeviceOwnerOrProfileOwnerPackage(userId);
if (ownerPackage != null) {
- return callingUid == mPm.getPackageUidInternal(
- ownerPackage, 0, userId, callingUid);
+ return callingUid == snapshot.getPackageUidInternal(ownerPackage, 0, userId,
+ callingUid);
}
return false;
}
@@ -659,9 +672,10 @@ public final class SuspendPackageHelper {
return;
}
final int[] targetUserIds = new int[] {userId};
+ final Computer snapshot = mPm.snapshotComputer();
for (String packageName : affectedPackages) {
final Bundle appExtras = suspended
- ? getSuspendedPackageAppExtras(packageName, userId, SYSTEM_UID)
+ ? getSuspendedPackageAppExtras(snapshot, packageName, userId, SYSTEM_UID)
: null;
final Bundle intentExtras;
if (appExtras != null) {
diff --git a/services/core/java/com/android/server/pm/TEST_MAPPING b/services/core/java/com/android/server/pm/TEST_MAPPING
index f07c9eca6a15..88a298a756d4 100644
--- a/services/core/java/com/android/server/pm/TEST_MAPPING
+++ b/services/core/java/com/android/server/pm/TEST_MAPPING
@@ -15,6 +15,9 @@
"name": "CtsClassloaderSplitsHostTestCases"
},
{
+ "name": "CtsCompilationTestCases"
+ },
+ {
"name": "CtsAppEnumerationTestCases"
},
{
@@ -111,9 +114,6 @@
},
{
"name": "PackageManagerServiceHostTests"
- },
- {
- "name": "CtsCompilationTestCases"
}
],
"imports": [
diff --git a/services/core/java/com/android/server/pm/UserDataPreparer.java b/services/core/java/com/android/server/pm/UserDataPreparer.java
index 504769064808..95482d7c7f1a 100644
--- a/services/core/java/com/android/server/pm/UserDataPreparer.java
+++ b/services/core/java/com/android/server/pm/UserDataPreparer.java
@@ -118,8 +118,11 @@ class UserDataPreparer {
flags | StorageManager.FLAG_STORAGE_DE, false);
} else {
try {
- Log.e(TAG, "prepareUserData failed", e);
- RecoverySystem.rebootPromptAndWipeUserData(mContext, "prepareUserData failed");
+ Log.wtf(TAG, "prepareUserData failed for user " + userId, e);
+ if (userId == UserHandle.USER_SYSTEM) {
+ RecoverySystem.rebootPromptAndWipeUserData(mContext,
+ "prepareUserData failed for system user");
+ }
} catch (IOException e2) {
throw new RuntimeException("error rebooting into recovery", e2);
}
diff --git a/services/core/java/com/android/server/pm/UserManagerInternal.java b/services/core/java/com/android/server/pm/UserManagerInternal.java
index eb2de6012745..0e6d5e5ed463 100644
--- a/services/core/java/com/android/server/pm/UserManagerInternal.java
+++ b/services/core/java/com/android/server/pm/UserManagerInternal.java
@@ -312,4 +312,12 @@ public abstract class UserManagerInternal {
*/
public abstract void setDefaultCrossProfileIntentFilters(
@UserIdInt int parentUserId, @UserIdInt int profileUserId);
+
+ /**
+ * Returns {@code true} if the system should ignore errors when preparing
+ * the storage directories for the user with ID {@code userId}. This will
+ * return {@code false} for all new users; it will only return {@code true}
+ * for users that already existed on-disk from an older version of Android.
+ */
+ public abstract boolean shouldIgnorePrepareStorageErrors(int userId);
}
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index d99305d728b9..5ec406b597d5 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -211,6 +211,8 @@ public class UserManagerService extends IUserManager.Stub {
private static final String TAG_SEED_ACCOUNT_OPTIONS = "seedAccountOptions";
private static final String TAG_LAST_REQUEST_QUIET_MODE_ENABLED_CALL =
"lastRequestQuietModeEnabledCall";
+ private static final String TAG_IGNORE_PREPARE_STORAGE_ERRORS =
+ "ignorePrepareStorageErrors";
private static final String ATTR_KEY = "key";
private static final String ATTR_VALUE_TYPE = "type";
private static final String ATTR_MULTIPLE = "m";
@@ -320,6 +322,14 @@ public class UserManagerService extends IUserManager.Stub {
private long mLastRequestQuietModeEnabledMillis;
+ /**
+ * {@code true} if the system should ignore errors when preparing the
+ * storage directories for this user. This is {@code false} for all new
+ * users; it will only be {@code true} for users that already existed
+ * on-disk from an older version of Android.
+ */
+ private boolean mIgnorePrepareStorageErrors;
+
void setLastRequestQuietModeEnabledMillis(long millis) {
mLastRequestQuietModeEnabledMillis = millis;
}
@@ -328,6 +338,25 @@ public class UserManagerService extends IUserManager.Stub {
return mLastRequestQuietModeEnabledMillis;
}
+ boolean getIgnorePrepareStorageErrors() {
+ return mIgnorePrepareStorageErrors;
+ }
+
+ @SuppressWarnings("AndroidFrameworkCompatChange") // This is not an app-visible API.
+ void setIgnorePrepareStorageErrors() {
+ // This method won't be called for new users. But to fully rule out
+ // the possibility of mIgnorePrepareStorageErrors ever being true
+ // for any user on any device that launched with T or later, we also
+ // explicitly check that DEVICE_INITIAL_SDK_INT is below T before
+ // honoring the request to set mIgnorePrepareStorageErrors to true.
+ if (Build.VERSION.DEVICE_INITIAL_SDK_INT < Build.VERSION_CODES.TIRAMISU) {
+ mIgnorePrepareStorageErrors = true;
+ return;
+ }
+ Slog.w(LOG_TAG, "Not setting mIgnorePrepareStorageErrors to true"
+ + " since this is a new device");
+ }
+
void clearSeedAccountData() {
seedAccountName = null;
seedAccountType = null;
@@ -1564,13 +1593,13 @@ public class UserManagerService extends IUserManager.Stub {
}
@Override
- public boolean isCredentialSharedWithParent(@UserIdInt int userId) {
+ public boolean isCredentialSharableWithParent(@UserIdInt int userId) {
checkManageOrInteractPermissionIfCallerInOtherProfileGroup(userId,
- "isCredentialSharedWithParent");
+ "isCredentialSharableWithParent");
synchronized (mUsersLock) {
UserTypeDetails userTypeDetails = getUserTypeDetailsNoChecks(userId);
return userTypeDetails != null && userTypeDetails.isProfile()
- && userTypeDetails.isCredentialSharedWithParent();
+ && userTypeDetails.isCredentialSharableWithParent();
}
}
@@ -3408,6 +3437,10 @@ public class UserManagerService extends IUserManager.Stub {
serializer.endTag(/* namespace */ null, TAG_LAST_REQUEST_QUIET_MODE_ENABLED_CALL);
}
+ serializer.startTag(/* namespace */ null, TAG_IGNORE_PREPARE_STORAGE_ERRORS);
+ serializer.text(String.valueOf(userData.getIgnorePrepareStorageErrors()));
+ serializer.endTag(/* namespace */ null, TAG_IGNORE_PREPARE_STORAGE_ERRORS);
+
serializer.endTag(null, TAG_USER);
serializer.endDocument();
@@ -3517,6 +3550,7 @@ public class UserManagerService extends IUserManager.Stub {
Bundle legacyLocalRestrictions = null;
RestrictionsSet localRestrictions = null;
Bundle globalRestrictions = null;
+ boolean ignorePrepareStorageErrors = true; // default is true for old users
final TypedXmlPullParser parser = Xml.resolvePullParser(is);
int type;
@@ -3595,6 +3629,11 @@ public class UserManagerService extends IUserManager.Stub {
if (type == XmlPullParser.TEXT) {
lastRequestQuietModeEnabledTimestamp = Long.parseLong(parser.getText());
}
+ } else if (TAG_IGNORE_PREPARE_STORAGE_ERRORS.equals(tag)) {
+ type = parser.next();
+ if (type == XmlPullParser.TEXT) {
+ ignorePrepareStorageErrors = Boolean.parseBoolean(parser.getText());
+ }
}
}
}
@@ -3622,6 +3661,9 @@ public class UserManagerService extends IUserManager.Stub {
userData.persistSeedData = persistSeedData;
userData.seedAccountOptions = seedAccountOptions;
userData.setLastRequestQuietModeEnabledMillis(lastRequestQuietModeEnabledTimestamp);
+ if (ignorePrepareStorageErrors) {
+ userData.setIgnorePrepareStorageErrors();
+ }
synchronized (mRestrictionsLock) {
if (baseRestrictions != null) {
@@ -4106,11 +4148,11 @@ public class UserManagerService extends IUserManager.Stub {
continue;
}
if (filter.direction == DefaultCrossProfileIntentFilter.Direction.TO_PARENT) {
- mPm.addCrossProfileIntentFilter(
+ mPm.addCrossProfileIntentFilter(mPm.snapshotComputer(),
filter.filter, mContext.getOpPackageName(), profileUserId, parentUserId,
filter.flags);
} else {
- mPm.addCrossProfileIntentFilter(
+ mPm.addCrossProfileIntentFilter(mPm.snapshotComputer(),
filter.filter, mContext.getOpPackageName(), parentUserId, profileUserId,
filter.flags);
}
@@ -4596,12 +4638,12 @@ public class UserManagerService extends IUserManager.Stub {
final String restriction = getUserRemovalRestriction(userId);
if (getUserRestrictions(UserHandle.getCallingUserId()).getBoolean(restriction, false)) {
Slog.w(LOG_TAG, "Cannot remove user. " + restriction + " is enabled.");
- return UserManager.REMOVE_RESULT_ERROR;
+ return UserManager.REMOVE_RESULT_ERROR_USER_RESTRICTION;
}
}
if (userId == UserHandle.USER_SYSTEM) {
Slog.e(LOG_TAG, "System user cannot be removed.");
- return UserManager.REMOVE_RESULT_ERROR;
+ return UserManager.REMOVE_RESULT_ERROR_SYSTEM_USER;
}
final long ident = Binder.clearCallingIdentity();
@@ -4613,7 +4655,7 @@ public class UserManagerService extends IUserManager.Stub {
if (userData == null) {
Slog.e(LOG_TAG,
"Cannot remove user " + userId + ", invalid user id provided.");
- return UserManager.REMOVE_RESULT_ERROR;
+ return UserManager.REMOVE_RESULT_ERROR_USER_NOT_FOUND;
}
if (mRemovingUserIds.get(userId)) {
@@ -5367,37 +5409,82 @@ public class UserManagerService extends IUserManager.Stub {
(new Shell()).exec(this, in, out, err, args, callback, resultReceiver);
}
- private int onShellCommand(Shell shell, String cmd) {
+ private static final String PREFIX_HELP_COMMAND = " ";
+ private static final String PREFIX_HELP_DESCRIPTION = " ";
+ private static final String PREFIX_HELP_DESCRIPTION_EXTRA_LINES = " ";
+
+ private static final String CMD_HELP = "help";
+ private static final String CMD_LIST = "list";
+ private static final String CMD_REPORT_SYSTEM_USER_PACKAGE_ALLOWLIST_PROBLEMS =
+ "report-system-user-package-whitelist-problems";
+
+ private static final String ARG_V = "-v";
+ private static final String ARG_VERBOSE = "--verbose";
+ private static final String ARG_ALL = "--all";
+ private static final String ARG_CRITICAL_ONLY = "--critical-only";
+ private static final String ARG_MODE = "--mode";
+
+ private final class Shell extends ShellCommand {
+
+ @Override
+ public void onHelp() {
+ final PrintWriter pw = getOutPrintWriter();
+ pw.printf("User manager (user) commands:\n");
+
+ pw.printf("%s%s\n", PREFIX_HELP_COMMAND, CMD_HELP);
+ pw.printf("%sPrints this help text.\n\n", PREFIX_HELP_DESCRIPTION);
+
+ pw.printf("%s%s [%s] [%s]\n", PREFIX_HELP_COMMAND, CMD_LIST, ARG_V, ARG_ALL);
+ pw.printf("%sPrints all users on the system.\n\n", PREFIX_HELP_DESCRIPTION);
+
+ pw.printf("%s%s [%s | %s] [%s] [%s MODE]\n", PREFIX_HELP_COMMAND,
+ CMD_REPORT_SYSTEM_USER_PACKAGE_ALLOWLIST_PROBLEMS,
+ ARG_V, ARG_VERBOSE, ARG_CRITICAL_ONLY, ARG_MODE);
+
+ pw.printf("%sReports all issues on user-type package allowlist XML files. Options:\n",
+ PREFIX_HELP_DESCRIPTION);
+ pw.printf("%s%s | %s: shows extra info, like number of issues\n",
+ PREFIX_HELP_DESCRIPTION, ARG_V, ARG_VERBOSE);
+ pw.printf("%s%s: show only critical issues, excluding warnings\n",
+ PREFIX_HELP_DESCRIPTION, ARG_CRITICAL_ONLY);
+ pw.printf("%s%s MODE: shows what errors would be if device used mode MODE\n"
+ + "%s(where MODE is the allowlist mode integer as defined by "
+ + "config_userTypePackageWhitelistMode)\n\n",
+ PREFIX_HELP_DESCRIPTION, ARG_MODE, PREFIX_HELP_DESCRIPTION_EXTRA_LINES);
+ }
+
+ @Override
+ public int onCommand(String cmd) {
if (cmd == null) {
- return shell.handleDefaultCommands(cmd);
+ return handleDefaultCommands(cmd);
}
- final PrintWriter pw = shell.getOutPrintWriter();
try {
switch(cmd) {
- case "list":
- return runList(pw, shell);
- case "report-system-user-package-whitelist-problems":
- return runReportPackageWhitelistProblems(pw, shell);
+ case CMD_LIST:
+ return runList();
+ case CMD_REPORT_SYSTEM_USER_PACKAGE_ALLOWLIST_PROBLEMS:
+ return runReportPackageAllowlistProblems();
default:
- return shell.handleDefaultCommands(cmd);
+ return handleDefaultCommands(cmd);
}
} catch (RemoteException e) {
- pw.println("Remote exception: " + e);
+ getOutPrintWriter().println("Remote exception: " + e);
}
return -1;
}
- private int runList(PrintWriter pw, Shell shell) throws RemoteException {
+ private int runList() throws RemoteException {
+ final PrintWriter pw = getOutPrintWriter();
boolean all = false;
boolean verbose = false;
String opt;
- while ((opt = shell.getNextOption()) != null) {
+ while ((opt = getNextOption()) != null) {
switch (opt) {
- case "-v":
+ case ARG_V:
verbose = true;
break;
- case "--all":
+ case ARG_ALL:
all = true;
break;
default:
@@ -5471,22 +5558,23 @@ public class UserManagerService extends IUserManager.Stub {
}
}
- private int runReportPackageWhitelistProblems(PrintWriter pw, Shell shell) {
+ private int runReportPackageAllowlistProblems() {
+ final PrintWriter pw = getOutPrintWriter();
boolean verbose = false;
boolean criticalOnly = false;
int mode = UserSystemPackageInstaller.USER_TYPE_PACKAGE_WHITELIST_MODE_NONE;
String opt;
- while ((opt = shell.getNextOption()) != null) {
+ while ((opt = getNextOption()) != null) {
switch (opt) {
- case "-v":
- case "--verbose":
+ case ARG_V:
+ case ARG_VERBOSE:
verbose = true;
break;
- case "--critical-only":
+ case ARG_CRITICAL_ONLY:
criticalOnly = true;
break;
- case "--mode":
- mode = Integer.parseInt(shell.getNextArgRequired());
+ case ARG_MODE:
+ mode = Integer.parseInt(getNextArgRequired());
break;
default:
pw.println("Invalid option: " + opt);
@@ -5494,15 +5582,17 @@ public class UserManagerService extends IUserManager.Stub {
}
}
- Slog.d(LOG_TAG, "runReportPackageWhitelistProblems(): verbose=" + verbose
+ Slog.d(LOG_TAG, "runReportPackageAllowlistProblems(): verbose=" + verbose
+ ", criticalOnly=" + criticalOnly
+ ", mode=" + UserSystemPackageInstaller.modeToString(mode));
try (IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ")) {
- mSystemPackageInstaller.dumpPackageWhitelistProblems(ipw, mode, verbose, criticalOnly);
+ mSystemPackageInstaller.dumpPackageWhitelistProblems(ipw, mode, verbose,
+ criticalOnly);
}
return 0;
}
+ }
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
@@ -5732,6 +5822,9 @@ public class UserManagerService extends IUserManager.Stub {
pw.println();
}
}
+
+ pw.println(" Ignore errors preparing storage: "
+ + userData.getIgnorePrepareStorageErrors());
}
private static void dumpTimeAgo(PrintWriter pw, StringBuilder sb, long nowTime, long time) {
@@ -6135,6 +6228,14 @@ public class UserManagerService extends IUserManager.Stub {
UserManagerService.this.setDefaultCrossProfileIntentFilters(
profileUserId, userTypeDetails, restrictions, parentUserId);
}
+
+ @Override
+ public boolean shouldIgnorePrepareStorageErrors(int userId) {
+ synchronized (mUsersLock) {
+ UserData userData = mUsers.get(userId);
+ return userData != null && userData.getIgnorePrepareStorageErrors();
+ }
+ }
}
/**
@@ -6186,32 +6287,6 @@ public class UserManagerService extends IUserManager.Stub {
}
}
- private class Shell extends ShellCommand {
- @Override
- public int onCommand(String cmd) {
- return onShellCommand(this, cmd);
- }
-
- @Override
- public void onHelp() {
- final PrintWriter pw = getOutPrintWriter();
- pw.println("User manager (user) commands:");
- pw.println(" help");
- pw.println(" Prints this help text.");
- pw.println("");
- pw.println(" list [-v] [-all]");
- pw.println(" Prints all users on the system.");
- pw.println(" report-system-user-package-whitelist-problems [-v | --verbose] "
- + "[--critical-only] [--mode MODE]");
- pw.println(" Reports all issues on user-type package whitelist XML files. Options:");
- pw.println(" -v | --verbose : shows extra info, like number of issues");
- pw.println(" --critical-only: show only critical issues, excluding warnings");
- pw.println(" --mode MODE: shows what errors would be if device used mode MODE (where"
- + " MODE is the whitelist mode integer as defined by "
- + "config_userTypePackageWhitelistMode)");
- }
- }
-
private static void debug(String message) {
Slog.d(LOG_TAG, message
+ (DBG_WITH_STACKTRACE ? " called at\n" + Debug.getCallers(10, " ") : ""));
@@ -6297,7 +6372,8 @@ public class UserManagerService extends IUserManager.Stub {
* {@link SecurityException} if not.
*/
private void verifyCallingPackage(String callingPackage, int callingUid) {
- int packageUid = mPm.getPackageUid(callingPackage, 0, UserHandle.getUserId(callingUid));
+ int packageUid = mPm.snapshotComputer()
+ .getPackageUid(callingPackage, 0, UserHandle.getUserId(callingUid));
if (packageUid != callingUid) {
throw new SecurityException("Specified package " + callingPackage
+ " does not match the calling uid " + callingUid);
diff --git a/services/core/java/com/android/server/pm/UserTypeDetails.java b/services/core/java/com/android/server/pm/UserTypeDetails.java
index 2f5e2388f6a8..4aad1a7f3881 100644
--- a/services/core/java/com/android/server/pm/UserTypeDetails.java
+++ b/services/core/java/com/android/server/pm/UserTypeDetails.java
@@ -161,7 +161,7 @@ public final class UserTypeDetails {
*
* <p> Default value is false
*/
- private final boolean mIsCredentialSharedWithParent;
+ private final boolean mIsCredentialSharableWithParent;
private UserTypeDetails(@NonNull String name, boolean enabled, int maxAllowed,
@UserInfoFlag int baseType, @UserInfoFlag int defaultUserInfoPropertyFlags, int label,
@@ -174,7 +174,7 @@ public final class UserTypeDetails {
@Nullable Bundle defaultSecureSettings,
@Nullable List<DefaultCrossProfileIntentFilter> defaultCrossProfileIntentFilters,
boolean isMediaSharedWithParent,
- boolean isCredentialSharedWithParent) {
+ boolean isCredentialSharableWithParent) {
this.mName = name;
this.mEnabled = enabled;
this.mMaxAllowed = maxAllowed;
@@ -194,7 +194,7 @@ public final class UserTypeDetails {
this.mBadgeColors = badgeColors;
this.mDarkThemeBadgeColors = darkThemeBadgeColors;
this.mIsMediaSharedWithParent = isMediaSharedWithParent;
- this.mIsCredentialSharedWithParent = isCredentialSharedWithParent;
+ this.mIsCredentialSharableWithParent = isCredentialSharableWithParent;
}
/**
@@ -323,8 +323,8 @@ public final class UserTypeDetails {
* Returns true if the user has shared encryption credential with parent user or
* false otherwise.
*/
- public boolean isCredentialSharedWithParent() {
- return mIsCredentialSharedWithParent;
+ public boolean isCredentialSharableWithParent() {
+ return mIsCredentialSharableWithParent;
}
/** Returns a {@link Bundle} representing the default user restrictions. */
@@ -419,7 +419,7 @@ public final class UserTypeDetails {
private @DrawableRes int mBadgePlain = Resources.ID_NULL;
private @DrawableRes int mBadgeNoBackground = Resources.ID_NULL;
private boolean mIsMediaSharedWithParent = false;
- private boolean mIsCredentialSharedWithParent = false;
+ private boolean mIsCredentialSharableWithParent = false;
public Builder setName(String name) {
mName = name;
@@ -521,10 +521,10 @@ public final class UserTypeDetails {
/**
* Sets shared media property for the user.
- * @param isCredentialSharedWithParent the value to be set, true or false
+ * @param isCredentialSharableWithParent the value to be set, true or false
*/
- public Builder setIsCredentialSharedWithParent(boolean isCredentialSharedWithParent) {
- mIsCredentialSharedWithParent = isCredentialSharedWithParent;
+ public Builder setIsCredentialSharableWithParent(boolean isCredentialSharableWithParent) {
+ mIsCredentialSharableWithParent = isCredentialSharableWithParent;
return this;
}
@@ -571,7 +571,7 @@ public final class UserTypeDetails {
mDefaultSecureSettings,
mDefaultCrossProfileIntentFilters,
mIsMediaSharedWithParent,
- mIsCredentialSharedWithParent);
+ mIsCredentialSharableWithParent);
}
private boolean hasBadge() {
diff --git a/services/core/java/com/android/server/pm/UserTypeFactory.java b/services/core/java/com/android/server/pm/UserTypeFactory.java
index 1e3b67c394cb..cb18c6d83788 100644
--- a/services/core/java/com/android/server/pm/UserTypeFactory.java
+++ b/services/core/java/com/android/server/pm/UserTypeFactory.java
@@ -122,7 +122,7 @@ public final class UserTypeFactory {
.setLabel(0)
.setDefaultRestrictions(null)
.setIsMediaSharedWithParent(true)
- .setIsCredentialSharedWithParent(true);
+ .setIsCredentialSharableWithParent(true);
}
/**
@@ -154,7 +154,7 @@ public final class UserTypeFactory {
.setDefaultRestrictions(getDefaultManagedProfileRestrictions())
.setDefaultSecureSettings(getDefaultManagedProfileSecureSettings())
.setDefaultCrossProfileIntentFilters(getDefaultManagedCrossProfileIntentFilter())
- .setIsCredentialSharedWithParent(true);
+ .setIsCredentialSharableWithParent(true);
}
/**
diff --git a/services/core/java/com/android/server/pm/VerificationParams.java b/services/core/java/com/android/server/pm/VerificationParams.java
index 4334cbdce1f2..7423bf65c6a5 100644
--- a/services/core/java/com/android/server/pm/VerificationParams.java
+++ b/services/core/java/com/android/server/pm/VerificationParams.java
@@ -72,6 +72,7 @@ import android.util.Pair;
import android.util.Slog;
import com.android.server.DeviceIdleInternal;
+import com.android.server.sdksandbox.SdkSandboxManagerLocal;
import java.io.File;
import java.util.ArrayList;
@@ -372,9 +373,10 @@ final class VerificationParams extends HandlerParams {
* Determine if we have any installed package verifiers. If we
* do, then we'll defer to them to verify the packages.
*/
+ final Computer snapshot = mPm.snapshotComputer();
final int requiredUid = requiredVerifierPackage == null ? -1
- : mPm.getPackageUid(requiredVerifierPackage, MATCH_DEBUG_TRIAGED_MISSING,
- verifierUserId);
+ : snapshot.getPackageUid(requiredVerifierPackage,
+ MATCH_DEBUG_TRIAGED_MISSING, verifierUserId);
verificationState.setRequiredVerifierUid(requiredUid);
final boolean isVerificationEnabled = isVerificationEnabled(pkgLite,
verifierUserId);
@@ -391,8 +393,8 @@ final class VerificationParams extends HandlerParams {
verification.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
// Query all live verifiers based on current user state
- final ParceledListSlice<ResolveInfo> receivers = mPm.queryIntentReceivers(verification,
- PACKAGE_MIME_TYPE, 0, verifierUserId);
+ final ParceledListSlice<ResolveInfo> receivers = mPm.queryIntentReceivers(snapshot,
+ verification, PACKAGE_MIME_TYPE, 0, verifierUserId);
if (DEBUG_VERIFY) {
Slog.d(TAG, "Found " + receivers.getList().size() + " verifiers for intent "
@@ -440,9 +442,22 @@ final class VerificationParams extends HandlerParams {
final long verificationTimeout = VerificationUtils.getVerificationTimeout(mPm.mContext,
streaming);
- final List<ComponentName> sufficientVerifiers = matchVerifiers(pkgLite,
+ List<ComponentName> sufficientVerifiers = matchVerifiers(pkgLite,
receivers.getList(), verificationState);
+ // Add broadcastReceiver Component to verify Sdk before run in Sdk sandbox.
+ if (pkgLite.isSdkLibrary) {
+ if (sufficientVerifiers == null) {
+ sufficientVerifiers = new ArrayList<>();
+ }
+ ComponentName sdkSandboxComponentName = new ComponentName("android",
+ SdkSandboxManagerLocal.VERIFIER_RECEIVER);
+ sufficientVerifiers.add(sdkSandboxComponentName);
+
+ // Add uid of system_server the same uid for SdkSandboxManagerService
+ verificationState.addSufficientVerifier(Process.myUid());
+ }
+
DeviceIdleInternal idleController =
mPm.mInjector.getLocalService(DeviceIdleInternal.class);
final BroadcastOptions options = BroadcastOptions.makeBasic();
diff --git a/services/core/java/com/android/server/pm/WatchedIntentFilter.java b/services/core/java/com/android/server/pm/WatchedIntentFilter.java
index 30f276e8386a..5d7a2a3bd426 100644
--- a/services/core/java/com/android/server/pm/WatchedIntentFilter.java
+++ b/services/core/java/com/android/server/pm/WatchedIntentFilter.java
@@ -84,7 +84,7 @@ public class WatchedIntentFilter
}
// Convert an {@link IntentFilter} to a {@link WatchedIntentFilter}
- protected WatchedIntentFilter(IntentFilter f) {
+ public WatchedIntentFilter(IntentFilter f) {
mFilter = new IntentFilter(f);
}
diff --git a/services/core/java/com/android/server/pm/dex/ArtManagerService.java b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
index e28a6ea8ea6b..7e4da945709b 100644
--- a/services/core/java/com/android/server/pm/dex/ArtManagerService.java
+++ b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
@@ -31,13 +31,13 @@ import android.content.pm.dex.ArtManagerInternal;
import android.content.pm.dex.DexMetadataHelper;
import android.content.pm.dex.ISnapshotRuntimeProfileCallback;
import android.content.pm.dex.PackageOptimizationInfo;
-import com.android.server.pm.pkg.parsing.PackageInfoWithoutStateUtils;
import android.os.Binder;
import android.os.Build;
import android.os.Handler;
import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.os.RemoteException;
+import android.os.ServiceManager;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.system.Os;
@@ -55,6 +55,7 @@ import com.android.server.pm.Installer;
import com.android.server.pm.Installer.InstallerException;
import com.android.server.pm.PackageManagerServiceCompilerMapping;
import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.parsing.PackageInfoWithoutStateUtils;
import dalvik.system.DexFile;
import dalvik.system.VMRuntime;
@@ -92,7 +93,7 @@ public class ArtManagerService extends android.content.pm.dex.IArtManager.Stub {
private static final String BOOT_IMAGE_PROFILE_NAME = "android.prof";
private final Context mContext;
- private final IPackageManager mPackageManager;
+ private IPackageManager mPackageManager;
private final Object mInstallLock;
@GuardedBy("mInstallLock")
private final Installer mInstaller;
@@ -103,10 +104,9 @@ public class ArtManagerService extends android.content.pm.dex.IArtManager.Stub {
verifyTronLoggingConstants();
}
- public ArtManagerService(Context context, IPackageManager pm, Installer installer,
+ public ArtManagerService(Context context, Installer installer,
Object installLock) {
mContext = context;
- mPackageManager = pm;
mInstaller = installer;
mInstallLock = installLock;
mHandler = new Handler(BackgroundThread.getHandler().getLooper());
@@ -114,6 +114,15 @@ public class ArtManagerService extends android.content.pm.dex.IArtManager.Stub {
LocalServices.addService(ArtManagerInternal.class, new ArtManagerInternalImpl());
}
+ @NonNull
+ private IPackageManager getPackageManager() {
+ if (mPackageManager == null) {
+ mPackageManager = IPackageManager.Stub.asInterface(
+ ServiceManager.getService("package"));
+ }
+ return mPackageManager;
+ }
+
private boolean checkAndroidPermissions(int callingUid, String callingPackage) {
// Callers always need this permission
mContext.enforceCallingOrSelfPermission(
@@ -157,7 +166,7 @@ public class ArtManagerService extends android.content.pm.dex.IArtManager.Stub {
}
PackageInfo info = null;
try {
- info = mPackageManager.getPackageInfo(packageName, /*flags*/ 0, /*userId*/ 0);
+ info = getPackageManager().getPackageInfo(packageName, /*flags*/ 0, /*userId*/ 0);
} catch (RemoteException ignored) {
// Should not happen.
}
@@ -221,7 +230,7 @@ public class ArtManagerService extends android.content.pm.dex.IArtManager.Stub {
// TODO(calin): consider adding an API to PMS which can retrieve the
// PackageParser.Package.
- info = mPackageManager.getPackageInfo(packageName, /*flags*/ 0, /*userId*/ 0);
+ info = getPackageManager().getPackageInfo(packageName, /*flags*/ 0, /*userId*/ 0);
} catch (RemoteException ignored) {
// Should not happen.
}
diff --git a/services/core/java/com/android/server/pm/dex/DexManager.java b/services/core/java/com/android/server/pm/dex/DexManager.java
index 5371454db43c..17109e97ddf1 100644
--- a/services/core/java/com/android/server/pm/dex/DexManager.java
+++ b/services/core/java/com/android/server/pm/dex/DexManager.java
@@ -23,6 +23,8 @@ import static com.android.server.pm.dex.PackageDexUsage.PackageUseInfo;
import static java.util.function.Function.identity;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
@@ -33,6 +35,7 @@ import android.os.BatteryManager;
import android.os.FileUtils;
import android.os.PowerManager;
import android.os.RemoteException;
+import android.os.ServiceManager;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.storage.StorageManager;
@@ -109,7 +112,7 @@ public class DexManager {
// record class loaders or ISAs.)
private final DynamicCodeLogger mDynamicCodeLogger;
- private final IPackageManager mPackageManager;
+ private IPackageManager mPackageManager;
private final PackageDexOptimizer mPackageDexOptimizer;
private final Object mInstallLock;
@GuardedBy("mInstallLock")
@@ -128,16 +131,22 @@ public class DexManager {
private static int DEX_SEARCH_FOUND_SPLIT = 2; // dex file is a split apk
private static int DEX_SEARCH_FOUND_SECONDARY = 3; // dex file is a secondary dex
- public DexManager(Context context, IPackageManager pms, PackageDexOptimizer pdo,
- Installer installer, Object installLock) {
+ public DexManager(Context context, PackageDexOptimizer pdo, Installer installer,
+ Object installLock) {
+ this(context, pdo, installer, installLock, null);
+ }
+
+ @VisibleForTesting
+ public DexManager(Context context, PackageDexOptimizer pdo, Installer installer,
+ Object installLock, @Nullable IPackageManager packageManager) {
mContext = context;
mPackageCodeLocationsCache = new HashMap<>();
mPackageDexUsage = new PackageDexUsage();
- mPackageManager = pms;
mPackageDexOptimizer = pdo;
mInstaller = installer;
mInstallLock = installLock;
- mDynamicCodeLogger = new DynamicCodeLogger(pms, installer);
+ mDynamicCodeLogger = new DynamicCodeLogger(installer);
+ mPackageManager = packageManager;
// This is currently checked to handle tests that pass in a null context.
// TODO(b/174783329): Modify the tests to pass in a mocked Context, PowerManager,
@@ -157,6 +166,15 @@ public class DexManager {
}
}
+ @NonNull
+ private IPackageManager getPackageManager() {
+ if (mPackageManager == null) {
+ mPackageManager = IPackageManager.Stub.asInterface(
+ ServiceManager.getService("package"));
+ }
+ return mPackageManager;
+ }
+
public DynamicCodeLogger getDynamicCodeLogger() {
return mDynamicCodeLogger;
}
@@ -529,7 +547,7 @@ public class DexManager {
PackageInfo pkg;
try {
- pkg = mPackageManager.getPackageInfo(packageName, /*flags*/0,
+ pkg = getPackageManager().getPackageInfo(packageName, /*flags*/0,
dexUseInfo.getOwnerUserId());
} catch (RemoteException e) {
throw new AssertionError(e);
@@ -673,7 +691,7 @@ public class DexManager {
// to get back the real app uid and its storage kind. These are only used
// to perform extra validation in installd.
// TODO(calin): maybe a bit overkill.
- pkg = mPackageManager.getPackageInfo(packageName, /*flags*/0,
+ pkg = getPackageManager().getPackageInfo(packageName, /*flags*/0,
dexUseInfo.getOwnerUserId());
} catch (RemoteException ignore) {
// Can't happen, DexManager is local.
diff --git a/services/core/java/com/android/server/pm/dex/DynamicCodeLogger.java b/services/core/java/com/android/server/pm/dex/DynamicCodeLogger.java
index 75b4e38e42f5..9b94e993f967 100644
--- a/services/core/java/com/android/server/pm/dex/DynamicCodeLogger.java
+++ b/services/core/java/com/android/server/pm/dex/DynamicCodeLogger.java
@@ -19,11 +19,13 @@ package com.android.server.pm.dex;
import static com.android.server.pm.dex.PackageDynamicCodeLoading.FILE_TYPE_DEX;
import static com.android.server.pm.dex.PackageDynamicCodeLoading.FILE_TYPE_NATIVE;
+import android.annotation.NonNull;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageInfo;
import android.os.FileUtils;
import android.os.RemoteException;
+import android.os.ServiceManager;
import android.os.UserHandle;
import android.os.storage.StorageManager;
import android.util.EventLog;
@@ -58,20 +60,30 @@ public class DynamicCodeLogger {
private static final String DCL_DEX_SUBTAG = "dcl";
private static final String DCL_NATIVE_SUBTAG = "dcln";
- private final IPackageManager mPackageManager;
+ private IPackageManager mPackageManager;
private final PackageDynamicCodeLoading mPackageDynamicCodeLoading;
private final Installer mInstaller;
- DynamicCodeLogger(IPackageManager pms, Installer installer) {
- this(pms, installer, new PackageDynamicCodeLoading());
+ DynamicCodeLogger(Installer installer) {
+ mInstaller = installer;
+ mPackageDynamicCodeLoading = new PackageDynamicCodeLoading();
}
@VisibleForTesting
- DynamicCodeLogger(IPackageManager pms, Installer installer,
- PackageDynamicCodeLoading packageDynamicCodeLoading) {
- mPackageManager = pms;
- mPackageDynamicCodeLoading = packageDynamicCodeLoading;
+ DynamicCodeLogger(@NonNull IPackageManager packageManager, @NonNull Installer installer,
+ @NonNull PackageDynamicCodeLoading packageDynamicCodeLoading) {
+ mPackageManager = packageManager;
mInstaller = installer;
+ mPackageDynamicCodeLoading = packageDynamicCodeLoading;
+ }
+
+ @NonNull
+ private IPackageManager getPackageManager() {
+ if (mPackageManager == null) {
+ mPackageManager = IPackageManager.Stub.asInterface(
+ ServiceManager.getService("package"));
+ }
+ return mPackageManager;
}
public Set<String> getAllPackagesWithDynamicCodeLoading() {
@@ -104,7 +116,7 @@ public class DynamicCodeLogger {
try {
PackageInfo ownerInfo =
- mPackageManager.getPackageInfo(packageName, /*flags*/ 0, userId);
+ getPackageManager().getPackageInfo(packageName, /*flags*/ 0, userId);
appInfo = ownerInfo == null ? null : ownerInfo.applicationInfo;
} catch (RemoteException ignored) {
// Can't happen, we're local.
@@ -167,7 +179,7 @@ public class DynamicCodeLogger {
loadingUid = appInfo.uid;
} else {
try {
- loadingUid = mPackageManager.getPackageUid(loadingPackageName, /*flags*/ 0,
+ loadingUid = getPackageManager().getPackageUid(loadingPackageName, /*flags*/ 0,
userId);
} catch (RemoteException ignored) {
// Can't happen, we're local.
@@ -223,7 +235,7 @@ public class DynamicCodeLogger {
public void recordNative(int loadingUid, String path) {
String[] packages;
try {
- packages = mPackageManager.getPackagesForUid(loadingUid);
+ packages = getPackageManager().getPackagesForUid(loadingUid);
if (packages == null || packages.length == 0) {
return;
}
diff --git a/services/core/java/com/android/server/pm/dex/OWNERS b/services/core/java/com/android/server/pm/dex/OWNERS
index 052a4ca52afd..5ca8ddd1fe17 100644
--- a/services/core/java/com/android/server/pm/dex/OWNERS
+++ b/services/core/java/com/android/server/pm/dex/OWNERS
@@ -1,3 +1,4 @@
alanstokes@google.com
jiakaiz@google.com
ngeoffray@google.com
+mast@google.com
diff --git a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
index 63469cb24f2f..8d1bcfcb3938 100644
--- a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
+++ b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
@@ -122,6 +122,12 @@ public class PackageInfoUtils {
info.isStub = pkg.isStub();
info.coreApp = pkg.isCoreApp();
+ if (pkgSetting != null && !pkgSetting.hasSharedUser()) {
+ // It is possible that this shared UID app has left
+ info.sharedUserId = null;
+ info.sharedUserLabel = 0;
+ }
+
if ((flags & PackageManager.GET_ACTIVITIES) != 0) {
final int N = pkg.getActivities().size();
if (N > 0) {
diff --git a/services/core/java/com/android/server/pm/permission/OneTimePermissionUserManager.java b/services/core/java/com/android/server/pm/permission/OneTimePermissionUserManager.java
index 46fde4b59d8b..60602337ba1a 100644
--- a/services/core/java/com/android/server/pm/permission/OneTimePermissionUserManager.java
+++ b/services/core/java/com/android/server/pm/permission/OneTimePermissionUserManager.java
@@ -272,6 +272,10 @@ public class OneTimePermissionUserManager {
mHandler.removeCallbacksAndMessages(mToken);
if (importance > IMPORTANCE_CACHED) {
+ if (mRevokeAfterKilledDelay == 0) {
+ onPackageInactiveLocked();
+ return;
+ }
// Delay revocation in case app is restarting
mHandler.postDelayed(() -> {
int imp = mActivityManager.getUidImportance(mUid);
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 71554eee3127..5a05134bed81 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -562,12 +562,6 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
@Override
- public void revokeOwnPermissionsOnKill(@NonNull String packageName,
- @NonNull List<String> permissions) {
- mPermissionManagerServiceImpl.revokeOwnPermissionsOnKill(packageName, permissions);
- }
-
- @Override
public boolean shouldShowRequestPermissionRationale(String packageName, String permissionName,
int userId) {
return mPermissionManagerServiceImpl.shouldShowRequestPermissionRationale(packageName,
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 9961ae51b92d..009d155e96ef 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
@@ -1403,7 +1403,7 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt
}
} else {
if (ps.getUserStateOrDefault(userId).isInstantApp() && !bp.isInstant()) {
- throw new SecurityException("Cannot grant non-ephemeral permission" + permName
+ throw new SecurityException("Cannot grant non-ephemeral permission " + permName
+ " for package " + packageName);
}
@@ -1597,25 +1597,6 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt
}
}
- @Override
- public void revokeOwnPermissionsOnKill(String packageName, List<String> permissions) {
- final int callingUid = Binder.getCallingUid();
- int callingUserId = UserHandle.getUserId(callingUid);
- int targetPackageUid = mPackageManagerInt.getPackageUid(packageName, 0, callingUserId);
- if (targetPackageUid != callingUid) {
- throw new SecurityException("uid " + callingUid
- + " cannot revoke permissions for package " + packageName + " with uid "
- + targetPackageUid);
- }
- for (String permName : permissions) {
- if (!checkCallingOrSelfPermission(permName)) {
- throw new SecurityException("uid " + callingUid + " cannot revoke permission "
- + permName + " because it does not hold that permission");
- }
- }
- mPermissionControllerManager.revokeOwnPermissionsOnKill(packageName, permissions);
- }
-
private boolean mayManageRolePermission(int uid) {
final PackageManager packageManager = mContext.getPackageManager();
final String[] packageNames = packageManager.getPackagesForUid(uid);
@@ -3291,10 +3272,13 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt
} else if (pkg.isSystemExt()) {
permissions = systemConfig.getSystemExtPrivAppPermissions(pkg.getPackageName());
} else if (containingApexPackageName != null) {
+ final ApexManager apexManager = ApexManager.getInstance();
+ final String apexName = apexManager.getApexModuleNameForPackageName(
+ containingApexPackageName);
final Set<String> privAppPermissions = systemConfig.getPrivAppPermissions(
pkg.getPackageName());
final Set<String> apexPermissions = systemConfig.getApexPrivAppPermissions(
- containingApexPackageName, pkg.getPackageName());
+ apexName, pkg.getPackageName());
if (privAppPermissions != null) {
// TODO(andreionea): Remove check as soon as all apk-in-apex
// permission allowlists are migrated.
@@ -3532,8 +3516,9 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt
final Boolean granted =
SystemConfig.getInstance().getOemPermissions(pkg.getPackageName()).get(permission);
if (granted == null) {
- throw new IllegalStateException("OEM permission" + permission + " requested by package "
- + pkg.getPackageName() + " must be explicitly declared granted or not");
+ throw new IllegalStateException("OEM permission " + permission
+ + " requested by package " + pkg.getPackageName()
+ + " must be explicitly declared granted or not");
}
return Boolean.TRUE == granted;
}
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java
index 3e28320a2130..3771f030aefa 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java
@@ -327,28 +327,6 @@ public interface PermissionManagerServiceInterface extends PermissionManagerInte
void revokePostNotificationPermissionWithoutKillForTest(String packageName, int userId);
/**
- * Triggers the revocation of one or more permissions for a package, under the following
- * conditions:
- * <ul>
- * <li>The package {@code packageName} must be under the same UID as the calling process
- * (typically, the target package is the calling package).
- * <li>Each permission in {@code permissions} must be granted to the package
- * {@code packageName}.
- * <li>Each permission in {@code permissions} must be a runtime permission.
- * </ul>
- * <p>
- * Background permissions which have no corresponding foreground permission still granted once
- * the revocation is effective will also be revoked.
- * <p>
- * This revocation happens asynchronously and kills all processes running in the same UID as
- * {@code packageName}. It will be triggered once it is safe to do so.
- *
- * @param packageName The name of the package for which the permissions will be revoked.
- * @param permissions List of permissions to be revoked.
- */
- void revokeOwnPermissionsOnKill(String packageName, List<String> permissions);
-
- /**
* Get whether you should show UI with rationale for requesting a permission. You should do this
* only if you do not have the permission and the context in which the permission is requested
* does not clearly communicate to the user what would be the benefit from grating this
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackage.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackage.java
index f6f9faf98c40..40f859c5e82e 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackage.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackage.java
@@ -287,9 +287,6 @@ public interface ParsingPackage extends ParsingPackageRead {
ParsingPackage setInstallLocation(int installLocation);
- /** @see R#styleable.AndroidManifest_inheritKeyStoreKeys */
- ParsingPackage setInheritKeyStoreKeys(boolean inheritKeyStoreKeys);
-
/** @see R#styleable.AndroidManifest_sharedUserMaxSdkVersion */
ParsingPackage setLeavingSharedUid(boolean leavingSharedUid);
@@ -305,6 +302,8 @@ public interface ParsingPackage extends ParsingPackageRead {
ParsingPackage setMinSdkVersion(int minSdkVersion);
+ ParsingPackage setMaxSdkVersion(int maxSdkVersion);
+
ParsingPackage setNetworkSecurityConfigRes(int networkSecurityConfigRes);
ParsingPackage setNonLocalizedLabel(CharSequence nonLocalizedLabel);
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageImpl.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageImpl.java
index 67670272ef8b..67d9aecf01bd 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageImpl.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageImpl.java
@@ -383,6 +383,7 @@ public class ParsingPackageImpl implements ParsingPackage, ParsingPackageHidden,
@Nullable
private SparseIntArray minExtensionVersions;
private int minSdkVersion = ParsingUtils.DEFAULT_MIN_SDK_VERSION;
+ private int maxSdkVersion = ParsingUtils.DEFAULT_MAX_SDK_VERSION;
private int networkSecurityConfigRes;
@Nullable
private CharSequence nonLocalizedLabel;
@@ -494,7 +495,6 @@ public class ParsingPackageImpl implements ParsingPackage, ParsingPackageHidden,
ATTRIBUTIONS_ARE_USER_VISIBLE,
RESET_ENABLED_SETTINGS_ON_APP_DATA_CLEARED,
SDK_LIBRARY,
- INHERIT_KEYSTORE_KEYS,
})
public @interface Values {}
private static final long EXTERNAL_STORAGE = 1L;
@@ -547,9 +547,8 @@ public class ParsingPackageImpl implements ParsingPackage, ParsingPackageHidden,
private static final long ATTRIBUTIONS_ARE_USER_VISIBLE = 1L << 47;
private static final long RESET_ENABLED_SETTINGS_ON_APP_DATA_CLEARED = 1L << 48;
private static final long SDK_LIBRARY = 1L << 49;
- private static final long INHERIT_KEYSTORE_KEYS = 1L << 50;
- private static final long ENABLE_ON_BACK_INVOKED_CALLBACK = 1L << 51;
- private static final long LEAVING_SHARED_UID = 1L << 52;
+ private static final long ENABLE_ON_BACK_INVOKED_CALLBACK = 1L << 50;
+ private static final long LEAVING_SHARED_UID = 1L << 51;
}
private ParsingPackageImpl setBoolean(@Booleans.Values long flag, boolean value) {
@@ -1308,6 +1307,7 @@ public class ParsingPackageImpl implements ParsingPackage, ParsingPackageHidden,
dest.writeFloat(this.maxAspectRatio);
dest.writeFloat(this.minAspectRatio);
dest.writeInt(this.minSdkVersion);
+ dest.writeInt(this.maxSdkVersion);
dest.writeInt(this.networkSecurityConfigRes);
dest.writeCharSequence(this.nonLocalizedLabel);
dest.writeString(this.permission);
@@ -1456,6 +1456,7 @@ public class ParsingPackageImpl implements ParsingPackage, ParsingPackageHidden,
this.maxAspectRatio = in.readFloat();
this.minAspectRatio = in.readFloat();
this.minSdkVersion = in.readInt();
+ this.maxSdkVersion = in.readInt();
this.networkSecurityConfigRes = in.readInt();
this.nonLocalizedLabel = in.readCharSequence();
this.permission = in.readString();
@@ -2070,6 +2071,11 @@ public class ParsingPackageImpl implements ParsingPackage, ParsingPackageHidden,
}
@Override
+ public int getMaxSdkVersion() {
+ return maxSdkVersion;
+ }
+
+ @Override
public int getNetworkSecurityConfigRes() {
return networkSecurityConfigRes;
}
@@ -2394,11 +2400,6 @@ public class ParsingPackageImpl implements ParsingPackage, ParsingPackageHidden,
}
@Override
- public boolean shouldInheritKeyStoreKeys() {
- return getBoolean(Booleans.INHERIT_KEYSTORE_KEYS);
- }
-
- @Override
public boolean isOnBackInvokedCallbackEnabled() {
return getBoolean(Booleans.ENABLE_ON_BACK_INVOKED_CALLBACK);
}
@@ -2552,11 +2553,6 @@ public class ParsingPackageImpl implements ParsingPackage, ParsingPackageHidden,
}
@Override
- public ParsingPackageImpl setInheritKeyStoreKeys(boolean value) {
- return setBoolean(Booleans.INHERIT_KEYSTORE_KEYS, value);
- }
-
- @Override
public ParsingPackageImpl setLeavingSharedUid(boolean value) {
return setBoolean(Booleans.LEAVING_SHARED_UID, value);
}
@@ -2604,6 +2600,12 @@ public class ParsingPackageImpl implements ParsingPackage, ParsingPackageHidden,
}
@Override
+ public ParsingPackageImpl setMaxSdkVersion(int value) {
+ maxSdkVersion = value;
+ return this;
+ }
+
+ @Override
public ParsingPackageImpl setNetworkSecurityConfigRes(int value) {
networkSecurityConfigRes = value;
return this;
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageRead.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageRead.java
index 50033f652bfd..20b1ed8d0c3e 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageRead.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageRead.java
@@ -352,11 +352,6 @@ public interface ParsingPackageRead extends PkgWithoutStateAppInfo, PkgWithoutSt
int getLocaleConfigRes();
/**
- * @see R.styleable#AndroidManifest_inheritKeyStoreKeys
- */
- boolean shouldInheritKeyStoreKeys();
-
- /**
* @see R.styleable.AndroidManifestApplication_enableOnBackInvokedCallback
*/
boolean isOnBackInvokedCallbackEnabled();
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
index ed1ab01e1d12..f255db4a9801 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
@@ -91,6 +91,7 @@ import com.android.internal.R;
import com.android.internal.os.ClassLoaderFactory;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.XmlUtils;
+import com.android.server.pm.SharedUidMigration;
import com.android.server.pm.permission.CompatibilityPermissionInfo;
import com.android.server.pm.pkg.component.ComponentMutateUtils;
import com.android.server.pm.pkg.component.ComponentParseUtils;
@@ -208,6 +209,8 @@ public class ParsingPackageUtils {
public static final int SDK_VERSION = Build.VERSION.SDK_INT;
public static final String[] SDK_CODENAMES = Build.VERSION.ACTIVE_CODENAMES;
+ public static final String[] PREVIOUS_CODENAMES =
+ Build.VERSION.KNOWN_CODENAMES.toArray(new String[]{});
public static boolean sCompatibilityModeEnabled = true;
public static boolean sUseRoundIcon = false;
@@ -235,9 +238,15 @@ public class ParsingPackageUtils {
*/
public static final int PARSE_IGNORE_OVERLAY_REQUIRED_SYSTEM_PROPERTY = 1 << 7;
public static final int PARSE_FRAMEWORK_RES_SPLITS = 1 << 8;
+ public static final int PARSE_CHECK_MAX_SDK_VERSION = 1 << 9;
public static final int PARSE_CHATTY = 1 << 31;
+ /** The total maximum number of activities, services, providers and activity-aliases */
+ private static final int MAX_NUM_COMPONENTS = 30000;
+ private static final String MAX_NUM_COMPONENTS_ERR_MSG =
+ "Total number of components has exceeded the maximum number: " + MAX_NUM_COMPONENTS;
+
@IntDef(flag = true, prefix = { "PARSE_" }, value = {
PARSE_CHATTY,
PARSE_COLLECT_CERTIFICATES,
@@ -833,11 +842,20 @@ public class ParsingPackageUtils {
if (result.isError()) {
return input.error(result);
}
+
+ if (hasTooManyComponents(pkg)) {
+ return input.error(MAX_NUM_COMPONENTS_ERR_MSG);
+ }
}
return input.success(pkg);
}
+ private static boolean hasTooManyComponents(ParsingPackage pkg) {
+ return pkg.getActivities().size() + pkg.getServices().size() + pkg.getProviders().size()
+ > MAX_NUM_COMPONENTS;
+ }
+
/**
* For parsing non-MainComponents. Main ones have an order and some special handling which is
* done directly in {@link #parseSplitApplication(ParseInput, ParsingPackage, Resources,
@@ -893,9 +911,7 @@ public class ParsingPackageUtils {
.setTargetSandboxVersion(anInteger(PARSE_DEFAULT_TARGET_SANDBOX,
R.styleable.AndroidManifest_targetSandboxVersion, sa))
/* Set the global "on SD card" flag */
- .setExternalStorage((flags & PARSE_EXTERNAL_STORAGE) != 0)
- .setInheritKeyStoreKeys(bool(false,
- R.styleable.AndroidManifest_inheritKeyStoreKeys, sa));
+ .setExternalStorage((flags & PARSE_EXTERNAL_STORAGE) != 0);
boolean foundApp = false;
final int depth = parser.getDepth();
@@ -1003,7 +1019,7 @@ public class ParsingPackageUtils {
case TAG_FEATURE_GROUP:
return parseFeatureGroup(input, pkg, res, parser);
case TAG_USES_SDK:
- return parseUsesSdk(input, pkg, res, parser);
+ return parseUsesSdk(input, pkg, res, parser, flags);
case TAG_SUPPORT_SCREENS:
return parseSupportScreens(input, pkg, res, parser);
case TAG_PROTECTED_BROADCAST:
@@ -1047,8 +1063,11 @@ public class ParsingPackageUtils {
}
}
- int maxSdkVersion = anInteger(0, R.styleable.AndroidManifest_sharedUserMaxSdkVersion, sa);
- boolean leaving = (maxSdkVersion != 0) && (maxSdkVersion < Build.VERSION.RESOURCES_SDK_INT);
+ boolean leaving = false;
+ if (!SharedUidMigration.isDisabled()) {
+ int max = anInteger(0, R.styleable.AndroidManifest_sharedUserMaxSdkVersion, sa);
+ leaving = (max != 0) && (max < Build.VERSION.RESOURCES_SDK_INT);
+ }
return input.success(pkg
.setLeavingSharedUid(leaving)
@@ -1512,15 +1531,17 @@ public class ParsingPackageUtils {
}
private static ParseResult<ParsingPackage> parseUsesSdk(ParseInput input,
- ParsingPackage pkg, Resources res, XmlResourceParser parser)
+ ParsingPackage pkg, Resources res, XmlResourceParser parser, int flags)
throws IOException, XmlPullParserException {
if (SDK_VERSION > 0) {
+ final boolean checkMaxSdkVersion = (flags & PARSE_CHECK_MAX_SDK_VERSION) != 0;
TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestUsesSdk);
try {
int minVers = ParsingUtils.DEFAULT_MIN_SDK_VERSION;
String minCode = null;
int targetVers = ParsingUtils.DEFAULT_TARGET_SDK_VERSION;
String targetCode = null;
+ int maxVers = Integer.MAX_VALUE;
TypedValue val = sa.peekValue(R.styleable.AndroidManifestUsesSdk_minSdkVersion);
if (val != null) {
@@ -1548,6 +1569,14 @@ public class ParsingPackageUtils {
targetCode = minCode;
}
+ if (checkMaxSdkVersion) {
+ val = sa.peekValue(R.styleable.AndroidManifestUsesSdk_maxSdkVersion);
+ if (val != null) {
+ // maxSdkVersion only supports integer
+ maxVers = val.data;
+ }
+ }
+
ParseResult<Integer> targetSdkVersionResult = FrameworkParsingPackageUtils
.computeTargetSdkVersion(targetVers, targetCode, SDK_CODENAMES, input);
if (targetSdkVersionResult.isError()) {
@@ -1572,6 +1601,15 @@ public class ParsingPackageUtils {
pkg.setMinSdkVersion(minSdkVersion)
.setTargetSdkVersion(targetSdkVersion);
+ if (checkMaxSdkVersion) {
+ ParseResult<Integer> maxSdkVersionResult = FrameworkParsingPackageUtils
+ .computeMaxSdkVersion(maxVers, SDK_VERSION, input);
+ if (maxSdkVersionResult.isError()) {
+ return input.error(maxSdkVersionResult);
+ }
+ int maxSdkVersion = maxSdkVersionResult.getResult();
+ pkg.setMaxSdkVersion(maxSdkVersion);
+ }
int type;
final int innerDepth = parser.getDepth();
@@ -2121,6 +2159,9 @@ public class ParsingPackageUtils {
if (result.isError()) {
return input.error(result);
}
+ if (hasTooManyComponents(pkg)) {
+ return input.error(MAX_NUM_COMPONENTS_ERR_MSG);
+ }
}
if (TextUtils.isEmpty(pkg.getStaticSharedLibName()) && TextUtils.isEmpty(
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingUtils.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingUtils.java
index cb474df8b469..07512855d276 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/ParsingUtils.java
@@ -50,6 +50,7 @@ public class ParsingUtils {
public static final String ANDROID_RES_NAMESPACE = "http://schemas.android.com/apk/res/android";
public static final int DEFAULT_MIN_SDK_VERSION = 1;
+ public static final int DEFAULT_MAX_SDK_VERSION = Integer.MAX_VALUE;
public static final int DEFAULT_TARGET_SDK_VERSION = 0;
public static final int NOT_SET = -1;
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/PkgWithoutStateAppInfo.java b/services/core/java/com/android/server/pm/pkg/parsing/PkgWithoutStateAppInfo.java
index 3205b76d6dad..99bcdb964c2f 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/PkgWithoutStateAppInfo.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/PkgWithoutStateAppInfo.java
@@ -250,6 +250,11 @@ public interface PkgWithoutStateAppInfo {
int getMinSdkVersion();
/**
+ * @see R.styleable#AndroidManifestUsesSdk_maxSdkVersion
+ */
+ int getMaxSdkVersion();
+
+ /**
* @see ApplicationInfo#getNativeHeapZeroInitialized()
* @see R.styleable#AndroidManifestApplication_nativeHeapZeroInitialized
*/
diff --git a/services/core/java/com/android/server/policy/KeyCombinationManager.java b/services/core/java/com/android/server/policy/KeyCombinationManager.java
index 68e078c519ba..9213c87f12ec 100644
--- a/services/core/java/com/android/server/policy/KeyCombinationManager.java
+++ b/services/core/java/com/android/server/policy/KeyCombinationManager.java
@@ -48,7 +48,7 @@ public class KeyCombinationManager {
// The rule has been triggered by current keys.
@GuardedBy("mLock")
private TwoKeysCombinationRule mTriggeredRule;
- private final Handler mHandler = new Handler();
+ private final Handler mHandler;
// Keys in a key combination must be pressed within this interval of each other.
private static final long COMBINE_KEY_DELAY_MILLIS = 150;
@@ -93,6 +93,11 @@ public class KeyCombinationManager {
return false;
}
+ // The excessive delay before it dispatching to client.
+ long getKeyInterceptDelayMs() {
+ return COMBINE_KEY_DELAY_MILLIS;
+ }
+
abstract void execute();
abstract void cancel();
@@ -103,7 +108,8 @@ public class KeyCombinationManager {
}
}
- public KeyCombinationManager() {
+ public KeyCombinationManager(Handler handler) {
+ mHandler = handler;
}
void addRule(TwoKeysCombinationRule rule) {
@@ -195,10 +201,18 @@ public class KeyCombinationManager {
*/
long getKeyInterceptTimeout(int keyCode) {
synchronized (mLock) {
- if (forAllActiveRules((rule) -> rule.shouldInterceptKey(keyCode))) {
- return mDownTimes.get(keyCode) + COMBINE_KEY_DELAY_MILLIS;
+ if (mDownTimes.get(keyCode) == 0) {
+ return 0;
+ }
+ long delayMs = 0;
+ for (final TwoKeysCombinationRule rule : mActiveRules) {
+ if (rule.shouldInterceptKey(keyCode)) {
+ delayMs = Math.max(delayMs, rule.getKeyInterceptDelayMs());
+ }
}
- return 0;
+ // Make sure the delay is less than COMBINE_KEY_DELAY_MILLIS.
+ delayMs = Math.min(delayMs, COMBINE_KEY_DELAY_MILLIS);
+ return mDownTimes.get(keyCode) + delayMs;
}
}
diff --git a/services/core/java/com/android/server/policy/PermissionPolicyInternal.java b/services/core/java/com/android/server/policy/PermissionPolicyInternal.java
index 20b7ccd39287..92b9944b74cf 100644
--- a/services/core/java/com/android/server/policy/PermissionPolicyInternal.java
+++ b/services/core/java/com/android/server/policy/PermissionPolicyInternal.java
@@ -57,6 +57,7 @@ public abstract class PermissionPolicyInternal {
* prompt should be shown if the app targets S-, is currently running in a visible, focused
* task, has the REVIEW_REQUIRED flag set on its implicit notification permission, and has
* created at least one notification channel (even if it has since been deleted).
+ *
* @param packageName The package whose permission is being checked
* @param userId The user for whom the package is being started
* @param taskId The task the notification prompt should be attached to
@@ -66,10 +67,22 @@ public abstract class PermissionPolicyInternal {
/**
* Determine if a particular task is in the proper state to show a system-triggered permission
- * prompt. A prompt can be shown if the task is focused, visible, and running.
+ * prompt. A prompt can be shown if the task is focused, visible, and running and
+ * 1. The intent is a launcher intent (action is ACTION_MAIN, category is LAUNCHER), or
+ * 2. The activity belongs to the same package as the one which launched the task originally,
+ * and the task was started with a launcher intent
+ *
* @param taskInfo The task to be checked
+ * @param currPkg The package of the current top visible activity
+ * @param intent The intent of the current top visible activity
+ */
+ public abstract boolean shouldShowNotificationDialogForTask(@Nullable TaskInfo taskInfo,
+ @Nullable String currPkg, @Nullable Intent intent);
+
+ /**
+ * @return true if an intent will resolve to a permission request dialog activity
*/
- public abstract boolean canShowPermissionPromptForTask(@Nullable TaskInfo taskInfo);
+ public abstract boolean isIntentToPermissionDialog(@NonNull Intent intent);
/**
* @return Whether the policy is initialized for a user.
diff --git a/services/core/java/com/android/server/policy/PermissionPolicyService.java b/services/core/java/com/android/server/policy/PermissionPolicyService.java
index f2ce0d4c49d3..bd9e8923e984 100644
--- a/services/core/java/com/android/server/policy/PermissionPolicyService.java
+++ b/services/core/java/com/android/server/policy/PermissionPolicyService.java
@@ -21,6 +21,8 @@ import static android.app.AppOpsManager.MODE_ALLOWED;
import static android.app.AppOpsManager.MODE_FOREGROUND;
import static android.app.AppOpsManager.MODE_IGNORED;
import static android.app.AppOpsManager.OP_NONE;
+import static android.content.pm.PackageManager.ACTION_REQUEST_PERMISSIONS;
+import static android.content.pm.PackageManager.ACTION_REQUEST_PERMISSIONS_FOR_OTHER;
import static android.content.pm.PackageManager.FLAG_PERMISSION_APPLY_RESTRICTION;
import static android.content.pm.PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED;
import static android.content.pm.PackageManager.FLAG_PERMISSION_REVOKED_COMPAT;
@@ -54,6 +56,8 @@ 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;
@@ -109,6 +113,7 @@ 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();
@@ -148,8 +153,10 @@ public final class PermissionPolicyService extends SystemService {
private List<String> mAppOpPermissions;
- private Context mContext;
+ private final Context mContext;
+ private final Handler mHandler;
private PackageManagerInternal mPackageManagerInternal;
+ private PermissionManagerServiceInternal mPermissionManagerInternal;
private NotificationManagerInternal mNotificationManager;
private final KeyguardManager mKeyguardManager;
private final PackageManager mPackageManager;
@@ -158,6 +165,7 @@ 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());
@@ -167,7 +175,7 @@ public final class PermissionPolicyService extends SystemService {
public void onStart() {
mPackageManagerInternal = LocalServices.getService(
PackageManagerInternal.class);
- PermissionManagerServiceInternal permissionManagerInternal = LocalServices.getService(
+ mPermissionManagerInternal = LocalServices.getService(
PermissionManagerServiceInternal.class);
final IAppOpsService appOpsService = IAppOpsService.Stub.asInterface(
ServiceManager.getService(Context.APP_OPS_SERVICE));
@@ -199,7 +207,7 @@ public final class PermissionPolicyService extends SystemService {
}
});
- permissionManagerInternal.addOnRuntimePermissionStateChangedListener(
+ mPermissionManagerInternal.addOnRuntimePermissionStateChangedListener(
this::synchronizePackagePermissionsAndAppOpsAsyncForUser);
mAppOpsCallback = new IAppOpsCallback.Stub() {
@@ -211,7 +219,7 @@ public final class PermissionPolicyService extends SystemService {
};
final ArrayList<PermissionInfo> dangerousPerms =
- permissionManagerInternal.getAllPermissionsWithProtection(
+ mPermissionManagerInternal.getAllPermissionsWithProtection(
PermissionInfo.PROTECTION_DANGEROUS);
try {
int numDangerousPerms = dangerousPerms.size();
@@ -236,7 +244,7 @@ public final class PermissionPolicyService extends SystemService {
}
final List<PermissionInfo> appOpPermissionInfos =
- permissionManagerInternal.getAllPermissionsWithProtectionFlags(
+ mPermissionManagerInternal.getAllPermissionsWithProtectionFlags(
PermissionInfo.PROTECTION_FLAG_APPOP);
mAppOpPermissions = new ArrayList<>();
final int appOpPermissionInfosSize = appOpPermissionInfos.size();
@@ -1016,7 +1024,7 @@ public final class PermissionPolicyService extends SystemService {
ActivityInterceptorInfo info) {
String action = info.intent.getAction();
ActivityInterceptResult result = null;
- if (!PackageManager.ACTION_REQUEST_PERMISSIONS_FOR_OTHER.equals(action)
+ if (!ACTION_REQUEST_PERMISSIONS_FOR_OTHER.equals(action)
&& !PackageManager.ACTION_REQUEST_PERMISSIONS.equals(action)) {
return null;
}
@@ -1033,7 +1041,7 @@ public final class PermissionPolicyService extends SystemService {
&& !mContinueNotifGrantMessageUids.contains(info.realCallingUid)) {
return result;
}
- if (PackageManager.ACTION_REQUEST_PERMISSIONS_FOR_OTHER.equals(action)) {
+ if (ACTION_REQUEST_PERMISSIONS_FOR_OTHER.equals(action)) {
String otherPkg = info.intent.getStringExtra(Intent.EXTRA_PACKAGE_NAME);
if (otherPkg == null || (mPackageManager.getPermissionFlags(
POST_NOTIFICATIONS, otherPkg, UserHandle.of(info.userId))
@@ -1052,8 +1060,8 @@ public final class PermissionPolicyService extends SystemService {
public void onActivityLaunched(TaskInfo taskInfo, ActivityInfo activityInfo,
ActivityInterceptorInfo info) {
super.onActivityLaunched(taskInfo, activityInfo, info);
- if (!shouldShowNotificationDialogOrClearFlags(info.intent,
- info.checkedOptions)) {
+ if (!shouldShowNotificationDialogOrClearFlags(taskInfo,
+ activityInfo.packageName, info.intent, info.checkedOptions, true)) {
return;
}
UserHandle user = UserHandle.of(taskInfo.userId);
@@ -1085,7 +1093,7 @@ public final class PermissionPolicyService extends SystemService {
return false;
}
- if (PackageManager.ACTION_REQUEST_PERMISSIONS_FOR_OTHER.equals(intent.getAction())
+ if (ACTION_REQUEST_PERMISSIONS_FOR_OTHER.equals(intent.getAction())
&& (callingUid != Process.SYSTEM_UID || !SYSTEM_PKG.equals(callingPackage))) {
return false;
}
@@ -1104,18 +1112,48 @@ public final class PermissionPolicyService extends SystemService {
launchNotificationPermissionRequestDialog(packageName, user, taskId);
}
+ @Override
+ public boolean isIntentToPermissionDialog(@NonNull Intent intent) {
+ return Objects.equals(intent.getPackage(),
+ mPackageManager.getPermissionControllerPackageName())
+ && (Objects.equals(intent.getAction(), ACTION_REQUEST_PERMISSIONS_FOR_OTHER)
+ || Objects.equals(intent.getAction(), ACTION_REQUEST_PERMISSIONS));
+ }
+
+ @Override
+ public boolean shouldShowNotificationDialogForTask(TaskInfo taskInfo, String currPkg,
+ Intent intent) {
+ return shouldShowNotificationDialogOrClearFlags(
+ taskInfo, currPkg, intent, null, false);
+ }
+
/**
- * Determine if we should show a notification dialog, or clear the REVIEW_REQUIRED flag,
- * from a particular package for a particular intent. Returns true if:
+ * Determine if a particular task is in the proper state to show a system-triggered
+ * permission prompt. A prompt can be shown if the task is just starting, or the task is
+ * currently focused, visible, and running, and,
* 1. The isEligibleForLegacyPermissionPrompt ActivityOption is set, or
- * 2. The intent is a launcher intent (action is ACTION_MAIN, category is LAUNCHER)
+ * 2. The intent is a launcher intent (action is ACTION_MAIN, category is LAUNCHER), or
+ * 3. The activity belongs to the same package as the one which launched the task
+ * originally, and the task was started with a launcher intent
+ * @param taskInfo The task to be checked
+ * @param currPkg The package of the current top visible activity
+ * @param intent The intent of the current top visible activity
*/
- private boolean shouldShowNotificationDialogOrClearFlags(Intent intent,
- ActivityOptions options) {
- if ((options != null && options.isEligibleForLegacyPermissionPrompt())) {
- return true;
+ private boolean shouldShowNotificationDialogOrClearFlags(TaskInfo taskInfo, String currPkg,
+ Intent intent, ActivityOptions options, boolean activityStart) {
+ if (intent == null || currPkg == null || taskInfo == null
+ || (!(taskInfo.isFocused && taskInfo.isVisible && taskInfo.isRunning)
+ && !activityStart)) {
+ return false;
}
+ return isLauncherIntent(intent)
+ || (options != null && options.isEligibleForLegacyPermissionPrompt())
+ || (currPkg.equals(taskInfo.baseActivity.getPackageName())
+ && isLauncherIntent(taskInfo.baseIntent));
+ }
+
+ private boolean isLauncherIntent(Intent intent) {
return Intent.ACTION_MAIN.equals(intent.getAction())
&& intent.getCategories() != null
&& (intent.getCategories().contains(Intent.CATEGORY_LAUNCHER)
@@ -1144,14 +1182,15 @@ public final class PermissionPolicyService extends SystemService {
Intent grantPermission = mPackageManager
.buildRequestPermissionsIntent(new String[] { POST_NOTIFICATIONS });
grantPermission.setAction(
- PackageManager.ACTION_REQUEST_PERMISSIONS_FOR_OTHER);
+ ACTION_REQUEST_PERMISSIONS_FOR_OTHER);
grantPermission.putExtra(Intent.EXTRA_PACKAGE_NAME, pkgName);
ActivityOptions options = new ActivityOptions(new Bundle());
options.setTaskOverlay(true, false);
options.setLaunchTaskId(taskId);
try {
- mContext.startActivityAsUser(grantPermission, options.toBundle(), user);
+ mHandler.postDelayed(() -> mContext.startActivityAsUser(
+ grantPermission, options.toBundle(), user), ACTIVITY_START_DELAY_MS);
} catch (Exception e) {
Log.e(LOG_TAG, "couldn't start grant permission dialog"
+ "for other package " + pkgName, e);
@@ -1170,12 +1209,6 @@ public final class PermissionPolicyService extends SystemService {
}
}
- @Override
- public boolean canShowPermissionPromptForTask(@Nullable TaskInfo taskInfo) {
- return taskInfo != null && taskInfo.isFocused && taskInfo.isVisible
- && taskInfo.isRunning;
- }
-
/**
* Check if the intent action is removed for the calling package (often based on target SDK
* version). If the action is removed, we'll silently cancel the activity launch.
@@ -1251,10 +1284,12 @@ public final class PermissionPolicyService extends SystemService {
}
boolean hasCreatedNotificationChannels = mNotificationManager
.getNumNotificationChannelsForPackage(pkgName, uid, true) > 0;
+ boolean granted = mPermissionManagerInternal.checkUidPermission(uid, POST_NOTIFICATIONS)
+ == PackageManager.PERMISSION_GRANTED;
int flags = mPackageManager.getPermissionFlags(POST_NOTIFICATIONS, pkgName, user);
boolean explicitlySet = (flags & PermissionManager.EXPLICIT_SET_FLAGS) != 0;
boolean needsReview = (flags & FLAG_PERMISSION_REVIEW_REQUIRED) != 0;
- return hasCreatedNotificationChannels && (needsReview || !explicitlySet);
+ return !granted && hasCreatedNotificationChannels && (needsReview || !explicitlySet);
}
}
}
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index cc93d4c1c3ff..1ac373f074ec 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -792,7 +792,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
public void onWakeUp() {
synchronized (mLock) {
if (shouldEnableWakeGestureLp()
- && mBatteryManagerInternal.getPlugType() != BATTERY_PLUGGED_WIRELESS) {
+ && getBatteryManagerInternal().getPlugType() != BATTERY_PLUGGED_WIRELESS) {
performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY, false,
"Wake Up");
wakeUp(SystemClock.uptimeMillis(), mAllowTheaterModeWakeFromWakeGesture,
@@ -1023,7 +1023,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
break;
}
case SHORT_PRESS_POWER_LOCK_OR_SLEEP: {
- if (keyguardOn()) {
+ if (mKeyguardDelegate == null || !mKeyguardDelegate.hasKeyguard()
+ || !mKeyguardDelegate.isSecure(mCurrentUserId) || keyguardOn()) {
sleepDefaultDisplayFromPowerButton(eventTime, 0);
} else {
lockNow(null /*options*/);
@@ -2124,7 +2125,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
private void initKeyCombinationRules() {
- mKeyCombinationManager = new KeyCombinationManager();
+ mKeyCombinationManager = new KeyCombinationManager(mHandler);
final boolean screenshotChordEnabled = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_enableScreenshotChord);
@@ -2215,11 +2216,20 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mBackKeyHandled = true;
interceptAccessibilityGestureTv();
}
-
@Override
void cancel() {
cancelAccessibilityGestureTv();
}
+ @Override
+ long getKeyInterceptDelayMs() {
+ // Use a timeout of 0 to prevent additional latency in processing of
+ // this key. This will potentially cause some unwanted UI actions if the
+ // user does end up triggering the key combination later, but in most
+ // cases, the user will simply hit a single key, and this will allow us
+ // to process it without first waiting to see if the combination is
+ // going to be triggered.
+ return 0;
+ }
});
mKeyCombinationManager.addRule(
@@ -2229,11 +2239,14 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mBackKeyHandled = true;
interceptBugreportGestureTv();
}
-
@Override
void cancel() {
cancelBugreportGestureTv();
}
+ @Override
+ long getKeyInterceptDelayMs() {
+ return 0;
+ }
});
}
}
diff --git a/services/core/java/com/android/server/power/ShutdownThread.java b/services/core/java/com/android/server/power/ShutdownThread.java
index dcfb8b5e7b33..a82d4eaa5b28 100644
--- a/services/core/java/com/android/server/power/ShutdownThread.java
+++ b/services/core/java/com/android/server/power/ShutdownThread.java
@@ -27,6 +27,7 @@ import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.PackageManagerInternal;
import android.media.AudioAttributes;
import android.os.FileUtils;
import android.os.Handler;
@@ -525,8 +526,7 @@ public final class ShutdownThread extends Thread {
shutdownTimingLog.traceBegin("ShutdownPackageManager");
metricStarted(METRIC_PM);
- final PackageManagerService pm = (PackageManagerService)
- ServiceManager.getService("package");
+ final PackageManagerInternal pm = LocalServices.getService(PackageManagerInternal.class);
if (pm != null) {
pm.shutdown();
}
diff --git a/services/core/java/com/android/server/slice/SliceManagerService.java b/services/core/java/com/android/server/slice/SliceManagerService.java
index ee0e5ba916b9..e3dcfd0c89c0 100644
--- a/services/core/java/com/android/server/slice/SliceManagerService.java
+++ b/services/core/java/com/android/server/slice/SliceManagerService.java
@@ -247,6 +247,8 @@ public class SliceManagerService extends ISliceManager.Stub {
if (autoGrantPermissions != null && callingPkg != null) {
// Need to own the Uri to call in with permissions to grant.
enforceOwner(callingPkg, uri, userId);
+ // b/208232850: Needs to verify caller before granting slice access
+ verifyCaller(callingPkg);
for (String perm : autoGrantPermissions) {
if (mContext.checkPermission(perm, pid, uid) == PERMISSION_GRANTED) {
int providerUser = ContentProvider.getUserIdFromUri(uri, userId);
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/AidlUtil.java b/services/core/java/com/android/server/soundtrigger_middleware/AidlUtil.java
new file mode 100644
index 000000000000..f3457f5a221b
--- /dev/null
+++ b/services/core/java/com/android/server/soundtrigger_middleware/AidlUtil.java
@@ -0,0 +1,71 @@
+/*
+ * 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.soundtrigger_middleware;
+
+import android.media.soundtrigger.PhraseRecognitionEvent;
+import android.media.soundtrigger.PhraseRecognitionExtra;
+import android.media.soundtrigger.RecognitionEvent;
+import android.media.soundtrigger.RecognitionStatus;
+import android.media.soundtrigger.SoundModelType;
+
+/**
+ * Utilities for working with sound trigger related AIDL generated types.
+ */
+public class AidlUtil {
+ /**
+ * Initialize a new recognition event.
+ * @return The new event.
+ */
+ static RecognitionEvent newEmptyRecognitionEvent() {
+ RecognitionEvent result = new RecognitionEvent();
+ result.data = new byte[0];
+ return result;
+ }
+
+ /**
+ * Initialize a new phrase recognition event.
+ * @return The new event.
+ */
+ static PhraseRecognitionEvent newEmptyPhraseRecognitionEvent() {
+ PhraseRecognitionEvent result = new PhraseRecognitionEvent();
+ result.common = newEmptyRecognitionEvent();
+ result.phraseExtras = new PhraseRecognitionExtra[0];
+ return result;
+ }
+
+ /**
+ * Creates a new generic abort event.
+ * @return The new event.
+ */
+ static RecognitionEvent newAbortEvent() {
+ RecognitionEvent event = newEmptyRecognitionEvent();
+ event.type = SoundModelType.GENERIC;
+ event.status = RecognitionStatus.ABORTED;
+ return event;
+ }
+
+ /**
+ * Creates a new generic phrase event.
+ * @return The new event.
+ */
+ static PhraseRecognitionEvent newAbortPhraseEvent() {
+ PhraseRecognitionEvent event = newEmptyPhraseRecognitionEvent();
+ event.common.type = SoundModelType.KEYPHRASE;
+ event.common.status = RecognitionStatus.ABORTED;
+ return event;
+ }
+}
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHalConcurrentCaptureHandler.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHalConcurrentCaptureHandler.java
index 990b21c211a3..c0ab65a3215c 100644
--- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHalConcurrentCaptureHandler.java
+++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHalConcurrentCaptureHandler.java
@@ -24,7 +24,6 @@ import android.media.soundtrigger.PhraseSoundModel;
import android.media.soundtrigger.Properties;
import android.media.soundtrigger.RecognitionConfig;
import android.media.soundtrigger.RecognitionEvent;
-import android.media.soundtrigger.RecognitionStatus;
import android.media.soundtrigger.SoundModel;
import android.media.soundtrigger.SoundModelType;
import android.media.soundtrigger.Status;
@@ -391,21 +390,14 @@ public class SoundTriggerHalConcurrentCaptureHandler implements ISoundTriggerHal
/** Notify the client that recognition has been aborted. */
private static void notifyAbort(int modelHandle, LoadedModel model) {
switch (model.type) {
- case SoundModelType.GENERIC: {
- RecognitionEvent event = new RecognitionEvent();
- event.status = RecognitionStatus.ABORTED;
- event.type = SoundModelType.GENERIC;
- model.callback.recognitionCallback(modelHandle, event);
- }
- break;
-
- case SoundModelType.KEYPHRASE: {
- PhraseRecognitionEvent event = new PhraseRecognitionEvent();
- event.common.status = RecognitionStatus.ABORTED;
- event.common.type = SoundModelType.KEYPHRASE;
- model.callback.phraseRecognitionCallback(modelHandle, event);
- }
- break;
+ case SoundModelType.GENERIC:
+ model.callback.recognitionCallback(modelHandle, AidlUtil.newAbortEvent());
+ break;
+
+ case SoundModelType.KEYPHRASE:
+ model.callback.phraseRecognitionCallback(modelHandle,
+ AidlUtil.newAbortPhraseEvent());
+ break;
}
}
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java
index 934b0e46ee95..fd8dee8416f6 100644
--- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java
+++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java
@@ -25,6 +25,7 @@ import android.media.soundtrigger.Properties;
import android.media.soundtrigger.RecognitionConfig;
import android.media.soundtrigger.RecognitionEvent;
import android.media.soundtrigger.SoundModel;
+import android.media.soundtrigger.SoundModelType;
import android.media.soundtrigger.Status;
import android.media.soundtrigger_middleware.ISoundTriggerCallback;
import android.media.soundtrigger_middleware.ISoundTriggerModule;
@@ -305,9 +306,12 @@ class SoundTriggerModule implements IBinder.DeathRecipient, ISoundTriggerHal.Glo
@Override
public void stopRecognition(int modelHandle) {
+ Model model;
synchronized (SoundTriggerModule.this) {
- mLoadedModels.get(modelHandle).stopRecognition();
+ checkValid();
+ model = mLoadedModels.get(modelHandle);
}
+ model.stopRecognition();
}
@Override
@@ -374,6 +378,7 @@ class SoundTriggerModule implements IBinder.DeathRecipient, ISoundTriggerHal.Glo
private class Model implements ISoundTriggerHal.ModelCallback {
public int mHandle;
private ModelState mState = ModelState.INIT;
+ private int mType = SoundModelType.INVALID;
private SoundTriggerMiddlewareImpl.AudioSessionProvider.AudioSession mSession;
private @NonNull
@@ -390,6 +395,7 @@ class SoundTriggerModule implements IBinder.DeathRecipient, ISoundTriggerHal.Glo
SoundTriggerMiddlewareImpl.AudioSessionProvider.AudioSession audioSession) {
mSession = audioSession;
mHandle = mHalService.loadSoundModel(model, this);
+ mType = SoundModelType.GENERIC;
setState(ModelState.LOADED);
mLoadedModels.put(mHandle, this);
return mHandle;
@@ -399,7 +405,7 @@ class SoundTriggerModule implements IBinder.DeathRecipient, ISoundTriggerHal.Glo
SoundTriggerMiddlewareImpl.AudioSessionProvider.AudioSession audioSession) {
mSession = audioSession;
mHandle = mHalService.loadPhraseSoundModel(model, this);
-
+ mType = SoundModelType.KEYPHRASE;
setState(ModelState.LOADED);
mLoadedModels.put(mHandle, this);
return mHandle;
@@ -422,12 +428,41 @@ class SoundTriggerModule implements IBinder.DeathRecipient, ISoundTriggerHal.Glo
}
private void stopRecognition() {
- if (getState() == ModelState.LOADED) {
- // This call is idempotent in order to avoid races.
- return;
+ synchronized (SoundTriggerModule.this) {
+ if (getState() == ModelState.LOADED) {
+ // This call is idempotent in order to avoid races.
+ return;
+ }
}
+ // This must be invoked outside the lock.
mHalService.stopRecognition(mHandle);
- setState(ModelState.LOADED);
+
+ // No more callbacks for this model after this point.
+ synchronized (SoundTriggerModule.this) {
+ // Generate an abortion callback to the client if the model is still active.
+ if (getState() == ModelState.ACTIVE) {
+ if (mCallback != null) {
+ try {
+ switch (mType) {
+ case SoundModelType.GENERIC:
+ mCallback.onRecognition(mHandle, AidlUtil.newAbortEvent(),
+ mSession.mSessionHandle);
+ break;
+ case SoundModelType.KEYPHRASE:
+ mCallback.onPhraseRecognition(mHandle,
+ AidlUtil.newAbortPhraseEvent(),
+ mSession.mSessionHandle);
+ break;
+ default:
+ throw new RuntimeException(
+ "Unexpected model type: " + mType);
+ }
+ } catch (RemoteException e) {
+ }
+ }
+ setState(ModelState.LOADED);
+ }
+ }
}
/** Request a forced recognition event. Will do nothing if recognition is inactive. */
@@ -518,4 +553,5 @@ class SoundTriggerModule implements IBinder.DeathRecipient, ISoundTriggerHal.Glo
}
}
}
+
}
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 2e60f130bc4b..526dccb72e39 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -1633,7 +1633,14 @@ public class StatsPullAtomService extends SystemService {
if (adapter != null) {
SynchronousResultReceiver bluetoothReceiver =
new SynchronousResultReceiver("bluetooth");
- adapter.requestControllerActivityEnergyInfo(bluetoothReceiver);
+ adapter.requestControllerActivityEnergyInfo(
+ Runnable::run,
+ info -> {
+ Bundle bundle = new Bundle();
+ bundle.putParcelable(BatteryStats.RESULT_RECEIVER_CONTROLLER_KEY, info);
+ bluetoothReceiver.send(0, bundle);
+ }
+ );
return awaitControllerInfo(bluetoothReceiver);
} else {
Slog.e(TAG, "Failed to get bluetooth adapter!");
@@ -2338,51 +2345,25 @@ public class StatsPullAtomService extends SystemService {
}
int pullProcessDmabufMemory(int atomTag, List<StatsEvent> pulledData) {
- List<ProcessMemoryState> managedProcessList =
- LocalServices.getService(ActivityManagerInternal.class)
- .getMemoryStateForProcesses();
- for (ProcessMemoryState process : managedProcessList) {
- KernelAllocationStats.ProcessDmabuf proc =
- KernelAllocationStats.getDmabufAllocations(process.pid);
- if (proc == null || (proc.retainedBuffersCount <= 0 && proc.mappedBuffersCount <= 0)) {
- continue;
- }
- pulledData.add(
- FrameworkStatsLog.buildStatsEvent(
- atomTag,
- process.uid,
- process.processName,
- process.oomScore,
- proc.retainedSizeKb,
- proc.retainedBuffersCount,
- proc.mappedSizeKb,
- proc.mappedBuffersCount));
+ KernelAllocationStats.ProcessDmabuf[] procBufs =
+ KernelAllocationStats.getDmabufAllocations();
+
+ if (procBufs == null) {
+ return StatsManager.PULL_SKIP;
}
- SparseArray<String> processCmdlines = getProcessCmdlines();
- managedProcessList.forEach(managedProcess -> processCmdlines.delete(managedProcess.pid));
- int size = processCmdlines.size();
- for (int i = 0; i < size; ++i) {
- int pid = processCmdlines.keyAt(i);
- int uid = getUidForPid(pid);
- // ignore root processes (unlikely to be interesting)
- if (uid <= 0) {
- continue;
- }
- KernelAllocationStats.ProcessDmabuf proc =
- KernelAllocationStats.getDmabufAllocations(pid);
- if (proc == null || (proc.retainedBuffersCount <= 0 && proc.mappedBuffersCount <= 0)) {
- continue;
- }
- pulledData.add(
- FrameworkStatsLog.buildStatsEvent(
- atomTag,
- uid,
- processCmdlines.valueAt(i),
- -1001 /*Placeholder for native processes, OOM_SCORE_ADJ_MIN - 1.*/,
- proc.retainedSizeKb,
- proc.retainedBuffersCount,
- proc.mappedSizeKb,
- proc.mappedBuffersCount));
+ for (KernelAllocationStats.ProcessDmabuf procBuf : procBufs) {
+ pulledData.add(FrameworkStatsLog.buildStatsEvent(
+ atomTag,
+ procBuf.uid,
+ procBuf.processName,
+ procBuf.oomScore,
+ procBuf.retainedSizeKb,
+ procBuf.retainedBuffersCount,
+ 0, /* mapped_dmabuf_kb - deprecated */
+ 0, /* mapped_dmabuf_count - deprecated */
+ procBuf.surfaceFlingerSizeKb,
+ procBuf.surfaceFlingerCount
+ ));
}
return StatsManager.PULL_SUCCESS;
}
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 59b9daf709d8..80877382f75a 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -36,6 +36,7 @@ import android.app.Notification;
import android.app.StatusBarManager;
import android.app.compat.CompatChanges;
import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledAfter;
import android.compat.annotation.EnabledSince;
import android.content.ComponentName;
import android.content.Context;
@@ -135,6 +136,17 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D
@EnabledSince(targetSdkVersion = Build.VERSION_CODES.S)
private static final long LOCK_DOWN_COLLAPSE_STATUS_BAR = 173031413L;
+ /**
+ * In apps targeting {@link android.os.Build.VERSION_CODES#TIRAMISU} or higher, calling
+ * {@link android.service.quicksettings.TileService#requestListeningState} will check that the
+ * calling package (uid) and the package of the target {@link android.content.ComponentName}
+ * match. It'll also make sure that the context used can take actions on behalf of the current
+ * user.
+ */
+ @ChangeId
+ @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.S_V2)
+ static final long REQUEST_LISTENING_MUST_MATCH_PACKAGE = 172251878L;
+
private final Context mContext;
private final Handler mHandler = new Handler();
@@ -1652,6 +1664,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D
@Override
public void hideCurrentInputMethodForBubbles() {
+ enforceStatusBarService();
final long token = Binder.clearCallingIdentity();
try {
InputMethodManagerInternal.get().hideCurrentInputMethod(
@@ -1776,6 +1789,42 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D
}
@Override
+ public void requestTileServiceListeningState(
+ @NonNull ComponentName componentName,
+ int userId
+ ) {
+ int callingUid = Binder.getCallingUid();
+ String packageName = componentName.getPackageName();
+
+ boolean mustPerformChecks = CompatChanges.isChangeEnabled(
+ REQUEST_LISTENING_MUST_MATCH_PACKAGE, callingUid);
+
+ if (mustPerformChecks) {
+ // Check calling user can act on behalf of current user
+ userId = mActivityManagerInternal.handleIncomingUser(Binder.getCallingPid(), callingUid,
+ userId, false, ActivityManagerInternal.ALLOW_NON_FULL,
+ "requestTileServiceListeningState", packageName);
+
+ // Check calling uid matches package
+ checkCallingUidPackage(packageName, callingUid, userId);
+
+ int currentUser = mActivityManagerInternal.getCurrentUserId();
+
+ // Check current user
+ if (userId != currentUser) {
+ throw new IllegalArgumentException("User " + userId + " is not the current user.");
+ }
+ }
+ if (mBar != null) {
+ try {
+ mBar.requestTileServiceListeningState(componentName);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "requestTileServiceListeningState", e);
+ }
+ }
+ }
+
+ @Override
public void requestAddTile(
@NonNull ComponentName componentName,
@NonNull CharSequence label,
diff --git a/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java b/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java
index c0207f044b83..16592d764e64 100644
--- a/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java
+++ b/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java
@@ -24,6 +24,7 @@ import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
import android.os.Binder;
import android.os.Environment;
import android.os.FileObserver;
@@ -31,7 +32,6 @@ import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
import android.os.ResultReceiver;
-import android.os.ServiceManager;
import android.os.ShellCallback;
import android.os.ShellCommand;
import android.os.UserHandle;
@@ -49,6 +49,7 @@ import com.android.internal.util.DumpUtils;
import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.EventLogTags;
+import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.pm.PackageManagerService;
@@ -187,10 +188,10 @@ public class DeviceStorageMonitorService extends SystemService {
// when it's within 150% of the threshold, we try trimming usage
// back to 200% of the threshold.
if (file.getUsableSpace() < (lowBytes * 3) / 2) {
- final PackageManagerService pms = (PackageManagerService) ServiceManager
- .getService("package");
+ final PackageManagerInternal pm =
+ LocalServices.getService(PackageManagerInternal.class);
try {
- pms.freeStorage(vol.getFsUuid(), lowBytes * 2, 0);
+ pm.freeStorage(vol.getFsUuid(), lowBytes * 2, 0);
} catch (IOException e) {
Slog.w(TAG, e);
}
@@ -264,10 +265,10 @@ public class DeviceStorageMonitorService extends SystemService {
for (VolumeInfo vol : storage.getWritablePrivateVolumes()) {
final File file = vol.getPath();
if (file.getUsableSpace() < file.getTotalSpace() * storageThresholdPercentHigh / 100) {
- final PackageManagerService pms = (PackageManagerService) ServiceManager
- .getService("package");
+ final PackageManagerInternal pm =
+ LocalServices.getService(PackageManagerInternal.class);
try {
- pms.freeAllAppCacheAboveQuota(vol.getFsUuid());
+ pm.freeAllAppCacheAboveQuota(vol.getFsUuid());
} catch (IOException e) {
Slog.w(TAG, e);
}
diff --git a/services/core/java/com/android/server/trust/TEST_MAPPING b/services/core/java/com/android/server/trust/TEST_MAPPING
new file mode 100644
index 000000000000..be8ed67f459b
--- /dev/null
+++ b/services/core/java/com/android/server/trust/TEST_MAPPING
@@ -0,0 +1,15 @@
+{
+ "presubmit": [
+ {
+ "name": "TrustTests",
+ "options": [
+ {
+ "include-filter": "android.trust.test"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ }
+ ]
+ }
+ ]
+ } \ No newline at end of file
diff --git a/services/core/java/com/android/server/trust/TrustAgentWrapper.java b/services/core/java/com/android/server/trust/TrustAgentWrapper.java
index 20cd8f5c12f8..d3748140a5a5 100644
--- a/services/core/java/com/android/server/trust/TrustAgentWrapper.java
+++ b/services/core/java/com/android/server/trust/TrustAgentWrapper.java
@@ -40,12 +40,16 @@ import android.os.PersistableBundle;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.UserHandle;
+import android.service.trust.GrantTrustResult;
import android.service.trust.ITrustAgentService;
import android.service.trust.ITrustAgentServiceCallback;
import android.service.trust.TrustAgentService;
import android.util.Log;
+import android.util.Pair;
import android.util.Slog;
+import com.android.internal.infra.AndroidFuture;
+
import java.util.Collections;
import java.util.List;
@@ -156,7 +160,9 @@ public class TrustAgentWrapper {
}
mTrusted = true;
mTrustable = false;
- mMessage = (CharSequence) msg.obj;
+ Pair<CharSequence, AndroidFuture<GrantTrustResult>> pair = (Pair) msg.obj;
+ mMessage = pair.first;
+ AndroidFuture<GrantTrustResult> resultCallback = pair.second;
int flags = msg.arg1;
mDisplayTrustGrantedMessage = (flags & FLAG_GRANT_TRUST_DISPLAY_MESSAGE) != 0;
if ((flags & FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE) != 0) {
@@ -189,7 +195,7 @@ public class TrustAgentWrapper {
mTrustManagerService.mArchive.logGrantTrust(mUserId, mName,
(mMessage != null ? mMessage.toString() : null),
durationMs, flags);
- mTrustManagerService.updateTrust(mUserId, flags);
+ mTrustManagerService.updateTrust(mUserId, flags, resultCallback);
break;
case MSG_TRUST_TIMEOUT:
if (DEBUG) Slog.d(TAG, "Trust timed out : " + mName.flattenToShortString());
@@ -198,6 +204,8 @@ public class TrustAgentWrapper {
// Fall through.
case MSG_REVOKE_TRUST:
mTrusted = false;
+ mTrustable = false;
+ mWaitingForTrustableDowngrade = false;
mDisplayTrustGrantedMessage = false;
mMessage = null;
mHandler.removeMessages(MSG_TRUST_TIMEOUT);
@@ -312,13 +320,18 @@ public class TrustAgentWrapper {
private ITrustAgentServiceCallback mCallback = new ITrustAgentServiceCallback.Stub() {
@Override
- public void grantTrust(CharSequence message, long durationMs, int flags) {
+ public void grantTrust(
+ CharSequence message,
+ long durationMs,
+ int flags,
+ AndroidFuture resultCallback) {
if (DEBUG) {
Slog.d(TAG, "enableTrust(" + message + ", durationMs = " + durationMs
+ ", flags = " + flags + ")");
}
- Message msg = mHandler.obtainMessage(MSG_GRANT_TRUST, flags, 0, message);
+ Message msg = mHandler.obtainMessage(
+ MSG_GRANT_TRUST, flags, 0, Pair.create(message, resultCallback));
msg.getData().putLong(DATA_DURATION, durationMs);
msg.sendToTarget();
}
@@ -512,12 +525,23 @@ public class TrustAgentWrapper {
}
/**
- * @see android.service.trust.TrustAgentService#onUserRequestedUnlock()
+ * @see android.service.trust.TrustAgentService#onUserRequestedUnlock(boolean)
*/
- public void onUserRequestedUnlock() {
+ public void onUserRequestedUnlock(boolean dismissKeyguard) {
+ try {
+ if (mTrustAgentService != null) {
+ mTrustAgentService.onUserRequestedUnlock(dismissKeyguard);
+ }
+ } catch (RemoteException e) {
+ onError(e);
+ }
+ }
+
+ /** @see android.service.trust.TrustAgentService#onUserMayRequestUnlock() */
+ public void onUserMayRequestUnlock() {
try {
if (mTrustAgentService != null) {
- mTrustAgentService.onUserRequestedUnlock();
+ mTrustAgentService.onUserMayRequestUnlock();
}
} catch (RemoteException e) {
onError(e);
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index bd4b8d15f453..a486364518b9 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -61,6 +61,7 @@ import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
import android.security.Authorization;
+import android.service.trust.GrantTrustResult;
import android.service.trust.TrustAgentService;
import android.text.TextUtils;
import android.util.ArrayMap;
@@ -77,6 +78,7 @@ import android.view.WindowManagerGlobal;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.content.PackageMonitor;
+import com.android.internal.infra.AndroidFuture;
import com.android.internal.util.DumpUtils;
import com.android.internal.widget.LockPatternUtils;
import com.android.server.LocalServices;
@@ -131,6 +133,7 @@ public class TrustManagerService extends SystemService {
private static final int MSG_SCHEDULE_TRUST_TIMEOUT = 15;
private static final int MSG_USER_REQUESTED_UNLOCK = 16;
private static final int MSG_REFRESH_TRUSTABLE_TIMERS_AFTER_AUTH = 17;
+ private static final int MSG_USER_MAY_REQUEST_UNLOCK = 18;
private static final String REFRESH_DEVICE_LOCKED_EXCEPT_USER = "except";
@@ -495,13 +498,28 @@ public class TrustManagerService extends SystemService {
}
}
- public void updateTrust(int userId, int flags) {
- updateTrust(userId, flags, false /* isFromUnlock */);
+ /** Triggers a trust update. */
+ public void updateTrust(
+ int userId,
+ int flags) {
+ updateTrust(userId, flags, null);
}
- private void updateTrust(int userId, int flags, boolean isFromUnlock) {
+ /** Triggers a trust update. */
+ public void updateTrust(
+ int userId,
+ int flags,
+ @Nullable AndroidFuture<GrantTrustResult> resultCallback) {
+ updateTrust(userId, flags, false /* isFromUnlock */, resultCallback);
+ }
+
+ private void updateTrust(
+ int userId,
+ int flags,
+ boolean isFromUnlock,
+ @Nullable AndroidFuture<GrantTrustResult> resultCallback) {
if (ENABLE_ACTIVE_UNLOCK_FLAG) {
- updateTrustWithRenewableUnlock(userId, flags, isFromUnlock);
+ updateTrustWithRenewableUnlock(userId, flags, isFromUnlock, resultCallback);
} else {
updateTrustWithNonrenewableTrust(userId, flags, isFromUnlock);
}
@@ -553,7 +571,11 @@ public class TrustManagerService extends SystemService {
}
}
- private void updateTrustWithRenewableUnlock(int userId, int flags, boolean isFromUnlock) {
+ private void updateTrustWithRenewableUnlock(
+ int userId,
+ int flags,
+ boolean isFromUnlock,
+ @Nullable AndroidFuture<GrantTrustResult> resultCallback) {
boolean managed = aggregateIsTrustManaged(userId);
dispatchOnTrustManagedChanged(managed, userId);
if (mStrongAuthTracker.isTrustAllowedForUser(userId)
@@ -614,8 +636,18 @@ public class TrustManagerService extends SystemService {
isTrustableTimeout /* isTrustableTimeout */);
}
}
- }
+ boolean wasLocked = !alreadyUnlocked;
+ boolean shouldSendCallback = wasLocked && pendingTrustState == TrustState.TRUSTED;
+ if (shouldSendCallback) {
+ if (resultCallback != null) {
+ if (DEBUG) Slog.d(TAG, "calling back with UNLOCKED_BY_GRANT");
+ resultCallback.complete(
+ GrantTrustResult.withStatus(
+ GrantTrustResult.STATUS_UNLOCKED_BY_GRANT));
+ }
+ }
+ }
private void updateTrustUsuallyManaged(int userId, boolean managed) {
synchronized (mTrustUsuallyManagedForUser) {
@@ -715,7 +747,7 @@ public class TrustManagerService extends SystemService {
(disabledFeatures & DevicePolicyManager.KEYGUARD_DISABLE_TRUST_AGENTS) != 0;
List<ComponentName> enabledAgents = lockPatternUtils.getEnabledTrustAgents(userInfo.id);
- if (enabledAgents == null) {
+ if (enabledAgents.isEmpty()) {
if (DEBUG) Slog.d(TAG, "refreshAgentList: skipping user " + userInfo.id
+ ": no agents enabled by user");
continue;
@@ -1080,9 +1112,7 @@ public class TrustManagerService extends SystemService {
}
List<ComponentName> previouslyEnabledAgents = utils.getEnabledTrustAgents(userId);
- if (previouslyEnabledAgents != null) {
- discoveredAgents.addAll(previouslyEnabledAgents);
- }
+ discoveredAgents.addAll(previouslyEnabledAgents);
utils.setEnabledTrustAgents(discoveredAgents, userId);
Settings.Secure.putIntForUser(mContext.getContentResolver(),
Settings.Secure.TRUST_AGENTS_INITIALIZED, 1, userId);
@@ -1192,7 +1222,7 @@ public class TrustManagerService extends SystemService {
if (successful) {
mStrongAuthTracker.allowTrustFromUnlock(userId);
// Allow the presence of trust on a successful unlock attempt to extend unlock
- updateTrust(userId, 0 /* flags */, true);
+ updateTrust(userId, 0 /* flags */, true, null);
mHandler.obtainMessage(MSG_REFRESH_TRUSTABLE_TIMERS_AFTER_AUTH, userId).sendToTarget();
}
@@ -1204,11 +1234,27 @@ public class TrustManagerService extends SystemService {
}
}
- private void dispatchUserRequestedUnlock(int userId) {
+ private void dispatchUserRequestedUnlock(int userId, boolean dismissKeyguard) {
+ if (DEBUG) {
+ Slog.d(TAG, "dispatchUserRequestedUnlock(user=" + userId + ", dismissKeyguard="
+ + dismissKeyguard + ")");
+ }
+ for (int i = 0; i < mActiveAgents.size(); i++) {
+ AgentInfo info = mActiveAgents.valueAt(i);
+ if (info.userId == userId) {
+ info.agent.onUserRequestedUnlock(dismissKeyguard);
+ }
+ }
+ }
+
+ private void dispatchUserMayRequestUnlock(int userId) {
+ if (DEBUG) {
+ Slog.d(TAG, "dispatchUserMayRequestUnlock(user=" + userId + ")");
+ }
for (int i = 0; i < mActiveAgents.size(); i++) {
AgentInfo info = mActiveAgents.valueAt(i);
if (info.userId == userId) {
- info.agent.onUserRequestedUnlock();
+ info.agent.onUserMayRequestUnlock();
}
}
}
@@ -1343,9 +1389,17 @@ public class TrustManagerService extends SystemService {
}
@Override
- public void reportUserRequestedUnlock(int userId) throws RemoteException {
+ public void reportUserRequestedUnlock(int userId, boolean dismissKeyguard)
+ throws RemoteException {
enforceReportPermission();
- mHandler.obtainMessage(MSG_USER_REQUESTED_UNLOCK, userId).sendToTarget();
+ mHandler.obtainMessage(MSG_USER_REQUESTED_UNLOCK, userId, dismissKeyguard ? 1 : 0)
+ .sendToTarget();
+ }
+
+ @Override
+ public void reportUserMayRequestUnlock(int userId) throws RemoteException {
+ enforceReportPermission();
+ mHandler.obtainMessage(MSG_USER_MAY_REQUEST_UNLOCK, userId).sendToTarget();
}
@Override
@@ -1685,7 +1739,10 @@ public class TrustManagerService extends SystemService {
dispatchUnlockAttempt(msg.arg1 != 0, msg.arg2);
break;
case MSG_USER_REQUESTED_UNLOCK:
- dispatchUserRequestedUnlock(msg.arg1);
+ dispatchUserRequestedUnlock(msg.arg1, msg.arg2 != 0);
+ break;
+ case MSG_USER_MAY_REQUEST_UNLOCK:
+ dispatchUserMayRequestUnlock(msg.arg1);
break;
case MSG_DISPATCH_UNLOCK_LOCKOUT:
dispatchUnlockLockout(msg.arg1, msg.arg2);
@@ -1727,7 +1784,7 @@ public class TrustManagerService extends SystemService {
break;
case MSG_REFRESH_DEVICE_LOCKED_FOR_USER:
if (msg.arg2 == 1) {
- updateTrust(msg.arg1, 0 /* flags */, true /* isFromUnlock */);
+ updateTrust(msg.arg1, 0 /* flags */, true /* isFromUnlock */, null);
}
final int unlockedUser = msg.getData().getInt(
REFRESH_DEVICE_LOCKED_EXCEPT_USER, UserHandle.USER_NULL);
diff --git a/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java b/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java
index 53a9244837ed..672458bef4a7 100644
--- a/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java
+++ b/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java
@@ -42,8 +42,8 @@ import android.media.tv.interactive.ITvInteractiveAppService;
import android.media.tv.interactive.ITvInteractiveAppServiceCallback;
import android.media.tv.interactive.ITvInteractiveAppSession;
import android.media.tv.interactive.ITvInteractiveAppSessionCallback;
-import android.media.tv.interactive.TvInteractiveAppInfo;
import android.media.tv.interactive.TvInteractiveAppService;
+import android.media.tv.interactive.TvInteractiveAppServiceInfo;
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
@@ -130,7 +130,7 @@ public class TvInteractiveAppManagerService extends SystemService {
new Intent(TvInteractiveAppService.SERVICE_INTERFACE),
PackageManager.GET_SERVICES | PackageManager.GET_META_DATA,
userId);
- List<TvInteractiveAppInfo> iAppList = new ArrayList<>();
+ List<TvInteractiveAppServiceInfo> iAppList = new ArrayList<>();
for (ResolveInfo ri : services) {
ServiceInfo si = ri.serviceInfo;
@@ -143,8 +143,8 @@ public class TvInteractiveAppManagerService extends SystemService {
ComponentName component = new ComponentName(si.packageName, si.name);
try {
- TvInteractiveAppInfo info =
- new TvInteractiveAppInfo(mContext, component);
+ TvInteractiveAppServiceInfo info =
+ new TvInteractiveAppServiceInfo(mContext, component);
iAppList.add(info);
} catch (Exception e) {
Slogf.e(TAG, "failed to load TV Interactive App service " + si.name, e);
@@ -154,10 +154,10 @@ public class TvInteractiveAppManagerService extends SystemService {
}
// sort the iApp list by iApp service id
- Collections.sort(iAppList, Comparator.comparing(TvInteractiveAppInfo::getId));
+ Collections.sort(iAppList, Comparator.comparing(TvInteractiveAppServiceInfo::getId));
Map<String, TvInteractiveAppState> iAppMap = new HashMap<>();
ArrayMap<String, Integer> tiasAppCount = new ArrayMap<>(iAppMap.size());
- for (TvInteractiveAppInfo info : iAppList) {
+ for (TvInteractiveAppServiceInfo info : iAppList) {
String iAppServiceId = info.getId();
if (DEBUG) {
Slogf.d(TAG, "add " + iAppServiceId);
@@ -195,7 +195,7 @@ public class TvInteractiveAppManagerService extends SystemService {
for (String iAppServiceId : userState.mIAppMap.keySet()) {
if (!iAppMap.containsKey(iAppServiceId)) {
- TvInteractiveAppInfo info = userState.mIAppMap.get(iAppServiceId).mInfo;
+ TvInteractiveAppServiceInfo info = userState.mIAppMap.get(iAppServiceId).mInfo;
ServiceState serviceState = userState.mServiceStateMap.get(info.getComponent());
if (serviceState != null) {
abortPendingCreateSessionRequestsLocked(serviceState, iAppServiceId, userId);
@@ -283,7 +283,7 @@ public class TvInteractiveAppManagerService extends SystemService {
userState.mCallbacks.finishBroadcast();
}
- private int getInteractiveAppUid(TvInteractiveAppInfo info) {
+ private int getInteractiveAppUid(TvInteractiveAppServiceInfo info) {
try {
return getContext().getPackageManager().getApplicationInfo(
info.getServiceInfo().packageName, 0).uid;
@@ -642,7 +642,7 @@ public class TvInteractiveAppManagerService extends SystemService {
private final class BinderService extends ITvInteractiveAppManager.Stub {
@Override
- public List<TvInteractiveAppInfo> getTvInteractiveAppServiceList(int userId) {
+ public List<TvInteractiveAppServiceInfo> getTvInteractiveAppServiceList(int userId) {
final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
Binder.getCallingUid(), userId, "getTvInteractiveAppServiceList");
final long identity = Binder.clearCallingIdentity();
@@ -653,7 +653,7 @@ public class TvInteractiveAppManagerService extends SystemService {
mGetServiceListCalled = true;
}
UserState userState = getOrCreateUserStateLocked(resolvedUserId);
- List<TvInteractiveAppInfo> iAppList = new ArrayList<>();
+ List<TvInteractiveAppServiceInfo> iAppList = new ArrayList<>();
for (TvInteractiveAppState state : userState.mIAppMap.values()) {
iAppList.add(state.mInfo);
}
@@ -665,42 +665,6 @@ public class TvInteractiveAppManagerService extends SystemService {
}
@Override
- public void prepare(String tiasId, int type, int userId) {
- // TODO: bind service
- final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
- Binder.getCallingUid(), userId, "prepare");
- final long identity = Binder.clearCallingIdentity();
- try {
- synchronized (mLock) {
- UserState userState = getOrCreateUserStateLocked(resolvedUserId);
- TvInteractiveAppState iAppState = userState.mIAppMap.get(tiasId);
- if (iAppState == null) {
- Slogf.e(TAG, "failed to prepare TIAS - unknown TIAS id " + tiasId);
- return;
- }
- ComponentName componentName = iAppState.mInfo.getComponent();
- ServiceState serviceState = userState.mServiceStateMap.get(componentName);
- if (serviceState == null) {
- serviceState = new ServiceState(
- componentName, tiasId, resolvedUserId, true, type);
- userState.mServiceStateMap.put(componentName, serviceState);
- updateServiceConnectionLocked(componentName, resolvedUserId);
- } else if (serviceState.mService != null) {
- serviceState.mService.prepare(type);
- } else {
- serviceState.mPendingPrepare = true;
- serviceState.mPendingPrepareType = type;
- updateServiceConnectionLocked(componentName, resolvedUserId);
- }
- }
- } catch (RemoteException e) {
- Slogf.e(TAG, "error in prepare", e);
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- }
-
- @Override
public void registerAppLinkInfo(String tiasId, AppLinkInfo appLinkInfo, int userId) {
final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
Binder.getCallingUid(), userId, "registerAppLinkInfo: " + appLinkInfo);
@@ -1360,6 +1324,32 @@ public class TvInteractiveAppManagerService extends SystemService {
}
@Override
+ public void sendSigningResult(
+ IBinder sessionToken, String signingId, byte[] result, int userId) {
+ if (DEBUG) {
+ Slogf.d(TAG, "sendSigningResult(signingId=%s)", signingId);
+ }
+ final int callingUid = Binder.getCallingUid();
+ final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
+ userId, "sendSigningResult");
+ SessionState sessionState = null;
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ try {
+ sessionState = getSessionStateLocked(sessionToken, callingUid,
+ resolvedUserId);
+ getSessionLocked(sessionState).sendSigningResult(signingId, result);
+ } catch (RemoteException | SessionNotFoundException e) {
+ Slogf.e(TAG, "error in sendSigningResult", e);
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ @Override
public void setSurface(IBinder sessionToken, Surface surface, int userId) {
final int callingUid = Binder.getCallingUid();
final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
@@ -1679,7 +1669,6 @@ public class TvInteractiveAppManagerService extends SystemService {
}
boolean shouldBind = (!serviceState.mSessionTokens.isEmpty())
- || (serviceState.mPendingPrepare)
|| (!serviceState.mPendingAppLinkInfo.isEmpty())
|| (!serviceState.mPendingAppLinkCommand.isEmpty());
@@ -1738,7 +1727,7 @@ public class TvInteractiveAppManagerService extends SystemService {
private static final class TvInteractiveAppState {
private String mIAppServiceId;
private ComponentName mComponentName;
- private TvInteractiveAppInfo mInfo;
+ private TvInteractiveAppServiceInfo mInfo;
private int mUid;
private int mIAppNumber;
}
@@ -1831,22 +1820,13 @@ public class TvInteractiveAppManagerService extends SystemService {
private final List<Pair<AppLinkInfo, Boolean>> mPendingAppLinkInfo = new ArrayList<>();
private final List<Bundle> mPendingAppLinkCommand = new ArrayList<>();
- private boolean mPendingPrepare = false;
- private Integer mPendingPrepareType = null;
private ITvInteractiveAppService mService;
private ServiceCallback mCallback;
private boolean mBound;
private boolean mReconnecting;
private ServiceState(ComponentName component, String tias, int userId) {
- this(component, tias, userId, false, null);
- }
-
- private ServiceState(ComponentName component, String tias, int userId,
- boolean pendingPrepare, Integer prepareType) {
mComponent = component;
- mPendingPrepare = pendingPrepare;
- mPendingPrepareType = prepareType;
mConnection = new InteractiveAppServiceConnection(component, userId);
mIAppServiceId = tias;
}
@@ -1894,19 +1874,6 @@ public class TvInteractiveAppManagerService extends SystemService {
}
}
- if (serviceState.mPendingPrepare) {
- final long identity = Binder.clearCallingIdentity();
- try {
- serviceState.mService.prepare(serviceState.mPendingPrepareType);
- serviceState.mPendingPrepare = false;
- serviceState.mPendingPrepareType = null;
- } catch (RemoteException e) {
- Slogf.e(TAG, "error in prepare when onServiceConnected", e);
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- }
-
if (!serviceState.mPendingAppLinkInfo.isEmpty()) {
for (Iterator<Pair<AppLinkInfo, Boolean>> it =
serviceState.mPendingAppLinkInfo.iterator();
@@ -2221,6 +2188,24 @@ public class TvInteractiveAppManagerService extends SystemService {
}
@Override
+ public void onRequestSigning(String id, String algorithm, String alias, byte[] data) {
+ synchronized (mLock) {
+ if (DEBUG) {
+ Slogf.d(TAG, "onRequestSigning");
+ }
+ if (mSessionState.mSession == null || mSessionState.mClient == null) {
+ return;
+ }
+ try {
+ mSessionState.mClient.onRequestSigning(
+ id, algorithm, alias, data, mSessionState.mSeq);
+ } catch (RemoteException e) {
+ Slogf.e(TAG, "error in onRequestSigning", e);
+ }
+ }
+ }
+
+ @Override
public void onAdRequest(AdRequest request) {
synchronized (mLock) {
if (DEBUG) {
diff --git a/services/core/java/com/android/server/utils/TimingsTraceAndSlog.java b/services/core/java/com/android/server/utils/TimingsTraceAndSlog.java
index 397acfac2812..b45c962811ad 100644
--- a/services/core/java/com/android/server/utils/TimingsTraceAndSlog.java
+++ b/services/core/java/com/android/server/utils/TimingsTraceAndSlog.java
@@ -88,7 +88,7 @@ public final class TimingsTraceAndSlog extends TimingsTraceLog {
@Override
public void traceBegin(@NonNull String name) {
- Slog.i(mTag, name);
+ Slog.d(mTag, name);
super.traceBegin(name);
}
diff --git a/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java b/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java
index 30e261725a73..092853f298c2 100644
--- a/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java
+++ b/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java
@@ -39,7 +39,7 @@ import android.telephony.SubscriptionManager;
import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
import android.telephony.TelephonyCallback;
import android.telephony.TelephonyManager;
-import android.telephony.TelephonyManager.CarrierPrivilegesListener;
+import android.telephony.TelephonyManager.CarrierPrivilegesCallback;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Slog;
@@ -98,8 +98,7 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver {
@NonNull private final OnSubscriptionsChangedListener mSubscriptionChangedListener;
@NonNull
- private final List<CarrierPrivilegesListener> mCarrierPrivilegesChangedListeners =
- new ArrayList<>();
+ private final List<CarrierPrivilegesCallback> mCarrierPrivilegesCallbacks = new ArrayList<>();
@NonNull private TelephonySubscriptionSnapshot mCurrentSnapshot;
@@ -151,20 +150,21 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver {
executor, mSubscriptionChangedListener);
mTelephonyManager.registerTelephonyCallback(executor, mActiveDataSubIdListener);
- registerCarrierPrivilegesListeners();
+ registerCarrierPrivilegesCallbacks();
}
- private void registerCarrierPrivilegesListeners() {
+ // TODO(b/221306368): Refactor with the new onCarrierServiceChange in the new CPCallback
+ private void registerCarrierPrivilegesCallbacks() {
final HandlerExecutor executor = new HandlerExecutor(mHandler);
final int modemCount = mTelephonyManager.getActiveModemCount();
try {
for (int i = 0; i < modemCount; i++) {
- CarrierPrivilegesListener carrierPrivilegesListener =
- new CarrierPrivilegesListener() {
+ CarrierPrivilegesCallback carrierPrivilegesCallback =
+ new CarrierPrivilegesCallback() {
@Override
public void onCarrierPrivilegesChanged(
- @NonNull List<String> privilegedPackageNames,
- @NonNull int[] privilegedUids) {
+ @NonNull Set<String> privilegedPackageNames,
+ @NonNull Set<Integer> privilegedUids) {
// Re-trigger the synchronous check (which is also very cheap due
// to caching in CarrierPrivilegesTracker). This allows consistency
// with the onSubscriptionsChangedListener and broadcasts.
@@ -172,9 +172,9 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver {
}
};
- mTelephonyManager.addCarrierPrivilegesListener(
- i, executor, carrierPrivilegesListener);
- mCarrierPrivilegesChangedListeners.add(carrierPrivilegesListener);
+ mTelephonyManager.registerCarrierPrivilegesCallback(
+ i, executor, carrierPrivilegesCallback);
+ mCarrierPrivilegesCallbacks.add(carrierPrivilegesCallback);
}
} catch (IllegalArgumentException e) {
Slog.wtf(TAG, "Encounted exception registering carrier privileges listeners", e);
@@ -191,15 +191,15 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver {
mSubscriptionManager.removeOnSubscriptionsChangedListener(mSubscriptionChangedListener);
mTelephonyManager.unregisterTelephonyCallback(mActiveDataSubIdListener);
- unregisterCarrierPrivilegesListeners();
+ unregisterCarrierPrivilegesCallbacks();
}
- private void unregisterCarrierPrivilegesListeners() {
- for (CarrierPrivilegesListener carrierPrivilegesListener :
- mCarrierPrivilegesChangedListeners) {
- mTelephonyManager.removeCarrierPrivilegesListener(carrierPrivilegesListener);
+ private void unregisterCarrierPrivilegesCallbacks() {
+ for (CarrierPrivilegesCallback carrierPrivilegesCallback :
+ mCarrierPrivilegesCallbacks) {
+ mTelephonyManager.unregisterCarrierPrivilegesCallback(carrierPrivilegesCallback);
}
- mCarrierPrivilegesChangedListeners.clear();
+ mCarrierPrivilegesCallbacks.clear();
}
/**
@@ -283,7 +283,7 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver {
}
private void handleActionMultiSimConfigChanged(Context context, Intent intent) {
- unregisterCarrierPrivilegesListeners();
+ unregisterCarrierPrivilegesCallbacks();
// Clear invalid slotIds from the mReadySubIdsBySlotId map.
final int modemCount = mTelephonyManager.getActiveModemCount();
@@ -296,7 +296,7 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver {
}
}
- registerCarrierPrivilegesListeners();
+ registerCarrierPrivilegesCallbacks();
handleSubscriptionsChanged();
}
diff --git a/services/core/java/com/android/server/vibrator/VibrationSettings.java b/services/core/java/com/android/server/vibrator/VibrationSettings.java
index b05b44bcb1d2..77da75118958 100644
--- a/services/core/java/com/android/server/vibrator/VibrationSettings.java
+++ b/services/core/java/com/android/server/vibrator/VibrationSettings.java
@@ -355,8 +355,10 @@ final class VibrationSettings {
}
}
- if (!shouldVibrateForRingerModeLocked(usage)) {
- return Vibration.Status.IGNORED_FOR_RINGER_MODE;
+ if (!attrs.isFlagSet(VibrationAttributes.FLAG_BYPASS_INTERRUPTION_POLICY)) {
+ if (!shouldVibrateForRingerModeLocked(usage)) {
+ return Vibration.Status.IGNORED_FOR_RINGER_MODE;
+ }
}
}
return null;
@@ -386,12 +388,12 @@ final class VibrationSettings {
* Return {@code true} if the device should vibrate for current ringer mode.
*
* <p>This checks the current {@link AudioManager#getRingerModeInternal()} against user settings
- * for ringtone usage only. All other usages are allowed by this method.
+ * for ringtone and notification usages. All other usages are allowed by this method.
*/
@GuardedBy("mLock")
private boolean shouldVibrateForRingerModeLocked(@VibrationAttributes.Usage int usageHint) {
- if (usageHint != USAGE_RINGTONE) {
- // Only ringtone vibrations are disabled when phone is on silent mode.
+ if ((usageHint != USAGE_RINGTONE) && (usageHint != USAGE_NOTIFICATION)) {
+ // Only ringtone and notification vibrations are disabled when phone is on silent mode.
return true;
}
// If audio manager was not loaded yet then assume most restrictive mode.
diff --git a/services/core/java/com/android/server/vibrator/VibrationStepConductor.java b/services/core/java/com/android/server/vibrator/VibrationStepConductor.java
index 58407cf7fd46..e12426b2b02c 100644
--- a/services/core/java/com/android/server/vibrator/VibrationStepConductor.java
+++ b/services/core/java/com/android/server/vibrator/VibrationStepConductor.java
@@ -60,8 +60,6 @@ final class VibrationStepConductor implements IBinder.DeathRecipient {
static final float RAMP_OFF_AMPLITUDE_MIN = 1e-3f;
static final List<Step> EMPTY_STEP_LIST = new ArrayList<>();
- private final Object mLock = new Object();
-
// Used within steps.
public final VibrationSettings vibrationSettings;
public final DeviceVibrationEffectAdapter deviceEffectAdapter;
@@ -74,6 +72,11 @@ final class VibrationStepConductor implements IBinder.DeathRecipient {
private final Queue<Step> mPendingOnVibratorCompleteSteps = new LinkedList<>();
// Signalling fields.
+ // Note that vibrator callback signals may happen inside vibrator HAL calls made by the
+ // VibrationThread, or on an external executor, so this lock should not be held for anything
+ // other than updating signalling state - particularly not during HAL calls or when invoking
+ // other callbacks that may trigger calls into the thread.
+ private final Object mLock = new Object();
@GuardedBy("mLock")
private final IntArray mSignalVibratorsComplete;
@GuardedBy("mLock")
@@ -334,9 +337,9 @@ final class VibrationStepConductor implements IBinder.DeathRecipient {
* The state update is recorded for processing on the main execution thread (VibrationThread).
*/
public void notifyVibratorComplete(int vibratorId) {
- if (Build.IS_DEBUGGABLE) {
- expectIsVibrationThread(false);
- }
+ // HAL callbacks may be triggered directly within HAL calls, so these notifications
+ // could be on the VibrationThread as it calls the HAL, or some other executor later.
+ // Therefore no thread assertion is made here.
if (DEBUG) {
Slog.d(TAG, "Vibration complete reported by vibrator " + vibratorId);
@@ -356,9 +359,9 @@ final class VibrationStepConductor implements IBinder.DeathRecipient {
* (VibrationThread).
*/
public void notifySyncedVibrationComplete() {
- if (Build.IS_DEBUGGABLE) {
- expectIsVibrationThread(false);
- }
+ // HAL callbacks may be triggered directly within HAL calls, so these notifications
+ // could be on the VibrationThread as it calls the HAL, or some other executor later.
+ // Therefore no thread assertion is made here.
if (DEBUG) {
Slog.d(TAG, "Synced vibration complete reported by vibrator manager");
@@ -394,7 +397,7 @@ final class VibrationStepConductor implements IBinder.DeathRecipient {
int[] vibratorsToProcess = null;
boolean doCancel = false;
boolean doCancelImmediate = false;
- // Swap out the queue of completions to process.
+ // Collect signals to process, but don't keep the lock while processing them.
synchronized (mLock) {
if (mSignalCancelImmediate) {
if (mCancelledImmediately) {
@@ -407,6 +410,7 @@ final class VibrationStepConductor implements IBinder.DeathRecipient {
doCancel = true;
}
if (!doCancelImmediate && mSignalVibratorsComplete.size() > 0) {
+ // Swap out the queue of completions to process.
vibratorsToProcess = mSignalVibratorsComplete.toArray(); // makes a copy
mSignalVibratorsComplete.clear();
}
diff --git a/services/core/java/com/android/server/vibrator/VibrationThread.java b/services/core/java/com/android/server/vibrator/VibrationThread.java
index 205ea62496ff..cecc5c04dedc 100644
--- a/services/core/java/com/android/server/vibrator/VibrationThread.java
+++ b/services/core/java/com/android/server/vibrator/VibrationThread.java
@@ -22,6 +22,7 @@ import android.os.IBinder;
import android.os.PowerManager;
import android.os.Process;
import android.os.RemoteException;
+import android.os.SystemClock;
import android.os.Trace;
import android.os.WorkSource;
import android.util.Slog;
@@ -176,7 +177,7 @@ final class VibrationThread extends Thread {
* @return true if the vibration completed, or false if waiting timed out.
*/
public boolean waitForThreadIdle(long maxWaitMillis) {
- long now = System.currentTimeMillis();
+ long now = SystemClock.elapsedRealtime();
long deadline = now + maxWaitMillis;
synchronized (mLock) {
while (true) {
@@ -191,7 +192,7 @@ final class VibrationThread extends Thread {
} catch (InterruptedException e) {
Slog.w(TAG, "VibrationThread interrupted waiting to stop, continuing");
}
- now = System.currentTimeMillis();
+ now = SystemClock.elapsedRealtime();
}
}
}
diff --git a/services/core/java/com/android/server/vibrator/VibratorManagerService.java b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
index 9ec1079e46cc..1260e5dbc9f7 100644
--- a/services/core/java/com/android/server/vibrator/VibratorManagerService.java
+++ b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
@@ -464,10 +464,9 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
&& shouldCancelVibration(
mCurrentExternalVibration.externalVibration.getVibrationAttributes(),
usageFilter)) {
- endVibrationLocked(mCurrentExternalVibration, Vibration.Status.CANCELLED);
mCurrentExternalVibration.externalVibration.mute();
- mCurrentExternalVibration = null;
- setExternalControl(false);
+ endExternalVibrateLocked(Vibration.Status.CANCELLED,
+ /* continueExternalControl= */ false);
}
} finally {
Binder.restoreCallingIdentity(ident);
@@ -1283,7 +1282,7 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
}
/** Holder for a {@link ExternalVibration}. */
- private final class ExternalVibrationHolder {
+ private final class ExternalVibrationHolder implements IBinder.DeathRecipient {
public final ExternalVibration externalVibration;
public int scale;
@@ -1308,6 +1307,18 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
mEndTimeDebug = System.currentTimeMillis();
}
+ public void binderDied() {
+ synchronized (mLock) {
+ if (mCurrentExternalVibration != null) {
+ if (DEBUG) {
+ Slog.d(TAG, "External vibration finished because binder died");
+ }
+ endExternalVibrateLocked(Vibration.Status.CANCELLED,
+ /* continueExternalControl= */ false);
+ }
+ }
+ }
+
public Vibration.DebugInfo getDebugInfo() {
return new Vibration.DebugInfo(
mStartTimeDebug, mEndTimeDebug, /* effect= */ null, /* originalEffect= */ null,
@@ -1450,10 +1461,36 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
}
}
+ /**
+ * Ends the external vibration, and clears related service state.
+ *
+ * @param status the status to end the associated Vibration with
+ * @param continueExternalControl indicates whether external control will continue. If not, the
+ * HAL will have external control turned off.
+ */
+ @GuardedBy("mLock")
+ private void endExternalVibrateLocked(Vibration.Status status,
+ boolean continueExternalControl) {
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "endExternalVibrateLocked");
+ try {
+ if (mCurrentExternalVibration == null) {
+ return;
+ }
+ endVibrationLocked(mCurrentExternalVibration, status);
+ mCurrentExternalVibration.externalVibration.unlinkToDeath(
+ mCurrentExternalVibration);
+ mCurrentExternalVibration = null;
+ if (!continueExternalControl) {
+ setExternalControl(false);
+ }
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
+ }
+ }
+
/** Implementation of {@link IExternalVibratorService} to be triggered on external control. */
@VisibleForTesting
final class ExternalVibratorService extends IExternalVibratorService.Stub {
- ExternalVibrationDeathRecipient mCurrentExternalDeathRecipient;
@Override
public int onExternalVibrationStart(ExternalVibration vib) {
@@ -1469,7 +1506,7 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
return IExternalVibratorService.SCALE_MUTE;
}
- ExternalVibrationHolder cancelingExternalVibration = null;
+ boolean alreadyUnderExternalControl = false;
boolean waitForCompletion = false;
int scale;
synchronized (mLock) {
@@ -1504,13 +1541,13 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
//
// Note that this doesn't support multiple concurrent external controls, as we
// would need to mute the old one still if it came from a different controller.
+ alreadyUnderExternalControl = true;
mCurrentExternalVibration.externalVibration.mute();
- endVibrationLocked(mCurrentExternalVibration, Vibration.Status.CANCELLED);
- cancelingExternalVibration = mCurrentExternalVibration;
+ endExternalVibrateLocked(Vibration.Status.CANCELLED,
+ /* continueExternalControl= */ true);
}
mCurrentExternalVibration = new ExternalVibrationHolder(vib);
- mCurrentExternalDeathRecipient = new ExternalVibrationDeathRecipient();
- vib.linkToDeath(mCurrentExternalDeathRecipient);
+ vib.linkToDeath(mCurrentExternalVibration);
mCurrentExternalVibration.scale = mVibrationScaler.getExternalVibrationScale(
vib.getVibrationAttributes().getUsage());
scale = mCurrentExternalVibration.scale;
@@ -1520,14 +1557,13 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
if (!mVibrationThread.waitForThreadIdle(VIBRATION_CANCEL_WAIT_MILLIS)) {
Slog.e(TAG, "Timed out waiting for vibration to cancel");
synchronized (mLock) {
- stopExternalVibrateLocked(Vibration.Status.IGNORED_ERROR_CANCELLING);
+ endExternalVibrateLocked(Vibration.Status.IGNORED_ERROR_CANCELLING,
+ /* continueExternalControl= */ false);
}
return IExternalVibratorService.SCALE_MUTE;
}
}
- if (cancelingExternalVibration == null) {
- // We only need to set external control if it was not already set by another
- // external vibration.
+ if (!alreadyUnderExternalControl) {
if (DEBUG) {
Slog.d(TAG, "Vibrator going under external control.");
}
@@ -1547,29 +1583,12 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
if (DEBUG) {
Slog.e(TAG, "Stopping external vibration" + vib);
}
- stopExternalVibrateLocked(Vibration.Status.FINISHED);
+ endExternalVibrateLocked(Vibration.Status.FINISHED,
+ /* continueExternalControl= */ false);
}
}
}
- @GuardedBy("mLock")
- private void stopExternalVibrateLocked(Vibration.Status status) {
- Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "stopExternalVibrateLocked");
- try {
- if (mCurrentExternalVibration == null) {
- return;
- }
- endVibrationLocked(mCurrentExternalVibration, status);
- mCurrentExternalVibration.externalVibration.unlinkToDeath(
- mCurrentExternalDeathRecipient);
- mCurrentExternalDeathRecipient = null;
- mCurrentExternalVibration = null;
- setExternalControl(false);
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
- }
- }
-
private boolean hasExternalControlCapability() {
for (int i = 0; i < mVibrators.size(); i++) {
if (mVibrators.valueAt(i).hasCapability(IVibrator.CAP_EXTERNAL_CONTROL)) {
@@ -1578,19 +1597,6 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
}
return false;
}
-
- private class ExternalVibrationDeathRecipient implements IBinder.DeathRecipient {
- public void binderDied() {
- synchronized (mLock) {
- if (mCurrentExternalVibration != null) {
- if (DEBUG) {
- Slog.d(TAG, "External vibration finished because binder died");
- }
- stopExternalVibrateLocked(Vibration.Status.CANCELLED);
- }
- }
- }
- }
}
/** Provide limited functionality from {@link VibratorManagerService} as shell commands. */
diff --git a/services/core/java/com/android/server/wm/AccessibilityWindowsPopulator.java b/services/core/java/com/android/server/wm/AccessibilityWindowsPopulator.java
index f9689a8a2bca..11ddac6a9740 100644
--- a/services/core/java/com/android/server/wm/AccessibilityWindowsPopulator.java
+++ b/services/core/java/com/android/server/wm/AccessibilityWindowsPopulator.java
@@ -27,8 +27,10 @@ import android.graphics.RectF;
import android.graphics.Region;
import android.os.Handler;
import android.os.IBinder;
+import android.os.InputConfig;
import android.os.Looper;
import android.os.Message;
+import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
import android.view.IWindow;
@@ -93,8 +95,6 @@ public final class AccessibilityWindowsPopulator extends WindowInfosListener {
mService = service;
mAccessibilityController = accessibilityController;
mHandler = new MyHandler(mService.mH.getLooper());
-
- register();
}
/**
@@ -153,7 +153,8 @@ public final class AccessibilityWindowsPopulator extends WindowInfosListener {
final List<InputWindowHandle> tempVisibleWindows = new ArrayList<>();
for (InputWindowHandle window : windowHandles) {
- if (window.visible && window.getWindow() != null) {
+ final boolean visible = (window.inputConfig & InputConfig.NOT_VISIBLE) == 0;
+ if (visible && window.getWindow() != null) {
tempVisibleWindows.add(window);
}
}
@@ -217,8 +218,10 @@ public final class AccessibilityWindowsPopulator extends WindowInfosListener {
}
mWindowsNotificationEnabled = register;
if (mWindowsNotificationEnabled) {
- populateVisibleWindowHandlesAndNotifyWindowsChangeIfNeeded();
+ Pair<InputWindowHandle[], DisplayInfo[]> info = register();
+ onWindowInfosChangedInternal(info.first, info.second);
} else {
+ unregister();
releaseResources();
}
}
@@ -641,7 +644,8 @@ public final class AccessibilityWindowsPopulator extends WindowInfosListener {
final RecentsAnimationController controller = service.getRecentsAnimationController();
instance.mIgnoreDuetoRecentsAnimation = windowState != null && controller != null
&& controller.shouldIgnoreForAccessibility(windowState);
- instance.mIsTrustedOverlay = inputWindowHandle.trustedOverlay;
+ instance.mIsTrustedOverlay =
+ (inputWindowHandle.inputConfig & InputConfig.TRUSTED_OVERLAY) != 0;
// TODO (b/199358388) : gets the letterbox bounds of the window from other way.
if (windowState != null && windowState.areAppWindowBoundsLetterboxed()) {
diff --git a/services/core/java/com/android/server/wm/ActivityClientController.java b/services/core/java/com/android/server/wm/ActivityClientController.java
index a4a200da686b..8018d5652b1b 100644
--- a/services/core/java/com/android/server/wm/ActivityClientController.java
+++ b/services/core/java/com/android/server/wm/ActivityClientController.java
@@ -746,9 +746,11 @@ class ActivityClientController extends IActivityClientController.Stub {
// if it is not already expanding to fullscreen. Otherwise, the arguments will
// be used the next time the activity enters PiP.
final Task rootTask = r.getRootTask();
- rootTask.setPictureInPictureAspectRatio(r.pictureInPictureArgs.getAspectRatio(),
- r.pictureInPictureArgs.getExpandedAspectRatio());
- rootTask.setPictureInPictureActions(r.pictureInPictureArgs.getActions());
+ rootTask.setPictureInPictureAspectRatio(
+ r.pictureInPictureArgs.getAspectRatioFloat(),
+ r.pictureInPictureArgs.getExpandedAspectRatioFloat());
+ rootTask.setPictureInPictureActions(r.pictureInPictureArgs.getActions(),
+ r.pictureInPictureArgs.getCloseAction());
}
}
} finally {
@@ -757,12 +759,12 @@ class ActivityClientController extends IActivityClientController.Stub {
}
@Override
- public void setPreferDockBigOverlays(IBinder token, boolean preferDockBigOverlays) {
+ public void setShouldDockBigOverlays(IBinder token, boolean shouldDockBigOverlays) {
final long origId = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
final ActivityRecord r = ActivityRecord.forTokenLocked(token);
- r.setPreferDockBigOverlays(preferDockBigOverlays);
+ r.setShouldDockBigOverlays(shouldDockBigOverlays);
}
} finally {
Binder.restoreCallingIdentity(origId);
@@ -828,7 +830,7 @@ class ActivityClientController extends IActivityClientController.Stub {
if (params.hasSetAspectRatio()
&& !mService.mWindowManager.isValidPictureInPictureAspectRatio(
- r.mDisplayContent, params.getAspectRatio())) {
+ r.mDisplayContent, params.getAspectRatioFloat())) {
throw new IllegalArgumentException(String.format(caller
+ ": Aspect ratio is too extreme (must be between %f and %f).",
minAspectRatio, maxAspectRatio));
@@ -836,7 +838,7 @@ class ActivityClientController extends IActivityClientController.Stub {
if (mService.mSupportsExpandedPictureInPicture && params.hasSetExpandedAspectRatio()
&& !mService.mWindowManager.isValidExpandedPictureInPictureAspectRatio(
- r.mDisplayContent, params.getExpandedAspectRatio())) {
+ r.mDisplayContent, params.getExpandedAspectRatioFloat())) {
throw new IllegalArgumentException(String.format(caller
+ ": Expanded aspect ratio is not extreme enough (must not be between"
+ " %f and %f).",
diff --git a/services/core/java/com/android/server/wm/ActivityInterceptorCallback.java b/services/core/java/com/android/server/wm/ActivityInterceptorCallback.java
index 06c58baee1f9..1d65cbb70ffe 100644
--- a/services/core/java/com/android/server/wm/ActivityInterceptorCallback.java
+++ b/services/core/java/com/android/server/wm/ActivityInterceptorCallback.java
@@ -58,6 +58,7 @@ public abstract class ActivityInterceptorCallback {
@IntDef(suffix = { "_ORDERED_ID" }, value = {
FIRST_ORDERED_ID,
PERMISSION_POLICY_ORDERED_ID,
+ INTENT_RESOLVER_ORDERED_ID,
VIRTUAL_DEVICE_SERVICE_ORDERED_ID,
LAST_ORDERED_ID // Update this when adding new ids
})
@@ -75,6 +76,11 @@ public abstract class ActivityInterceptorCallback {
public static final int PERMISSION_POLICY_ORDERED_ID = 1;
/**
+ * The identifier for {@link com.android.server.pm.IntentResolverInterceptor}.
+ */
+ public static final int INTENT_RESOLVER_ORDERED_ID = 2;
+
+ /**
* The identifier for {@link com.android.server.companion.virtual.VirtualDeviceManagerService}
* interceptor.
*/
diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
index a8dd856c2191..7f84f61a91ff 100644
--- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
@@ -191,6 +191,35 @@ class ActivityMetricsLogger {
private long mCurrentTransitionStartTimeNs;
/** Non-null when a {@link TransitionInfo} is created for this state. */
private TransitionInfo mAssociatedTransitionInfo;
+ /** The sequence id for trace. It is used to map the traces before resolving intent. */
+ private static int sTraceSeqId;
+ /** The trace format is "launchingActivity#$seqId:$state(:$packageName)". */
+ final String mTraceName;
+
+ LaunchingState() {
+ if (!Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
+ mTraceName = null;
+ return;
+ }
+ // Use an id because the launching app is not yet known before resolving intent.
+ sTraceSeqId++;
+ mTraceName = "launchingActivity#" + sTraceSeqId;
+ Trace.asyncTraceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, mTraceName, 0);
+ }
+
+ void stopTrace(boolean abort) {
+ if (mTraceName == null) return;
+ Trace.asyncTraceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER, mTraceName, 0);
+ final String launchResult;
+ if (mAssociatedTransitionInfo == null) {
+ launchResult = ":failed";
+ } else {
+ launchResult = (abort ? ":canceled:" : ":completed:")
+ + mAssociatedTransitionInfo.mLastLaunchedActivity.packageName;
+ }
+ // Put a supplement trace as the description of the async trace with the same id.
+ Trace.instant(Trace.TRACE_TAG_ACTIVITY_MANAGER, mTraceName + launchResult);
+ }
@VisibleForTesting
boolean allDrawn() {
@@ -549,10 +578,10 @@ class ActivityMetricsLogger {
}
if (existingInfo == null) {
- // Only notify the observer for a new launching event.
- launchObserverNotifyIntentStarted(intent, transitionStartTimeNs);
final LaunchingState launchingState = new LaunchingState();
launchingState.mCurrentTransitionStartTimeNs = transitionStartTimeNs;
+ // Only notify the observer for a new launching event.
+ launchObserverNotifyIntentStarted(intent, transitionStartTimeNs);
return launchingState;
}
existingInfo.mLaunchingState.mCurrentTransitionStartTimeNs = transitionStartTimeNs;
@@ -574,7 +603,7 @@ class ActivityMetricsLogger {
@Nullable ActivityOptions options) {
if (launchedActivity == null) {
// The launch is aborted, e.g. intent not resolved, class not found.
- abort(null /* info */, "nothing launched");
+ abort(launchingState, "nothing launched");
return;
}
@@ -601,7 +630,7 @@ class ActivityMetricsLogger {
if (launchedActivity.isReportedDrawn() && launchedActivity.isVisible()) {
// Launched activity is already visible. We cannot measure windows drawn delay.
- abort(info, "launched activity already visible");
+ abort(launchingState, "launched activity already visible");
return;
}
@@ -633,7 +662,7 @@ class ActivityMetricsLogger {
final TransitionInfo newInfo = TransitionInfo.create(launchedActivity, launchingState,
options, processRunning, processSwitch, newActivityCreated, resultCode);
if (newInfo == null) {
- abort(info, "unrecognized launch");
+ abort(launchingState, "unrecognized launch");
return;
}
@@ -657,7 +686,7 @@ class ActivityMetricsLogger {
for (int i = mTransitionInfoList.size() - 2; i >= 0; i--) {
final TransitionInfo prevInfo = mTransitionInfoList.get(i);
if (prevInfo.mIsDrawn || !prevInfo.mLastLaunchedActivity.mVisibleRequested) {
- abort(prevInfo, "nothing will be drawn");
+ scheduleCheckActivityToBeDrawn(prevInfo.mLastLaunchedActivity, 0 /* delay */);
}
}
}
@@ -757,6 +786,10 @@ class ActivityMetricsLogger {
/** Makes sure that the reference to the removed activity is cleared. */
void notifyActivityRemoved(@NonNull ActivityRecord r) {
mLastTransitionInfo.remove(r);
+ final TransitionInfo info = getActiveTransitionInfo(r);
+ if (info != null) {
+ abort(info, "removed");
+ }
final int packageUid = r.info.applicationInfo.uid;
final PackageCompatStateInfo compatStateInfo = mPackageUidToCompatStateInfo.get(packageUid);
@@ -870,23 +903,29 @@ class ActivityMetricsLogger {
}
}
+ private void abort(@NonNull LaunchingState state, String cause) {
+ if (state.mAssociatedTransitionInfo != null) {
+ abort(state.mAssociatedTransitionInfo, cause);
+ return;
+ }
+ if (DEBUG_METRICS) Slog.i(TAG, "abort launch cause=" + cause);
+ state.stopTrace(true /* abort */);
+ launchObserverNotifyIntentFailed();
+ }
+
/** Aborts tracking of current launch metrics. */
- private void abort(TransitionInfo info, String cause) {
+ private void abort(@NonNull TransitionInfo info, String cause) {
done(true /* abort */, info, cause, 0L /* timestampNs */);
}
/** Called when the given transition (info) is no longer active. */
- private void done(boolean abort, @Nullable TransitionInfo info, String cause,
+ private void done(boolean abort, @NonNull TransitionInfo info, String cause,
long timestampNs) {
if (DEBUG_METRICS) {
Slog.i(TAG, "done abort=" + abort + " cause=" + cause + " timestamp=" + timestampNs
+ " info=" + info);
}
- if (info == null) {
- launchObserverNotifyIntentFailed();
- return;
- }
-
+ info.mLaunchingState.stopTrace(abort);
stopLaunchTrace(info);
final Boolean isHibernating =
mLastHibernationStates.remove(info.mLastLaunchedActivity.packageName);
@@ -1453,7 +1492,7 @@ class ActivityMetricsLogger {
/** Starts trace for an activity is actually launching. */
private void startLaunchTrace(@NonNull TransitionInfo info) {
if (DEBUG_METRICS) Slog.i(TAG, "startLaunchTrace " + info);
- if (!Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
+ if (info.mLaunchingState.mTraceName == null) {
return;
}
info.mLaunchTraceName = "launching: " + info.mLastLaunchedActivity.packageName;
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index e66f309d2ccc..4bef126ee2c8 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -278,6 +278,7 @@ import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
+import android.gui.DropInputMode;
import android.hardware.HardwareBuffer;
import android.net.Uri;
import android.os.Binder;
@@ -533,7 +534,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// activity can enter picture in picture while pausing (only when switching to another task)
PictureInPictureParams pictureInPictureArgs = new PictureInPictureParams.Builder().build();
// The PiP params used when deferring the entering of picture-in-picture.
- boolean preferDockBigOverlays;
+ boolean shouldDockBigOverlays;
int launchCount; // count of launches since last state
long lastLaunchTime; // time of last launch of this activity
ComponentName requestedVrComponent; // the requested component for handling VR mode.
@@ -549,7 +550,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
private void updateEnterpriseThumbnailDrawable(Context context) {
DevicePolicyManager dpm = context.getSystemService(DevicePolicyManager.class);
- mEnterpriseThumbnailDrawable = dpm.getDrawable(
+ mEnterpriseThumbnailDrawable = dpm.getResources().getDrawable(
WORK_PROFILE_ICON, OUTLINE, PROFILE_SWITCH_ANIMATION,
() -> context.getDrawable(R.drawable.ic_corp_badge));
}
@@ -782,6 +783,10 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
boolean startingDisplayed;
boolean startingMoved;
+ /** The last set {@link DropInputMode} for this activity surface. */
+ @DropInputMode
+ private int mLastDropInputMode = DropInputMode.NONE;
+
/**
* If it is non-null, it requires all activities who have the same starting data to be drawn
* to remove the starting window.
@@ -1548,6 +1553,60 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
rootTask.setHasBeenVisible(true);
}
}
+
+ // Update the input mode if the embedded mode is changed.
+ updateUntrustedEmbeddingInputProtection();
+ }
+
+ @Override
+ void setSurfaceControl(SurfaceControl sc) {
+ super.setSurfaceControl(sc);
+ if (sc != null) {
+ mLastDropInputMode = DropInputMode.NONE;
+ updateUntrustedEmbeddingInputProtection();
+ }
+ }
+
+ /**
+ * Sets to drop input when obscured to activity if it is embedded in untrusted mode.
+ *
+ * Although the untrusted embedded activity should be invisible when behind other overlay,
+ * theoretically even if this activity is the top most, app can still move surface of activity
+ * below it to the top. As a result, we want to update the input mode to drop when obscured for
+ * all untrusted activities.
+ */
+ private void updateUntrustedEmbeddingInputProtection() {
+ final SurfaceControl sc = getSurfaceControl();
+ if (sc == null) {
+ return;
+ }
+ if (isEmbeddedInUntrustedMode()) {
+ // Set drop input to OBSCURED when untrusted embedded.
+ setDropInputMode(DropInputMode.OBSCURED);
+ } else {
+ // Reset drop input mode when this activity is not embedded in untrusted mode.
+ setDropInputMode(DropInputMode.NONE);
+ }
+ }
+
+ @VisibleForTesting
+ void setDropInputMode(@DropInputMode int mode) {
+ if (mLastDropInputMode != mode && getSurfaceControl() != null) {
+ mLastDropInputMode = mode;
+ mWmService.mTransactionFactory.get()
+ .setDropInputMode(getSurfaceControl(), mode)
+ .apply();
+ }
+ }
+
+ private boolean isEmbeddedInUntrustedMode() {
+ final TaskFragment organizedTaskFragment = getOrganizedTaskFragment();
+ if (organizedTaskFragment == null) {
+ // Not embedded.
+ return false;
+ }
+ // Check if trusted.
+ return !organizedTaskFragment.isAllowedToEmbedActivityInTrustedMode(this);
}
void updateAnimatingActivityRegistry() {
@@ -1983,7 +2042,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
mLetterboxUiController = new LetterboxUiController(mWmService, this);
mCameraCompatControlEnabled = mWmService.mContext.getResources()
.getBoolean(R.bool.config_isCameraCompatControlForStretchedIssuesEnabled);
- preferDockBigOverlays = mWmService.mContext.getResources()
+ shouldDockBigOverlays = mWmService.mContext.getResources()
.getBoolean(R.bool.config_dockBigOverlayWindows);
if (_createTime > 0) {
@@ -2417,7 +2476,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
private boolean transferSplashScreenIfNeeded() {
- if (!mHandleExitSplashScreen || mStartingSurface == null || mStartingWindow == null
+ if (finishing || !mHandleExitSplashScreen || mStartingSurface == null
+ || mStartingWindow == null
|| mTransferringSplashScreenState == TRANSFER_SPLASH_SCREEN_FINISH) {
return false;
}
@@ -2452,7 +2512,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// either way, abort and reset the sequence.
if (parcelable == null
|| mTransferringSplashScreenState != TRANSFER_SPLASH_SCREEN_COPYING
- || mStartingWindow == null) {
+ || mStartingWindow == null
+ || finishing) {
if (parcelable != null) {
parcelable.clearIfNeeded();
}
@@ -2952,6 +3013,14 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
return false;
}
+ // Check to see if PiP is supported for the display this container is on.
+ if (mDisplayContent != null && !mDisplayContent.mDwpcHelper.isWindowingModeSupported(
+ WINDOWING_MODE_PINNED)) {
+ Slog.w(TAG, "Display " + mDisplayContent.getDisplayId()
+ + " doesn't support enter picture-in-picture mode. caller = " + caller);
+ return false;
+ }
+
boolean isCurrentAppLocked =
mAtmService.getLockTaskModeState() != LOCK_TASK_MODE_NONE;
final TaskDisplayArea taskDisplayArea = getDisplayArea();
@@ -3642,6 +3711,20 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
return;
}
finishing = true;
+
+ // Transfer the launch cookie to the next running activity above this in the same task.
+ if (mLaunchCookie != null && mState != RESUMED && task != null && !task.mInRemoveTask
+ && !task.isClearingToReuseTask()) {
+ final ActivityRecord nextCookieTarget = task.getActivity(
+ // Intend to only associate the same app by checking uid.
+ r -> r.mLaunchCookie == null && !r.finishing && r.isUid(getUid()),
+ this, false /* includeBoundary */, false /* traverseTopToBottom */);
+ if (nextCookieTarget != null) {
+ nextCookieTarget.mLaunchCookie = mLaunchCookie;
+ mLaunchCookie = null;
+ }
+ }
+
final TaskFragment taskFragment = getTaskFragment();
if (taskFragment != null) {
final Task task = taskFragment.getTask();
@@ -5428,6 +5511,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
return false;
}
+ // Untrusted embedded activity can be visible only if there is no other overlay window.
+ if (hasOverlayOverUntrustedModeEmbedded()) {
+ return false;
+ }
+
// Check if the activity is on a sleeping display, canTurnScreenOn will also check
// keyguard visibility
if (mDisplayContent.isSleeping()) {
@@ -5437,6 +5525,25 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
}
+ /**
+ * Checks if there are any activities or other containers that belong to the same task on top of
+ * this activity when embedded in untrusted mode.
+ */
+ boolean hasOverlayOverUntrustedModeEmbedded() {
+ if (!isEmbeddedInUntrustedMode() || getRootTask() == null) {
+ // The activity is not embedded in untrusted mode.
+ return false;
+ }
+
+ // Check if there are any activities with different UID over the activity that is embedded
+ // in untrusted mode. Traverse bottom to top with boundary so that it will only check
+ // activities above this activity.
+ final ActivityRecord differentUidOverlayActivity = getRootTask().getActivity(
+ a -> a.getUid() != getUid(), this /* boundary */, false /* includeBoundary */,
+ false /* traverseTopToBottom */);
+ return differentUidOverlayActivity != null;
+ }
+
void updateVisibilityIgnoringKeyguard(boolean behindFullscreenActivity) {
visibleIgnoringKeyguard = (!behindFullscreenActivity || mLaunchTaskBehind)
&& showToCurrentUser();
@@ -5502,19 +5609,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
"makeInvisible", true /* beforeStopping */);
// Defer telling the client it is hidden if it can enter Pip and isn't current paused,
// stopped or stopping. This gives it a chance to enter Pip in onPause().
- // TODO: There is still a question surrounding activities in multi-window mode that want
- // to enter Pip after they are paused, but are still visible. I they should be okay to
- // enter Pip in those cases, but not "auto-Pip" which is what this condition covers and
- // the current contract for "auto-Pip" is that the app should enter it before onPause
- // returns. Just need to confirm this reasoning makes sense.
final boolean deferHidingClient = canEnterPictureInPicture
&& !isState(STARTED, STOPPING, STOPPED, PAUSED);
- if (!mTransitionController.isShellTransitionsEnabled()
- && deferHidingClient && pictureInPictureArgs.isAutoEnterEnabled()) {
- // Go ahead and just put the activity in pip if it supports auto-pip.
- mAtmService.enterPictureInPictureMode(this, pictureInPictureArgs);
- return;
- }
setDeferHidingClient(deferHidingClient);
setVisibility(false);
@@ -6669,7 +6765,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
// Choose the default behavior for Launcher and SystemUI when the SplashScreen style is
// not specified in the ActivityOptions.
- if (mLaunchSourceType == LAUNCH_SOURCE_TYPE_HOME) {
+ if (mLaunchSourceType == LAUNCH_SOURCE_TYPE_HOME
+ || launchedFromUid == Process.SHELL_UID) {
return false;
} else if (mLaunchSourceType == LAUNCH_SOURCE_TYPE_SYSTEMUI) {
return true;
@@ -6689,7 +6786,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// solid color splash screen.
// Need to check sourceRecord before in case this activity is launched from service.
return !startActivity || !(mLaunchSourceType == LAUNCH_SOURCE_TYPE_SYSTEM
- || mLaunchSourceType == LAUNCH_SOURCE_TYPE_HOME);
+ || mLaunchSourceType == LAUNCH_SOURCE_TYPE_HOME
+ || launchedFromUid == Process.SHELL_UID);
}
private int getSplashscreenTheme(ActivityOptions options) {
@@ -9475,9 +9573,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
getTask().getRootTask().onPictureInPictureParamsChanged();
}
- void setPreferDockBigOverlays(boolean preferDockBigOverlays) {
- this.preferDockBigOverlays = preferDockBigOverlays;
- getTask().getRootTask().onPreferDockBigOverlaysChanged();
+ void setShouldDockBigOverlays(boolean shouldDockBigOverlays) {
+ this.shouldDockBigOverlays = shouldDockBigOverlays;
+ getTask().getRootTask().onShouldDockBigOverlaysChanged();
}
@Override
diff --git a/services/core/java/com/android/server/wm/ActivityRecordInputSink.java b/services/core/java/com/android/server/wm/ActivityRecordInputSink.java
index 19d5449254ff..8622bd32fc68 100644
--- a/services/core/java/com/android/server/wm/ActivityRecordInputSink.java
+++ b/services/core/java/com/android/server/wm/ActivityRecordInputSink.java
@@ -19,6 +19,7 @@ package com.android.server.wm;
import android.app.compat.CompatChanges;
import android.compat.annotation.ChangeId;
import android.os.IBinder;
+import android.os.InputConfig;
import android.os.InputConstants;
import android.os.Looper;
import android.os.Process;
@@ -111,13 +112,12 @@ class ActivityRecordInputSink {
mActivityRecord.getDisplayId());
inputWindowHandle.replaceTouchableRegionWithCrop = true;
inputWindowHandle.name = mName;
+ inputWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_INPUT_CONSUMER;
inputWindowHandle.ownerUid = Process.myUid();
inputWindowHandle.ownerPid = Process.myPid();
- inputWindowHandle.layoutParamsFlags =
- WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
- | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH;
inputWindowHandle.dispatchingTimeoutMillis =
InputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
+ inputWindowHandle.inputConfig = InputConfig.NOT_FOCUSABLE;
return inputWindowHandle;
}
@@ -169,5 +169,4 @@ class ActivityRecordInputSink {
finishInputEvent(event, true);
}
}
-
}
diff --git a/services/core/java/com/android/server/wm/ActivityStartInterceptor.java b/services/core/java/com/android/server/wm/ActivityStartInterceptor.java
index c5fcd12efa78..cdeb86c3ee77 100644
--- a/services/core/java/com/android/server/wm/ActivityStartInterceptor.java
+++ b/services/core/java/com/android/server/wm/ActivityStartInterceptor.java
@@ -355,10 +355,10 @@ class ActivityStartInterceptor {
* @return The intercepting intent if needed.
*/
private Intent interceptWithConfirmCredentialsIfNeeded(ActivityInfo aInfo, int userId) {
- if (!mService.mAmInternal.shouldConfirmCredentials(userId)) {
+ if ((aInfo.flags & ActivityInfo.FLAG_SHOW_WHEN_LOCKED) != 0
+ || !mService.mAmInternal.shouldConfirmCredentials(userId)) {
return null;
}
- // TODO(b/28935539): should allow certain activities to bypass work challenge
final IntentSender target = createIntentSenderForOriginalIntent(mCallingUid,
FLAG_CANCEL_CURRENT | FLAG_ONE_SHOT | FLAG_IMMUTABLE);
final KeyguardManager km = (KeyguardManager) mServiceContext
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index fd2afd47bec4..7abcc4b808a1 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -1716,9 +1716,10 @@ class ActivityStarter {
// If we are not able to proceed, disassociate the activity from the task. Leaving an
// activity in an incomplete state can lead to issues, such as performing operations
// without a window container.
- final Task rootTask = mStartActivity.getRootTask();
- if (rootTask != null) {
+ if (mStartActivity.getTask() != null) {
mStartActivity.finishIfPossible("startActivity", true /* oomAdj */);
+ } else if (mStartActivity.getParent() != null) {
+ mStartActivity.getParent().removeChild(mStartActivity);
}
// Root task should also be detached from display and be removed if it's empty.
@@ -1816,7 +1817,8 @@ class ActivityStarter {
}
if (mTargetRootTask == null) {
- mTargetRootTask = getLaunchRootTask(mStartActivity, mLaunchFlags, targetTask, mOptions);
+ mTargetRootTask = getOrCreateRootTask(mStartActivity, mLaunchFlags, targetTask,
+ mOptions);
}
if (newTask) {
final Task taskToAffiliate = (mLaunchTaskBehind && mSourceRecord != null)
@@ -1925,7 +1927,7 @@ class ActivityStarter {
} else if (mInTask != null) {
return mInTask;
} else {
- final Task rootTask = getLaunchRootTask(mStartActivity, mLaunchFlags, null /* task */,
+ final Task rootTask = getOrCreateRootTask(mStartActivity, mLaunchFlags, null /* task */,
mOptions);
final ActivityRecord top = rootTask.getTopNonFinishingActivity();
if (top != null) {
@@ -2022,22 +2024,12 @@ class ActivityStarter {
private boolean canEmbedActivity(@NonNull TaskFragment taskFragment,
@NonNull ActivityRecord starting, boolean newTask, Task targetTask) {
final Task hostTask = taskFragment.getTask();
- if (hostTask == null) {
- return false;
- }
-
- // Allowing the embedding if the task is owned by system.
- final int hostUid = hostTask.effectiveUid;
- if (UserHandle.getAppId(hostUid) == Process.SYSTEM_UID) {
- return true;
- }
-
- if (!taskFragment.isAllowedToEmbedActivity(starting)) {
+ // Not allowed embedding a separate task or without host task.
+ if (hostTask == null || newTask || targetTask != hostTask) {
return false;
}
- // Not allowed embedding task.
- return !newTask && (targetTask == null || targetTask == hostTask);
+ return taskFragment.isAllowedToEmbedActivity(starting);
}
/**
@@ -2233,7 +2225,7 @@ class ActivityStarter {
if (targetTask.getRootTask() == null) {
// Target root task got cleared when we all activities were removed above.
// Go ahead and reset it.
- mTargetRootTask = getLaunchRootTask(mStartActivity, mLaunchFlags,
+ mTargetRootTask = getOrCreateRootTask(mStartActivity, mLaunchFlags,
null /* task */, mOptions);
mTargetRootTask.addChild(targetTask, !mLaunchTaskBehind /* toTop */,
(mStartActivity.info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0);
@@ -2695,10 +2687,11 @@ class ActivityStarter {
// launched into the same root task.
mTargetRootTask = Task.fromWindowContainerToken(mSourceRecord.mLaunchRootTask);
} else {
- final Task launchRootTask =
- getLaunchRootTask(mStartActivity, mLaunchFlags, intentTask, mOptions);
+ final Task rootTask =
+ getOrCreateRootTask(mStartActivity, mLaunchFlags, intentTask, mOptions);
+ // TODO(b/184806710): #getOrCreateRootTask should never return null?
mTargetRootTask =
- launchRootTask != null ? launchRootTask : intentActivity.getRootTask();
+ rootTask != null ? rootTask : intentActivity.getRootTask();
}
}
@@ -2738,10 +2731,11 @@ class ActivityStarter {
false /* includingParents */);
intentTask = intentTask.getParent().asTaskFragment().getTask();
}
- // If the task is in multi-windowing mode, the activity may already be on
+ // If the activity is visible in multi-windowing mode, it may already be on
// the top (visible to user but not the global top), then the result code
// should be START_DELIVERED_TO_TOP instead of START_TASK_TO_FRONT.
final boolean wasTopOfVisibleRootTask = intentActivity.mVisibleRequested
+ && intentActivity.inMultiWindowMode()
&& intentActivity == mTargetRootTask.topRunningActivity();
// We only want to move to the front, if we aren't going to launch on a
// different root task. If we launch on a different root task, we will put the
@@ -2929,7 +2923,7 @@ class ActivityStarter {
return launchFlags;
}
- private Task getLaunchRootTask(ActivityRecord r, int launchFlags, Task task,
+ private Task getOrCreateRootTask(ActivityRecord r, int launchFlags, Task task,
ActivityOptions aOptions) {
// We are reusing a task, keep the root task!
if (mReuseTask != null) {
@@ -2938,7 +2932,7 @@ class ActivityStarter {
final boolean onTop =
(aOptions == null || !aOptions.getAvoidMoveToFront()) && !mLaunchTaskBehind;
- return mRootWindowContainer.getLaunchRootTask(r, aOptions, task, mSourceRootTask, onTop,
+ return mRootWindowContainer.getOrCreateRootTask(r, aOptions, task, mSourceRootTask, onTop,
mLaunchParams, launchFlags);
}
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index cecfccd1f836..01dfb91d12be 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -680,4 +680,15 @@ public abstract class ActivityTaskManagerInternal {
/** Get the app tasks for a package */
public abstract List<ActivityManager.AppTask> getAppTasks(String pkgName, int uid);
+
+ /**
+ * Determine if there exists a task which meets the criteria set by the PermissionPolicyService
+ * to show a system-owned permission dialog over, for a given package
+ * @see PermissionPolicyInternal.shouldShowNotificationDialogForTask
+ *
+ * @param pkgName The package whose activity must be top
+ * @param uid The uid that must have a top activity
+ * @return a task ID if a valid task ID is found. Otherwise, return INVALID_TASK_ID
+ */
+ public abstract int getTaskToShowPermissionDialogOn(String pkgName, int uid);
}
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index bfccdf97c680..8b6262f0fcca 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -205,8 +205,6 @@ import android.os.UpdateLock;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.WorkSource;
-import android.os.storage.IStorageManager;
-import android.os.storage.StorageManager;
import android.provider.Settings;
import android.service.dreams.DreamActivity;
import android.service.dreams.DreamManagerInternal;
@@ -3525,14 +3523,16 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
}
// Only update the saved args from the args that are set
r.setPictureInPictureParams(params);
- final float aspectRatio = r.pictureInPictureArgs.getAspectRatio();
- final float expandedAspectRatio = r.pictureInPictureArgs.getExpandedAspectRatio();
+ final float aspectRatio = r.pictureInPictureArgs.getAspectRatioFloat();
+ final float expandedAspectRatio =
+ r.pictureInPictureArgs.getExpandedAspectRatioFloat();
final List<RemoteAction> actions = r.pictureInPictureArgs.getActions();
+ final RemoteAction closeAction = r.pictureInPictureArgs.getCloseAction();
mRootWindowContainer.moveActivityToPinnedRootTask(r,
null /* launchIntoPipHostActivity */, "enterPictureInPictureMode");
final Task task = r.getTask();
task.setPictureInPictureAspectRatio(aspectRatio, expandedAspectRatio);
- task.setPictureInPictureActions(actions);
+ task.setPictureInPictureActions(actions, closeAction);
// Continue the pausing process after entering pip.
if (task.getPausingActivity() == r) {
@@ -4300,11 +4300,6 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
SystemProperties.set("persist.sys.locale",
locales.get(bestLocaleIndex).toLanguageTag());
LocaleList.setDefault(locales, bestLocaleIndex);
-
- final Message m = PooledLambda.obtainMessage(
- ActivityTaskManagerService::sendLocaleToMountDaemonMsg, this,
- locales.get(bestLocaleIndex));
- mH.sendMessage(m);
}
mTempConfig.seq = increaseConfigurationSeqLocked();
@@ -4458,17 +4453,6 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
Settings.System.putConfigurationForUser(resolver, config, userId);
}
- private void sendLocaleToMountDaemonMsg(Locale l) {
- try {
- IBinder service = ServiceManager.getService("mount");
- IStorageManager storageManager = IStorageManager.Stub.asInterface(service);
- Log.d(TAG, "Storing locale " + l.toLanguageTag() + " for decryption UI");
- storageManager.setField(StorageManager.SYSTEM_LOCALE_KEY, l.toLanguageTag());
- } catch (RemoteException e) {
- Log.e(TAG, "Error storing locale for decryption UI", e);
- }
- }
-
private void expireStartAsCallerTokenMsg(IBinder permissionToken) {
mStartActivitySources.remove(permissionToken);
mExpiredStartAsCallerTokens.add(permissionToken);
@@ -6754,5 +6738,13 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
}
return tasks;
}
+
+ @Override
+ public int getTaskToShowPermissionDialogOn(String pkgName, int uid) {
+ synchronized (ActivityTaskManagerService.this.mGlobalLock) {
+ return ActivityTaskManagerService.this.mRootWindowContainer
+ .getTaskToShowPermissionDialogOn(pkgName, uid);
+ }
+ }
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
index 5573f161d1c1..eb5ca9c2f43b 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
@@ -402,7 +402,8 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
activities.add(r.info);
});
}
- if (!displayContent.mDwpcHelper.canContainActivities(activities)) {
+ if (!displayContent.mDwpcHelper.canContainActivities(activities,
+ displayContent.getWindowingMode())) {
return false;
}
}
@@ -954,7 +955,7 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
// This is the first time we failed -- restart process and
// retry.
r.launchFailed = true;
- proc.removeActivity(r, true /* keepAssociation */);
+ r.detachFromProcess();
throw e;
}
} finally {
@@ -1046,6 +1047,9 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
// If a dead object exception was thrown -- fall through to
// restart the application.
knownToBeDead = true;
+ // Remove the process record so it won't be considered as alive.
+ mService.mProcessNames.remove(wpc.mName, wpc.mUid);
+ mService.mProcessMap.remove(wpc.getPid());
}
r.notifyUnknownVisibilityLaunchedForKeyguardTransition();
@@ -1436,20 +1440,20 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
final Rect bounds = options.getLaunchBounds();
task.setBounds(bounds);
- Task launchRootTask =
- mRootWindowContainer.getLaunchRootTask(null, options, task, ON_TOP);
+ Task targetRootTask =
+ mRootWindowContainer.getOrCreateRootTask(null, options, task, ON_TOP);
- if (launchRootTask != currentRootTask) {
- moveHomeRootTaskToFrontIfNeeded(flags, launchRootTask.getDisplayArea(), reason);
- task.reparent(launchRootTask, ON_TOP, REPARENT_KEEP_ROOT_TASK_AT_FRONT,
+ if (targetRootTask != currentRootTask) {
+ moveHomeRootTaskToFrontIfNeeded(flags, targetRootTask.getDisplayArea(), reason);
+ task.reparent(targetRootTask, ON_TOP, REPARENT_KEEP_ROOT_TASK_AT_FRONT,
!ANIMATE, DEFER_RESUME, reason);
- currentRootTask = launchRootTask;
+ currentRootTask = targetRootTask;
reparented = true;
// task.reparent() should already placed the task on top,
// still need moveTaskToFrontLocked() below for any transition settings.
}
- if (launchRootTask.shouldResizeRootTaskWithLaunchBounds()) {
- launchRootTask.resize(bounds, !PRESERVE_WINDOWS, !DEFER_RESUME);
+ if (targetRootTask.shouldResizeRootTaskWithLaunchBounds()) {
+ targetRootTask.resize(bounds, !PRESERVE_WINDOWS, !DEFER_RESUME);
} else {
// WM resizeTask must be done after the task is moved to the correct stack,
// because Task's setBounds() also updates dim layer's bounds, but that has
@@ -1693,7 +1697,7 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
*/
boolean restoreRecentTaskLocked(Task task, ActivityOptions aOptions, boolean onTop) {
final Task rootTask =
- mRootWindowContainer.getLaunchRootTask(null, aOptions, task, onTop);
+ mRootWindowContainer.getOrCreateRootTask(null, aOptions, task, onTop);
final WindowContainer parent = task.getParent();
if (parent == rootTask || task == rootTask) {
diff --git a/services/core/java/com/android/server/wm/AsyncRotationController.java b/services/core/java/com/android/server/wm/AsyncRotationController.java
index 9e889ad11b8e..e79e77cee58b 100644
--- a/services/core/java/com/android/server/wm/AsyncRotationController.java
+++ b/services/core/java/com/android/server/wm/AsyncRotationController.java
@@ -144,7 +144,8 @@ class AsyncRotationController extends FadeAnimationController implements Consume
// Legacy animation doesn't need to wait for the start transaction.
if (mTransitionOp == OP_LEGACY) {
mIsStartTransactionCommitted = true;
- } else if (displayContent.mTransitionController.useShellTransitionsRotation()) {
+ } else if (displayContent.mTransitionController.useShellTransitionsRotation()
+ || displayContent.mTransitionController.isCollecting(displayContent)) {
keepAppearanceInPreviousRotation();
}
}
@@ -329,8 +330,12 @@ class AsyncRotationController extends FadeAnimationController implements Consume
void hideImmediately(WindowToken windowToken) {
final boolean original = mHideImmediately;
mHideImmediately = true;
+ final Operation op = new Operation(Operation.ACTION_FADE);
+ mTargetWindowTokens.put(windowToken, op);
fadeWindowToken(false /* show */, windowToken, ANIMATION_TYPE_FIXED_TRANSFORM);
+ op.mLeash = windowToken.getAnimationLeash();
mHideImmediately = original;
+ if (DEBUG) Slog.d(TAG, "hideImmediately " + windowToken.getTopChild());
}
/** Returns {@code true} if the window will rotate independently. */
diff --git a/services/core/java/com/android/server/wm/BLASTSync.md b/services/core/java/com/android/server/wm/BLASTSync.md
new file mode 100644
index 000000000000..2f39d6db385e
--- /dev/null
+++ b/services/core/java/com/android/server/wm/BLASTSync.md
@@ -0,0 +1,108 @@
+= What does it mean for BLAST Sync to work? =
+There are two BLAST sync primitives on the server side, BLASTSyncEngine and applyWithNextDraw.
+Both of them are used to solve subclasses of this category of problem:
+ 1. You have some server side changes, which will trigger both WM/SysUI initiated SurfaceControl.Transactions,
+ and also trigger a client redraw/update
+ 2. You want to synchronize the redraw of those clients with the application of those WM/SysUI side changes.
+
+Put simply, you would like to synchronize the graphical effects of some WM changes with the graphical output of various windows
+observing those changes.
+
+To talk about exactly what the primitives guarantee, we need to clarify what we mean by server side changes.
+In this document we will use a term syncable state to refer to any state mutated under the WindowManager lock
+which when observed by the client, produces a visible outcome in the produced frame.
+For example the current Configuration.
+
+The guarantee provided by Server-side BLAST Sync Primitives is thus:
+Guarantee 1: If you make a set of changes to syncable state, at the same time that you begin a sync,
+then the first frame drawn by the client after observing the syncable state will be sent in a transaction
+to the consumer of the sync which was begun, rather than directly sent to SurfaceFlinger.
+
+Here "at the same time" means in the same critical section (while holding the WM lock)
+For example this guarantee means that you can write code like:
+ window.performConfigurationChange(someConfiguration)
+ window.applyOnNextDraw(consumer)
+And the consumer will always be passed the first frame containing the configuration change. This can work with any
+syncable state not just Configuration.
+
+The following is the protocol and additional requirements for BLAST sync, and an analysis of why it is correct. Due to time
+constraints we analyze it for a single window only (as this is actually the hard part).
+
+Protocol requirements:
+ Server protocol, precondition, begin a syncSeqId integer per window at 0:
+ SA: Enter the critical section
+ SB: Change syncable state, any number of times, prepare any number of syncs (and
+ increment the seqId if a sync was prepared, assosciate it with the sync)
+ SC: Leave the critical section
+ SD: Send syncable state updates to the client, always paired with the current seqId
+ SE: When the client calls finishDrawing, execute the consumer for each sync with
+ seqId <= the seqId which the client passed to finishDrawing
+ Client protocol:
+ CA: Observe state and seqid changes up until a fixed frame deadline, then execute performTraversals
+ CB: If the seqId is incremeneted at the time of the frame deadline, configure the renderer to
+ redirect the next draw in to a transaction, record the seqId at the time
+ CC: When the draw is finished, send the transaction containing the draw to WM with the
+ previously recorded seqId
+ Additional requirements/assumptions:
+ 1. The server may only send changes to the syncable state paired with the seqId. The client may
+ only receive them together (e.g. not from other sources)
+ 2. In between changing and sending syncable state, the lock must be released and acquired again
+ 3. The client wont draw a frame reflecting syncable state changes without passing through "performTraversals"
+ 4. Drawing never fails
+ 5. There are no blocking calls between the client or the server
+
+Note that the server can begin the protocol at any time, so it may be possible for the client to proceed through
+phases SA, SB, SC, and SD multiple times before the client receives any messages.
+
+To show that the guarantee can't be violated, we use a notation of sequences, where we describe interleaving
+of protocol events. For duplicate events, we attach a number, e.g. SA_1, SA_2.
+
+We proceed by contradiction, imagine there was some sequence (..., SA_N, ...) for which the guarantee was
+not upheld. This means that either
+ 1. finishDrawing with the assosciate seqId was never sent to the server OR
+ 2. It was sent too late (after the first frame was sent to SF instead of WM) OR
+ 3. It was sent too early (not containing the state changes originating with SA_N)
+If it was sent neither too late, nor too early, and contained the assosciated seqId, then protocol step SE
+says that the frame will be passed to the consumer and we uphold our guarantee.
+
+The first case is impossible because step SD says that the server always sends the seqId if a sync was prepared.
+If we send it the client must receive it. Since we only increment the seqId, and the client only takes the
+seqId from us (requirement 1, protocol step SB), the received ID must be higher than the clients previous seqId.
+CA says that performTraversals will execute, and CB says that when it does, if the seqId is higher than before
+it will schedule the render to sync. Requirement 4 says drawing never fails, so CC must execute, and so we will always
+eventually send every seqId (or a seqId > than it) back to the server.
+
+It also can't be sent too late. By requirement 2 we must release and acquire the lock
+after after changing and before emitting syncable state changes. This means it's guaranteed
+that even in an ordering like AcquireLock, ChangeState, PrepareSync, Release lock we can't
+send the state changes before prepareSync, and so they can always include at least the seqId
+assosciated with changestate (or a later one).
+Since we only receive the SeqId with the State changes (requirement 1),
+and we wont draw state changes without passing through perform traversals (requirement 3) the first frame
+containing the state change must have been generated by a call to performTraversals which also observed
+the seqId change, and so it will appropriately configure the renderer.
+
+By the same argument it can't be sent too early! Since we only send seqIds we receive from the server,
+and we only send seqIds after completing a drawing pass of the assosciated state.
+
+So we can see that no matter at what time the server makes syncable state changes, the first frame will
+always be delivered to the draw handler. Assuming that the client and server uphold this protocol and these
+requirements.
+
+The trickiest part of the implementation at the moment is due to assosciating seqId. Currently we send one of the most
+most important pieces of syncable state (configuration) over multiple channels. Namely ClientTransaction
+and MSG_RESIZED. The ordering of these relative to sync preparation in server code is undefined, in fact we have cases like
+this all the time:
+ acquireLock()
+ changeConfiguration()
+ // time passes, but still in critical section
+ prepareSync()
+ releaseLock()
+This is exactly the kind of case Guarantee 1 mentions as an example. In previous incarnations of the code this worked
+because relayoutWindow needed to acquire the same lock and relayoutWindow was a necessary part of completing sync.
+
+Now that we have no barrier, that could create issues, because at the time we change configuration (and send the change
+to the client via ClientTransaction), we haven't even incremented the seqId yet, and so how can the client observe it
+at the same time as the state? We solve this by pushing all client communication through a handler thread that has to
+acquire the lock. This ensures we uphold requirement 2.
+
diff --git a/services/core/java/com/android/server/wm/BackNavigationController.java b/services/core/java/com/android/server/wm/BackNavigationController.java
index 23f14a7b7a16..dbc01413e6fa 100644
--- a/services/core/java/com/android/server/wm/BackNavigationController.java
+++ b/services/core/java/com/android/server/wm/BackNavigationController.java
@@ -25,6 +25,7 @@ import android.content.ComponentName;
import android.graphics.Point;
import android.graphics.Rect;
import android.hardware.HardwareBuffer;
+import android.os.Bundle;
import android.os.RemoteCallback;
import android.os.RemoteException;
import android.os.SystemProperties;
@@ -44,7 +45,11 @@ import com.android.internal.protolog.common.ProtoLog;
class BackNavigationController {
private static final String TAG = "BackNavigationController";
- private static final String BACK_PREDICTABILITY_PROP = "persist.debug.back_predictability";
+ // By default, enable new back dispatching without any animations.
+ private static final int BACK_PREDICTABILITY_PROP =
+ SystemProperties.getInt("persist.debug.back_predictability", 1);
+ private static final int ANIMATIONS_MASK = 1 << 1;
+ private static final int SCREENSHOT_MASK = 1 << 2;
@Nullable
private TaskSnapshotController mTaskSnapshotController;
@@ -53,11 +58,15 @@ class BackNavigationController {
* Returns true if the back predictability feature is enabled
*/
static boolean isEnabled() {
- return SystemProperties.getInt(BACK_PREDICTABILITY_PROP, 0) > 0;
+ return BACK_PREDICTABILITY_PROP > 0;
}
static boolean isScreenshotEnabled() {
- return false;
+ return (BACK_PREDICTABILITY_PROP & SCREENSHOT_MASK) != 0;
+ }
+
+ private static boolean isAnimationEnabled() {
+ return (BACK_PREDICTABILITY_PROP & ANIMATIONS_MASK) != 0;
}
/**
@@ -93,14 +102,17 @@ class BackNavigationController {
ActivityRecord prev;
WindowContainer<?> removedWindowContainer;
ActivityRecord activityRecord;
+ ActivityRecord prevTaskTopActivity = null;
SurfaceControl animationLeashParent;
WindowConfiguration taskWindowConfiguration;
HardwareBuffer screenshotBuffer = null;
+ SurfaceControl screenshotSurface;
int prevTaskId;
int prevUserId;
RemoteAnimationTarget topAppTarget;
SurfaceControl animLeash;
- IOnBackInvokedCallback callback = null;
+ IOnBackInvokedCallback applicationCallback = null;
+ IOnBackInvokedCallback systemCallback = null;
synchronized (task.mWmService.mGlobalLock) {
@@ -116,15 +128,14 @@ class BackNavigationController {
removedWindowContainer = activityRecord;
taskWindowConfiguration = window.getWindowConfiguration();
}
- IOnBackInvokedCallback applicationCallback = null;
- IOnBackInvokedCallback systemCallback = null;
if (window != null) {
applicationCallback = window.getApplicationOnBackInvokedCallback();
- callback = applicationCallback;
- if (callback == null) {
- systemCallback = window.getSystemOnBackInvokedCallback();
- callback = systemCallback;
- }
+ systemCallback = window.getSystemOnBackInvokedCallback();
+ }
+ if (applicationCallback == null && systemCallback == null) {
+ // Return null when either there's no window, or apps have just initialized and
+ // have not finished registering callbacks.
+ return null;
}
ProtoLog.d(WM_DEBUG_BACK_PREVIEW, "startBackNavigation task=%s, "
@@ -133,24 +144,24 @@ class BackNavigationController {
task, activityRecord, applicationCallback, systemCallback);
// TODO Temp workaround for Sysui until b/221071505 is fixed
- if (activityRecord == null && callback != null) {
+ if (activityRecord == null && applicationCallback != null) {
return new BackNavigationInfo(BackNavigationInfo.TYPE_CALLBACK,
null /* topWindowLeash */, null /* screenshotSurface */,
null /* screenshotBuffer */, null /* taskWindowConfiguration */,
null /* onBackNavigationDone */,
- callback /* onBackInvokedCallback */);
+ applicationCallback /* onBackInvokedCallback */);
}
// For IME and Home, either a callback is registered, or we do nothing. In both cases,
// we don't need to pass the leashes below.
if (activityRecord == null || task.getDisplayContent().getImeContainer().isVisible()
|| activityRecord.isActivityTypeHome()) {
- if (callback != null) {
+ if (applicationCallback != null) {
return new BackNavigationInfo(BackNavigationInfo.TYPE_CALLBACK,
null /* topWindowLeash */, null /* screenshotSurface */,
null /* screenshotBuffer */, null /* taskWindowConfiguration */,
null /* onBackNavigationDone */,
- callback /* onBackInvokedCallback */);
+ applicationCallback /* onBackInvokedCallback */);
} else {
return null;
}
@@ -159,12 +170,12 @@ class BackNavigationController {
prev = task.getActivity(
(r) -> !r.finishing && r.getTask() == task && !r.isTopRunningActivity());
- if (callback != null) {
+ if (applicationCallback != null) {
return new BackNavigationInfo(BackNavigationInfo.TYPE_CALLBACK,
null /* topWindowLeash */, null /* screenshotSurface */,
null /* screenshotBuffer */, null /* taskWindowConfiguration */,
null /* onBackNavigationDone */,
- callback /* onBackInvokedCallback */);
+ applicationCallback /* onBackInvokedCallback */);
} else if (prev != null) {
backType = BackNavigationInfo.TYPE_CROSS_ACTIVITY;
} else if (task.returnsToHomeRootTask()) {
@@ -188,8 +199,8 @@ class BackNavigationController {
prevTaskId = prevTask != null ? prevTask.mTaskId : 0;
prevUserId = prevTask != null ? prevTask.mUserId : 0;
- ProtoLog.d(WM_DEBUG_BACK_PREVIEW, "Previous Activity is %s",
- prev != null ? prev.mActivityComponent : null);
+ ProtoLog.d(WM_DEBUG_BACK_PREVIEW, "Previous Activity is %s. "
+ + "Back type is %s", prev != null ? prev.mActivityComponent : null, backType);
//TODO(207481538) Remove once the infrastructure to support per-activity screenshot is
// implemented. For now we simply have the mBackScreenshots hash map that dumbly
@@ -204,6 +215,7 @@ class BackNavigationController {
return null;
}
// Prepare a leash to animate the current top window
+ // TODO(b/220934562): Use surface animator to better manage animation conflicts.
animLeash = removedWindowContainer.makeAnimationLeash()
.setName("BackPreview Leash for " + removedWindowContainer)
.setHidden(false)
@@ -231,12 +243,30 @@ class BackNavigationController {
activityRecord.windowType);
}
- SurfaceControl.Builder builder = new SurfaceControl.Builder()
+ screenshotSurface = new SurfaceControl.Builder()
.setName("BackPreview Screenshot for " + prev)
.setParent(animationLeashParent)
.setHidden(false)
- .setBLASTLayer();
- SurfaceControl screenshotSurface = builder.build();
+ .setBLASTLayer()
+ .build();
+ if (backType == BackNavigationInfo.TYPE_RETURN_TO_HOME && isAnimationEnabled()) {
+ task.mBackGestureStarted = true;
+ // Make launcher show from behind by marking its top activity as visible and
+ // launch-behind to bump its visibility for the duration of the back gesture.
+ prevTaskTopActivity = prevTask.getTopNonFinishingActivity();
+ if (prevTaskTopActivity != null) {
+ if (!prevTaskTopActivity.mVisibleRequested) {
+ prevTaskTopActivity.setVisibility(true);
+ }
+ prevTaskTopActivity.mLaunchTaskBehind = true;
+ ProtoLog.d(WM_DEBUG_BACK_PREVIEW,
+ "Setting Activity.mLauncherTaskBehind to true. Activity=%s",
+ prevTaskTopActivity);
+ prevTaskTopActivity.mRootWindowContainer.ensureActivitiesVisible(
+ null /* starting */, 0 /* configChanges */,
+ false /* preserveWindows */);
+ }
+ }
// Find a screenshot of the previous activity
@@ -253,17 +283,20 @@ class BackNavigationController {
WindowContainer<?> finalRemovedWindowContainer = removedWindowContainer;
try {
- activityRecord.token.linkToDeath(
- () -> resetSurfaces(finalRemovedWindowContainer), 0);
+ activityRecord.token.linkToDeath(() -> resetSurfaces(finalRemovedWindowContainer), 0);
} catch (RemoteException e) {
Slog.e(TAG, "Failed to link to death", e);
resetSurfaces(removedWindowContainer);
return null;
}
- RemoteCallback onBackNavigationDone = new RemoteCallback(
- result -> resetSurfaces(finalRemovedWindowContainer
- ));
+ int finalBackType = backType;
+ final IOnBackInvokedCallback callback =
+ applicationCallback != null ? applicationCallback : systemCallback;
+ ActivityRecord finalPrevTaskTopActivity = prevTaskTopActivity;
+ RemoteCallback onBackNavigationDone = new RemoteCallback(result -> onBackNavigationDone(
+ result, finalRemovedWindowContainer, finalBackType, task,
+ finalPrevTaskTopActivity));
return new BackNavigationInfo(backType,
topAppTarget,
screenshotSurface,
@@ -273,6 +306,39 @@ class BackNavigationController {
callback);
}
+ private void onBackNavigationDone(
+ Bundle result, WindowContainer windowContainer, int backType,
+ Task task, ActivityRecord prevTaskTopActivity) {
+ SurfaceControl surfaceControl = windowContainer.getSurfaceControl();
+ boolean triggerBack = result != null
+ ? result.getBoolean(BackNavigationInfo.KEY_TRIGGER_BACK)
+ : false;
+ ProtoLog.d(WM_DEBUG_BACK_PREVIEW, "onBackNavigationDone backType=%s, "
+ + "task=%s, prevTaskTopActivity=%s", backType, task, prevTaskTopActivity);
+
+ if (backType == BackNavigationInfo.TYPE_RETURN_TO_HOME && isAnimationEnabled()) {
+ if (triggerBack) {
+ if (surfaceControl != null && surfaceControl.isValid()) {
+ // When going back to home, hide the task surface before it is re-parented to
+ // avoid flicker.
+ SurfaceControl.Transaction t = windowContainer.getSyncTransaction();
+ t.hide(surfaceControl);
+ t.apply();
+ }
+ }
+ if (prevTaskTopActivity != null && !triggerBack) {
+ // Restore the launch-behind state.
+ task.mTaskSupervisor.scheduleLaunchTaskBehindComplete(prevTaskTopActivity.token);
+ prevTaskTopActivity.mLaunchTaskBehind = false;
+ ProtoLog.d(WM_DEBUG_BACK_PREVIEW,
+ "Setting Activity.mLauncherTaskBehind to false. Activity=%s",
+ prevTaskTopActivity);
+ }
+ } else {
+ task.mBackGestureStarted = false;
+ }
+ resetSurfaces(windowContainer);
+ }
private HardwareBuffer getActivitySnapshot(@NonNull Task task,
ComponentName activityComponent) {
diff --git a/services/core/java/com/android/server/wm/ContentRecorder.java b/services/core/java/com/android/server/wm/ContentRecorder.java
index 07a0c372778b..87523f44d4b6 100644
--- a/services/core/java/com/android/server/wm/ContentRecorder.java
+++ b/services/core/java/com/android/server/wm/ContentRecorder.java
@@ -17,6 +17,7 @@
package com.android.server.wm;
import static android.view.ContentRecordingSession.RECORD_CONTENT_DISPLAY;
+import static android.view.ContentRecordingSession.RECORD_CONTENT_TASK;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONTENT_RECORDING;
@@ -26,6 +27,7 @@ import android.content.res.Configuration;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.IBinder;
+import android.provider.DeviceConfig;
import android.view.ContentRecordingSession;
import android.view.Display;
import android.view.SurfaceControl;
@@ -39,6 +41,11 @@ import com.android.internal.protolog.common.ProtoLog;
final class ContentRecorder {
/**
+ * The key for accessing the device config that controls if task recording is supported.
+ */
+ @VisibleForTesting static final String KEY_RECORD_TASK_FEATURE = "record_task_content";
+
+ /**
* The display content this class is handling recording for.
*/
@NonNull
@@ -48,7 +55,7 @@ final class ContentRecorder {
* The session for content recording, or null if this DisplayContent is not being used for
* recording.
*/
- @VisibleForTesting private ContentRecordingSession mContentRecordingSession = null;
+ private ContentRecordingSession mContentRecordingSession = null;
/**
* The WindowContainer for the level of the hierarchy to record.
@@ -187,6 +194,8 @@ final class ContentRecorder {
mDisplayContent.mWmService.mTransactionFactory.get().remove(mRecordedSurface).apply();
mRecordedSurface = null;
clearContentRecordingSession();
+ // Do not need to force remove the VirtualDisplay; this is handled by the media
+ // projection service.
}
}
@@ -215,46 +224,12 @@ final class ContentRecorder {
return;
}
- final int contentToRecord = mContentRecordingSession.getContentToRecord();
- if (contentToRecord != RECORD_CONTENT_DISPLAY) {
- // TODO(b/216625226) handle task-based recording
- // Not a valid region, or recording is disabled, so fall back to prior MediaProjection
- // approach.
- clearContentRecordingSession();
- ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
- "Unable to start recording due to invalid region for display %d",
- mDisplayContent.getDisplayId());
- return;
- }
- // Given the WindowToken of the DisplayArea to record, retrieve the associated
- // SurfaceControl.
- IBinder tokenToRecord = mContentRecordingSession.getTokenToRecord();
- if (tokenToRecord == null) {
- // Unexpectedly missing token. Fall back to prior MediaProjection approach.
- clearContentRecordingSession();
- ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
- "Unable to start recording due to null token for display %d",
- mDisplayContent.getDisplayId());
- return;
- }
-
- final WindowContainer wc =
- mDisplayContent.mWmService.mWindowContextListenerController.getContainer(
- tokenToRecord);
- if (wc == null) {
- // Un-set the window token to record for this VirtualDisplay. Fall back to the
- // original MediaProjection approach.
- mDisplayContent.mWmService.mDisplayManagerInternal.setWindowManagerMirroring(
- mDisplayContent.getDisplayId(), false);
- clearContentRecordingSession();
- ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
- "Unable to retrieve window container to start recording for "
- + "display %d",
- mDisplayContent.getDisplayId());
+ mRecordedWindowContainer = retrieveRecordedWindowContainer();
+ if (mRecordedWindowContainer == null) {
+ // Either the token is missing, or the window associated with the token is missing.
+ // Error has already been handled, so just leave.
return;
}
- // TODO(206461622) Migrate to using the RootDisplayArea
- mRecordedWindowContainer = wc.getDisplayContent();
final Point surfaceSize = fetchSurfaceSizeIfPresent();
if (surfaceSize == null) {
@@ -296,6 +271,107 @@ final class ContentRecorder {
}
/**
+ * Retrieves the {@link WindowContainer} for the level of the hierarchy to start recording,
+ * indicated by the {@link #mContentRecordingSession}. Performs any error handling and state
+ * updates necessary if the {@link WindowContainer} could not be retrieved.
+ * {@link #mContentRecordingSession} must be non-null.
+ *
+ * @return a {@link WindowContainer} to record, or {@code null} if an error was encountered. The
+ * error is logged and any cleanup is handled.
+ */
+ @Nullable
+ private WindowContainer retrieveRecordedWindowContainer() {
+ final int contentToRecord = mContentRecordingSession.getContentToRecord();
+ // Given the WindowToken of the region to record, retrieve the associated
+ // SurfaceControl.
+ final IBinder tokenToRecord = mContentRecordingSession.getTokenToRecord();
+ if (tokenToRecord == null) {
+ handleStartRecordingFailed();
+ ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
+ "Unable to start recording due to null token for display %d",
+ mDisplayContent.getDisplayId());
+ return null;
+ }
+ switch (contentToRecord) {
+ case RECORD_CONTENT_DISPLAY:
+ final WindowContainer wc =
+ mDisplayContent.mWmService.mWindowContextListenerController.getContainer(
+ tokenToRecord);
+ if (wc == null) {
+ // Un-set the window token to record for this VirtualDisplay. Fall back to
+ // Display stack capture for the entire display.
+ mDisplayContent.mWmService.mDisplayManagerInternal.setWindowManagerMirroring(
+ mDisplayContent.getDisplayId(), false);
+ handleStartRecordingFailed();
+ ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
+ "Unable to retrieve window container to start recording for "
+ + "display %d", mDisplayContent.getDisplayId());
+ return null;
+ }
+ // TODO(206461622) Migrate to using the RootDisplayArea
+ return wc.getDisplayContent();
+ case RECORD_CONTENT_TASK:
+ if (!DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_WINDOW_MANAGER,
+ KEY_RECORD_TASK_FEATURE, false)) {
+ handleStartRecordingFailed();
+ ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
+ "Unable to record task since feature is disabled %d",
+ mDisplayContent.getDisplayId());
+ return null;
+ }
+ Task taskToRecord = WindowContainer.fromBinder(tokenToRecord).asTask();
+ if (taskToRecord == null) {
+ handleStartRecordingFailed();
+ ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
+ "Unable to retrieve task to start recording for "
+ + "display %d", mDisplayContent.getDisplayId());
+ }
+ return taskToRecord;
+ default:
+ // Not a valid region, or recording is disabled, so fall back to Display stack
+ // capture for the entire display.
+ handleStartRecordingFailed();
+ ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
+ "Unable to start recording due to invalid region for display %d",
+ mDisplayContent.getDisplayId());
+ return null;
+ }
+ }
+
+ /**
+ * Exit this recording session.
+ * <p>
+ * If this is a task session, tear down the recording entirely. Do not fall back
+ * to recording the entire display on the display stack; this would surprise the user
+ * given they selected task capture.
+ * </p><p>
+ * If this is a display session, just stop recording by layer mirroring. Fall back to recording
+ * from the display stack.
+ * </p>
+ */
+ private void handleStartRecordingFailed() {
+ final boolean shouldExitTaskRecording = mContentRecordingSession != null
+ && mContentRecordingSession.getContentToRecord() == RECORD_CONTENT_TASK;
+ if (shouldExitTaskRecording) {
+ // Clean up the cached session first, since tearing down the display will generate
+ // display
+ // events which will trickle back to here.
+ clearContentRecordingSession();
+ tearDownVirtualDisplay();
+ } else {
+ clearContentRecordingSession();
+ }
+ }
+
+ /**
+ * Ensure recording does not fall back to the display stack; ensure the recording is stopped
+ * and the client notified by tearing down the virtual display.
+ */
+ private void tearDownVirtualDisplay() {
+ // TODO(b/219761722) Clean up the VirtualDisplay if task mirroring fails
+ }
+
+ /**
* Apply transformations to the mirrored surface to ensure the captured contents are scaled to
* fit and centred in the output surface.
*
diff --git a/services/core/java/com/android/server/wm/DisplayArea.java b/services/core/java/com/android/server/wm/DisplayArea.java
index 08681119a306..dfa3b743292e 100644
--- a/services/core/java/com/android/server/wm/DisplayArea.java
+++ b/services/core/java/com/android/server/wm/DisplayArea.java
@@ -662,7 +662,7 @@ public class DisplayArea<T extends WindowContainer> extends WindowContainer<T> {
mDimmer.resetDimStates();
}
- if (mDimmer.updateDims(getPendingTransaction(), mTmpDimBoundsRect)) {
+ if (mDimmer.updateDims(getSyncTransaction(), mTmpDimBoundsRect)) {
scheduleAnimation();
}
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 718a28de6af9..f4314570d0a0 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -128,9 +128,8 @@ import static com.android.server.wm.DisplayContentProto.RESUMED_ACTIVITY;
import static com.android.server.wm.DisplayContentProto.ROOT_DISPLAY_AREA;
import static com.android.server.wm.DisplayContentProto.SCREEN_ROTATION_ANIMATION;
import static com.android.server.wm.DisplayContentProto.SLEEP_TOKENS;
-import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_ALL;
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION;
-import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS;
+import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_WINDOW_ANIMATION;
import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
import static com.android.server.wm.WindowContainerChildProto.DISPLAY_CONTENT;
@@ -144,7 +143,6 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import static com.android.server.wm.WindowManagerService.H.REPORT_HARD_KEYBOARD_STATUS_CHANGE;
import static com.android.server.wm.WindowManagerService.H.WINDOW_HIDE_TIMEOUT;
-import static com.android.server.wm.WindowManagerService.LAYOUT_REPEAT_THRESHOLD;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_PLACING_SURFACES;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_ASSIGN_LAYERS;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE_SURFACES;
@@ -627,9 +625,6 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
@VisibleForTesting
SurfaceControl mInputMethodSurfaceParent;
- /** The screenshot IME surface to place on the task while transitioning to the next task. */
- SurfaceControl mImeScreenshot;
-
private final PointerEventDispatcher mPointerEventDispatcher;
private final InsetsStateController mInsetsStateController;
@@ -3974,10 +3969,13 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
// If the IME target is the input target, before it changes, prepare the IME screenshot
// for the last IME target when its task is applying app transition. This is for the
// better IME transition to keep IME visibility when transitioning to the next task.
- if (mImeLayeringTarget != null && mImeLayeringTarget.isAnimating(PARENTS | TRANSITION,
- ANIMATION_TYPE_APP_TRANSITION | ANIMATION_TYPE_RECENTS)
- && mImeLayeringTarget == mImeInputTarget) {
- attachAndShowImeScreenshotOnTarget();
+ if (mImeLayeringTarget != null && mImeLayeringTarget == mImeInputTarget) {
+ boolean nonAppImeTargetAnimatingExit = mImeLayeringTarget.mAnimatingExit
+ && mImeLayeringTarget.mAttrs.type != TYPE_BASE_APPLICATION
+ && mImeLayeringTarget.isSelfAnimating(0, ANIMATION_TYPE_WINDOW_ANIMATION);
+ if (mImeLayeringTarget.inAppOrRecentsTransition() || nonAppImeTargetAnimatingExit) {
+ showImeScreenshot();
+ }
}
ProtoLog.i(WM_DEBUG_IME, "setInputMethodTarget %s", target);
@@ -4025,71 +4023,129 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
mImeControlTarget = target;
}
- @VisibleForTesting
- void attachAndShowImeScreenshotOnTarget() {
- // No need to attach screenshot if the IME target not exists or screen is off.
- if (!shouldImeAttachedToApp() || !mWmService.mPolicy.isScreenOn()) {
- return;
+ // ========== Begin of ImeScreenshot stuff ==========
+ /** The screenshot IME surface to place on the task while transitioning to the next task. */
+ ImeScreenshot mImeScreenshot;
+
+ static final class ImeScreenshot {
+ private WindowState mImeTarget;
+ private SurfaceControl.Builder mSurfaceBuilder;
+ private SurfaceControl mImeSurface;
+
+ ImeScreenshot(SurfaceControl.Builder surfaceBuilder, @NonNull WindowState imeTarget) {
+ mSurfaceBuilder = surfaceBuilder;
+ mImeTarget = imeTarget;
}
- final SurfaceControl.Transaction t = getPendingTransaction();
- // Prepare IME screenshot for the target if it allows to attach into.
- if (mInputMethodWindow != null && mInputMethodWindow.isVisible()) {
- final Task task = mImeLayeringTarget.getTask();
+ WindowState getImeTarget() {
+ return mImeTarget;
+ }
+
+ private SurfaceControl createImeSurface(SurfaceControl.ScreenshotHardwareBuffer b,
+ Transaction t) {
+ final HardwareBuffer buffer = b.getHardwareBuffer();
+ if (DEBUG_INPUT_METHOD) {
+ Slog.d(TAG, "create IME snapshot for "
+ + mImeTarget + ", buff width=" + buffer.getWidth()
+ + ", height=" + buffer.getHeight());
+ }
+ final WindowState imeWindow = mImeTarget.getDisplayContent().mInputMethodWindow;
+ final ActivityRecord activity = mImeTarget.mActivityRecord;
+ final SurfaceControl imeParent = mImeTarget.mAttrs.type == TYPE_BASE_APPLICATION
+ ? activity.getSurfaceControl()
+ : mImeTarget.getSurfaceControl();
+ final SurfaceControl imeSurface = mSurfaceBuilder
+ .setName("IME-snapshot-surface")
+ .setBLASTLayer()
+ .setFormat(buffer.getFormat())
+ // Attaching IME snapshot to the associated IME layering target on the
+ // activity when:
+ // - The target is activity main window: attaching on top of the activity.
+ // - The target is non-activity main window (e.g. activity overlay or
+ // dialog-themed activity): attaching on top of the target since the layer has
+ // already above the activity.
+ .setParent(imeParent)
+ .setCallsite("DisplayContent.attachAndShowImeScreenshotOnTarget")
+ .build();
+ // Make IME snapshot as trusted overlay
+ InputMonitor.setTrustedOverlayInputInfo(imeSurface, t, imeWindow.getDisplayId(),
+ "IME-snapshot-surface");
+ t.setBuffer(imeSurface, buffer);
+ t.setColorSpace(activity.mSurfaceControl, ColorSpace.get(ColorSpace.Named.SRGB));
+ t.setLayer(imeSurface, 1);
+
+ final Point surfacePosition = new Point(
+ imeWindow.getFrame().left - mImeTarget.getFrame().left,
+ imeWindow.getFrame().top - mImeTarget.getFrame().top);
+ if (imeParent == activity.getSurfaceControl()) {
+ t.setPosition(imeSurface, surfacePosition.x, surfacePosition.y);
+ } else {
+ surfacePosition.offset(mImeTarget.mAttrs.surfaceInsets.left,
+ mImeTarget.mAttrs.surfaceInsets.top);
+ t.setPosition(imeSurface, surfacePosition.x, surfacePosition.y);
+ }
+ return imeSurface;
+ }
+
+ private void removeImeSurface(Transaction t) {
+ if (mImeSurface != null) {
+ if (DEBUG_INPUT_METHOD) Slog.d(TAG, "remove IME snapshot");
+ t.remove(mImeSurface);
+ mImeSurface = null;
+ }
+ }
+
+ void attachAndShow(Transaction t) {
+ final DisplayContent dc = mImeTarget.getDisplayContent();
+ // Prepare IME screenshot for the target if it allows to attach into.
+ final Task task = mImeTarget.getTask();
// Re-new the IME screenshot when it does not exist or the size changed.
- final boolean renewImeSurface = mImeScreenshot == null
- || mImeScreenshot.getWidth() != mInputMethodWindow.getFrame().width()
- || mImeScreenshot.getHeight() != mInputMethodWindow.getFrame().height();
+ final boolean renewImeSurface = mImeSurface == null
+ || mImeSurface.getWidth() != dc.mInputMethodWindow.getFrame().width()
+ || mImeSurface.getHeight() != dc.mInputMethodWindow.getFrame().height();
if (task != null && !task.isActivityTypeHomeOrRecents()) {
SurfaceControl.ScreenshotHardwareBuffer imeBuffer = renewImeSurface
- ? mWmService.mTaskSnapshotController.snapshotImeFromAttachedTask(task)
+ ? dc.mWmService.mTaskSnapshotController.snapshotImeFromAttachedTask(task)
: null;
if (imeBuffer != null) {
// Remove the last IME surface when the surface needs to renew.
- removeImeSurfaceImmediately();
- mImeScreenshot = createImeSurface(imeBuffer, t);
+ removeImeSurface(t);
+ mImeSurface = createImeSurface(imeBuffer, t);
+ }
+ }
+ final boolean isValidSnapshot = mImeSurface != null && mImeSurface.isValid();
+ // Showing the IME screenshot if the target has already in app transition stage.
+ // Note that if the current IME insets is not showing, no need to show IME screenshot
+ // to reflect the true IME insets visibility and the app task layout as possible.
+ if (isValidSnapshot
+ && dc.getInsetsStateController().getImeSourceProvider().isImeShowing()) {
+ if (DEBUG_INPUT_METHOD) {
+ Slog.d(TAG, "show IME snapshot, ime target=" + mImeTarget);
}
+ t.show(mImeSurface);
+ } else if (!isValidSnapshot) {
+ removeImeSurface(t);
}
}
- final boolean isValidSnapshot = mImeScreenshot != null && mImeScreenshot.isValid();
- // Showing the IME screenshot if the target has already in app transition stage.
- // Note that if the current IME insets is not showing, no need to show IME screenshot
- // to reflect the true IME insets visibility and the app task layout as possible.
- if (isValidSnapshot && getInsetsStateController().getImeSourceProvider().isImeShowing()) {
- if (DEBUG_INPUT_METHOD) {
- Slog.d(TAG, "show IME snapshot, ime target=" + mImeLayeringTarget);
- }
- t.show(mImeScreenshot);
- } else if (!isValidSnapshot) {
- removeImeSurfaceImmediately();
+ void detach(Transaction t) {
+ removeImeSurface(t);
}
}
- @VisibleForTesting
- SurfaceControl createImeSurface(SurfaceControl.ScreenshotHardwareBuffer imeBuffer,
- Transaction t) {
- final HardwareBuffer buffer = imeBuffer.getHardwareBuffer();
- if (DEBUG_INPUT_METHOD) Slog.d(TAG, "create IME snapshot for "
- + mImeLayeringTarget + ", buff width=" + buffer.getWidth()
- + ", height=" + buffer.getHeight());
- final ActivityRecord activity = mImeLayeringTarget.mActivityRecord;
- final SurfaceControl imeSurface = mWmService.mSurfaceControlFactory.apply(null)
- .setName("IME-snapshot-surface")
- .setBLASTLayer()
- .setFormat(buffer.getFormat())
- .setParent(activity.getSurfaceControl())
- .setCallsite("DisplayContent.attachAndShowImeScreenshotOnTarget")
- .build();
- // Make IME snapshot as trusted overlay
- InputMonitor.setTrustedOverlayInputInfo(imeSurface, t, getDisplayId(),
- "IME-snapshot-surface");
- t.setBuffer(imeSurface, buffer);
- t.setColorSpace(mSurfaceControl, ColorSpace.get(ColorSpace.Named.SRGB));
- t.setLayer(imeSurface, 1);
- t.setPosition(imeSurface, mInputMethodWindow.getDisplayFrame().left,
- mInputMethodWindow.getDisplayFrame().top);
- return imeSurface;
+ private void attachAndShowImeScreenshotOnTarget() {
+ // No need to attach screenshot if the IME target not exists or screen is off.
+ if (!shouldImeAttachedToApp() || !mWmService.mPolicy.isScreenOn()) {
+ return;
+ }
+
+ final SurfaceControl.Transaction t = getPendingTransaction();
+ // Prepare IME screenshot for the target if it allows to attach into.
+ if (mInputMethodWindow != null && mInputMethodWindow.isVisible()) {
+ mImeScreenshot = new ImeScreenshot(
+ mWmService.mSurfaceControlFactory.apply(null), mImeLayeringTarget);
+ mImeScreenshot.attachAndShow(t);
+ }
}
/**
@@ -4111,8 +4167,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
void removeImeScreenshotIfPossible() {
if (mImeLayeringTarget == null
|| mImeLayeringTarget.mAttrs.type != TYPE_APPLICATION_STARTING
- && !mImeLayeringTarget.isAnimating(PARENTS | TRANSITION,
- ANIMATION_TYPE_APP_TRANSITION | ANIMATION_TYPE_RECENTS)) {
+ && !mImeLayeringTarget.inAppOrRecentsTransition()) {
removeImeSurfaceImmediately();
}
}
@@ -4120,11 +4175,11 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
/** Removes the IME screenshot immediately. */
void removeImeSurfaceImmediately() {
if (mImeScreenshot != null) {
- if (DEBUG_INPUT_METHOD) Slog.d(TAG, "remove IME snapshot");
- getSyncTransaction().remove(mImeScreenshot);
+ mImeScreenshot.detach(getSyncTransaction());
mImeScreenshot = null;
}
}
+ // ========== End of ImeScreenshot stuff ==========
/**
* The IME input target is the window which receives input from IME. It is also a candidate
@@ -4212,17 +4267,17 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
*/
@VisibleForTesting
SurfaceControl computeImeParent() {
+ if (mImeLayeringTarget != null && mImeInputTarget != null
+ && mImeLayeringTarget.mActivityRecord != mImeInputTarget.getActivityRecord()) {
+ // Do not change parent if the window hasn't requested IME.
+ return null;
+ }
// Attach it to app if the target is part of an app and such app is covering the entire
// screen. If it's not covering the entire screen the IME might extend beyond the apps
// bounds.
if (shouldImeAttachedToApp()) {
- if (mImeLayeringTarget.mActivityRecord != mImeInputTarget.getActivityRecord()) {
- // Do not change parent if the window hasn't requested IME.
- return null;
- }
return mImeLayeringTarget.mActivityRecord.getSurfaceControl();
}
-
// Otherwise, we just attach it to where the display area policy put it.
return mImeWindowsContainer.getParent() != null
? mImeWindowsContainer.getParent().getSurfaceControl() : null;
@@ -4433,7 +4488,9 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
* hierarchy.
*/
void onWindowAnimationFinished(@NonNull WindowContainer wc, int type) {
- if (type == ANIMATION_TYPE_APP_TRANSITION || type == ANIMATION_TYPE_RECENTS) {
+ if (mImeScreenshot != null && (wc == mImeScreenshot.getImeTarget()
+ || wc.getWindow(w -> w == mImeScreenshot.getImeTarget()) != null)
+ && (type & WindowState.EXIT_ANIMATING_TYPES) != 0) {
removeImeSurfaceImmediately();
}
}
@@ -4444,56 +4501,38 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
mTmpUpdateAllDrawn.clear();
- int repeats = 0;
- do {
- repeats++;
- if (repeats > 6) {
- Slog.w(TAG, "Animation repeat aborted after too many iterations");
- clearLayoutNeeded();
- break;
- }
-
- if (DEBUG_LAYOUT_REPEATS) surfacePlacer.debugLayoutRepeats("On entry to LockedInner",
- pendingLayoutChanges);
-
- if ((pendingLayoutChanges & FINISH_LAYOUT_REDO_WALLPAPER) != 0) {
- mWallpaperController.adjustWallpaperWindows();
- }
+ if (DEBUG_LAYOUT_REPEATS) surfacePlacer.debugLayoutRepeats("On entry to LockedInner",
+ pendingLayoutChanges);
- if ((pendingLayoutChanges & FINISH_LAYOUT_REDO_CONFIG) != 0) {
- if (DEBUG_LAYOUT) Slog.v(TAG, "Computing new config from layout");
- if (updateOrientation()) {
- setLayoutNeeded();
- sendNewConfiguration();
- }
- }
+ if ((pendingLayoutChanges & FINISH_LAYOUT_REDO_WALLPAPER) != 0) {
+ mWallpaperController.adjustWallpaperWindows();
+ }
- if ((pendingLayoutChanges & FINISH_LAYOUT_REDO_LAYOUT) != 0) {
+ if ((pendingLayoutChanges & FINISH_LAYOUT_REDO_CONFIG) != 0) {
+ if (DEBUG_LAYOUT) Slog.v(TAG, "Computing new config from layout");
+ if (updateOrientation()) {
setLayoutNeeded();
+ sendNewConfiguration();
}
+ }
- // FIRST LOOP: Perform a layout, if needed.
- if (repeats < LAYOUT_REPEAT_THRESHOLD) {
- performLayout(repeats == 1, false /* updateInputWindows */);
- } else {
- Slog.w(TAG, "Layout repeat skipped after too many iterations");
- }
+ if ((pendingLayoutChanges & FINISH_LAYOUT_REDO_LAYOUT) != 0) {
+ setLayoutNeeded();
+ }
- // FIRST AND ONE HALF LOOP: Make WindowManagerPolicy think it is animating.
- pendingLayoutChanges = 0;
+ // Perform a layout, if needed.
+ performLayout(true /* initial */, false /* updateInputWindows */);
+ pendingLayoutChanges = 0;
- Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "applyPostLayoutPolicy");
- try {
- mDisplayPolicy.beginPostLayoutPolicyLw();
- forAllWindows(mApplyPostLayoutPolicy, true /* traverseTopToBottom */);
- pendingLayoutChanges |= mDisplayPolicy.finishPostLayoutPolicyLw();
- } finally {
- Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
- }
- if (DEBUG_LAYOUT_REPEATS) surfacePlacer.debugLayoutRepeats(
- "after finishPostLayoutPolicyLw", pendingLayoutChanges);
- mInsetsStateController.onPostLayout();
- } while (pendingLayoutChanges != 0);
+ Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "applyPostLayoutPolicy");
+ try {
+ mDisplayPolicy.beginPostLayoutPolicyLw();
+ forAllWindows(mApplyPostLayoutPolicy, true /* traverseTopToBottom */);
+ mDisplayPolicy.finishPostLayoutPolicyLw();
+ } finally {
+ Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
+ }
+ mInsetsStateController.onPostLayout();
mTmpApplySurfaceChangesTransactionState.reset();
@@ -4960,10 +4999,6 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
// docked divider while keeping the app itself below the docked divider, so instead
// we will put the docked divider below the IME. @see #assignRelativeLayerForImeTargetChild
//
- // In the case the IME target is animating, the animation Z order may be different
- // than the WindowContainer Z order, so it's difficult to be sure we have the correct
- // IME target. In this case we just layer the IME over its parent surface.
- //
// In the case where we have no IME target we let its window parent to place it.
//
// Keep IME window in surface parent as long as app's starting window
@@ -4975,13 +5010,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
? mImeControlTarget.getWindow().mToken : null;
final boolean canImeTargetSetRelativeLayer = imeTarget.getSurfaceControl() != null
&& imeTarget.mToken == imeControlTargetToken
- && !imeTarget.inMultiWindowMode()
- // We don't need to set relative layer if the IME target in non-multi-window
- // mode is the activity main window since updateImeParent will ensure the IME
- // surface be attached on the fullscreen activity.
- && imeTarget.mAttrs.type != TYPE_BASE_APPLICATION
- && imeTarget.mToken.getActivity(app -> app.isAnimating(TRANSITION | PARENTS,
- ANIMATION_TYPE_ALL & ~ANIMATION_TYPE_RECENTS)) == null;
+ && !imeTarget.inMultiWindowMode();
if (canImeTargetSetRelativeLayer) {
mImeWindowsContainer.assignRelativeLayer(t, imeTarget.getSurfaceControl(),
// TODO: We need to use an extra level on the app surface to ensure
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 4148d8b7d853..88d7dff4ff1a 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -42,11 +42,9 @@ import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
import static android.view.WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW;
import static android.view.WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON;
import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
-import static android.view.WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_INTERCEPT_GLOBAL_DRAG_AND_DROP;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
@@ -79,7 +77,6 @@ import static android.window.DisplayAreaOrganizer.FEATURE_UNDEFINED;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_SCREEN_ON;
import static com.android.server.policy.PhoneWindowManager.TOAST_WINDOW_TIMEOUT;
-import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
import static com.android.server.policy.WindowManagerPolicy.TRANSIT_ENTER;
import static com.android.server.policy.WindowManagerPolicy.TRANSIT_EXIT;
import static com.android.server.policy.WindowManagerPolicy.TRANSIT_HIDE;
@@ -117,6 +114,7 @@ import android.os.UserHandle;
import android.util.ArraySet;
import android.util.PrintWriterPrinter;
import android.util.Slog;
+import android.util.SparseArray;
import android.view.DisplayCutout;
import android.view.DisplayInfo;
import android.view.Gravity;
@@ -136,6 +134,7 @@ import android.view.WindowManager.LayoutParams;
import android.view.WindowManagerGlobal;
import android.view.WindowManagerPolicyConstants;
import android.view.accessibility.AccessibilityManager;
+import android.window.ClientWindowFrames;
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
@@ -340,15 +339,12 @@ public class DisplayPolicy {
private static final Rect sTmpRect2 = new Rect();
private static final Rect sTmpLastParentFrame = new Rect();
private static final Rect sTmpDisplayCutoutSafe = new Rect();
- private static final Rect sTmpDisplayFrame = new Rect();
- private static final Rect sTmpParentFrame = new Rect();
- private static final Rect sTmpFrame = new Rect();
+ private static final ClientWindowFrames sTmpClientFrames = new ClientWindowFrames();
private final WindowLayout mWindowLayout = new WindowLayout();
private WindowState mTopFullscreenOpaqueWindowState;
private boolean mTopIsFullscreen;
- private boolean mForceStatusBar;
private int mNavBarOpacityMode = NAV_BAR_OPAQUE_WHEN_FREEFORM_OR_DOCKED;
private boolean mForceShowSystemBars;
@@ -940,6 +936,26 @@ public class DisplayPolicy {
break;
}
+ if (LayoutParams.isSystemAlertWindowType(attrs.type)) {
+ float maxOpacity = mService.mMaximumObscuringOpacityForTouch;
+ if (attrs.alpha > maxOpacity
+ && (attrs.flags & FLAG_NOT_TOUCHABLE) != 0
+ && (attrs.privateFlags & PRIVATE_FLAG_TRUSTED_OVERLAY) == 0) {
+ // The app is posting a SAW with the intent of letting touches pass through, but
+ // they are going to be deemed untrusted and will be blocked. Try to honor the
+ // intent of letting touches pass through at the cost of 0.2 opacity for app
+ // compatibility reasons. More details on b/218777508.
+ Slog.w(TAG, String.format(
+ "App %s has a system alert window (type = %d) with FLAG_NOT_TOUCHABLE and "
+ + "LayoutParams.alpha = %.2f > %.2f, setting alpha to %.2f to "
+ + "let touches pass through (if this is isn't desirable, remove "
+ + "flag FLAG_NOT_TOUCHABLE).",
+ attrs.packageName, attrs.type, attrs.alpha, maxOpacity, maxOpacity));
+ attrs.alpha = maxOpacity;
+ win.mWinAnimator.mAlpha = maxOpacity;
+ }
+ }
+
// Check if alternate bars positions were updated.
if (mStatusBarAlt == win) {
mStatusBarAltPosition = getAltBarPosition(attrs);
@@ -1136,9 +1152,8 @@ public class DisplayPolicy {
}
},
- // For IME we use regular frame.
(displayFrames, windowContainer, inOutFrame) -> {
- inOutFrame.set(win.getFrame());
+ // For IME, we don't modify the frame.
});
mDisplayContent.setInsetProvider(ITYPE_BOTTOM_MANDATORY_GESTURES, win,
@@ -1473,9 +1488,30 @@ public class DisplayPolicy {
displayFrames.mInsetsState, displayFrames.mDisplayCutoutSafe,
displayFrames.mUnrestricted, win.getWindowingMode(), UNSPECIFIED_LENGTH,
UNSPECIFIED_LENGTH, win.getRequestedVisibilities(),
- null /* attachedWindowFrame */, win.mGlobalScale,
- sTmpDisplayFrame, sTmpParentFrame, sTmpFrame);
- controller.computeSimulatedState(win, displayFrames, sTmpFrame);
+ null /* attachedWindowFrame */, win.mGlobalScale, sTmpClientFrames);
+ final SparseArray<InsetsSource> sources = win.getProvidedInsetsSources();
+ final InsetsState state = displayFrames.mInsetsState;
+ for (int index = sources.size() - 1; index >= 0; index--) {
+ final int type = sources.keyAt(index);
+ state.addSource(controller.getSourceProvider(type).createSimulatedSource(
+ displayFrames, sTmpClientFrames.frame));
+ }
+ }
+ }
+
+ // 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);
+ mWindowLayout.computeFrames(win.getLayoutingAttrs(displayFrames.mRotation),
+ displayFrames.mInsetsState, displayFrames.mDisplayCutoutSafe,
+ displayFrames.mUnrestricted, win.getWindowingMode(), UNSPECIFIED_LENGTH,
+ UNSPECIFIED_LENGTH, win.getRequestedVisibilities(),
+ null /* attachedWindowFrame */, win.mGlobalScale, sTmpClientFrames);
+ win.updateSourceFrame(sTmpClientFrames.frame);
}
}
@@ -1504,10 +1540,6 @@ public class DisplayPolicy {
displayFrames = win.getDisplayFrames(displayFrames);
final WindowManager.LayoutParams attrs = win.getLayoutingAttrs(displayFrames.mRotation);
- final WindowFrames windowFrames = win.getWindowFrames();
- final Rect pf = windowFrames.mParentFrame;
- final Rect df = windowFrames.mDisplayFrame;
- final Rect f = windowFrames.mFrame;
final Rect attachedWindowFrame = attached != null ? attached.getFrame() : null;
// If this window has different LayoutParams for rotations, we cannot trust its requested
@@ -1516,27 +1548,12 @@ public class DisplayPolicy {
final int requestedWidth = trustedSize ? win.mRequestedWidth : UNSPECIFIED_LENGTH;
final int requestedHeight = trustedSize ? win.mRequestedHeight : UNSPECIFIED_LENGTH;
- sTmpLastParentFrame.set(pf);
-
- final boolean clippedByDisplayCutout = mWindowLayout.computeFrames(attrs,
- win.getInsetsState(), displayFrames.mDisplayCutoutSafe,
+ mWindowLayout.computeFrames(attrs, win.getInsetsState(), displayFrames.mDisplayCutoutSafe,
win.getBounds(), win.getWindowingMode(), requestedWidth, requestedHeight,
win.getRequestedVisibilities(), attachedWindowFrame, win.mGlobalScale,
- df, pf, f);
- windowFrames.setParentFrameWasClippedByDisplayCutout(clippedByDisplayCutout);
-
- if (DEBUG_LAYOUT) Slog.v(TAG, "Compute frame " + attrs.getTitle()
- + ": sim=#" + Integer.toHexString(attrs.softInputMode)
- + " attach=" + attached + " type=" + attrs.type
- + " flags=" + ViewDebug.flagsToString(LayoutParams.class, "flags", attrs.flags)
- + " pf=" + pf.toShortString() + " df=" + df.toShortString()
- + " f=" + f.toShortString());
+ sTmpClientFrames);
- if (!sTmpLastParentFrame.equals(pf)) {
- windowFrames.setContentChanged(true);
- }
-
- win.setFrame();
+ win.setFrames(sTmpClientFrames);
}
WindowState getTopFullscreenOpaqueWindow() {
@@ -1558,7 +1575,6 @@ public class DisplayPolicy {
mStatusBarBackgroundWindows.clear();
mStatusBarColorCheckedBounds.setEmpty();
mStatusBarBackgroundCheckedBounds.setEmpty();
- mForceStatusBar = false;
mAllowLockscreenWhenOn = false;
mShowingDream = false;
@@ -1599,9 +1615,6 @@ public class DisplayPolicy {
&& attrs.type < FIRST_SYSTEM_WINDOW;
if (mTopFullscreenOpaqueWindowState == null) {
final int fl = attrs.flags;
- if ((fl & FLAG_FORCE_NOT_FULLSCREEN) != 0) {
- mForceStatusBar = true;
- }
if (win.isDreamWindow()) {
// If the lockscreen was showing when the dream started then wait
// for the dream to draw before hiding the lockscreen.
@@ -1710,21 +1723,9 @@ public class DisplayPolicy {
}
/**
- * Called following layout of all windows and after policy has been applied
- * to each window. If in this function you do
- * something that may have modified the animation state of another window,
- * be sure to return non-zero in order to perform another pass through layout.
- *
- * @return Return any bit set of
- * {@link WindowManagerPolicy#FINISH_LAYOUT_REDO_LAYOUT},
- * {@link WindowManagerPolicy#FINISH_LAYOUT_REDO_CONFIG},
- * {@link WindowManagerPolicy#FINISH_LAYOUT_REDO_WALLPAPER}, or
- * {@link WindowManagerPolicy#FINISH_LAYOUT_REDO_ANIM}.
+ * Called following layout of all windows and after policy has been applied to each window.
*/
- public int finishPostLayoutPolicyLw() {
- int changes = 0;
- boolean topIsFullscreen = false;
-
+ public void finishPostLayoutPolicyLw() {
// If we are not currently showing a dream then remember the current
// lockscreen state. We will use this to determine whether the dream
// started while the lockscreen was showing and remember this state
@@ -1733,41 +1734,6 @@ public class DisplayPolicy {
mDreamingLockscreen = mService.mPolicy.isKeyguardShowingAndNotOccluded();
}
- if (getStatusBar() != null) {
- if (DEBUG_LAYOUT) Slog.i(TAG, "force=" + mForceStatusBar
- + " top=" + mTopFullscreenOpaqueWindowState);
- final boolean forceShowStatusBar = (getStatusBar().getAttrs().privateFlags
- & PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR) != 0;
-
- boolean topAppHidesStatusBar = topAppHidesStatusBar();
- if (mForceStatusBar || forceShowStatusBar) {
- if (DEBUG_LAYOUT) Slog.v(TAG, "Showing status bar: forced");
- // Maintain fullscreen layout until incoming animation is complete.
- topIsFullscreen = mTopIsFullscreen && mStatusBar.isAnimatingLw();
- } else if (mTopFullscreenOpaqueWindowState != null) {
- topIsFullscreen = topAppHidesStatusBar;
- // The subtle difference between the window for mTopFullscreenOpaqueWindowState
- // and mTopIsFullscreen is that mTopIsFullscreen is set only if the window
- // requests to hide the status bar. Not sure if there is another way that to be the
- // case though.
- if (!topIsFullscreen) {
- topAppHidesStatusBar = false;
- }
- }
- StatusBarManagerInternal statusBar = getStatusBarManagerInternal();
- if (statusBar != null) {
- statusBar.setTopAppHidesStatusBar(topAppHidesStatusBar);
- }
- }
-
- if (mTopIsFullscreen != topIsFullscreen) {
- if (!topIsFullscreen) {
- // Force another layout when status bar becomes fully shown.
- changes |= FINISH_LAYOUT_REDO_LAYOUT;
- }
- mTopIsFullscreen = topIsFullscreen;
- }
-
updateSystemBarAttributes();
if (mShowingDream != mLastShowingDream) {
@@ -1777,7 +1743,6 @@ public class DisplayPolicy {
}
mService.mPolicy.setAllowLockscreenWhenOn(getDisplayId(), mAllowLockscreenWhenOn);
- return changes;
}
/**
@@ -2441,6 +2406,18 @@ public class DisplayPolicy {
mForceShowSystemBars = multiWindowTaskVisible || freeformRootTaskVisible;
mDisplayContent.getInsetsPolicy().updateBarControlTarget(win);
+ final boolean topAppHidesStatusBar = topAppHidesStatusBar();
+ if (getStatusBar() != null) {
+ final StatusBarManagerInternal statusBar = getStatusBarManagerInternal();
+ if (statusBar != null) {
+ statusBar.setTopAppHidesStatusBar(topAppHidesStatusBar);
+ }
+ }
+
+ // If the top app is not fullscreen, only the default rotation animation is allowed.
+ mTopIsFullscreen = topAppHidesStatusBar
+ && (mNotificationShade == null || !mNotificationShade.isVisible());
+
int appearance = APPEARANCE_OPAQUE_NAVIGATION_BARS | APPEARANCE_OPAQUE_STATUS_BARS;
appearance = configureStatusBarOpacity(appearance);
appearance = configureNavBarOpacity(appearance, multiWindowTaskVisible,
@@ -2781,7 +2758,6 @@ public class DisplayPolicy {
}
}
pw.print(prefix); pw.print("mTopIsFullscreen="); pw.println(mTopIsFullscreen);
- pw.print(prefix); pw.print("mForceStatusBar="); pw.print(mForceStatusBar);
pw.print(prefix); pw.print("mForceShowNavigationBarEnabled=");
pw.print(mForceShowNavigationBarEnabled);
pw.print(" mAllowLockscreenWhenOn="); pw.println(mAllowLockscreenWhenOn);
diff --git a/services/core/java/com/android/server/wm/DisplayWindowPolicyControllerHelper.java b/services/core/java/com/android/server/wm/DisplayWindowPolicyControllerHelper.java
index 60d2a5da9286..27d46ecfb91a 100644
--- a/services/core/java/com/android/server/wm/DisplayWindowPolicyControllerHelper.java
+++ b/services/core/java/com/android/server/wm/DisplayWindowPolicyControllerHelper.java
@@ -18,6 +18,7 @@ package com.android.server.wm;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.WindowConfiguration;
import android.content.pm.ActivityInfo;
import android.os.UserHandle;
import android.util.ArraySet;
@@ -63,13 +64,14 @@ class DisplayWindowPolicyControllerHelper {
}
/**
- * @see DisplayWindowPolicyController#canContainActivities(List)
+ * @see DisplayWindowPolicyController#canContainActivities(List, int)
*/
- public boolean canContainActivities(@NonNull List<ActivityInfo> activities) {
+ public boolean canContainActivities(@NonNull List<ActivityInfo> activities,
+ @WindowConfiguration.WindowingMode int windowingMode) {
if (mDisplayWindowPolicyController == null) {
return true;
}
- return mDisplayWindowPolicyController.canContainActivities(activities);
+ return mDisplayWindowPolicyController.canContainActivities(activities, windowingMode);
}
/**
@@ -126,6 +128,17 @@ class DisplayWindowPolicyControllerHelper {
}
}
+ /**
+ * @see DisplayWindowPolicyController#isWindowingModeSupported(int)
+ */
+ public final boolean isWindowingModeSupported(
+ @WindowConfiguration.WindowingMode int windowingMode) {
+ if (mDisplayWindowPolicyController == null) {
+ return true;
+ }
+ return mDisplayWindowPolicyController.isWindowingModeSupported(windowingMode);
+ }
+
void dump(String prefix, PrintWriter pw) {
if (mDisplayWindowPolicyController != null) {
pw.println();
diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java
index 00380bb6e84e..c47d778c60bc 100644
--- a/services/core/java/com/android/server/wm/DragState.java
+++ b/services/core/java/com/android/server/wm/DragState.java
@@ -44,6 +44,7 @@ import android.hardware.input.InputManager;
import android.os.Binder;
import android.os.Build;
import android.os.IBinder;
+import android.os.InputConfig;
import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
@@ -127,7 +128,7 @@ class DragState {
@Nullable private ValueAnimator mAnimator;
private final Interpolator mCubicEaseOutInterpolator = new DecelerateInterpolator(1.5f);
- private Point mDisplaySize = new Point();
+ private final Point mDisplaySize = new Point();
// A surface used to catch input events for the drag-and-drop operation.
SurfaceControl mInputSurface;
@@ -160,8 +161,7 @@ class DragState {
private void showInputSurface() {
if (mInputSurface == null) {
- mInputSurface = mService.makeSurfaceBuilder(
- mService.mRoot.getDisplayContent(mDisplayContent.getDisplayId()).getSession())
+ mInputSurface = mService.makeSurfaceBuilder(mDisplayContent.getSession())
.setContainerLayer()
.setName("Drag and Drop Input Consumer")
.setCallsite("DragState.showInputSurface")
@@ -174,17 +174,18 @@ class DragState {
return;
}
- mTransaction.show(mInputSurface);
- mTransaction.setInputWindowInfo(mInputSurface, h);
- mTransaction.setLayer(mInputSurface, Integer.MAX_VALUE);
-
+ // Crop the input surface to the display size.
mTmpClipRect.set(0, 0, mDisplaySize.x, mDisplaySize.y);
- mTransaction.setWindowCrop(mInputSurface, mTmpClipRect);
+
+ mTransaction.show(mInputSurface)
+ .setInputWindowInfo(mInputSurface, h)
+ .setLayer(mInputSurface, Integer.MAX_VALUE)
+ .setCrop(mInputSurface, mTmpClipRect);
// syncInputWindows here to ensure the input window info is sent before the
// transferTouchFocus is called.
- mTransaction.syncInputWindows();
- mTransaction.apply(true);
+ mTransaction.syncInputWindows()
+ .apply(true /*sync*/);
}
/**
@@ -361,29 +362,20 @@ class DragState {
display.getDisplayId());
mDragWindowHandle.name = "drag";
mDragWindowHandle.token = mClientChannel.getToken();
- mDragWindowHandle.layoutParamsFlags = 0;
mDragWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_DRAG;
mDragWindowHandle.dispatchingTimeoutMillis = DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
- mDragWindowHandle.visible = true;
- // Allows the system to consume keys when dragging is active. This can also be used to
- // modify the drag state on key press. Example, cancel drag on escape key.
- mDragWindowHandle.focusable = true;
- mDragWindowHandle.hasWallpaper = false;
- mDragWindowHandle.paused = false;
mDragWindowHandle.ownerPid = Process.myPid();
mDragWindowHandle.ownerUid = Process.myUid();
- mDragWindowHandle.inputFeatures = 0;
mDragWindowHandle.scaleFactor = 1.0f;
+ // Keep the default behavior of this window to be focusable, which allows the system
+ // to consume keys when dragging is active. This can also be used to modify the drag
+ // state on key press. For example, cancel drag on escape key.
+ mDragWindowHandle.inputConfig = InputConfig.PREVENT_SPLITTING;
+
// The drag window cannot receive new touches.
mDragWindowHandle.touchableRegion.setEmpty();
- // The drag window covers the entire display
- mDragWindowHandle.frameLeft = 0;
- mDragWindowHandle.frameTop = 0;
- mDragWindowHandle.frameRight = mDisplaySize.x;
- mDragWindowHandle.frameBottom = mDisplaySize.y;
-
// Pause rotations before a drag.
ProtoLog.d(WM_DEBUG_ORIENTATION, "Pausing rotation during drag");
mService.mRoot.forAllDisplays(dc -> {
diff --git a/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java b/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java
index aa5e20d9ec7f..7844bffb6247 100644
--- a/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java
+++ b/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java
@@ -108,8 +108,11 @@ class EnsureActivitiesVisibleHelper {
&& childTaskFragment.getTopNonFinishingActivity() != null) {
childTaskFragment.updateActivityVisibilities(starting, configChanges,
preserveWindows, notifyClients);
+ // The TaskFragment should fully occlude the activities below if the bounds
+ // equals to its parent task, unless it is translucent.
mBehindFullyOccludedContainer |=
- childTaskFragment.getBounds().equals(mTaskFragment.getBounds());
+ (childTaskFragment.getBounds().equals(mTaskFragment.getBounds())
+ && !childTaskFragment.isTranslucent(starting));
if (mAboveTop && mTop.getTaskFragment() == childTaskFragment) {
mAboveTop = false;
}
diff --git a/services/core/java/com/android/server/wm/HighRefreshRateDenylist.java b/services/core/java/com/android/server/wm/HighRefreshRateDenylist.java
index 5e8d795ce955..5d088d886b14 100644
--- a/services/core/java/com/android/server/wm/HighRefreshRateDenylist.java
+++ b/services/core/java/com/android/server/wm/HighRefreshRateDenylist.java
@@ -41,9 +41,6 @@ class HighRefreshRateDenylist {
private final String[] mDefaultDenylist;
private final Object mLock = new Object();
- private DeviceConfigInterface mDeviceConfig;
- private OnPropertiesChangedListener mListener = new OnPropertiesChangedListener();
-
static HighRefreshRateDenylist create(@NonNull Resources r) {
return new HighRefreshRateDenylist(r, DeviceConfigInterface.REAL);
}
@@ -51,10 +48,9 @@ class HighRefreshRateDenylist {
@VisibleForTesting
HighRefreshRateDenylist(Resources r, DeviceConfigInterface deviceConfig) {
mDefaultDenylist = r.getStringArray(R.array.config_highRefreshRateBlacklist);
- mDeviceConfig = deviceConfig;
- mDeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
- BackgroundThread.getExecutor(), mListener);
- final String property = mDeviceConfig.getProperty(DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
+ deviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
+ BackgroundThread.getExecutor(), new OnPropertiesChangedListener());
+ final String property = deviceConfig.getProperty(DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
KEY_HIGH_REFRESH_RATE_BLACKLIST);
updateDenylist(property);
}
@@ -95,14 +91,6 @@ class HighRefreshRateDenylist {
}
}
- /** Used to prevent WmTests leaking issues. */
- @VisibleForTesting
- void dispose() {
- mDeviceConfig.removeOnPropertiesChangedListener(mListener);
- mDeviceConfig = null;
- mDenylistedPackages.clear();
- }
-
private class OnPropertiesChangedListener implements DeviceConfig.OnPropertiesChangedListener {
public void onPropertiesChanged(@NonNull DeviceConfig.Properties properties) {
if (properties.getKeyset().contains(KEY_HIGH_REFRESH_RATE_BLACKLIST)) {
diff --git a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
index 199517c441ad..0d4cfa3a8128 100644
--- a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
@@ -29,6 +29,7 @@ import static com.android.server.wm.WindowManagerService.H.UPDATE_MULTI_WINDOW_S
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.graphics.Rect;
import android.os.Trace;
import android.util.proto.ProtoOutputStream;
import android.view.InsetsSource;
@@ -79,8 +80,8 @@ final class ImeInsetsSourceProvider extends WindowContainerInsetsSourceProvider
}
@Override
- void updateSourceFrame() {
- super.updateSourceFrame();
+ void updateSourceFrame(Rect frame) {
+ super.updateSourceFrame(frame);
onSourceChanged();
}
diff --git a/services/core/java/com/android/server/wm/InputConfigAdapter.java b/services/core/java/com/android/server/wm/InputConfigAdapter.java
new file mode 100644
index 000000000000..2dcde4ee2ba8
--- /dev/null
+++ b/services/core/java/com/android/server/wm/InputConfigAdapter.java
@@ -0,0 +1,138 @@
+/*
+ * 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.wm;
+
+import android.os.InputConfig;
+import android.view.InputWindowHandle.InputConfigFlags;
+import android.view.WindowManager.LayoutParams;
+
+import java.util.List;
+
+/**
+ * A helper to determine the {@link InputConfigFlags} that control the behavior of an input window
+ * from several WM attributes.
+ */
+class InputConfigAdapter {
+ private InputConfigAdapter() {}
+
+ /** Describes a mapping from a flag value to a {@link InputConfigFlags} value. */
+ private static class FlagMapping {
+ final int mFlag;
+ final int mInputConfig;
+ final boolean mInverted;
+
+ FlagMapping(int flag, int inputConfig, boolean inverted) {
+ mFlag = flag;
+ mInputConfig = inputConfig;
+ mInverted = inverted;
+ }
+ }
+
+ /**
+ * A mapping from {@link LayoutParams.InputFeatureFlags} to {@link InputConfigFlags} for
+ * input configurations that can be mapped directly from a corresponding LayoutParams input
+ * feature.
+ */
+ private static final List<FlagMapping> INPUT_FEATURE_TO_CONFIG_MAP = List.of(
+ new FlagMapping(
+ LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL,
+ InputConfig.NO_INPUT_CHANNEL, false /* inverted */),
+ new FlagMapping(
+ LayoutParams.INPUT_FEATURE_DISABLE_USER_ACTIVITY,
+ InputConfig.DISABLE_USER_ACTIVITY, false /* inverted */),
+ new FlagMapping(
+ LayoutParams.INPUT_FEATURE_SPY,
+ InputConfig.SPY, false /* inverted */));
+
+ @InputConfigFlags
+ private static final int INPUT_FEATURE_TO_CONFIG_MASK =
+ computeMask(INPUT_FEATURE_TO_CONFIG_MAP);
+
+ /**
+ * A mapping from {@link LayoutParams.Flags} to {@link InputConfigFlags} for input
+ * configurations that can be mapped directly from a corresponding LayoutParams flag.
+ *
+ * NOTE: The layout params flag {@link LayoutParams#FLAG_NOT_FOCUSABLE} is not handled by this
+ * adapter, and must be handled explicitly.
+ */
+ private static final List<FlagMapping> LAYOUT_PARAM_FLAG_TO_CONFIG_MAP = List.of(
+ new FlagMapping(
+ LayoutParams.FLAG_NOT_TOUCHABLE,
+ InputConfig.NOT_TOUCHABLE, false /* inverted */),
+ new FlagMapping(
+ LayoutParams.FLAG_SPLIT_TOUCH,
+ InputConfig.PREVENT_SPLITTING, true /* inverted */),
+ new FlagMapping(
+ LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
+ InputConfig.WATCH_OUTSIDE_TOUCH, false /* inverted */),
+ new FlagMapping(
+ LayoutParams.FLAG_SLIPPERY,
+ InputConfig.SLIPPERY, false /* inverted */));
+
+ @InputConfigFlags
+ private static final int LAYOUT_PARAM_FLAG_TO_CONFIG_MASK =
+ computeMask(LAYOUT_PARAM_FLAG_TO_CONFIG_MAP);
+
+ /**
+ * Returns a mask of all the input config flags configured by
+ * {@link #getInputConfigFromWindowParams(int, int, int)}.
+ */
+ @InputConfigFlags
+ static int getMask() {
+ return LAYOUT_PARAM_FLAG_TO_CONFIG_MASK | INPUT_FEATURE_TO_CONFIG_MASK
+ | InputConfig.IS_WALLPAPER;
+ }
+
+ /**
+ * Get the {@link InputConfigFlags} value that provides the input window behavior specified by
+ * the given WindowManager attributes.
+ *
+ * Use {@link #getMask()} to get the mask of all the input config flags set by this method.
+ *
+ * @param type the window type
+ * @param flags the window flags
+ * @param inputFeatures the input feature flags
+ */
+ @InputConfigFlags
+ static int getInputConfigFromWindowParams(@LayoutParams.WindowType int type,
+ @LayoutParams.Flags int flags, @LayoutParams.InputFeatureFlags int inputFeatures) {
+ return (type == LayoutParams.TYPE_WALLPAPER ? InputConfig.IS_WALLPAPER : 0)
+ | applyMapping(flags, LAYOUT_PARAM_FLAG_TO_CONFIG_MAP)
+ | applyMapping(inputFeatures, INPUT_FEATURE_TO_CONFIG_MAP);
+ }
+
+ @InputConfigFlags
+ private static int applyMapping(int flags, List<FlagMapping> flagToConfigMap) {
+ int inputConfig = 0;
+ for (final FlagMapping mapping : flagToConfigMap) {
+ final boolean flagSet = (flags & mapping.mFlag) != 0;
+ if (flagSet != mapping.mInverted) {
+ inputConfig |= mapping.mInputConfig;
+ }
+ }
+ return inputConfig;
+ }
+
+ @InputConfigFlags
+ private static int computeMask(List<FlagMapping> flagToConfigMap) {
+ int mask = 0;
+ for (final FlagMapping mapping : flagToConfigMap) {
+ mask |= mapping.mInputConfig;
+ }
+ return mask;
+ }
+}
diff --git a/services/core/java/com/android/server/wm/InputConsumerImpl.java b/services/core/java/com/android/server/wm/InputConsumerImpl.java
index cbd5646968d7..59be3e05f2c0 100644
--- a/services/core/java/com/android/server/wm/InputConsumerImpl.java
+++ b/services/core/java/com/android/server/wm/InputConsumerImpl.java
@@ -22,6 +22,7 @@ import android.graphics.Point;
import android.graphics.Rect;
import android.os.Binder;
import android.os.IBinder;
+import android.os.InputConfig;
import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
@@ -70,19 +71,14 @@ class InputConsumerImpl implements IBinder.DeathRecipient {
mWindowHandle.name = name;
mWindowHandle.token = mClientChannel.getToken();
mWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_INPUT_CONSUMER;
- mWindowHandle.layoutParamsFlags = 0;
mWindowHandle.dispatchingTimeoutMillis = DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
- mWindowHandle.visible = true;
- mWindowHandle.focusable = false;
- mWindowHandle.hasWallpaper = false;
- mWindowHandle.paused = false;
mWindowHandle.ownerPid = Process.myPid();
mWindowHandle.ownerUid = Process.myUid();
- mWindowHandle.inputFeatures = 0;
mWindowHandle.scaleFactor = 1.0f;
- mWindowHandle.trustedOverlay = true;
+ mWindowHandle.inputConfig = InputConfig.NOT_FOCUSABLE | InputConfig.TRUSTED_OVERLAY;
- mInputSurface = mService.makeSurfaceBuilder(mService.mRoot.getDisplayContent(displayId).getSession())
+ mInputSurface = mService.makeSurfaceBuilder(
+ mService.mRoot.getDisplayContent(displayId).getSession())
.setContainerLayer()
.setName("Input Consumer " + name)
.setCallsite("InputConsumerImpl")
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index c4f685b69061..8038f4404799 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -21,7 +21,6 @@ import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import static android.view.WindowManager.INPUT_CONSUMER_PIP;
import static android.view.WindowManager.INPUT_CONSUMER_RECENTS_ANIMATION;
import static android.view.WindowManager.INPUT_CONSUMER_WALLPAPER;
-import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
import static android.view.WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL;
@@ -53,6 +52,7 @@ import android.annotation.Nullable;
import android.graphics.Region;
import android.os.Handler;
import android.os.IBinder;
+import android.os.InputConfig;
import android.os.Trace;
import android.os.UserHandle;
import android.util.ArrayMap;
@@ -61,6 +61,7 @@ import android.util.Slog;
import android.view.InputChannel;
import android.view.InputWindowHandle;
import android.view.SurfaceControl;
+import android.view.WindowManager;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.common.ProtoLog;
@@ -221,15 +222,13 @@ final class InputMonitor {
inputChannel, clientPid, clientUser, mDisplayId);
switch (name) {
case INPUT_CONSUMER_WALLPAPER:
- consumer.mWindowHandle.hasWallpaper = true;
+ consumer.mWindowHandle.inputConfig |= InputConfig.DUPLICATE_TOUCH_TO_WALLPAPER;
break;
case INPUT_CONSUMER_PIP:
- // The touchable region of the Pip input window is cropped to the bounds of the
- // stack, and we need FLAG_NOT_TOUCH_MODAL to ensure other events fall through
- consumer.mWindowHandle.layoutParamsFlags |= FLAG_NOT_TOUCH_MODAL;
+ // This is a valid consumer type, but we don't need any additional configurations.
break;
case INPUT_CONSUMER_RECENTS_ANIMATION:
- consumer.mWindowHandle.focusable = true;
+ consumer.mWindowHandle.inputConfig &= ~InputConfig.NOT_FOCUSABLE;
break;
default:
throw new IllegalArgumentException("Illegal input consumer : " + name
@@ -247,11 +246,24 @@ final class InputMonitor {
inputWindowHandle.setToken(w.mInputChannelToken);
inputWindowHandle.setDispatchingTimeoutMillis(w.getInputDispatchingTimeoutMillis());
inputWindowHandle.setTouchOcclusionMode(w.getTouchOcclusionMode());
- inputWindowHandle.setInputFeatures(w.mAttrs.inputFeatures);
inputWindowHandle.setPaused(w.mActivityRecord != null && w.mActivityRecord.paused);
- inputWindowHandle.setVisible(w.isVisible());
inputWindowHandle.setWindowToken(w.mClient);
+ // Update layout params flags to force the window to be not touch modal. We do this to
+ // restrict the window's touchable region to the task even if it requests touches outside
+ // its window bounds. An example is a dialog in primary split should get touches outside its
+ // window within the primary task but should not get any touches going to the secondary
+ // task.
+ int flags = w.mAttrs.flags;
+ if (w.mAttrs.isModal()) {
+ flags = flags | FLAG_NOT_TOUCH_MODAL;
+ }
+ inputWindowHandle.setLayoutParamsFlags(flags);
+ inputWindowHandle.setInputConfigMasked(
+ InputConfigAdapter.getInputConfigFromWindowParams(
+ w.mAttrs.type, flags, w.mAttrs.inputFeatures),
+ InputConfigAdapter.getMask());
+
final boolean focusable = w.canReceiveKeys()
&& (mService.mPerDisplayFocusEnabled || mDisplayContent.isOnTop());
inputWindowHandle.setFocusable(focusable);
@@ -270,17 +282,6 @@ final class InputMonitor {
// what is on screen to what is actually being touched in the UI.
inputWindowHandle.setScaleFactor(w.mGlobalScale != 1f ? (1f / w.mGlobalScale) : 1f);
- // Update layout params flags to force the window to be not touch modal. We do this to
- // restrict the window's touchable region to the task even if it request touches outside its
- // window bounds. An example is a dialog in primary split should get touches outside its
- // window within the primary task but should not get any touches going to the secondary
- // task.
- int flags = w.mAttrs.flags;
- if (w.mAttrs.isModal()) {
- flags = flags | FLAG_NOT_TOUCH_MODAL;
- }
- inputWindowHandle.setLayoutParamsFlags(flags);
-
boolean useSurfaceBoundsAsTouchRegion = false;
SurfaceControl touchableRegionCrop = null;
final Task task = w.getTask();
@@ -590,6 +591,8 @@ final class InputMonitor {
if (mAddWallpaperInputConsumerHandle) {
if (w.mAttrs.type == TYPE_WALLPAPER && w.isVisible()) {
+ mWallpaperInputConsumer.mWindowHandle
+ .replaceTouchableRegionWithCrop(null /* use this surface's bounds */);
// Add the wallpaper input consumer above the first visible wallpaper.
mWallpaperInputConsumer.show(mInputTransaction, w);
mAddWallpaperInputConsumerHandle = false;
@@ -631,24 +634,27 @@ final class InputMonitor {
static void populateOverlayInputInfo(InputWindowHandleWrapper inputWindowHandle,
WindowState w) {
- populateOverlayInputInfo(inputWindowHandle, w.isVisible());
+ populateOverlayInputInfo(inputWindowHandle);
inputWindowHandle.setTouchOcclusionMode(w.getTouchOcclusionMode());
}
// This would reset InputWindowHandle fields to prevent it could be found by input event.
// We need to check if any new field of InputWindowHandle could impact the result.
@VisibleForTesting
- static void populateOverlayInputInfo(InputWindowHandleWrapper inputWindowHandle,
- boolean isVisible) {
+ static void populateOverlayInputInfo(InputWindowHandleWrapper inputWindowHandle) {
inputWindowHandle.setDispatchingTimeoutMillis(0); // It should never receive input.
- inputWindowHandle.setVisible(isVisible);
inputWindowHandle.setFocusable(false);
- inputWindowHandle.setInputFeatures(INPUT_FEATURE_NO_INPUT_CHANNEL);
// The input window handle without input channel must not have a token.
inputWindowHandle.setToken(null);
inputWindowHandle.setScaleFactor(1f);
- inputWindowHandle.setLayoutParamsFlags(
- FLAG_NOT_TOUCH_MODAL | FLAG_NOT_TOUCHABLE | FLAG_NOT_FOCUSABLE);
+ final int defaultType = WindowManager.LayoutParams.TYPE_APPLICATION;
+ inputWindowHandle.setLayoutParamsType(defaultType);
+ inputWindowHandle.setInputConfigMasked(
+ InputConfigAdapter.getInputConfigFromWindowParams(
+ defaultType,
+ FLAG_NOT_TOUCHABLE,
+ INPUT_FEATURE_NO_INPUT_CHANNEL),
+ InputConfigAdapter.getMask());
inputWindowHandle.clearTouchableRegion();
inputWindowHandle.setTouchableRegionCrop(null);
}
@@ -666,7 +672,7 @@ final class InputMonitor {
inputWindowHandle.setName(name);
inputWindowHandle.setLayoutParamsType(TYPE_SECURE_SYSTEM_OVERLAY);
inputWindowHandle.setTrustedOverlay(true);
- populateOverlayInputInfo(inputWindowHandle, true /* isVisible */);
+ populateOverlayInputInfo(inputWindowHandle);
setInputWindowInfoIfNeeded(t, sc, inputWindowHandle);
}
diff --git a/services/core/java/com/android/server/wm/InputWindowHandleWrapper.java b/services/core/java/com/android/server/wm/InputWindowHandleWrapper.java
index 142d2933f046..301c1846249f 100644
--- a/services/core/java/com/android/server/wm/InputWindowHandleWrapper.java
+++ b/services/core/java/com/android/server/wm/InputWindowHandleWrapper.java
@@ -20,10 +20,13 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.graphics.Region;
import android.os.IBinder;
+import android.os.InputConfig;
import android.view.IWindow;
import android.view.InputApplicationHandle;
import android.view.InputWindowHandle;
+import android.view.InputWindowHandle.InputConfigFlags;
import android.view.SurfaceControl;
+import android.view.WindowManager;
import java.util.Objects;
@@ -31,8 +34,10 @@ import java.util.Objects;
* The wrapper of {@link InputWindowHandle} with field change detection to reduce unnecessary
* updates to surface, e.g. if there are no changes, then skip invocation of
* {@link SurfaceControl.Transaction#setInputWindowInfo(SurfaceControl, InputWindowHandle)}.
+ * It also sets the {@link InputConfigFlags} values for the input window.
*/
class InputWindowHandleWrapper {
+
/** The wrapped handle should not be directly exposed to avoid untracked changes. */
private final @NonNull InputWindowHandle mHandle;
@@ -65,7 +70,20 @@ class InputWindowHandleWrapper {
}
boolean isFocusable() {
- return mHandle.focusable;
+ return (mHandle.inputConfig & InputConfig.NOT_FOCUSABLE) == 0;
+ }
+
+ boolean isPaused() {
+ return (mHandle.inputConfig & InputConfig.PAUSE_DISPATCHING) != 0;
+ }
+
+ boolean isTrustedOverlay() {
+ return (mHandle.inputConfig & InputConfig.TRUSTED_OVERLAY) != 0;
+ }
+
+ boolean hasWallpaper() {
+ return (mHandle.inputConfig & InputConfig.DUPLICATE_TOUCH_TO_WALLPAPER)
+ != 0;
}
InputApplicationHandle getInputApplicationHandle() {
@@ -96,7 +114,7 @@ class InputWindowHandleWrapper {
mChanged = true;
}
- void setLayoutParamsFlags(int flags) {
+ void setLayoutParamsFlags(@WindowManager.LayoutParams.Flags int flags) {
if (mHandle.layoutParamsFlags == flags) {
return;
}
@@ -136,19 +154,11 @@ class InputWindowHandleWrapper {
mChanged = true;
}
- void setVisible(boolean visible) {
- if (mHandle.visible == visible) {
- return;
- }
- mHandle.visible = visible;
- mChanged = true;
- }
-
void setFocusable(boolean focusable) {
- if (mHandle.focusable == focusable) {
+ if (isFocusable() == focusable) {
return;
}
- mHandle.focusable = focusable;
+ mHandle.setInputConfig(InputConfig.NOT_FOCUSABLE, !focusable);
mChanged = true;
}
@@ -161,26 +171,27 @@ class InputWindowHandleWrapper {
}
void setHasWallpaper(boolean hasWallpaper) {
- if (mHandle.hasWallpaper == hasWallpaper) {
+ if (this.hasWallpaper() == hasWallpaper) {
return;
}
- mHandle.hasWallpaper = hasWallpaper;
+ mHandle.setInputConfig(InputConfig.DUPLICATE_TOUCH_TO_WALLPAPER,
+ hasWallpaper);
mChanged = true;
}
void setPaused(boolean paused) {
- if (mHandle.paused == paused) {
+ if (isPaused() == paused) {
return;
}
- mHandle.paused = paused;
+ mHandle.setInputConfig(InputConfig.PAUSE_DISPATCHING, paused);
mChanged = true;
}
void setTrustedOverlay(boolean trustedOverlay) {
- if (mHandle.trustedOverlay == trustedOverlay) {
+ if (isTrustedOverlay() == trustedOverlay) {
return;
}
- mHandle.trustedOverlay = trustedOverlay;
+ mHandle.setInputConfig(InputConfig.TRUSTED_OVERLAY, trustedOverlay);
mChanged = true;
}
@@ -208,14 +219,6 @@ class InputWindowHandleWrapper {
mChanged = true;
}
- void setInputFeatures(int features) {
- if (mHandle.inputFeatures == features) {
- return;
- }
- mHandle.inputFeatures = features;
- mChanged = true;
- }
-
void setDisplayId(int displayId) {
if (mHandle.displayId == displayId) {
return;
@@ -276,8 +279,14 @@ class InputWindowHandleWrapper {
mChanged = true;
}
- boolean isTrustedOverlay() {
- return mHandle.trustedOverlay;
+ void setInputConfigMasked(@InputConfigFlags int inputConfig, @InputConfigFlags int mask) {
+ final int inputConfigMasked = inputConfig & mask;
+ if (inputConfigMasked == (mHandle.inputConfig & mask)) {
+ return;
+ }
+ mHandle.inputConfig &= ~mask;
+ mHandle.inputConfig |= inputConfigMasked;
+ mChanged = true;
}
@Override
diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java
index 398816b331cb..9844cb5fe8f8 100644
--- a/services/core/java/com/android/server/wm/InsetsPolicy.java
+++ b/services/core/java/com/android/server/wm/InsetsPolicy.java
@@ -344,7 +344,6 @@ class InsetsPolicy {
// Navigation bar doesn't get influenced by anything else
if (type == ITYPE_NAVIGATION_BAR || type == ITYPE_EXTRA_NAVIGATION_BAR) {
- state.removeSource(ITYPE_IME);
state.removeSource(ITYPE_STATUS_BAR);
state.removeSource(ITYPE_CLIMATE_BAR);
state.removeSource(ITYPE_CAPTION_BAR);
@@ -424,14 +423,12 @@ class InsetsPolicy {
return state;
}
} else if (w.mActivityRecord != null && w.mActivityRecord.mImeInsetsFrozenUntilStartInput) {
- // During switching tasks with gestural navigation, if the IME is attached to
- // one app window on that time, even the next app window is behind the IME window,
- // conceptually the window should not receive the IME insets if the next window is
- // not eligible IME requester and ready to show IME on top of it.
- final boolean shouldImeAttachedToApp = mDisplayContent.shouldImeAttachedToApp();
+ // During switching tasks with gestural navigation, before the next IME input target
+ // starts the input, we should adjust and freeze the last IME visibility of the window
+ // in case delivering obsoleted IME insets state during transitioning.
final InsetsSource originalImeSource = originalState.peekSource(ITYPE_IME);
- if (shouldImeAttachedToApp && originalImeSource != null) {
+ if (originalImeSource != null) {
final boolean imeVisibility =
w.mActivityRecord.mLastImeShown || w.getRequestedVisibility(ITYPE_IME);
final InsetsState state = copyState ? new InsetsState(originalState)
diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
index 047bf2f53b68..f3f08b202fed 100644
--- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
@@ -84,6 +84,7 @@ abstract class InsetsSourceProvider {
private TriConsumer<DisplayFrames, WindowContainer, Rect> mImeFrameProvider;
private final Rect mImeOverrideFrame = new Rect();
private boolean mIsLeashReadyForDispatching;
+ private final Rect mSourceFrame = new Rect();
private final Rect mLastSourceFrame = new Rect();
private final Consumer<Transaction> mSetLeashPositionConsumer = t -> {
@@ -183,8 +184,8 @@ abstract class InsetsSourceProvider {
mImeFrameProvider = imeFrameProvider;
if (windowContainer == null) {
setServerVisible(false);
- mSource.setFrame(new Rect());
mSource.setVisibleFrame(null);
+ mSourceFrame.setEmpty();
} else {
mWindowContainer.getProvidedInsetsSources().put(mSource.getType(), mSource);
if (mControllable) {
@@ -208,7 +209,7 @@ abstract class InsetsSourceProvider {
* The source frame can affect the layout of other windows, so this should be called once the
* window container gets laid out.
*/
- void updateSourceFrame() {
+ void updateSourceFrame(Rect frame) {
if (mWindowContainer == null) {
return;
}
@@ -230,39 +231,25 @@ abstract class InsetsSourceProvider {
return;
}
- if (win.mGivenInsetsPending) {
- // If the given insets are pending, they are not reliable for now. The source frame
- // should be updated after the new given insets are sent to window manager.
- return;
- }
-
- // Make sure we set the valid source frame only when server visible is true, because the
- // frame may not yet determined that server side doesn't think the window is ready to
- // visible. (i.e. No surface, pending insets that were given during layout, etc..)
- if (mServerVisible) {
- mTmpRect.set(win.getFrame());
- if (mFrameProvider != null) {
- mFrameProvider.accept(mWindowContainer.getDisplayContent().mDisplayFrames,
- mWindowContainer, mTmpRect);
- } else {
- mTmpRect.inset(win.mGivenContentInsets);
- }
+ mSourceFrame.set(frame);
+ if (mFrameProvider != null) {
+ mFrameProvider.accept(mWindowContainer.getDisplayContent().mDisplayFrames,
+ mWindowContainer, mSourceFrame);
} else {
- mTmpRect.setEmpty();
+ mSourceFrame.inset(win.mGivenContentInsets);
}
- mSource.setFrame(mTmpRect);
+ updateSourceFrameForServerVisibility();
if (mImeFrameProvider != null) {
- mImeOverrideFrame.set(win.getFrame());
+ mImeOverrideFrame.set(frame);
mImeFrameProvider.accept(mWindowContainer.getDisplayContent().mDisplayFrames,
- mWindowContainer,
- mImeOverrideFrame);
+ mWindowContainer, mImeOverrideFrame);
}
if (win.mGivenVisibleInsets.left != 0 || win.mGivenVisibleInsets.top != 0
|| win.mGivenVisibleInsets.right != 0
|| win.mGivenVisibleInsets.bottom != 0) {
- mTmpRect.set(win.getFrame());
+ mTmpRect.set(frame);
mTmpRect.inset(win.mGivenVisibleInsets);
mSource.setVisibleFrame(mTmpRect);
} else {
@@ -270,13 +257,24 @@ abstract class InsetsSourceProvider {
}
}
+ private void updateSourceFrameForServerVisibility() {
+ // Make sure we set the valid source frame only when server visible is true, because the
+ // frame may not yet determined that server side doesn't think the window is ready to
+ // visible. (i.e. No surface, pending insets that were given during layout, etc..)
+ if (mServerVisible) {
+ mSource.setFrame(mSourceFrame);
+ } else {
+ mSource.setFrame(0, 0, 0, 0);
+ }
+ }
+
/** @return A new source computed by the specified window frame in the given display frames. */
- InsetsSource createSimulatedSource(DisplayFrames displayFrames, Rect winFrame) {
+ InsetsSource createSimulatedSource(DisplayFrames displayFrames, Rect frame) {
// Don't copy visible frame because it might not be calculated in the provided display
// frames and it is not significant for this usage.
final InsetsSource source = new InsetsSource(mSource.getType());
source.setVisible(mSource.isVisible());
- mTmpRect.set(winFrame);
+ mTmpRect.set(frame);
if (mFrameProvider != null) {
mFrameProvider.accept(displayFrames, mWindowContainer, mTmpRect);
}
@@ -296,7 +294,6 @@ abstract class InsetsSourceProvider {
? windowState.wouldBeVisibleIfPolicyIgnored() && windowState.isVisibleByPolicy()
: mWindowContainer.isVisibleRequested();
setServerVisible(isServerVisible);
- updateSourceFrame();
if (mControl != null) {
boolean changed = false;
final Point position = getWindowFrameSurfacePosition();
@@ -496,6 +493,7 @@ abstract class InsetsSourceProvider {
@VisibleForTesting
void setServerVisible(boolean serverVisible) {
mServerVisible = serverVisible;
+ updateSourceFrameForServerVisibility();
updateVisibility();
}
diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java
index 78608e2bf203..a19d72e37124 100644
--- a/services/core/java/com/android/server/wm/InsetsStateController.java
+++ b/services/core/java/com/android/server/wm/InsetsStateController.java
@@ -30,7 +30,6 @@ import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_IME;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.graphics.Rect;
import android.os.Trace;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -204,23 +203,6 @@ class InsetsStateController {
}
}
- /**
- * Computes insets state of the insets provider window in the display frames.
- *
- * @param win The owner window of insets provider.
- * @param displayFrames The display frames to create insets source.
- * @param winFrame The frame of the insets source window.
- */
- void computeSimulatedState(WindowState win, DisplayFrames displayFrames, Rect winFrame) {
- final InsetsState state = displayFrames.mInsetsState;
- for (int i = mProviders.size() - 1; i >= 0; i--) {
- final WindowContainerInsetsSourceProvider provider = mProviders.valueAt(i);
- if (provider.mWindowContainer == win) {
- state.addSource(provider.createSimulatedSource(displayFrames, winFrame));
- }
- }
- }
-
boolean isFakeTarget(@InternalInsetsType int type, InsetsControlTarget target) {
return mTypeFakeControlTargetMap.get(type) == target;
}
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index c55af9b6286e..7bf150b18e9b 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -443,6 +443,13 @@ class KeyguardController {
|| !mWindowManager.isKeyguardSecure(mService.getCurrentUserId());
}
+ /**
+ * @return Whether the dream activity is on top of default display.
+ */
+ boolean isShowingDream() {
+ return getDisplayState(DEFAULT_DISPLAY).mShowingDream;
+ }
+
private void dismissMultiWindowModeForTaskIfNeeded(int displayId,
@Nullable Task currentTaskControllingOcclusion) {
// TODO(b/113840485): Handle docked stack for individual display.
@@ -501,6 +508,7 @@ class KeyguardController {
private boolean mKeyguardGoingAway;
private boolean mDismissalRequested;
private boolean mOccluded;
+ private boolean mShowingDream;
private ActivityRecord mTopOccludesActivity;
private ActivityRecord mDismissingKeyguardActivity;
@@ -536,6 +544,7 @@ class KeyguardController {
mRequestDismissKeyguard = false;
mOccluded = false;
+ mShowingDream = false;
mTopOccludesActivity = null;
mDismissingKeyguardActivity = null;
@@ -570,9 +579,9 @@ class KeyguardController {
}
}
- final boolean dreaming = display.getDisplayPolicy().isShowingDreamLw() && (top != null
+ mShowingDream = display.getDisplayPolicy().isShowingDreamLw() && (top != null
&& top.getActivityType() == ACTIVITY_TYPE_DREAM);
- mOccluded = dreaming || occludedByActivity;
+ mOccluded = mShowingDream || occludedByActivity;
mRequestDismissKeyguard = lastDismissKeyguardActivity != mDismissingKeyguardActivity
&& !mOccluded
&& mDismissingKeyguardActivity != null
diff --git a/services/core/java/com/android/server/wm/LaunchParamsController.java b/services/core/java/com/android/server/wm/LaunchParamsController.java
index 8e5d73f13dfb..7bd2a4a28e69 100644
--- a/services/core/java/com/android/server/wm/LaunchParamsController.java
+++ b/services/core/java/com/android/server/wm/LaunchParamsController.java
@@ -142,18 +142,6 @@ class LaunchParamsController {
mService.deferWindowLayout();
try {
- if (mTmpParams.mPreferredTaskDisplayArea != null
- && task.getDisplayArea() != mTmpParams.mPreferredTaskDisplayArea) {
- mService.mRootWindowContainer.moveRootTaskToTaskDisplayArea(task.getRootTaskId(),
- mTmpParams.mPreferredTaskDisplayArea, true /* onTop */);
- }
-
- if (mTmpParams.hasWindowingMode() && task.isRootTask()
- && mTmpParams.mWindowingMode != task.getWindowingMode()) {
- task.setWindowingMode(task.getDisplayArea().validateWindowingMode(
- mTmpParams.mWindowingMode, activity, task));
- }
-
if (mTmpParams.mBounds.isEmpty()) {
return false;
}
diff --git a/services/core/java/com/android/server/wm/Letterbox.java b/services/core/java/com/android/server/wm/Letterbox.java
index 4b98013a99cc..40df02c176e5 100644
--- a/services/core/java/com/android/server/wm/Letterbox.java
+++ b/services/core/java/com/android/server/wm/Letterbox.java
@@ -24,6 +24,7 @@ import android.graphics.Color;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.IBinder;
+import android.os.InputConfig;
import android.os.Process;
import android.view.GestureDetector;
import android.view.InputChannel;
@@ -290,16 +291,12 @@ public class Letterbox {
win.getDisplayId());
mWindowHandle.name = name;
mWindowHandle.token = mToken;
- mWindowHandle.layoutParamsFlags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
- | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
- | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
- | WindowManager.LayoutParams.FLAG_SLIPPERY;
mWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_INPUT_CONSUMER;
mWindowHandle.dispatchingTimeoutMillis = DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
- mWindowHandle.visible = true;
mWindowHandle.ownerPid = Process.myPid();
mWindowHandle.ownerUid = Process.myUid();
mWindowHandle.scaleFactor = 1.0f;
+ mWindowHandle.inputConfig = InputConfig.NOT_FOCUSABLE | InputConfig.SLIPPERY;
}
void updateTouchableRegion(Rect frame) {
diff --git a/services/core/java/com/android/server/wm/LetterboxUiController.java b/services/core/java/com/android/server/wm/LetterboxUiController.java
index 8866343afe03..0038c716fee7 100644
--- a/services/core/java/com/android/server/wm/LetterboxUiController.java
+++ b/services/core/java/com/android/server/wm/LetterboxUiController.java
@@ -145,6 +145,14 @@ final class LetterboxUiController {
return;
}
updateRoundedCorners(w);
+ // If there is another main window that is not an application-starting window, we should
+ // update rounded corners for it as well, to avoid flickering rounded corners.
+ final WindowState nonStartingAppW = mActivityRecord.findMainWindow(
+ /* includeStartingApp= */ false);
+ if (nonStartingAppW != null && nonStartingAppW != w) {
+ updateRoundedCorners(nonStartingAppW);
+ }
+
updateWallpaperForLetterbox(w);
if (shouldShowLetterboxUi(w)) {
if (mLetterbox == null) {
diff --git a/services/core/java/com/android/server/wm/MirrorActiveUids.java b/services/core/java/com/android/server/wm/MirrorActiveUids.java
index 4e7f1d4cca18..b9aa9599babe 100644
--- a/services/core/java/com/android/server/wm/MirrorActiveUids.java
+++ b/services/core/java/com/android/server/wm/MirrorActiveUids.java
@@ -19,7 +19,7 @@ package com.android.server.wm;
import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
import android.app.ActivityManager.ProcessState;
-import android.util.SparseArray;
+import android.util.SparseIntArray;
import java.io.PrintWriter;
@@ -29,15 +29,14 @@ import java.io.PrintWriter;
* adjustment) or getting state from window manager (background start check).
*/
class MirrorActiveUids {
- private final SparseArray<UidRecord> mUidStates = new SparseArray<>();
+ /** Uid -> process state. */
+ private final SparseIntArray mUidStates = new SparseIntArray();
+
+ /** Uid -> number of non-app visible windows belong to the uid. */
+ private final SparseIntArray mNumNonAppVisibleWindowMap = new SparseIntArray();
synchronized void onUidActive(int uid, int procState) {
- UidRecord r = mUidStates.get(uid);
- if (r == null) {
- r = new UidRecord();
- mUidStates.put(uid, r);
- }
- r.mProcState = procState;
+ mUidStates.put(uid, procState);
}
synchronized void onUidInactive(int uid) {
@@ -45,22 +44,28 @@ class MirrorActiveUids {
}
synchronized void onUidProcStateChanged(int uid, int procState) {
- final UidRecord r = mUidStates.get(uid);
- if (r != null) {
- r.mProcState = procState;
+ final int index = mUidStates.indexOfKey(uid);
+ if (index >= 0) {
+ mUidStates.setValueAt(index, procState);
}
}
synchronized @ProcessState int getUidState(int uid) {
- final UidRecord r = mUidStates.get(uid);
- return r != null ? r.mProcState : PROCESS_STATE_NONEXISTENT;
+ return mUidStates.get(uid, PROCESS_STATE_NONEXISTENT);
}
/** Called when the surface of non-application (exclude toast) window is shown or hidden. */
synchronized void onNonAppSurfaceVisibilityChanged(int uid, boolean visible) {
- final UidRecord r = mUidStates.get(uid);
- if (r != null) {
- r.mNumNonAppVisibleWindow += visible ? 1 : -1;
+ final int index = mNumNonAppVisibleWindowMap.indexOfKey(uid);
+ if (index >= 0) {
+ final int num = mNumNonAppVisibleWindowMap.valueAt(index) + (visible ? 1 : -1);
+ if (num > 0) {
+ mNumNonAppVisibleWindowMap.setValueAt(index, num);
+ } else {
+ mNumNonAppVisibleWindowMap.removeAt(index);
+ }
+ } else if (visible) {
+ mNumNonAppVisibleWindowMap.append(uid, 1);
}
}
@@ -70,23 +75,15 @@ class MirrorActiveUids {
* {@link VisibleActivityProcessTracker}.
*/
synchronized boolean hasNonAppVisibleWindow(int uid) {
- final UidRecord r = mUidStates.get(uid);
- return r != null && r.mNumNonAppVisibleWindow > 0;
+ return mNumNonAppVisibleWindowMap.get(uid) > 0;
}
synchronized void dump(PrintWriter pw, String prefix) {
- pw.print(prefix + "NumNonAppVisibleWindowByUid:[");
- for (int i = mUidStates.size() - 1; i >= 0; i--) {
- final UidRecord r = mUidStates.valueAt(i);
- if (r.mNumNonAppVisibleWindow > 0) {
- pw.print(" " + mUidStates.keyAt(i) + ":" + r.mNumNonAppVisibleWindow);
- }
+ pw.print(prefix + "NumNonAppVisibleWindowUidMap:[");
+ for (int i = mNumNonAppVisibleWindowMap.size() - 1; i >= 0; i--) {
+ pw.print(" " + mNumNonAppVisibleWindowMap.keyAt(i) + ":"
+ + mNumNonAppVisibleWindowMap.valueAt(i));
}
pw.println("]");
}
-
- private static final class UidRecord {
- @ProcessState int mProcState;
- int mNumNonAppVisibleWindow;
- }
}
diff --git a/services/core/java/com/android/server/wm/PinnedTaskController.java b/services/core/java/com/android/server/wm/PinnedTaskController.java
index 06e3a73940b4..43d077664fd5 100644
--- a/services/core/java/com/android/server/wm/PinnedTaskController.java
+++ b/services/core/java/com/android/server/wm/PinnedTaskController.java
@@ -92,6 +92,7 @@ class PinnedTaskController {
// The set of actions and aspect-ratio for the that are currently allowed on the PiP activity
private ArrayList<RemoteAction> mActions = new ArrayList<>();
+ private RemoteAction mCloseAction;
private float mAspectRatio = -1f;
private float mExpandedAspectRatio = 0f;
@@ -154,7 +155,7 @@ class PinnedTaskController {
mPinnedTaskListener = listener;
notifyImeVisibilityChanged(mIsImeShowing, mImeHeight);
notifyMovementBoundsChanged(false /* fromImeAdjustment */);
- notifyActionsChanged(mActions);
+ notifyActionsChanged(mActions, mCloseAction);
} catch (RemoteException e) {
Log.e(TAG, "Failed to register pinned task listener", e);
}
@@ -408,12 +409,13 @@ class PinnedTaskController {
/**
* Sets the current set of actions.
*/
- void setActions(List<RemoteAction> actions) {
+ void setActions(List<RemoteAction> actions, RemoteAction closeAction) {
mActions.clear();
if (actions != null) {
mActions.addAll(actions);
}
- notifyActionsChanged(mActions);
+ mCloseAction = closeAction;
+ notifyActionsChanged(mActions, closeAction);
}
/**
@@ -450,10 +452,10 @@ class PinnedTaskController {
/**
* Notifies listeners that the PIP actions have changed.
*/
- private void notifyActionsChanged(List<RemoteAction> actions) {
+ private void notifyActionsChanged(List<RemoteAction> actions, RemoteAction closeAction) {
if (mPinnedTaskListener != null) {
try {
- mPinnedTaskListener.onActionsChanged(new ParceledListSlice(actions));
+ mPinnedTaskListener.onActionsChanged(new ParceledListSlice(actions), closeAction);
} catch (RemoteException e) {
Slog.e(TAG_WM, "Error delivering actions changed event.", e);
}
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index a407021c7594..e21ae05c0827 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -281,6 +281,7 @@ public class RecentsAnimationController implements DeathRecipient {
task.setCanAffectSystemUiFlags(behindSystemBars);
}
}
+ InputMethodManagerInternal.get().maybeFinishStylusHandwriting();
if (!behindSystemBars) {
// Hiding IME if IME window is not attached to app.
// Since some windowing mode is not proper to snapshot Task with IME window
@@ -553,10 +554,6 @@ public class RecentsAnimationController implements DeathRecipient {
mPendingStart = false;
- // Perform layout if it was scheduled before to make sure that we get correct content
- // insets for the target app window after a rotation
- mDisplayContent.performLayout(false /* initial */, false /* updateInputWindows */);
-
final Rect contentInsets;
final WindowState targetAppMainWindow = getTargetAppMainWindow();
if (targetAppMainWindow != null) {
diff --git a/services/core/java/com/android/server/wm/RefreshRatePolicy.java b/services/core/java/com/android/server/wm/RefreshRatePolicy.java
index 7bddb620c94d..f3713eb7f474 100644
--- a/services/core/java/com/android/server/wm/RefreshRatePolicy.java
+++ b/services/core/java/com/android/server/wm/RefreshRatePolicy.java
@@ -19,20 +19,46 @@ package com.android.server.wm;
import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
-import android.util.ArraySet;
+import android.hardware.display.DisplayManagerInternal.RefreshRateRange;
import android.view.Display;
import android.view.Display.Mode;
import android.view.DisplayInfo;
+import java.util.HashMap;
+
/**
* Policy to select a lower refresh rate for the display if applicable.
*/
class RefreshRatePolicy {
+ class PackageRefreshRate {
+ private final HashMap<String, RefreshRateRange> mPackages = new HashMap<>();
+
+ public void add(String s, float minRefreshRate, float maxRefreshRate) {
+ float minSupportedRefreshRate =
+ Math.max(RefreshRatePolicy.this.mMinSupportedRefreshRate, minRefreshRate);
+ float maxSupportedRefreshRate =
+ Math.min(RefreshRatePolicy.this.mMaxSupportedRefreshRate, maxRefreshRate);
+
+ mPackages.put(s,
+ new RefreshRateRange(minSupportedRefreshRate, maxSupportedRefreshRate));
+ }
+
+ public RefreshRateRange get(String s) {
+ return mPackages.get(s);
+ }
+
+ public void remove(String s) {
+ mPackages.remove(s);
+ }
+ }
+
private final Mode mLowRefreshRateMode;
- private final ArraySet<String> mNonHighRefreshRatePackages = new ArraySet<>();
+ private final PackageRefreshRate mNonHighRefreshRatePackages = new PackageRefreshRate();
private final HighRefreshRateDenylist mHighRefreshRateDenylist;
private final WindowManagerService mWmService;
+ private float mMinSupportedRefreshRate;
+ private float mMaxSupportedRefreshRate;
/**
* The following constants represent priority of the window. SF uses this information when
@@ -70,7 +96,12 @@ class RefreshRatePolicy {
Mode mode = displayInfo.getDefaultMode();
float[] refreshRates = displayInfo.getDefaultRefreshRates();
float bestRefreshRate = mode.getRefreshRate();
+ mMinSupportedRefreshRate = bestRefreshRate;
+ mMaxSupportedRefreshRate = bestRefreshRate;
for (int i = refreshRates.length - 1; i >= 0; i--) {
+ mMinSupportedRefreshRate = Math.min(mMinSupportedRefreshRate, refreshRates[i]);
+ mMaxSupportedRefreshRate = Math.max(mMaxSupportedRefreshRate, refreshRates[i]);
+
if (refreshRates[i] >= 60f && refreshRates[i] < bestRefreshRate) {
bestRefreshRate = refreshRates[i];
}
@@ -78,12 +109,13 @@ class RefreshRatePolicy {
return displayInfo.findDefaultModeByRefreshRate(bestRefreshRate);
}
- void addNonHighRefreshRatePackage(String packageName) {
- mNonHighRefreshRatePackages.add(packageName);
+ void addRefreshRateRangeForPackage(String packageName,
+ float minRefreshRate, float maxRefreshRate) {
+ mNonHighRefreshRatePackages.add(packageName, minRefreshRate, maxRefreshRate);
mWmService.requestTraversal();
}
- void removeNonHighRefreshRatePackage(String packageName) {
+ void removeRefreshRateRangeForPackage(String packageName) {
mNonHighRefreshRatePackages.remove(packageName);
mWmService.requestTraversal();
}
@@ -172,8 +204,9 @@ class RefreshRatePolicy {
// If app is using Camera, we set both the min and max refresh rate to the camera's
// preferred refresh rate to make sure we don't end up with a refresh rate lower
// than the camera capture rate, which will lead to dropping camera frames.
- if (mNonHighRefreshRatePackages.contains(packageName)) {
- return mLowRefreshRateMode.getRefreshRate();
+ RefreshRateRange range = mNonHighRefreshRatePackages.get(packageName);
+ if (range != null) {
+ return range.min;
}
return 0;
@@ -192,8 +225,9 @@ class RefreshRatePolicy {
final String packageName = w.getOwningPackage();
// If app is using Camera, force it to default (lower) refresh rate.
- if (mNonHighRefreshRatePackages.contains(packageName)) {
- return mLowRefreshRateMode.getRefreshRate();
+ RefreshRateRange range = mNonHighRefreshRatePackages.get(packageName);
+ if (range != null) {
+ return range.max;
}
return 0;
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index b9cd657da0e2..94fc51dc94d2 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -149,6 +149,7 @@ import com.android.server.LocalServices;
import com.android.server.am.ActivityManagerService;
import com.android.server.am.AppTimeTracker;
import com.android.server.am.UserState;
+import com.android.server.policy.PermissionPolicyInternal;
import com.android.server.policy.WindowManagerPolicy;
import java.io.FileDescriptor;
@@ -2727,9 +2728,9 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
return false;
}
- Task getLaunchRootTask(@Nullable ActivityRecord r, @Nullable ActivityOptions options,
+ Task getOrCreateRootTask(@Nullable ActivityRecord r, @Nullable ActivityOptions options,
@Nullable Task candidateTask, boolean onTop) {
- return getLaunchRootTask(r, options, candidateTask, null /* sourceTask */, onTop,
+ return getOrCreateRootTask(r, options, candidateTask, null /* sourceTask */, onTop,
null /* launchParams */, 0 /* launchFlags */);
}
@@ -2744,63 +2745,68 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
* @param launchFlags The launch flags for this launch.
* @param realCallingPid The pid from {@link ActivityStarter#setRealCallingPid}
* @param realCallingUid The uid from {@link ActivityStarter#setRealCallingUid}
- * @return The root task to use for the launch or INVALID_TASK_ID.
+ * @return The root task to use for the launch.
*/
- Task getLaunchRootTask(@Nullable ActivityRecord r,
+ Task getOrCreateRootTask(@Nullable ActivityRecord r,
@Nullable ActivityOptions options, @Nullable Task candidateTask,
@Nullable Task sourceTask, boolean onTop,
@Nullable LaunchParamsController.LaunchParams launchParams, int launchFlags) {
- int taskId = INVALID_TASK_ID;
- int displayId = INVALID_DISPLAY;
- TaskDisplayArea taskDisplayArea = null;
-
- // We give preference to the launch preference in activity options.
+ // First preference goes to the launch root task set in the activity options.
if (options != null) {
- taskId = options.getLaunchTaskId();
- displayId = options.getLaunchDisplayId();
- final WindowContainerToken daToken = options.getLaunchTaskDisplayArea();
- taskDisplayArea = daToken != null
- ? (TaskDisplayArea) WindowContainer.fromBinder(daToken.asBinder()) : null;
-
- final Task rootTask = Task.fromWindowContainerToken(options.getLaunchRootTask());
- if (rootTask != null) {
- return rootTask;
+ final Task candidateRoot = Task.fromWindowContainerToken(options.getLaunchRootTask());
+ if (canLaunchOnDisplay(r, candidateRoot)) {
+ return candidateRoot;
}
}
- // First preference for root task goes to the task Id set in the activity options. Use
- // the root task associated with that if possible.
- if (taskId != INVALID_TASK_ID) {
- // Temporarily set the task id to invalid in case in re-entry.
- options.setLaunchTaskId(INVALID_TASK_ID);
- final Task task = anyTaskForId(taskId,
- MATCH_ATTACHED_TASK_OR_RECENT_TASKS_AND_RESTORE, options, onTop);
- options.setLaunchTaskId(taskId);
- if (task != null) {
- return task.getRootTask();
+ // Next preference goes to the task id set in the activity options.
+ if (options != null) {
+ final int candidateTaskId = options.getLaunchTaskId();
+ if (candidateTaskId != INVALID_TASK_ID) {
+ // Temporarily set the task id to invalid in case in re-entry.
+ options.setLaunchTaskId(INVALID_TASK_ID);
+ final Task task = anyTaskForId(candidateTaskId,
+ MATCH_ATTACHED_TASK_OR_RECENT_TASKS_AND_RESTORE, options, onTop);
+ options.setLaunchTaskId(candidateTaskId);
+ if (canLaunchOnDisplay(r, task)) {
+ return task.getRootTask();
+ }
}
}
- final int activityType = resolveActivityType(r, options, candidateTask);
- Task rootTask = null;
-
- // Next preference for root task goes to the taskDisplayArea candidate.
- if (launchParams != null && launchParams.mPreferredTaskDisplayArea != null
- && canLaunchOnDisplay(r, launchParams.mPreferredTaskDisplayArea.getDisplayId())) {
+ // Next preference goes to the TaskDisplayArea candidate from launchParams
+ // or activity options.
+ TaskDisplayArea taskDisplayArea = null;
+ if (launchParams != null && launchParams.mPreferredTaskDisplayArea != null) {
taskDisplayArea = launchParams.mPreferredTaskDisplayArea;
+ } else if (options != null) {
+ final WindowContainerToken daToken = options.getLaunchTaskDisplayArea();
+ taskDisplayArea = daToken != null
+ ? (TaskDisplayArea) WindowContainer.fromBinder(daToken.asBinder()) : null;
+ if (taskDisplayArea == null) {
+ final int launchDisplayId = options.getLaunchDisplayId();
+ if (launchDisplayId != INVALID_DISPLAY) {
+ final DisplayContent displayContent = getDisplayContent(launchDisplayId);
+ if (displayContent != null) {
+ taskDisplayArea = displayContent.getDefaultTaskDisplayArea();
+ }
+ }
+ }
}
- if (taskDisplayArea == null && displayId != INVALID_DISPLAY
- && canLaunchOnDisplay(r, displayId)) {
- taskDisplayArea = getDisplayContent(displayId).getDefaultTaskDisplayArea();
- }
+
+ final int activityType = resolveActivityType(r, options, candidateTask);
if (taskDisplayArea != null) {
- return taskDisplayArea.getOrCreateRootTask(r, options, candidateTask,
- sourceTask, launchParams, launchFlags, activityType, onTop);
+ if (canLaunchOnDisplay(r, taskDisplayArea.getDisplayId())) {
+ return taskDisplayArea.getOrCreateRootTask(r, options, candidateTask,
+ sourceTask, launchParams, launchFlags, activityType, onTop);
+ } else {
+ taskDisplayArea = null;
+ }
}
// Give preference to the root task and display of the input task and activity if they
// match the mode we want to launch into.
- TaskDisplayArea container = null;
+ Task rootTask = null;
if (candidateTask != null) {
rootTask = candidateTask.getRootTask();
}
@@ -2810,10 +2816,11 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
int windowingMode = launchParams != null ? launchParams.mWindowingMode
: WindowConfiguration.WINDOWING_MODE_UNDEFINED;
if (rootTask != null) {
- container = rootTask.getDisplayArea();
- if (container != null && canLaunchOnDisplay(r, container.mDisplayContent.mDisplayId)) {
+ taskDisplayArea = rootTask.getDisplayArea();
+ if (taskDisplayArea != null
+ && canLaunchOnDisplay(r, taskDisplayArea.mDisplayContent.mDisplayId)) {
if (windowingMode == WindowConfiguration.WINDOWING_MODE_UNDEFINED) {
- windowingMode = container.resolveWindowingMode(r, options, candidateTask);
+ windowingMode = taskDisplayArea.resolveWindowingMode(r, options, candidateTask);
}
// Always allow organized tasks that created by organizer since the activity type
// of an organized task is decided by the activity type of its top child, which
@@ -2822,19 +2829,32 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
|| rootTask.mCreatedByOrganizer) {
return rootTask;
}
+ } else {
+ taskDisplayArea = null;
}
+
}
- if (container == null
- || !canLaunchOnDisplay(r, container.mDisplayContent.mDisplayId)) {
- container = getDefaultTaskDisplayArea();
- if (windowingMode == WindowConfiguration.WINDOWING_MODE_UNDEFINED) {
- windowingMode = container.resolveWindowingMode(r, options, candidateTask);
- }
+ // Falling back to default task container
+ if (taskDisplayArea == null) {
+ taskDisplayArea = getDefaultTaskDisplayArea();
+ }
+ return taskDisplayArea.getOrCreateRootTask(r, options, candidateTask, sourceTask,
+ launchParams, launchFlags, activityType, onTop);
+ }
+
+ private boolean canLaunchOnDisplay(ActivityRecord r, Task task) {
+ if (task == null) {
+ Slog.w(TAG, "canLaunchOnDisplay(), invalid task: " + task);
+ return false;
}
- return container.getOrCreateRootTask(r, options, candidateTask, sourceTask, launchParams,
- launchFlags, activityType, onTop);
+ if (!task.isAttached()) {
+ Slog.w(TAG, "canLaunchOnDisplay(), Task is not attached: " + task);
+ return false;
+ }
+
+ return canLaunchOnDisplay(r, task.getTaskDisplayArea().getDisplayId());
}
/** @return true if activity record is null or can be launched on provided display. */
@@ -2842,7 +2862,11 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
if (r == null) {
return true;
}
- return r.canBeLaunchedOnDisplay(displayId);
+ if (!r.canBeLaunchedOnDisplay(displayId)) {
+ Slog.w(TAG, "Not allow to launch " + r + " on display " + displayId);
+ return false;
+ }
+ return true;
}
int resolveActivityType(@Nullable ActivityRecord r, @Nullable ActivityOptions options,
@@ -3212,12 +3236,12 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
if (aOptions != null) {
// Resolve the root task the task should be placed in now based on options
// and reparent if needed.
- final Task launchRootTask =
- getLaunchRootTask(null, aOptions, task, onTop);
- if (launchRootTask != null && task.getRootTask() != launchRootTask) {
+ final Task targetRootTask =
+ getOrCreateRootTask(null, aOptions, task, onTop);
+ if (targetRootTask != null && task.getRootTask() != targetRootTask) {
final int reparentMode = onTop
? REPARENT_MOVE_ROOT_TASK_TO_FRONT : REPARENT_LEAVE_ROOT_TASK_IN_PLACE;
- task.reparent(launchRootTask, onTop, reparentMode, ANIMATE, DEFER_RESUME,
+ task.reparent(targetRootTask, onTop, reparentMode, ANIMATE, DEFER_RESUME,
"anyTaskForId");
}
}
@@ -3309,6 +3333,36 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
}
/**
+ * Iterate over all task fragments, to see if there exists one that meets the
+ * PermissionPolicyService's criteria to show a permission dialog.
+ */
+ public int getTaskToShowPermissionDialogOn(String pkgName, int uid) {
+ PermissionPolicyInternal pPi = mService.getPermissionPolicyInternal();
+ if (pPi == null) {
+ return INVALID_TASK_ID;
+ }
+
+ final int[] validTaskId = {INVALID_TASK_ID};
+ forAllLeafTaskFragments(fragment -> {
+ ActivityRecord record = fragment.getActivity((r) -> {
+ // skip hidden (or about to hide) apps, or the permission dialog
+ return r.canBeTopRunning() && r.isVisibleRequested()
+ && !pPi.isIntentToPermissionDialog(r.intent);
+ });
+ if (record != null && record.isUid(uid)
+ && Objects.equals(pkgName, record.packageName)
+ && pPi.shouldShowNotificationDialogForTask(record.getTask().getTaskInfo(),
+ pkgName, record.intent)) {
+ validTaskId[0] = record.getTask().mTaskId;
+ return true;
+ }
+ return false;
+ });
+
+ return validTaskId[0];
+ }
+
+ /**
* Dumps the activities matching the given {@param name} in the either the focused root task
* or all visible root tasks if {@param dumpVisibleRootTasksOnly} is true.
*/
@@ -3322,11 +3376,17 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
return new ArrayList<>();
}
} else {
+ final RecentTasks recentTasks = mWindowManager.mAtmService.getRecentTasks();
+ final int recentsComponentUid = recentTasks != null
+ ? recentTasks.getRecentsComponentUid()
+ : -1;
final ArrayList<ActivityRecord> activities = new ArrayList<>();
- forAllRootTasks(rootTask -> {
- if (!dumpVisibleRootTasksOnly || rootTask.shouldBeVisible(null)) {
- activities.addAll(rootTask.getDumpActivitiesLocked(name, userId));
+ forAllLeafTasks(task -> {
+ final boolean isRecents = (task.effectiveUid == recentsComponentUid);
+ if (!dumpVisibleRootTasksOnly || task.shouldBeVisible(null) || isRecents) {
+ activities.addAll(task.getDumpActivitiesLocked(name, userId));
}
+ return false;
});
return activities;
}
diff --git a/services/core/java/com/android/server/wm/RunningTasks.java b/services/core/java/com/android/server/wm/RunningTasks.java
index 3d6d1825adc7..1ec191ed7c05 100644
--- a/services/core/java/com/android/server/wm/RunningTasks.java
+++ b/services/core/java/com/android/server/wm/RunningTasks.java
@@ -57,8 +57,6 @@ class RunningTasks {
private ArraySet<Integer> mProfileIds;
private boolean mAllowed;
private boolean mFilterOnlyVisibleRecents;
- private Task mTopDisplayFocusRootTask;
- private Task mTopDisplayAdjacentTask;
private RecentTasks mRecentTasks;
private boolean mKeepIntentExtra;
@@ -78,17 +76,9 @@ class RunningTasks {
mAllowed = (flags & FLAG_ALLOWED) == FLAG_ALLOWED;
mFilterOnlyVisibleRecents =
(flags & FLAG_FILTER_ONLY_VISIBLE_RECENTS) == FLAG_FILTER_ONLY_VISIBLE_RECENTS;
- mTopDisplayFocusRootTask = root.getTopDisplayFocusedRootTask();
mRecentTasks = root.mService.getRecentTasks();
mKeepIntentExtra = (flags & FLAG_KEEP_INTENT_EXTRA) == FLAG_KEEP_INTENT_EXTRA;
- if (mTopDisplayFocusRootTask != null
- && mTopDisplayFocusRootTask.getAdjacentTaskFragment() != null) {
- mTopDisplayAdjacentTask = mTopDisplayFocusRootTask.getAdjacentTaskFragment().asTask();
- } else {
- mTopDisplayAdjacentTask = null;
- }
-
final PooledConsumer c = PooledLambda.obtainConsumer(RunningTasks::processTask, this,
PooledLambda.__(Task.class));
root.forAllLeafTasks(c, false);
@@ -132,18 +122,15 @@ class RunningTasks {
return;
}
- final Task rootTask = task.getRootTask();
- if (rootTask == mTopDisplayFocusRootTask && rootTask.getTopMostTask() == task) {
- // For the focused top root task, update the last root task active time so that it
- // can be used to determine the order of the tasks (it may not be set for newly
- // created tasks)
+ if (task.isVisible()) {
+ // For the visible task, update the last active time so that it can be used to determine
+ // the order of the tasks (it may not be set for newly created tasks)
task.touchActiveTime();
- } else if (rootTask == mTopDisplayAdjacentTask && rootTask.getTopMostTask() == task) {
- // The short-term workaround for launcher could get suitable running task info in
- // split screen.
- task.touchActiveTime();
- // TreeSet doesn't allow same value and make sure this task is lower than focus one.
- task.lastActiveTime--;
+ if (!task.isFocused()) {
+ // TreeSet doesn't allow the same value and make sure this task is lower than the
+ // focused one.
+ task.lastActiveTime -= mTmpSortedSet.size();
+ }
}
mTmpSortedSet.add(task);
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 0c60919180fa..9ad25ac8876f 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -232,14 +232,14 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
int requestedWidth, int requestedHeight, int viewFlags, int flags,
ClientWindowFrames outFrames, MergedConfiguration mergedConfiguration,
SurfaceControl outSurfaceControl, InsetsState outInsetsState,
- InsetsSourceControl[] outActiveControls) {
+ InsetsSourceControl[] outActiveControls, Bundle outSyncSeqIdBundle) {
if (false) Slog.d(TAG_WM, ">>>>>> ENTERED relayout from "
+ Binder.getCallingPid());
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, mRelayoutTag);
int res = mService.relayoutWindow(this, window, attrs,
requestedWidth, requestedHeight, viewFlags, flags,
outFrames, mergedConfiguration, outSurfaceControl, outInsetsState,
- outActiveControls);
+ outActiveControls, outSyncSeqIdBundle);
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
if (false) Slog.d(TAG_WM, "<<<<<< EXITING relayout to "
+ Binder.getCallingPid());
@@ -265,9 +265,9 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
@Override
public void finishDrawing(IWindow window,
- @Nullable SurfaceControl.Transaction postDrawTransaction) {
+ @Nullable SurfaceControl.Transaction postDrawTransaction, int seqId) {
if (DEBUG) Slog.v(TAG_WM, "IWindow finishDrawing called for " + window);
- mService.finishDrawingWindow(this, window, postDrawTransaction);
+ mService.finishDrawingWindow(this, window, postDrawTransaction, seqId);
}
@Override
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 7fe34f47c53c..f3cefca10b06 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -72,6 +72,7 @@ import static android.view.WindowManager.TRANSIT_TO_FRONT;
import static com.android.internal.policy.DecorView.DECOR_SHADOW_FOCUSED_HEIGHT_IN_DIP;
import static com.android.internal.policy.DecorView.DECOR_SHADOW_UNFOCUSED_HEIGHT_IN_DIP;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_BACK_PREVIEW;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_LOCKTASK;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_RECENTS_ANIMATIONS;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_STATES;
@@ -504,13 +505,6 @@ class Task extends TaskFragment {
*/
boolean mInRemoveTask;
- // When non-null, this is a transaction that will get applied on the next frame returned after
- // a relayout is requested from the client. While this is only valid on a leaf task; since the
- // transaction can effect an ancestor task, this also needs to keep track of the ancestor task
- // that this transaction manipulates because deferUntilFrame acts on individual surfaces.
- SurfaceControl.Transaction mMainWindowSizeChangeTransaction;
- Task mMainWindowSizeChangeTask;
-
private final AnimatingActivityRegistry mAnimatingActivityRegistry =
new AnimatingActivityRegistry();
@@ -616,6 +610,12 @@ class Task extends TaskFragment {
boolean mLastSurfaceShowing = true;
+ /**
+ * Tracks if a back gesture is in progress.
+ * Skips any system transition animations if this is set to {@code true}.
+ */
+ boolean mBackGestureStarted = false;
+
private Task(ActivityTaskManagerService atmService, int _taskId, Intent _intent,
Intent _affinityIntent, String _affinity, String _rootAffinity,
ComponentName _realActivity, ComponentName _origActivity, boolean _rootWasReset,
@@ -1530,7 +1530,7 @@ class Task extends TaskFragment {
mTaskSupervisor.removeTask(this, false /* killProcess */,
!REMOVE_FROM_RECENTS, reason);
}
- } else if (!mReuseTask && !mCreatedByOrganizer) {
+ } else if (!mReuseTask && shouldRemoveSelfOnLastChildRemoval()) {
// Remove entire task if it doesn't have any activity left and it isn't marked for reuse
// or created by task organizer.
if (!isRootTask()) {
@@ -1630,12 +1630,16 @@ class Task extends TaskFragment {
}
ActivityRecord performClearTop(ActivityRecord newR, int launchFlags) {
+ // The task should be preserved for putting new activity in case the last activity is
+ // finished if it is normal launch mode and not single top ("clear-task-top").
+ mReuseTask = true;
mTaskSupervisor.beginDeferResume();
final ActivityRecord result;
try {
result = clearTopActivities(newR, launchFlags);
} finally {
mTaskSupervisor.endDeferResume();
+ mReuseTask = false;
}
return result;
}
@@ -2043,8 +2047,10 @@ class Task extends TaskFragment {
Rect outOverrideBounds = getResolvedOverrideConfiguration().windowConfiguration.getBounds();
if (windowingMode == WINDOWING_MODE_FULLSCREEN) {
- // Use empty bounds to indicate "fill parent".
- outOverrideBounds.setEmpty();
+ if (!mCreatedByOrganizer) {
+ // Use empty bounds to indicate "fill parent".
+ outOverrideBounds.setEmpty();
+ }
// The bounds for fullscreen mode shouldn't be adjusted by minimal size. Otherwise if
// the parent or display is smaller than the size, the content may be cropped.
return;
@@ -3291,9 +3297,10 @@ class Task extends TaskFragment {
mTmpDimBoundsRect.offsetTo(0, 0);
}
- updateShadowsRadius(isFocused(), getSyncTransaction());
+ final SurfaceControl.Transaction t = getSyncTransaction();
+ updateShadowsRadius(isFocused(), t);
- if (mDimmer.updateDims(getPendingTransaction(), mTmpDimBoundsRect)) {
+ if (mDimmer.updateDims(t, mTmpDimBoundsRect)) {
scheduleAnimation();
}
@@ -3303,7 +3310,7 @@ class Task extends TaskFragment {
final boolean show = isVisible() || isAnimating(TRANSITION | PARENTS | CHILDREN);
if (mSurfaceControl != null) {
if (show != mLastSurfaceShowing) {
- getSyncTransaction().setVisibility(mSurfaceControl, show);
+ t.setVisibility(mSurfaceControl, show);
}
}
mLastSurfaceShowing = show;
@@ -3327,6 +3334,14 @@ class Task extends TaskFragment {
}
});
}
+ } else if (mBackGestureStarted) {
+ // Cancel playing transitions if a back navigation animation is in progress.
+ // This bit is set by {@link BackNavigationController} when a back gesture is started.
+ // It is used as a one-off transition overwrite that is cleared when the back gesture
+ // is committed and triggers a transition, or when the gesture is cancelled.
+ mBackGestureStarted = false;
+ mDisplayContent.mSkipAppTransitionAnimation = true;
+ ProtoLog.d(WM_DEBUG_BACK_PREVIEW, "Skipping app transition animation. task=%s", this);
} else {
super.applyAnimationUnchecked(lp, enter, transit, isVoiceInteraction, sources);
}
@@ -3408,7 +3423,7 @@ class Task extends TaskFragment {
info.positionInParent = getRelativePosition();
info.pictureInPictureParams = getPictureInPictureParams(top);
- info.preferDockBigOverlays = getPreferDockBigOverlays();
+ info.shouldDockBigOverlays = shouldDockBigOverlays();
if (info.pictureInPictureParams != null
&& info.pictureInPictureParams.isLaunchIntoPip()
&& top.getTopMostActivity().getLastParentBeforePip() != null) {
@@ -3461,9 +3476,9 @@ class Task extends TaskFragment {
? null : new PictureInPictureParams(topMostActivity.pictureInPictureArgs);
}
- private boolean getPreferDockBigOverlays() {
+ private boolean shouldDockBigOverlays() {
final ActivityRecord topMostActivity = getTopMostActivity();
- return topMostActivity != null && topMostActivity.preferDockBigOverlays;
+ return topMostActivity != null && topMostActivity.shouldDockBigOverlays;
}
Rect getDisplayCutoutInsets() {
@@ -4287,7 +4302,7 @@ class Task extends TaskFragment {
/**
* @return true if the task is currently focused.
*/
- private boolean isFocused() {
+ boolean isFocused() {
if (mDisplayContent == null || mDisplayContent.mFocusedApp == null) {
return false;
}
@@ -4359,7 +4374,7 @@ class Task extends TaskFragment {
}
}
- void onPreferDockBigOverlaysChanged() {
+ void onShouldDockBigOverlaysChanged() {
dispatchTaskInfoChangedIfNeeded(true /* force */);
}
@@ -4390,17 +4405,16 @@ class Task extends TaskFragment {
leaf.setMainWindowSizeChangeTransaction(t, origin);
return;
}
- mMainWindowSizeChangeTransaction = t;
- mMainWindowSizeChangeTask = t == null ? null : origin;
- }
-
- SurfaceControl.Transaction getMainWindowSizeChangeTransaction() {
- return mMainWindowSizeChangeTransaction;
+ final WindowState w = getTopVisibleAppMainWindow();
+ if (w != null) {
+ w.applyWithNextDraw((d) -> {
+ d.merge(t);
+ });
+ } else {
+ t.apply();
+ }
}
- Task getMainWindowSizeChangeTask() {
- return mMainWindowSizeChangeTask;
- }
void setActivityWindowingMode(int windowingMode) {
PooledConsumer c = PooledLambda.obtainConsumer(ActivityRecord::setWindowingMode,
@@ -6085,7 +6099,7 @@ class Task extends TaskFragment {
/**
* Sets the current picture-in-picture actions.
*/
- void setPictureInPictureActions(List<RemoteAction> actions) {
+ void setPictureInPictureActions(List<RemoteAction> actions, RemoteAction closeAction) {
if (!mWmService.mAtmService.mSupportsPictureInPicture) {
return;
}
@@ -6094,7 +6108,7 @@ class Task extends TaskFragment {
return;
}
- getDisplayContent().getPinnedTaskController().setActions(actions);
+ getDisplayContent().getPinnedTaskController().setActions(actions, closeAction);
}
public DisplayInfo getDisplayInfo() {
diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java
index 2f50b14968d5..7bb7870cea80 100644
--- a/services/core/java/com/android/server/wm/TaskDisplayArea.java
+++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java
@@ -824,9 +824,19 @@ final class TaskDisplayArea extends DisplayArea<WindowContainer> {
}
void setBackgroundColor(@ColorInt int colorInt) {
+ setBackgroundColor(colorInt, false /* restore */);
+ }
+
+ void setBackgroundColor(@ColorInt int colorInt, boolean restore) {
mBackgroundColor = colorInt;
Color color = Color.valueOf(colorInt);
- mColorLayerCounter++;
+
+ // We don't want to increment the mColorLayerCounter if we are restoring the background
+ // color after a surface migration because in that case the mColorLayerCounter already
+ // accounts for setting that background color.
+ if (!restore) {
+ mColorLayerCounter++;
+ }
// Only apply the background color if the TDA is actually attached and has a valid surface
// to set the background color on. We still want to keep track of the background color state
@@ -855,7 +865,7 @@ final class TaskDisplayArea extends DisplayArea<WindowContainer> {
super.migrateToNewSurfaceControl(t);
if (mColorLayerCounter > 0) {
- setBackgroundColor(mBackgroundColor);
+ setBackgroundColor(mBackgroundColor, true /* restore */);
}
if (mSplitScreenDividerAnchor == null) {
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index afc3087f4ee9..c0bc0191b16d 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -63,8 +63,6 @@ import static com.android.server.wm.TaskFragmentProto.DISPLAY_ID;
import static com.android.server.wm.TaskFragmentProto.MIN_HEIGHT;
import static com.android.server.wm.TaskFragmentProto.MIN_WIDTH;
import static com.android.server.wm.TaskFragmentProto.WINDOW_CONTAINER;
-import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
-import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
import static com.android.server.wm.WindowContainerChildProto.TASK_FRAGMENT;
import android.annotation.IntDef;
@@ -242,7 +240,7 @@ class TaskFragment extends WindowContainer<WindowContainer> {
/** Client assigned unique token for this TaskFragment if this is created by an organizer. */
@Nullable
- private IBinder mFragmentToken;
+ private final IBinder mFragmentToken;
/**
* Whether to delay the last activity of TaskFragment being immediately removed while finishing.
@@ -516,12 +514,13 @@ class TaskFragment extends WindowContainer<WindowContainer> {
* @see #isAllowedToEmbedActivityInTrustedMode(ActivityRecord)
*/
boolean isAllowedToEmbedActivity(@NonNull ActivityRecord a) {
- if ((a.info.flags & FLAG_ALLOW_UNTRUSTED_ACTIVITY_EMBEDDING)
- == FLAG_ALLOW_UNTRUSTED_ACTIVITY_EMBEDDING) {
- return true;
- }
+ return isAllowedToEmbedActivityInUntrustedMode(a)
+ || isAllowedToEmbedActivityInTrustedMode(a);
+ }
- return isAllowedToEmbedActivityInTrustedMode(a);
+ boolean isAllowedToEmbedActivityInUntrustedMode(@NonNull ActivityRecord a) {
+ return (a.info.flags & FLAG_ALLOW_UNTRUSTED_ACTIVITY_EMBEDDING)
+ == FLAG_ALLOW_UNTRUSTED_ACTIVITY_EMBEDDING;
}
/**
@@ -531,7 +530,7 @@ class TaskFragment extends WindowContainer<WindowContainer> {
* <li>the activity has declared the organizer host as trusted explicitly via known
* certificate.</li>
*/
- private boolean isAllowedToEmbedActivityInTrustedMode(@NonNull ActivityRecord a) {
+ boolean isAllowedToEmbedActivityInTrustedMode(@NonNull ActivityRecord a) {
if (UserHandle.getAppId(mTaskFragmentOrganizerUid) == SYSTEM_UID) {
// The system is trusted to embed other apps securely and for all users.
return true;
@@ -1460,7 +1459,8 @@ class TaskFragment extends WindowContainer<WindowContainer> {
// next activity.
final boolean lastResumedCanPip = prev.checkEnterPictureInPictureState(
"shouldAutoPipWhilePausing", userLeaving);
- if (lastResumedCanPip && prev.pictureInPictureArgs.isAutoEnterEnabled()) {
+ if (userLeaving && lastResumedCanPip
+ && prev.pictureInPictureArgs.isAutoEnterEnabled()) {
shouldAutoPip = true;
} else if (!lastResumedCanPip) {
// If the flag RESUME_WHILE_PAUSING is set, then continue to schedule the previous
@@ -2303,6 +2303,10 @@ class TaskFragment extends WindowContainer<WindowContainer> {
mMinHeight = minHeight;
}
+ boolean shouldRemoveSelfOnLastChildRemoval() {
+ return !mCreatedByOrganizer || mIsRemovalRequested;
+ }
+
@Override
void removeChild(WindowContainer child) {
removeChild(child, true /* removeSelfIfPossible */);
@@ -2318,7 +2322,7 @@ class TaskFragment extends WindowContainer<WindowContainer> {
mBackScreenshots.remove(r.mActivityComponent.flattenToString());
}
}
- if (removeSelfIfPossible && (!mCreatedByOrganizer || mIsRemovalRequested) && !hasChild()) {
+ if (removeSelfIfPossible && shouldRemoveSelfOnLastChildRemoval() && !hasChild()) {
removeImmediately("removeLastChild " + child);
}
}
@@ -2336,13 +2340,18 @@ class TaskFragment extends WindowContainer<WindowContainer> {
return;
}
mIsRemovalRequested = true;
- forAllActivities(r -> {
- if (withTransition) {
+ // The task order may be changed by finishIfPossible() for adjusting focus if there are
+ // nested tasks, so add all activities into a list to avoid missed removals.
+ final ArrayList<ActivityRecord> removingActivities = new ArrayList<>();
+ forAllActivities((Consumer<ActivityRecord>) removingActivities::add);
+ for (int i = removingActivities.size() - 1; i >= 0; --i) {
+ final ActivityRecord r = removingActivities.get(i);
+ if (withTransition && r.isVisible()) {
r.finishIfPossible(reason, false /* oomAdj */);
} else {
r.destroyIfPossible(reason);
}
- });
+ }
}
void setDelayLastActivityRemoval(boolean delay) {
@@ -2360,8 +2369,7 @@ class TaskFragment extends WindowContainer<WindowContainer> {
if (!hasChild()) {
return false;
}
- return isAnimating(TRANSITION | CHILDREN, WindowState.EXIT_ANIMATING_TYPES)
- || inTransition();
+ return isExitAnimationRunningSelfOrChild() || inTransition();
}
@Override
@@ -2382,10 +2390,18 @@ class TaskFragment extends WindowContainer<WindowContainer> {
void removeImmediately() {
mIsRemovalRequested = false;
resetAdjacentTaskFragment();
+ cleanUp();
super.removeImmediately();
sendTaskFragmentVanished();
}
+ /** Called on remove to cleanup. */
+ private void cleanUp() {
+ if (mIsEmbedded) {
+ mAtmService.mWindowOrganizerController.cleanUpEmbeddedTaskFragment(this);
+ }
+ }
+
@Override
Dimmer getDimmer() {
// If the window is in an embedded TaskFragment, we want to dim at the TaskFragment.
@@ -2409,7 +2425,7 @@ class TaskFragment extends WindowContainer<WindowContainer> {
// Bounds need to be relative, as the dim layer is a child.
final Rect dimBounds = getBounds();
dimBounds.offsetTo(0 /* newLeft */, 0 /* newTop */);
- if (mDimmer.updateDims(getPendingTransaction(), dimBounds)) {
+ if (mDimmer.updateDims(getSyncTransaction(), dimBounds)) {
scheduleAnimation();
}
}
diff --git a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
index 19f921deab4c..bdec49e2ec40 100644
--- a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
@@ -140,7 +140,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
mLastSentTaskFragmentInfos.put(tf, info);
tf.mTaskFragmentAppearedSent = true;
} catch (RemoteException e) {
- Slog.e(TAG, "Exception sending onTaskFragmentAppeared callback", e);
+ Slog.d(TAG, "Exception sending onTaskFragmentAppeared callback", e);
}
onTaskFragmentParentInfoChanged(organizer, tf);
}
@@ -150,7 +150,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
try {
organizer.onTaskFragmentVanished(tf.getTaskFragmentInfo());
} catch (RemoteException e) {
- Slog.e(TAG, "Exception sending onTaskFragmentVanished callback", e);
+ Slog.d(TAG, "Exception sending onTaskFragmentVanished callback", e);
}
tf.mTaskFragmentAppearedSent = false;
mLastSentTaskFragmentInfos.remove(tf);
@@ -175,7 +175,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
organizer.onTaskFragmentInfoChanged(tf.getTaskFragmentInfo());
mLastSentTaskFragmentInfos.put(tf, info);
} catch (RemoteException e) {
- Slog.e(TAG, "Exception sending onTaskFragmentInfoChanged callback", e);
+ Slog.d(TAG, "Exception sending onTaskFragmentInfoChanged callback", e);
}
}
@@ -198,7 +198,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
organizer.onTaskFragmentParentInfoChanged(tf.getFragmentToken(), parentConfig);
mLastSentTaskFragmentParentConfigs.put(tf, new Configuration(parentConfig));
} catch (RemoteException e) {
- Slog.e(TAG, "Exception sending onTaskFragmentParentInfoChanged callback", e);
+ Slog.d(TAG, "Exception sending onTaskFragmentParentInfoChanged callback", e);
}
}
@@ -210,7 +210,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
try {
organizer.onTaskFragmentError(errorCallbackToken, exceptionBundle);
} catch (RemoteException e) {
- Slog.e(TAG, "Exception sending onTaskFragmentError callback", e);
+ Slog.d(TAG, "Exception sending onTaskFragmentError callback", e);
}
}
}
diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java
index 331f1242da1d..ff5bfbee61f4 100644
--- a/services/core/java/com/android/server/wm/TaskOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java
@@ -800,17 +800,24 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
final long origId = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
- DisplayContent dc = mService.mWindowManager.mRoot
+ final DisplayContent dc = mService.mWindowManager.mRoot
.getDisplayContent(displayId);
- if (dc == null || dc.getImeTarget(IME_TARGET_LAYERING) == null) {
+ if (dc == null) {
+ return null;
+ }
+
+ final InsetsControlTarget imeLayeringTarget = dc.getImeTarget(IME_TARGET_LAYERING);
+ if (imeLayeringTarget == null || imeLayeringTarget.getWindow() == null) {
return null;
}
+
// Avoid WindowState#getRootTask() so we don't attribute system windows to a task.
- final Task task = dc.getImeTarget(IME_TARGET_LAYERING).getWindow().getTask();
+ final Task task = imeLayeringTarget.getWindow().asTask();
if (task == null) {
return null;
}
- return task.getRootTask().mRemoteToken.toWindowContainerToken();
+
+ return task.mRemoteToken.toWindowContainerToken();
}
} finally {
Binder.restoreCallingIdentity(origId);
diff --git a/services/core/java/com/android/server/wm/TaskPositioner.java b/services/core/java/com/android/server/wm/TaskPositioner.java
index 348cfb62582e..47c397d12720 100644
--- a/services/core/java/com/android/server/wm/TaskPositioner.java
+++ b/services/core/java/com/android/server/wm/TaskPositioner.java
@@ -40,6 +40,7 @@ import android.graphics.Point;
import android.graphics.Rect;
import android.os.Binder;
import android.os.IBinder;
+import android.os.InputConfig;
import android.os.Process;
import android.os.RemoteException;
import android.os.Trace;
@@ -219,30 +220,17 @@ class TaskPositioner implements IBinder.DeathRecipient {
displayContent.getDisplayId());
mDragWindowHandle.name = TAG;
mDragWindowHandle.token = mClientChannel.getToken();
- mDragWindowHandle.layoutParamsFlags = 0;
mDragWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_DRAG;
mDragWindowHandle.dispatchingTimeoutMillis = DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
- mDragWindowHandle.visible = true;
- // When dragging the window around, we do not want to steal focus for the window.
- mDragWindowHandle.focusable = false;
- mDragWindowHandle.hasWallpaper = false;
- mDragWindowHandle.paused = false;
mDragWindowHandle.ownerPid = Process.myPid();
mDragWindowHandle.ownerUid = Process.myUid();
- mDragWindowHandle.inputFeatures = 0;
mDragWindowHandle.scaleFactor = 1.0f;
+ // When dragging the window around, we do not want to steal focus for the window.
+ mDragWindowHandle.inputConfig = InputConfig.NOT_FOCUSABLE;
// The drag window cannot receive new touches.
mDragWindowHandle.touchableRegion.setEmpty();
- // The drag window covers the entire display.
- final Rect displayBounds = mTmpRect;
- displayContent.getBounds(mTmpRect);
- mDragWindowHandle.frameLeft = displayBounds.left;
- mDragWindowHandle.frameTop = displayBounds.top;
- mDragWindowHandle.frameRight = displayBounds.right;
- mDragWindowHandle.frameBottom = displayBounds.bottom;
-
// Pause rotations before a drag.
ProtoLog.d(WM_DEBUG_ORIENTATION, "Pausing rotation during re-position");
mDisplayContent.getDisplayRotation().pause();
@@ -250,6 +238,8 @@ class TaskPositioner implements IBinder.DeathRecipient {
// Notify InputMonitor to take mDragWindowHandle.
mService.mTaskPositioningController.showInputSurface(win.getDisplayId());
+ final Rect displayBounds = mTmpRect;
+ displayContent.getBounds(displayBounds);
final DisplayMetrics displayMetrics = displayContent.getDisplayMetrics();
mMinVisibleWidth = dipToPixel(MINIMUM_VISIBLE_WIDTH_IN_DP, displayMetrics);
mMinVisibleHeight = dipToPixel(MINIMUM_VISIBLE_HEIGHT_IN_DP, displayMetrics);
diff --git a/services/core/java/com/android/server/wm/TaskPositioningController.java b/services/core/java/com/android/server/wm/TaskPositioningController.java
index 8f24f2615fac..68bf2b2424e7 100644
--- a/services/core/java/com/android/server/wm/TaskPositioningController.java
+++ b/services/core/java/com/android/server/wm/TaskPositioningController.java
@@ -83,17 +83,18 @@ class TaskPositioningController {
return;
}
- mTransaction.show(mInputSurface);
- mTransaction.setInputWindowInfo(mInputSurface, h);
- mTransaction.setLayer(mInputSurface, Integer.MAX_VALUE);
-
final Display display = dc.getDisplay();
final Point p = new Point();
display.getRealSize(p);
-
mTmpClipRect.set(0, 0, p.x, p.y);
- mTransaction.setWindowCrop(mInputSurface, mTmpClipRect);
- mTransaction.syncInputWindows().apply();
+
+ mTransaction.show(mInputSurface)
+ .setInputWindowInfo(mInputSurface, h)
+ .setLayer(mInputSurface, Integer.MAX_VALUE)
+ .setPosition(mInputSurface, 0, 0)
+ .setCrop(mInputSurface, mTmpClipRect)
+ .syncInputWindows()
+ .apply();
}
boolean startMovingTask(IWindow window, float startX, float startY) {
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index 29d17429fa6a..21ca4bb6038b 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -216,6 +216,7 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
}
Task getTransientLaunchRestoreTarget(@NonNull WindowContainer container) {
+ if (mTransientLaunches == null) return null;
for (int i = 0; i < mTransientLaunches.size(); ++i) {
if (mTransientLaunches.keyAt(i).isDescendantOf(container)) {
return mTransientLaunches.valueAt(i);
@@ -491,7 +492,8 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
// Avoid commit visibility to false here, or else we will get a sudden
// "flash" / surface going invisible for a split second.
commitVisibility = false;
- } else {
+ } else if (ar.getDeferHidingClient()) {
+ // Legacy PIP-enter requires pause event with user-leaving.
mController.mAtm.mTaskSupervisor.mUserLeaving = true;
ar.getTaskFragment().startPausing(false /* uiSleeping */,
null /* resuming */, "finishTransition");
@@ -574,6 +576,7 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
false /* disableImeIcon */);
}
}
+ dc.removeImeSurfaceImmediately();
dc.handleCompleteDeferredRemoval();
}
}
@@ -1526,6 +1529,9 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
if (task != null && task.voiceSession != null) {
flags |= FLAG_IS_VOICE_INTERACTION;
}
+ if (task != null && task.isTranslucent(null)) {
+ flags |= FLAG_TRANSLUCENT;
+ }
final ActivityRecord record = wc.asActivityRecord();
if (record != null) {
if (record.mUseTransferredAnimation) {
diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java
index 043623392546..8840cd557de6 100644
--- a/services/core/java/com/android/server/wm/TransitionController.java
+++ b/services/core/java/com/android/server/wm/TransitionController.java
@@ -61,7 +61,7 @@ class TransitionController {
/** Whether to use shell-transitions rotation instead of fixed-rotation. */
private static final boolean SHELL_TRANSITIONS_ROTATION =
- SystemProperties.getBoolean("persist.debug.shell_transit_rotate", false);
+ SystemProperties.getBoolean("persist.wm.debug.shell_transit_rotate", false);
/** The same as legacy APP_TRANSITION_TIMEOUT_MS. */
private static final int DEFAULT_TIMEOUT_MS = 5000;
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 56014adb705d..e7b4e834eb5a 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -73,6 +73,7 @@ import android.annotation.Nullable;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
+import android.graphics.Color;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.Debug;
@@ -1195,6 +1196,23 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
return false;
}
+ boolean isExitAnimationRunningSelfOrChild() {
+ if (!mTransitionController.isShellTransitionsEnabled()) {
+ return isAnimating(TRANSITION | CHILDREN, WindowState.EXIT_ANIMATING_TYPES);
+ }
+ if (mTransitionController.isCollecting(this)) {
+ return true;
+ }
+
+ for (int i = mChildren.size() - 1; i >= 0; --i) {
+ WindowContainer child = mChildren.get(i);
+ if (child.isExitAnimationRunningSelfOrChild()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
void sendAppVisibilityToClients() {
for (int i = mChildren.size() - 1; i >= 0; --i) {
final WindowContainer wc = mChildren.get(i);
@@ -3807,7 +3825,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
private void setTaskBackgroundColor(@ColorInt int backgroundColor) {
TaskDisplayArea taskDisplayArea = getTaskDisplayArea();
- if (taskDisplayArea != null) {
+ if (taskDisplayArea != null && backgroundColor != Color.TRANSPARENT) {
taskDisplayArea.setBackgroundColor(backgroundColor);
// Atomic counter to make sure the clearColor callback is only called one.
diff --git a/services/core/java/com/android/server/wm/WindowManagerConstants.java b/services/core/java/com/android/server/wm/WindowManagerConstants.java
index bdbcd166dc0b..1931be4015c6 100644
--- a/services/core/java/com/android/server/wm/WindowManagerConstants.java
+++ b/services/core/java/com/android/server/wm/WindowManagerConstants.java
@@ -91,12 +91,6 @@ final class WindowManagerConstants {
updateSystemGestureExcludedByPreQStickyImmersive();
}
- @VisibleForTesting
- void dispose() {
- mDeviceConfig.removeOnPropertiesChangedListener(mListenerAndroid);
- mDeviceConfig.removeOnPropertiesChangedListener(mListenerWindowManager);
- }
-
private void onAndroidPropertiesChanged(DeviceConfig.Properties properties) {
synchronized (mGlobalLock) {
boolean updateSystemGestureExclusionLimit = false;
diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java
index 9585a4b93a97..0a3c3f049f43 100644
--- a/services/core/java/com/android/server/wm/WindowManagerInternal.java
+++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java
@@ -725,17 +725,18 @@ public abstract class WindowManagerInternal {
public abstract void hideIme(IBinder imeTargetWindowToken, int displayId);
/**
- * Tell window manager about a package that should not be running with high refresh rate
- * setting until removeNonHighRefreshRatePackage is called for the same package.
+ * Tell window manager about a package that should be running with a restricted range of
+ * refresh rate setting until removeRefreshRateRangeForPackage is called for the same package.
*
* This must not be called again for the same package.
*/
- public abstract void addNonHighRefreshRatePackage(@NonNull String packageName);
+ public abstract void addRefreshRateRangeForPackage(@NonNull String packageName,
+ float minRefreshRate, float maxRefreshRate);
/**
* Tell window manager to stop constraining refresh rate for the given package.
*/
- public abstract void removeNonHighRefreshRatePackage(@NonNull String packageName);
+ public abstract void removeRefreshRateRangeForPackage(@NonNull String packageName);
/**
* Checks if the device supports touch or faketouch.
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 555128bc1374..43e84ae91118 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -89,7 +89,6 @@ import static android.view.WindowManager.REMOVE_CONTENT_MODE_UNDEFINED;
import static android.view.WindowManager.TRANSIT_NONE;
import static android.view.WindowManager.TRANSIT_RELAUNCH;
import static android.view.WindowManagerGlobal.ADD_OKAY;
-import static android.view.WindowManagerGlobal.RELAYOUT_RES_BLAST_SYNC;
import static android.view.WindowManagerGlobal.RELAYOUT_RES_SURFACE_CHANGED;
import static android.view.WindowManagerPolicyConstants.NAV_BAR_INVALID;
import static android.view.WindowManagerPolicyConstants.TYPE_LAYER_MULTIPLIER;
@@ -119,7 +118,6 @@ import static com.android.server.wm.DisplayContent.IME_TARGET_LAYERING;
import static com.android.server.wm.RootWindowContainer.MATCH_ATTACHED_TASK_OR_RECENT_TASKS;
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_ALL;
import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
-import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DISPLAY;
@@ -141,6 +139,7 @@ import static com.android.server.wm.WindowManagerServiceDumpProto.HARD_KEYBOARD_
import static com.android.server.wm.WindowManagerServiceDumpProto.INPUT_METHOD_WINDOW;
import static com.android.server.wm.WindowManagerServiceDumpProto.POLICY;
import static com.android.server.wm.WindowManagerServiceDumpProto.ROOT_WINDOW_CONTAINER;
+import static com.android.server.wm.WindowManagerServiceDumpProto.WINDOW_FRAMES_VALID;
import android.Manifest;
import android.Manifest.permission;
@@ -191,6 +190,7 @@ import android.os.Handler;
import android.os.HandlerExecutor;
import android.os.IBinder;
import android.os.IRemoteCallback;
+import android.os.InputConfig;
import android.os.Looper;
import android.os.Message;
import android.os.Parcel;
@@ -404,7 +404,7 @@ public class WindowManagerService extends IWindowManager.Stub
/**
* Use WMShell for app transition.
*/
- public static final String ENABLE_SHELL_TRANSITIONS = "persist.debug.shell_transit";
+ public static final String ENABLE_SHELL_TRANSITIONS = "persist.wm.debug.shell_transit";
/**
* @see #ENABLE_SHELL_TRANSITIONS
@@ -743,6 +743,9 @@ public class WindowManagerService extends IWindowManager.Stub
private final DisplayHashController mDisplayHashController;
+ volatile float mMaximumObscuringOpacityForTouch =
+ InputManager.DEFAULT_MAXIMUM_OBSCURING_OPACITY_FOR_TOUCH;
+
@VisibleForTesting
final WindowContextListenerController mWindowContextListenerController =
new WindowContextListenerController();
@@ -780,6 +783,8 @@ public class WindowManagerService extends IWindowManager.Stub
DEVELOPMENT_RENDER_SHADOWS_IN_COMPOSITOR);
private final Uri mDisplaySettingsPathUri = Settings.Global.getUriFor(
DEVELOPMENT_WM_DISPLAY_SETTINGS_PATH);
+ private final Uri mMaximumObscuringOpacityForTouchUri = Settings.Global.getUriFor(
+ Settings.Global.MAXIMUM_OBSCURING_OPACITY_FOR_TOUCH);
public SettingsObserver() {
super(new Handler());
@@ -804,6 +809,8 @@ public class WindowManagerService extends IWindowManager.Stub
UserHandle.USER_ALL);
resolver.registerContentObserver(mDisplaySettingsPathUri, false, this,
UserHandle.USER_ALL);
+ resolver.registerContentObserver(mMaximumObscuringOpacityForTouchUri, false, this,
+ UserHandle.USER_ALL);
}
@Override
@@ -847,6 +854,11 @@ public class WindowManagerService extends IWindowManager.Stub
return;
}
+ if (mMaximumObscuringOpacityForTouchUri.equals(uri)) {
+ updateMaximumObscuringOpacityForTouch();
+ return;
+ }
+
@UpdateAnimationScaleMode
final int mode;
if (mWindowAnimationScaleUri.equals(uri)) {
@@ -866,6 +878,14 @@ public class WindowManagerService extends IWindowManager.Stub
void loadSettings() {
updateSystemUiSettings(false /* handleChange */);
updatePointerLocation();
+ updateMaximumObscuringOpacityForTouch();
+ }
+
+ void updateMaximumObscuringOpacityForTouch() {
+ ContentResolver resolver = mContext.getContentResolver();
+ mMaximumObscuringOpacityForTouch = Settings.Global.getFloat(resolver,
+ Settings.Global.MAXIMUM_OBSCURING_OPACITY_FOR_TOUCH,
+ InputManager.DEFAULT_MAXIMUM_OBSCURING_OPACITY_FOR_TOUCH);
}
void updateSystemUiSettings(boolean handleChange) {
@@ -2136,6 +2156,7 @@ public class WindowManagerService extends IWindowManager.Stub
w.mGivenTouchableRegion.scale(w.mGlobalScale);
}
w.setDisplayLayoutNeeded();
+ w.updateSourceFrame(w.getFrame());
mWindowPlacerLocked.performSurfacePlacement();
w.getDisplayContent().getInputMonitor().updateInputWindowsLw(true);
@@ -2190,7 +2211,7 @@ public class WindowManagerService extends IWindowManager.Stub
int requestedWidth, int requestedHeight, int viewVisibility, int flags,
ClientWindowFrames outFrames, MergedConfiguration mergedConfiguration,
SurfaceControl outSurfaceControl, InsetsState outInsetsState,
- InsetsSourceControl[] outActiveControls) {
+ InsetsSourceControl[] outActiveControls, Bundle outSyncIdBundle) {
Arrays.fill(outActiveControls, null);
int result = 0;
boolean configChanged;
@@ -2481,19 +2502,20 @@ public class WindowManagerService extends IWindowManager.Stub
ProtoLog.v(WM_DEBUG_FOCUS, "Relayout of %s: focusMayChange=%b",
win, focusMayChange);
- result |= mInTouchMode ? WindowManagerGlobal.RELAYOUT_RES_IN_TOUCH_MODE : 0;
-
if (DEBUG_LAYOUT) {
Slog.v(TAG_WM, "Relayout complete " + win + ": outFrames=" + outFrames);
}
win.mInRelayout = false;
if (mUseBLASTSync && win.useBLASTSync() && viewVisibility != View.GONE
- && win.mNextRelayoutUseSync) {
+ && (win.mSyncSeqId > win.mLastSeqIdSentToRelayout)) {
win.prepareDrawHandlers();
win.markRedrawForSyncReported();
- win.mNextRelayoutUseSync = false;
- result |= RELAYOUT_RES_BLAST_SYNC;
+
+ win.mLastSeqIdSentToRelayout = win.mSyncSeqId;
+ outSyncIdBundle.putInt("seqid", win.mSyncSeqId);
+ } else {
+ outSyncIdBundle.putInt("seqid", -1);
}
if (configChanged) {
@@ -2541,8 +2563,7 @@ public class WindowManagerService extends IWindowManager.Stub
if (win.isWinVisibleLw() && winAnimator.applyAnimationLocked(transit, false)) {
focusMayChange = true;
win.mAnimatingExit = true;
- } else if (win.mDisplayContent.okToAnimate() && win.isAnimating(TRANSITION | PARENTS,
- WindowState.EXIT_ANIMATING_TYPES)) {
+ } else if (win.mDisplayContent.okToAnimate() && win.isExitAnimationRunningSelfOrParent()) {
// Currently in a hide animation... turn this into
// an exit.
win.mAnimatingExit = true;
@@ -2615,7 +2636,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
void finishDrawingWindow(Session session, IWindow client,
- @Nullable SurfaceControl.Transaction postDrawTransaction) {
+ @Nullable SurfaceControl.Transaction postDrawTransaction, int seqId) {
if (postDrawTransaction != null) {
postDrawTransaction.sanitize();
}
@@ -2626,7 +2647,7 @@ public class WindowManagerService extends IWindowManager.Stub
WindowState win = windowForClientLocked(session, client, false);
ProtoLog.d(WM_DEBUG_ADD_REMOVE, "finishDrawingWindow: %s mDrawState=%s",
win, (win != null ? win.mWinAnimator.drawStateToString() : "null"));
- if (win != null && win.finishDrawing(postDrawTransaction)) {
+ if (win != null && win.finishDrawing(postDrawTransaction, seqId)) {
if (win.hasWallpaper()) {
win.getDisplayContent().pendingLayoutChanges |=
WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
@@ -3231,8 +3252,8 @@ public class WindowManagerService extends IWindowManager.Stub
if (!checkCallingPermission(permission.CONTROL_KEYGUARD, "dismissKeyguard")) {
throw new SecurityException("Requires CONTROL_KEYGUARD permission");
}
- if (mAtmService.isDreaming()) {
- mAtmService.mTaskSupervisor.wakeUp("dismissKeyguard");
+ if (mAtmService.mKeyguardController.isShowingDream()) {
+ mAtmService.mTaskSupervisor.wakeUp("leaveDream");
}
synchronized (mGlobalLock) {
mPolicy.dismissKeyguardLw(callback, message);
@@ -3260,7 +3281,7 @@ public class WindowManagerService extends IWindowManager.Stub
mContext.enforceCallingOrSelfPermission(
Manifest.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE,
Manifest.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE
- + " permission required to read keyguard visibility");
+ + " permission required to subscribe to keyguard locked state changes");
}
private void dispatchKeyguardLockedState() {
@@ -6437,9 +6458,13 @@ public class WindowManagerService extends IWindowManager.Stub
imeWindow.writeIdentifierToProto(proto, INPUT_METHOD_WINDOW);
}
proto.write(DISPLAY_FROZEN, mDisplayFrozen);
- final DisplayContent defaultDisplayContent = getDefaultDisplayContentLocked();
proto.write(FOCUSED_DISPLAY_ID, topFocusedDisplayContent.getDisplayId());
proto.write(HARD_KEYBOARD_AVAILABLE, mHardKeyboardAvailable);
+
+ // This is always true for now since we still update the window frames at the server side.
+ // Once we move the window layout to the client side, this can be false when we are waiting
+ // for the frames.
+ proto.write(WINDOW_FRAMES_VALID, true);
}
private void dumpWindowsLocked(PrintWriter pw, boolean dumpAll,
@@ -7963,18 +7988,20 @@ public class WindowManagerService extends IWindowManager.Stub
}
@Override
- public void addNonHighRefreshRatePackage(@NonNull String packageName) {
+ public void addRefreshRateRangeForPackage(@NonNull String packageName,
+ float minRefreshRate, float maxRefreshRate) {
synchronized (mGlobalLock) {
mRoot.forAllDisplays(dc -> dc.getDisplayPolicy().getRefreshRatePolicy()
- .addNonHighRefreshRatePackage(packageName));
+ .addRefreshRateRangeForPackage(
+ packageName, minRefreshRate, maxRefreshRate));
}
}
@Override
- public void removeNonHighRefreshRatePackage(@NonNull String packageName) {
+ public void removeRefreshRateRangeForPackage(@NonNull String packageName) {
synchronized (mGlobalLock) {
mRoot.forAllDisplays(dc -> dc.getDisplayPolicy().getRefreshRatePolicy()
- .removeNonHighRefreshRatePackage(packageName));
+ .removeRefreshRateRangeForPackage(packageName));
}
}
@@ -8447,43 +8474,48 @@ public class WindowManagerService extends IWindowManager.Stub
}
private void updateInputChannel(IBinder channelToken, int callingUid, int callingPid,
- int displayId, SurfaceControl surface, String name,
- InputApplicationHandle applicationHandle, int flags,
- int privateFlags, int type, Region region, IWindow window) {
- InputWindowHandle h = new InputWindowHandle(applicationHandle, displayId);
+ int displayId, SurfaceControl surface, String name,
+ InputApplicationHandle applicationHandle, int flags,
+ int privateFlags, int type, Region region, IWindow window) {
+ final InputWindowHandle h = new InputWindowHandle(applicationHandle, displayId);
h.token = channelToken;
h.setWindowToken(window);
h.name = name;
flags = sanitizeFlagSlippery(flags, name, callingUid, callingPid);
- final int sanitizedFlags = flags & (FLAG_NOT_TOUCHABLE
- | FLAG_SLIPPERY | LayoutParams.FLAG_NOT_FOCUSABLE);
- h.layoutParamsFlags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | sanitizedFlags;
+ final int sanitizedLpFlags =
+ (flags & (FLAG_NOT_TOUCHABLE | FLAG_SLIPPERY | LayoutParams.FLAG_NOT_FOCUSABLE))
+ | LayoutParams.FLAG_NOT_TOUCH_MODAL;
h.layoutParamsType = type;
- h.dispatchingTimeoutMillis = DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
- h.focusable = (flags & LayoutParams.FLAG_NOT_FOCUSABLE) == 0;
- h.hasWallpaper = false;
- h.paused = false;
+ h.layoutParamsFlags = sanitizedLpFlags;
+ // Do not allow any input features to be set without sanitizing them first.
+ h.inputConfig = InputConfigAdapter.getInputConfigFromWindowParams(
+ type, sanitizedLpFlags, 0 /*inputFeatures*/);
+
+
+ if ((flags & LayoutParams.FLAG_NOT_FOCUSABLE) != 0) {
+ h.inputConfig |= InputConfig.NOT_FOCUSABLE;
+ }
+
+ // Check private trusted overlay flag to set trustedOverlay field of input window handle.
+ if ((privateFlags & PRIVATE_FLAG_TRUSTED_OVERLAY) != 0) {
+ h.inputConfig |= InputConfig.TRUSTED_OVERLAY;
+ }
+
+ h.dispatchingTimeoutMillis = DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
h.ownerUid = callingUid;
h.ownerPid = callingPid;
- // Do not allow any input features to be set without sanitizing them first.
- h.inputFeatures = 0;
-
if (region == null) {
- h.replaceTouchableRegionWithCrop(null);
+ h.replaceTouchableRegionWithCrop = true;
} else {
h.touchableRegion.set(region);
- h.replaceTouchableRegionWithCrop = false;
- h.setTouchableRegionCrop(surface);
}
+ h.setTouchableRegionCrop(null /* use the input surface's bounds */);
- // Check private trusted overlay flag to set trustedOverlay field of input window handle.
- h.trustedOverlay = (privateFlags & PRIVATE_FLAG_TRUSTED_OVERLAY) != 0;
-
- SurfaceControl.Transaction t = mTransactionFactory.get();
+ final SurfaceControl.Transaction t = mTransactionFactory.get();
t.setInputWindowInfo(surface, h);
t.apply();
t.close();
diff --git a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
index 1cf4c1b0fbb2..5a2f28f4a365 100644
--- a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
+++ b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
@@ -566,9 +566,14 @@ public class WindowManagerShellCommand extends ShellCommand {
try (ZipOutputStream out = new ZipOutputStream(getRawOutputStream())) {
ArrayList<Pair<String, ByteTransferPipe>> requestList = new ArrayList<>();
synchronized (mInternal.mGlobalLock) {
+ final RecentTasks recentTasks = mInternal.mAtmService.getRecentTasks();
+ final int recentsComponentUid = recentTasks != null
+ ? recentTasks.getRecentsComponentUid()
+ : -1;
// Request dump from all windows parallelly before writing to disk.
mInternal.mRoot.forAllWindows(w -> {
- if (w.isVisible()) {
+ final boolean isRecents = (w.getUid() == recentsComponentUid);
+ if (w.isVisible() || isRecents) {
ByteTransferPipe pipe = null;
try {
pipe = new ByteTransferPipe();
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index ce27d739e1b1..044da3982e26 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -94,6 +94,7 @@ import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import java.util.function.IntSupplier;
/**
* Server side implementation for the interface for organizing windows
@@ -701,6 +702,8 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
sendTaskFragmentOperationFailure(tf.getTaskFragmentOrganizer(),
errorCallbackToken,
convertStartFailureToThrowable(result, activityIntent));
+ } else {
+ effects |= TRANSACT_EFFECTS_LIFECYCLE;
}
break;
}
@@ -808,26 +811,8 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
launchOpts.remove(WindowContainerTransaction.HierarchyOp.LAUNCH_KEY_TASK_ID);
final SafeActivityOptions safeOptions =
SafeActivityOptions.fromBundle(launchOpts, caller.mPid, caller.mUid);
- final Integer[] starterResult = {null};
- // startActivityFromRecents should not be called in lock.
- mService.mH.post(() -> {
- try {
- starterResult[0] = mService.mTaskSupervisor.startActivityFromRecents(
- caller.mPid, caller.mUid, taskId, safeOptions);
- } catch (Throwable t) {
- starterResult[0] = ActivityManager.START_CANCELED;
- Slog.w(TAG, t);
- }
- synchronized (mGlobalLock) {
- mGlobalLock.notifyAll();
- }
- });
- while (starterResult[0] == null) {
- try {
- mGlobalLock.wait();
- } catch (InterruptedException ignored) {
- }
- }
+ waitAsyncStart(() -> mService.mTaskSupervisor.startActivityFromRecents(
+ caller.mPid, caller.mUid, taskId, safeOptions));
break;
}
case HIERARCHY_OP_TYPE_PENDING_INTENT: {
@@ -836,22 +821,22 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
mService.mContext.getContentResolver())
: null;
- Bundle options = null;
+ ActivityOptions activityOptions = null;
if (hop.getPendingIntent().isActivity()) {
// Set the context display id as preferred for this activity launches, so that
// it can land on caller's display. Or just brought the task to front at the
// display where it was on since it has higher preference.
- ActivityOptions activityOptions = hop.getLaunchOptions() != null
+ activityOptions = hop.getLaunchOptions() != null
? new ActivityOptions(hop.getLaunchOptions())
: ActivityOptions.makeBasic();
activityOptions.setCallerDisplayId(DEFAULT_DISPLAY);
- options = activityOptions.toBundle();
}
-
- mService.mAmInternal.sendIntentSender(hop.getPendingIntent().getTarget(),
+ final Bundle options = activityOptions != null ? activityOptions.toBundle() : null;
+ waitAsyncStart(() -> mService.mAmInternal.sendIntentSender(
+ hop.getPendingIntent().getTarget(),
hop.getPendingIntent().getWhitelistToken(), 0 /* code */,
hop.getActivityIntent(), resolvedType, null /* finishReceiver */,
- null /* requiredPermission */, options);
+ null /* requiredPermission */, options));
break;
}
case HIERARCHY_OP_TYPE_START_SHORTCUT: {
@@ -912,6 +897,31 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
return effects;
}
+ /**
+ * Post and wait for the result of the activity start to prevent potential deadlock against
+ * {@link WindowManagerGlobalLock}.
+ */
+ private void waitAsyncStart(IntSupplier startActivity) {
+ final Integer[] starterResult = {null};
+ mService.mH.post(() -> {
+ try {
+ starterResult[0] = startActivity.getAsInt();
+ } catch (Throwable t) {
+ starterResult[0] = ActivityManager.START_CANCELED;
+ Slog.w(TAG, t);
+ }
+ synchronized (mGlobalLock) {
+ mGlobalLock.notifyAll();
+ }
+ });
+ while (starterResult[0] == null) {
+ try {
+ mGlobalLock.wait();
+ } catch (InterruptedException ignored) {
+ }
+ }
+ }
+
private int sanitizeAndApplyHierarchyOp(WindowContainer container,
WindowContainerTransaction.HierarchyOp hop) {
final Task task = container.asTask();
@@ -1468,6 +1478,10 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
return mLaunchTaskFragments.get(tfToken);
}
+ void cleanUpEmbeddedTaskFragment(TaskFragment taskFragment) {
+ mLaunchTaskFragments.remove(taskFragment.getFragmentToken());
+ }
+
static class CallerInfo {
final int mPid;
final int mUid;
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index ccd42364f6a3..bb7876734260 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -37,6 +37,9 @@ import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_
import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME;
import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION;
import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_VISIBLE;
+import static android.view.WindowCallbacks.RESIZE_MODE_DOCKED_DIVIDER;
+import static android.view.WindowCallbacks.RESIZE_MODE_FREEFORM;
+import static android.view.WindowCallbacks.RESIZE_MODE_INVALID;
import static android.view.WindowInsets.Type.systemBars;
import static android.view.WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
import static android.view.WindowLayout.UNSPECIFIED_LENGTH;
@@ -98,8 +101,6 @@ import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
import static android.view.WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
import static android.view.WindowManager.LayoutParams.isSystemAlertWindowType;
-import static android.view.WindowManagerGlobal.RELAYOUT_RES_DRAG_RESIZING_DOCKED;
-import static android.view.WindowManagerGlobal.RELAYOUT_RES_DRAG_RESIZING_FREEFORM;
import static android.view.WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME;
import static android.view.WindowManagerPolicyConstants.TYPE_LAYER_MULTIPLIER;
import static android.view.WindowManagerPolicyConstants.TYPE_LAYER_OFFSET;
@@ -134,6 +135,7 @@ import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITIO
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS;
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_STARTING_REVEAL;
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_WINDOW_ANIMATION;
+import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
import static com.android.server.wm.WindowContainerChildProto.WINDOW;
@@ -141,7 +143,6 @@ import static com.android.server.wm.WindowManagerDebugConfig.DEBUG;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_CONFIGURATION;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_INPUT_METHOD;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_POWER;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW_VERBOSE;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
@@ -368,7 +369,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
private boolean mDragResizingChangeReported = true;
private int mResizeMode;
private boolean mRedrawForSyncReported;
- boolean mNextRelayoutUseSync;
+ int mSyncSeqId = 0;
+ int mLastSeqIdSentToRelayout = 0;
/**
* {@code true} when the client was still drawing for sync when the sync-set was finished or
@@ -859,6 +861,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
/**
* @see #setOnBackInvokedCallback(IOnBackInvokedCallback)
*/
+ // TODO(b/224856664): Consolidate application and system callback into one.
private IOnBackInvokedCallback mApplicationOnBackInvokedCallback;
private IOnBackInvokedCallback mSystemOnBackInvokedCallback;
@@ -1124,7 +1127,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
this, onBackInvokedCallback);
if (priority >= 0) {
mApplicationOnBackInvokedCallback = onBackInvokedCallback;
+ mSystemOnBackInvokedCallback = null;
} else {
+ mApplicationOnBackInvokedCallback = null;
mSystemOnBackInvokedCallback = onBackInvokedCallback;
}
}
@@ -1190,6 +1195,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
mActivityRecord != null
? mActivityRecord.getInputApplicationHandle(false /* update */) : null,
getDisplayId()));
+ mInputWindowHandle.setFocusable(false);
mInputWindowHandle.setOwnerPid(s.mPid);
mInputWindowHandle.setOwnerUid(s.mUid);
mInputWindowHandle.setName(getName());
@@ -1392,15 +1398,19 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
// TODO(b/161810301): Make the frame be passed from the client side.
- void setFrame() {
- // TODO(b/161810301): Set the window frame here. We don't have to do it now because
- // DisplayPolicy has already done it for the window.
-
+ void setFrames(ClientWindowFrames clientWindowFrames) {
mHaveFrame = true;
final WindowFrames windowFrames = mWindowFrames;
-
- if (mRequestedWidth != mLastRequestedWidth || mRequestedHeight != mLastRequestedHeight) {
+ mTmpRect.set(windowFrames.mParentFrame);
+ windowFrames.mDisplayFrame.set(clientWindowFrames.displayFrame);
+ windowFrames.mParentFrame.set(clientWindowFrames.parentFrame);
+ windowFrames.mFrame.set(clientWindowFrames.frame);
+ windowFrames.setParentFrameWasClippedByDisplayCutout(
+ clientWindowFrames.isParentFrameClippedByDisplayCutout);
+
+ if (mRequestedWidth != mLastRequestedWidth || mRequestedHeight != mLastRequestedHeight
+ || !mTmpRect.equals(windowFrames.mParentFrame)) {
mLastRequestedWidth = mRequestedWidth;
mLastRequestedHeight = mRequestedHeight;
windowFrames.setContentChanged(true);
@@ -1429,16 +1439,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
windowFrames.mRelFrame.offsetTo(windowFrames.mFrame.left - parentLeft,
windowFrames.mFrame.top - parentTop);
- if (DEBUG_LAYOUT || DEBUG) {
- final int pw = windowFrames.mParentFrame.width();
- final int ph = windowFrames.mParentFrame.height();
- Slog.v(TAG, "Resolving (mRequestedWidth="
- + mRequestedWidth + ", mRequestedheight="
- + mRequestedHeight + ") to" + " (pw=" + pw + ", ph=" + ph
- + "): frame=" + windowFrames.mFrame.toShortString()
- + " " + mAttrs.getTitle());
- }
-
if (mAttrs.type == TYPE_DOCK_DIVIDER) {
if (!windowFrames.mFrame.equals(windowFrames.mLastFrame)) {
mMovedByResize = true;
@@ -1453,9 +1453,19 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
}
- // Update the source frame to provide insets to other windows during layout.
- if (mControllableInsetProvider != null) {
- mControllableInsetProvider.updateSourceFrame();
+ updateSourceFrame(windowFrames.mFrame);
+ }
+
+ void updateSourceFrame(Rect winFrame) {
+ if (mGivenInsetsPending) {
+ // The given insets are pending, and they are not reliable for now. The source frame
+ // should be updated after the new given insets are sent to window manager.
+ return;
+ }
+ final SparseArray<InsetsSource> providedSources = getProvidedInsetsSources();
+ final InsetsStateController controller = getDisplayContent().getInsetsStateController();
+ for (int i = providedSources.size() - 1; i >= 0; i--) {
+ controller.getSourceProvider(providedSources.keyAt(i)).updateSourceFrame(winFrame);
}
}
@@ -2609,8 +2619,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
mWmService.mAccessibilityController.onWindowTransition(this, transit);
}
}
- final boolean isAnimating = mAnimatingExit
- || isAnimating(TRANSITION | PARENTS, EXIT_ANIMATING_TYPES);
+ final boolean isAnimating = mAnimatingExit || isExitAnimationRunningSelfOrParent();
final boolean lastWindowIsStartingWindow = startingWindow && mActivityRecord != null
&& mActivityRecord.isLastWindow(this);
// We delay the removal of a window if it has a showing surface that can be used to run
@@ -3584,6 +3593,10 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
// Clear animating flags now, since the surface is now gone. (Note this is true even
// if the surface is saved, to outside world the surface is still NO_SURFACE.)
mAnimatingExit = false;
+
+ if (useBLASTSync()) {
+ immediatelyNotifyBlastSync();
+ }
}
void onSurfaceShownChanged(boolean shown) {
@@ -3931,17 +3944,34 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
true /* useLatestConfig */, false /* relayoutVisible */);
final boolean syncRedraw = shouldSendRedrawForSync();
final boolean reportDraw = syncRedraw || drawPending;
- final boolean forceRelayout = syncRedraw || reportOrientation || isDragResizeChanged();
+ final boolean isDragResizeChanged = isDragResizeChanged();
+ final boolean forceRelayout = syncRedraw || reportOrientation || isDragResizeChanged;
final DisplayContent displayContent = getDisplayContent();
final boolean alwaysConsumeSystemBars =
displayContent.getDisplayPolicy().areSystemBarsForcedShownLw();
final int displayId = displayContent.getDisplayId();
+ if (isDragResizeChanged) {
+ setDragResizing();
+ }
+ int resizeMode = RESIZE_MODE_INVALID;
+ if (isDragResizing()) {
+ switch (getResizeMode()) {
+ case DRAG_RESIZE_MODE_FREEFORM:
+ resizeMode = RESIZE_MODE_FREEFORM;
+ break;
+ case DRAG_RESIZE_MODE_DOCKED_DIVIDER:
+ resizeMode = RESIZE_MODE_DOCKED_DIVIDER;
+ break;
+ }
+ }
+
markRedrawForSyncReported();
try {
mClient.resized(mClientWindowFrames, reportDraw, mLastReportedConfiguration,
- forceRelayout, alwaysConsumeSystemBars, displayId);
+ forceRelayout, alwaysConsumeSystemBars, displayId, Integer.MAX_VALUE,
+ resizeMode);
if (drawPending && reportOrientation && mOrientationChanging) {
mOrientationChangeRedrawRequestTime = SystemClock.elapsedRealtime();
ProtoLog.v(WM_DEBUG_ORIENTATION,
@@ -4972,6 +5002,15 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
return false;
}
+ boolean isExitAnimationRunningSelfOrParent() {
+ return inAppOrRecentsTransition()
+ || isAnimating(0 /* flags */, ANIMATION_TYPE_WINDOW_ANIMATION);
+ }
+
+ boolean isExitAnimationRunningSelfOrChild() {
+ return isAnimating(CHILDREN, ANIMATION_TYPE_WINDOW_ANIMATION);
+ }
+
private boolean shouldFinishAnimatingExit() {
// Exit animation might be applied soon.
if (inTransition()) {
@@ -4983,7 +5022,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
return true;
}
// Exit animation is running.
- if (isAnimating(TRANSITION | PARENTS, EXIT_ANIMATING_TYPES)) {
+ if (isExitAnimationRunningSelfOrParent()) {
ProtoLog.d(WM_DEBUG_APP_TRANSITIONS, "shouldWaitAnimatingExit: isAnimating: %s",
this);
return false;
@@ -5076,7 +5115,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
@Override
boolean handleCompleteDeferredRemoval() {
- if (mRemoveOnExit && !isSelfAnimating(0 /* flags */, EXIT_ANIMATING_TYPES)) {
+ if (mRemoveOnExit && !isSelfAnimating(0 /* flags */, ANIMATION_TYPE_WINDOW_ANIMATION)) {
mRemoveOnExit = false;
removeImmediately();
}
@@ -5196,15 +5235,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
- if (isDragResizeChanged()) {
- setDragResizing();
- }
- final boolean freeformResizing = isDragResizing()
- && getResizeMode() == DRAG_RESIZE_MODE_FREEFORM;
- final boolean dockedResizing = isDragResizing()
- && getResizeMode() == DRAG_RESIZE_MODE_DOCKED_DIVIDER;
- result |= freeformResizing ? RELAYOUT_RES_DRAG_RESIZING_FREEFORM : 0;
- result |= dockedResizing ? RELAYOUT_RES_DRAG_RESIZING_DOCKED : 0;
return result;
}
@@ -5242,6 +5272,12 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
if (mControllableInsetProvider != null) {
return;
}
+ if (mDisplayContent.inTransition()) {
+ // Skip because the animation is usually unnoticeable (e.g. covered by rotation
+ // animation) and the animation bounds could be inconsistent, such as depending
+ // on when the window applies its draw transaction with new rotation.
+ return;
+ }
final DisplayInfo displayInfo = getDisplayInfo();
anim.initialize(mWindowFrames.mFrame.width(), mWindowFrames.mFrame.height(),
@@ -5486,10 +5522,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
float newHScale = mHScale * mGlobalScale * mWallpaperScale;
float newVScale = mVScale * mGlobalScale * mWallpaperScale;
- if (mLastHScale != newHScale ||
- mLastVScale != newVScale ) {
- getPendingTransaction().setMatrix(getSurfaceControl(),
- newHScale, 0, 0, newVScale);
+ if (mLastHScale != newHScale || mLastVScale != newVScale) {
+ getSyncTransaction().setMatrix(mSurfaceControl, newHScale, 0, 0, newVScale);
mLastHScale = newHScale;
mLastVScale = newVScale;
}
@@ -5909,7 +5943,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
// to draw even if the children draw first or don't need to sync, so we start
// in WAITING state rather than READY.
mSyncState = SYNC_STATE_WAITING_FOR_DRAW;
- mNextRelayoutUseSync = true;
+ mSyncSeqId++;
requestRedrawForSync();
return true;
}
@@ -5933,7 +5967,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
super.finishSync(outMergedTransaction, cancel);
}
- boolean finishDrawing(SurfaceControl.Transaction postDrawTransaction) {
+ boolean finishDrawing(SurfaceControl.Transaction postDrawTransaction, int syncSeqId) {
if (mOrientationChangeRedrawRequestTime > 0) {
final long duration =
SystemClock.elapsedRealtime() - mOrientationChangeRedrawRequestTime;
@@ -5980,18 +6014,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
void immediatelyNotifyBlastSync() {
prepareDrawHandlers();
- finishDrawing(null);
+ finishDrawing(null, Integer.MAX_VALUE);
mWmService.mH.removeMessages(WINDOW_STATE_BLAST_SYNC_TIMEOUT, this);
if (!useBLASTSync()) return;
-
- final Task task = getTask();
- if (task != null) {
- final SurfaceControl.Transaction t = task.getMainWindowSizeChangeTransaction();
- if (t != null) {
- mSyncTransaction.merge(t);
- }
- task.setMainWindowSizeChangeTransaction(null);
- }
}
@Override
@@ -6028,10 +6053,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
if (mRedrawForSyncReported) {
return false;
}
- final Task task = getTask();
- if (task != null && task.getMainWindowSizeChangeTransaction() != null) {
- return true;
- }
return useBLASTSync();
}
@@ -6065,7 +6086,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
*/
void applyWithNextDraw(Consumer<SurfaceControl.Transaction> consumer) {
mPendingDrawHandlers.add(consumer);
- mNextRelayoutUseSync = true;
+ mSyncSeqId++;
requestRedrawForSync();
mWmService.mH.sendNewMessageDelayed(WINDOW_STATE_BLAST_SYNC_TIMEOUT, this,
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index c17961e8a564..285a6d5bdf5f 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -442,50 +442,6 @@ class WindowStateAnimator {
return mService.useBLASTSync() && mWin.useBLASTSync();
}
- private boolean shouldConsumeMainWindowSizeTransaction() {
- // We only consume the transaction when the client is calling relayout
- // because this is the only time we know the frameNumber will be valid
- // due to the client renderer being paused. Put otherwise, only when
- // mInRelayout is true can we guarantee the next frame will contain
- // the most recent configuration.
- if (!mWin.mInRelayout) return false;
- // Since we can only do this for one window, we focus on the main application window
- if (mAttrType != TYPE_BASE_APPLICATION) return false;
- final Task task = mWin.getTask();
- if (task == null) return false;
- if (task.getMainWindowSizeChangeTransaction() == null) return false;
- // Likewise we only focus on the task root, since we can only use one window
- if (!mWin.mActivityRecord.isRootOfTask()) return false;
- return true;
- }
-
- void setSurfaceBoundariesLocked(SurfaceControl.Transaction t) {
- if (mSurfaceController == null) {
- return;
- }
-
- final WindowState w = mWin;
- final Task task = w.getTask();
- if (shouldConsumeMainWindowSizeTransaction()) {
- if (isInBlastSync()) {
- // If we're in a sync transaction, there's no need to call defer transaction.
- // The sync transaction will contain the buffer so the bounds change transaction
- // will only be applied with the buffer.
- t.merge(task.getMainWindowSizeChangeTransaction());
- task.setMainWindowSizeChangeTransaction(null);
- } else {
- mWin.applyWithNextDraw(finishedFrame -> {
- final SurfaceControl.Transaction sizeChangedTransaction =
- task.getMainWindowSizeChangeTransaction();
- if (sizeChangedTransaction != null) {
- finishedFrame.merge(sizeChangedTransaction);
- task.setMainWindowSizeChangeTransaction(null);
- }
- });
- }
- }
- }
-
void prepareSurfaceLocked(SurfaceControl.Transaction t) {
final WindowState w = mWin;
if (!hasSurface()) {
@@ -501,8 +457,6 @@ class WindowStateAnimator {
computeShownFrameLocked();
- setSurfaceBoundariesLocked(t);
-
if (w.isParentWindowHidden() || !w.isOnScreen()) {
hide(t, "prepareSurfaceLocked");
mWallpaperControllerLocked.hideWallpapers(w);
diff --git a/services/core/jni/gnss/MeasurementCorrections.cpp b/services/core/jni/gnss/MeasurementCorrections.cpp
index 8a3d84cbe9c6..07d0a45e9c40 100644
--- a/services/core/jni/gnss/MeasurementCorrections.cpp
+++ b/services/core/jni/gnss/MeasurementCorrections.cpp
@@ -44,6 +44,7 @@ using SingleSatCorrection_Aidl =
using ReflectingPlane_V1_0 =
android::hardware::gnss::measurement_corrections::V1_0::ReflectingPlane;
using ReflectingPlane_Aidl = android::hardware::gnss::measurement_corrections::ReflectingPlane;
+using ExcessPathInfo = SingleSatCorrection_Aidl::ExcessPathInfo;
using GnssConstellationType_V1_0 = android::hardware::gnss::V1_0::GnssConstellationType;
using GnssConstellationType_V2_0 = android::hardware::gnss::V2_0::GnssConstellationType;
using GnssConstellationType_Aidl = android::hardware::gnss::GnssConstellationType;
@@ -62,7 +63,7 @@ jmethodID method_correctionsHasEnvironmentBearing;
jmethodID method_correctionsGetEnvironmentBearingDegrees;
jmethodID method_correctionsGetEnvironmentBearingUncertaintyDegrees;
jmethodID method_listSize;
-jmethodID method_correctionListGet;
+jmethodID method_listGet;
jmethodID method_correctionSatFlags;
jmethodID method_correctionSatConstType;
jmethodID method_correctionSatId;
@@ -71,10 +72,17 @@ jmethodID method_correctionSatIsLosProb;
jmethodID method_correctionSatEpl;
jmethodID method_correctionSatEplUnc;
jmethodID method_correctionSatRefPlane;
+jmethodID method_correctionSatAttenuation;
+jmethodID method_correctionSatExcessPathInfoList;
jmethodID method_correctionPlaneLatDeg;
jmethodID method_correctionPlaneLngDeg;
jmethodID method_correctionPlaneAltDeg;
jmethodID method_correctionPlaneAzimDeg;
+jmethodID method_excessPathInfoFlags;
+jmethodID method_excessPathInfoEpl;
+jmethodID method_excessPathInfoEplUnc;
+jmethodID method_excessPathInfoRefPlane;
+jmethodID method_excessPathInfoAttenuation;
} // anonymous namespace
void MeasurementCorrections_class_init_once(JNIEnv* env, jclass clazz) {
@@ -103,7 +111,7 @@ void MeasurementCorrections_class_init_once(JNIEnv* env, jclass clazz) {
jclass corrListClass = env->FindClass("java/util/List");
method_listSize = env->GetMethodID(corrListClass, "size", "()I");
- method_correctionListGet = env->GetMethodID(corrListClass, "get", "(I)Ljava/lang/Object;");
+ method_listGet = env->GetMethodID(corrListClass, "get", "(I)Ljava/lang/Object;");
jclass singleSatCorrClass = env->FindClass("android/location/GnssSingleSatCorrection");
method_correctionSatFlags =
@@ -121,12 +129,27 @@ void MeasurementCorrections_class_init_once(JNIEnv* env, jclass clazz) {
env->GetMethodID(singleSatCorrClass, "getExcessPathLengthUncertaintyMeters", "()F");
method_correctionSatRefPlane = env->GetMethodID(singleSatCorrClass, "getReflectingPlane",
"()Landroid/location/GnssReflectingPlane;");
+ method_correctionSatAttenuation =
+ env->GetMethodID(singleSatCorrClass, "getCombinedAttenuationDb", "()F");
+ method_correctionSatExcessPathInfoList =
+ env->GetMethodID(singleSatCorrClass, "getGnssExcessPathInfoList", "()Ljava/util/List;");
jclass refPlaneClass = env->FindClass("android/location/GnssReflectingPlane");
method_correctionPlaneLatDeg = env->GetMethodID(refPlaneClass, "getLatitudeDegrees", "()D");
method_correctionPlaneLngDeg = env->GetMethodID(refPlaneClass, "getLongitudeDegrees", "()D");
method_correctionPlaneAltDeg = env->GetMethodID(refPlaneClass, "getAltitudeMeters", "()D");
method_correctionPlaneAzimDeg = env->GetMethodID(refPlaneClass, "getAzimuthDegrees", "()D");
+
+ jclass excessPathInfoClass = env->FindClass("android/location/GnssExcessPathInfo");
+ method_excessPathInfoFlags = env->GetMethodID(excessPathInfoClass, "getFlags", "()I");
+ method_excessPathInfoEpl =
+ env->GetMethodID(excessPathInfoClass, "getExcessPathLengthMeters", "()F");
+ method_excessPathInfoEplUnc =
+ env->GetMethodID(excessPathInfoClass, "getExcessPathLengthUncertaintyMeters", "()F");
+ method_excessPathInfoRefPlane = env->GetMethodID(excessPathInfoClass, "getReflectingPlane",
+ "()Landroid/location/GnssReflectingPlane;");
+ method_excessPathInfoAttenuation =
+ env->GetMethodID(excessPathInfoClass, "getAttenuationDb", "()F");
}
template <>
@@ -324,7 +347,8 @@ jboolean MeasurementCorrectionsIface_V1_1::setCallback(
SingleSatCorrection_V1_0
MeasurementCorrectionsUtil::getSingleSatCorrection_1_0_withoutConstellation(
JNIEnv* env, jobject singleSatCorrectionObj) {
- jint correctionFlags = env->CallIntMethod(singleSatCorrectionObj, method_correctionSatFlags);
+ uint16_t corrFlags = static_cast<uint16_t>(
+ env->CallIntMethod(singleSatCorrectionObj, method_correctionSatFlags));
jint satId = env->CallIntMethod(singleSatCorrectionObj, method_correctionSatId);
jfloat carrierFreqHz =
env->CallFloatMethod(singleSatCorrectionObj, method_correctionSatCarrierFreq);
@@ -332,14 +356,16 @@ MeasurementCorrectionsUtil::getSingleSatCorrection_1_0_withoutConstellation(
env->CallFloatMethod(singleSatCorrectionObj, method_correctionSatIsLosProb);
jfloat eplMeters = env->CallFloatMethod(singleSatCorrectionObj, method_correctionSatEpl);
jfloat eplUncMeters = env->CallFloatMethod(singleSatCorrectionObj, method_correctionSatEplUnc);
- uint16_t corrFlags = static_cast<uint16_t>(correctionFlags);
ReflectingPlane_V1_0 reflectingPlane;
- if ((corrFlags & GnssSingleSatCorrectionFlags_V1_0::HAS_REFLECTING_PLANE) != 0)
- MeasurementCorrectionsUtil::getReflectingPlane<ReflectingPlane_V1_0>(env,
- singleSatCorrectionObj,
+ if ((corrFlags & GnssSingleSatCorrectionFlags_V1_0::HAS_REFLECTING_PLANE) != 0) {
+ jobject reflectingPlaneObj =
+ env->CallObjectMethod(singleSatCorrectionObj, method_correctionSatRefPlane);
+ MeasurementCorrectionsUtil::setReflectingPlane<ReflectingPlane_V1_0>(env,
+ reflectingPlaneObj,
reflectingPlane);
-
+ env->DeleteLocalRef(reflectingPlaneObj);
+ }
SingleSatCorrection_V1_0 singleSatCorrection = {
.singleSatCorrectionFlags = corrFlags,
.svid = static_cast<uint16_t>(satId),
@@ -349,13 +375,14 @@ MeasurementCorrectionsUtil::getSingleSatCorrection_1_0_withoutConstellation(
.excessPathLengthUncertaintyMeters = eplUncMeters,
.reflectingPlane = reflectingPlane,
};
-
return singleSatCorrection;
}
SingleSatCorrection_Aidl MeasurementCorrectionsUtil::getSingleSatCorrection_Aidl(
JNIEnv* env, jobject singleSatCorrectionObj) {
- jint correctionFlags = env->CallIntMethod(singleSatCorrectionObj, method_correctionSatFlags);
+ int32_t corrFlags = static_cast<int32_t>(
+ env->CallIntMethod(singleSatCorrectionObj, method_correctionSatFlags));
+ jint constType = env->CallIntMethod(singleSatCorrectionObj, method_correctionSatConstType);
jint satId = env->CallIntMethod(singleSatCorrectionObj, method_correctionSatId);
jfloat carrierFreqHz =
env->CallFloatMethod(singleSatCorrectionObj, method_correctionSatCarrierFreq);
@@ -363,15 +390,10 @@ SingleSatCorrection_Aidl MeasurementCorrectionsUtil::getSingleSatCorrection_Aidl
env->CallFloatMethod(singleSatCorrectionObj, method_correctionSatIsLosProb);
jfloat eplMeters = env->CallFloatMethod(singleSatCorrectionObj, method_correctionSatEpl);
jfloat eplUncMeters = env->CallFloatMethod(singleSatCorrectionObj, method_correctionSatEplUnc);
- int32_t corrFlags = static_cast<int32_t>(correctionFlags);
-
- ReflectingPlane_Aidl reflectingPlane;
- if ((corrFlags & SingleSatCorrection_Aidl::SINGLE_SAT_CORRECTION_HAS_REFLECTING_PLANE) != 0)
- MeasurementCorrectionsUtil::getReflectingPlane<ReflectingPlane_Aidl>(env,
- singleSatCorrectionObj,
- reflectingPlane);
-
- jint constType = env->CallIntMethod(singleSatCorrectionObj, method_correctionSatConstType);
+ jfloat attenuationDb =
+ env->CallFloatMethod(singleSatCorrectionObj, method_correctionSatAttenuation);
+ std::vector<ExcessPathInfo> excessPathInfos =
+ MeasurementCorrectionsUtil::getExcessPathInfoList(env, singleSatCorrectionObj);
SingleSatCorrection_Aidl singleSatCorrection;
singleSatCorrection.singleSatCorrectionFlags = corrFlags;
@@ -379,9 +401,10 @@ SingleSatCorrection_Aidl MeasurementCorrectionsUtil::getSingleSatCorrection_Aidl
singleSatCorrection.svid = static_cast<int32_t>(satId);
singleSatCorrection.carrierFrequencyHz = carrierFreqHz;
singleSatCorrection.probSatIsLos = probSatIsLos;
- singleSatCorrection.excessPathLengthMeters = eplMeters;
- singleSatCorrection.excessPathLengthUncertaintyMeters = eplUncMeters;
- singleSatCorrection.reflectingPlane = reflectingPlane;
+ singleSatCorrection.combinedExcessPathLengthMeters = eplMeters;
+ singleSatCorrection.combinedExcessPathLengthUncertaintyMeters = eplUncMeters;
+ singleSatCorrection.combinedAttenuationDb = attenuationDb;
+ singleSatCorrection.excessPathInfos = excessPathInfos;
return singleSatCorrection;
}
@@ -391,8 +414,7 @@ void MeasurementCorrectionsUtil::getSingleSatCorrectionList_1_0(
hardware::hidl_vec<SingleSatCorrection_V1_0>& list) {
for (uint16_t i = 0; i < list.size(); ++i) {
jobject singleSatCorrectionObj =
- env->CallObjectMethod(singleSatCorrectionList, method_correctionListGet, i);
-
+ env->CallObjectMethod(singleSatCorrectionList, method_listGet, i);
SingleSatCorrection_V1_0 singleSatCorrection =
getSingleSatCorrection_1_0_withoutConstellation(env, singleSatCorrectionObj);
@@ -410,7 +432,7 @@ void MeasurementCorrectionsUtil::getSingleSatCorrectionList_1_1(
hardware::hidl_vec<SingleSatCorrection_V1_1>& list) {
for (uint16_t i = 0; i < list.size(); ++i) {
jobject singleSatCorrectionObj =
- env->CallObjectMethod(singleSatCorrectionList, method_correctionListGet, i);
+ env->CallObjectMethod(singleSatCorrectionList, method_listGet, i);
SingleSatCorrection_V1_0 singleSatCorrection_1_0 =
getSingleSatCorrection_1_0_withoutConstellation(env, singleSatCorrectionObj);
@@ -431,7 +453,7 @@ void MeasurementCorrectionsUtil::getSingleSatCorrectionList_Aidl(
JNIEnv* env, jobject singleSatCorrectionList, std::vector<SingleSatCorrection_Aidl>& list) {
for (uint16_t i = 0; i < list.size(); ++i) {
jobject singleSatCorrectionObj =
- env->CallObjectMethod(singleSatCorrectionList, method_correctionListGet, i);
+ env->CallObjectMethod(singleSatCorrectionList, method_listGet, i);
SingleSatCorrection_Aidl singleSatCorrection_Aidl =
getSingleSatCorrection_Aidl(env, singleSatCorrectionObj);
@@ -441,4 +463,63 @@ void MeasurementCorrectionsUtil::getSingleSatCorrectionList_Aidl(
}
}
+template <>
+void MeasurementCorrectionsUtil::setReflectingPlaneAzimuthDegrees<ReflectingPlane_V1_0>(
+ ReflectingPlane_V1_0& reflectingPlane, double azimuthDegreeRefPlane) {
+ reflectingPlane.azimuthDegrees = azimuthDegreeRefPlane;
+}
+
+template <>
+void MeasurementCorrectionsUtil::setReflectingPlaneAzimuthDegrees<ReflectingPlane_Aidl>(
+ ReflectingPlane_Aidl& reflectingPlane, double azimuthDegreeRefPlane) {
+ reflectingPlane.reflectingPlaneAzimuthDegrees = azimuthDegreeRefPlane;
+}
+
+std::vector<ExcessPathInfo> MeasurementCorrectionsUtil::getExcessPathInfoList(
+ JNIEnv* env, jobject singleSatCorrectionObj) {
+ jobject excessPathInfoListObj =
+ env->CallObjectMethod(singleSatCorrectionObj, method_correctionSatExcessPathInfoList);
+
+ int len = env->CallIntMethod(excessPathInfoListObj, method_listSize);
+ std::vector<ExcessPathInfo> list(len);
+ for (int i = 0; i < len; ++i) {
+ jobject excessPathInfoObj = env->CallObjectMethod(excessPathInfoListObj, method_listGet, i);
+ list[i] = getExcessPathInfo(env, excessPathInfoObj);
+ env->DeleteLocalRef(excessPathInfoObj);
+ }
+ env->DeleteLocalRef(excessPathInfoListObj);
+ return list;
+}
+
+ExcessPathInfo MeasurementCorrectionsUtil::getExcessPathInfo(JNIEnv* env,
+ jobject excessPathInfoObj) {
+ ExcessPathInfo excessPathInfo;
+ jint flags = env->CallIntMethod(excessPathInfoObj, method_excessPathInfoFlags);
+ excessPathInfo.excessPathInfoFlags = flags;
+ if ((flags & ExcessPathInfo::EXCESS_PATH_INFO_HAS_EXCESS_PATH_LENGTH) != 0) {
+ jfloat epl = env->CallFloatMethod(excessPathInfoObj, method_excessPathInfoEpl);
+ excessPathInfo.excessPathLengthMeters = epl;
+ }
+ if ((flags & ExcessPathInfo::EXCESS_PATH_INFO_HAS_EXCESS_PATH_LENGTH_UNC) != 0) {
+ jfloat eplUnc = env->CallFloatMethod(excessPathInfoObj, method_excessPathInfoEplUnc);
+ excessPathInfo.excessPathLengthUncertaintyMeters = eplUnc;
+ }
+ if ((flags & ExcessPathInfo::EXCESS_PATH_INFO_HAS_REFLECTING_PLANE) != 0) {
+ ReflectingPlane_Aidl reflectingPlane;
+ jobject reflectingPlaneObj =
+ env->CallObjectMethod(excessPathInfoObj, method_excessPathInfoRefPlane);
+ MeasurementCorrectionsUtil::setReflectingPlane<ReflectingPlane_Aidl>(env,
+ reflectingPlaneObj,
+ reflectingPlane);
+ env->DeleteLocalRef(reflectingPlaneObj);
+ excessPathInfo.reflectingPlane = reflectingPlane;
+ }
+ if ((flags & ExcessPathInfo::EXCESS_PATH_INFO_HAS_ATTENUATION) != 0) {
+ jfloat attenuation =
+ env->CallFloatMethod(excessPathInfoObj, method_excessPathInfoAttenuation);
+ excessPathInfo.attenuationDb = attenuation;
+ }
+ return excessPathInfo;
+}
+
} // namespace android::gnss
diff --git a/services/core/jni/gnss/MeasurementCorrections.h b/services/core/jni/gnss/MeasurementCorrections.h
index a2e602714326..598ad48d6ac1 100644
--- a/services/core/jni/gnss/MeasurementCorrections.h
+++ b/services/core/jni/gnss/MeasurementCorrections.h
@@ -43,7 +43,7 @@ extern jmethodID method_correctionsHasEnvironmentBearing;
extern jmethodID method_correctionsGetEnvironmentBearingDegrees;
extern jmethodID method_correctionsGetEnvironmentBearingUncertaintyDegrees;
extern jmethodID method_listSize;
-extern jmethodID method_correctionListGet;
+extern jmethodID method_listGet;
extern jmethodID method_correctionSatFlags;
extern jmethodID method_correctionSatConstType;
extern jmethodID method_correctionSatId;
@@ -52,6 +52,7 @@ extern jmethodID method_correctionSatIsLosProb;
extern jmethodID method_correctionSatEpl;
extern jmethodID method_correctionSatEplUnc;
extern jmethodID method_correctionSatRefPlane;
+extern jmethodID method_correctionSatExcessPathInfos;
extern jmethodID method_correctionPlaneLatDeg;
extern jmethodID method_correctionPlaneLngDeg;
extern jmethodID method_correctionPlaneAltDeg;
@@ -130,14 +131,20 @@ struct MeasurementCorrectionsUtil {
static bool translateMeasurementCorrections(JNIEnv* env, jobject correctionsObj,
T& corrections);
template <class T>
- static void getReflectingPlane(JNIEnv* env, jobject singleSatCorrectionObj, T& reflectingPlane);
+ static void setReflectingPlane(JNIEnv* env, jobject reflectingPlaneObj, T& reflectingPlane);
+ template <class T>
+ static void setReflectingPlaneAzimuthDegrees(T& reflectingPlane, double azimuthDegreeRefPlane);
+
+ static std::vector<
+ android::hardware::gnss::measurement_corrections::SingleSatCorrection::ExcessPathInfo>
+ getExcessPathInfoList(JNIEnv* env, jobject correctionsObj);
+ static android::hardware::gnss::measurement_corrections::SingleSatCorrection::ExcessPathInfo
+ getExcessPathInfo(JNIEnv* env, jobject correctionsObj);
};
template <class T>
-void MeasurementCorrectionsUtil::getReflectingPlane(JNIEnv* env, jobject singleSatCorrectionObj,
+void MeasurementCorrectionsUtil::setReflectingPlane(JNIEnv* env, jobject reflectingPlaneObj,
T& reflectingPlane) {
- jobject reflectingPlaneObj =
- env->CallObjectMethod(singleSatCorrectionObj, method_correctionSatRefPlane);
jdouble latitudeDegreesRefPlane =
env->CallDoubleMethod(reflectingPlaneObj, method_correctionPlaneLatDeg);
jdouble longitudeDegreesRefPlane =
@@ -149,8 +156,7 @@ void MeasurementCorrectionsUtil::getReflectingPlane(JNIEnv* env, jobject singleS
reflectingPlane.latitudeDegrees = latitudeDegreesRefPlane;
reflectingPlane.longitudeDegrees = longitudeDegreesRefPlane;
reflectingPlane.altitudeMeters = altitudeDegreesRefPlane;
- reflectingPlane.azimuthDegrees = azimuthDegreeRefPlane;
- env->DeleteLocalRef(reflectingPlaneObj);
+ setReflectingPlaneAzimuthDegrees<T>(reflectingPlane, azimuthDegreeRefPlane);
}
} // namespace android::gnss
diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp
index 1c6a3b5eb03f..0cd949457cd1 100644
--- a/services/core/jni/onload.cpp
+++ b/services/core/jni/onload.cpp
@@ -106,7 +106,6 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
register_android_server_HardwarePropertiesManagerService(env);
register_android_server_storage_AppFuse(env);
register_android_server_SyntheticPasswordManager(env);
- register_android_graphics_GraphicsStatsService(env);
register_android_hardware_display_DisplayViewport(env);
register_android_server_am_CachedAppOptimizer(env);
register_android_server_am_LowMemDetector(env);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
index 2090ab367438..48c40523e9c2 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
@@ -307,8 +307,8 @@ class ActiveAdmin {
public boolean mAdminCanGrantSensorsPermissions;
public boolean mPreferentialNetworkServiceEnabled =
DevicePolicyManager.PREFERENTIAL_NETWORK_SERVICE_ENABLED_DEFAULT;
- public PreferentialNetworkServiceConfig mPreferentialNetworkServiceConfig =
- PreferentialNetworkServiceConfig.DEFAULT;
+ public List<PreferentialNetworkServiceConfig> mPreferentialNetworkServiceConfigs =
+ List.of(PreferentialNetworkServiceConfig.DEFAULT);
private static final boolean USB_DATA_SIGNALING_ENABLED_DEFAULT = true;
boolean mUsbDataSignalingEnabled = USB_DATA_SIGNALING_ENABLED_DEFAULT;
@@ -1227,5 +1227,12 @@ class ActiveAdmin {
pw.print("mSsidDenylist=");
pw.println(mSsidDenylist);
+
+ if (mFactoryResetProtectionPolicy != null) {
+ pw.println("mFactoryResetProtectionPolicy:");
+ pw.increaseIndent();
+ mFactoryResetProtectionPolicy.dump(pw);
+ pw.decreaseIndent();
+ }
}
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
index 200b120843cc..834f65fa9e97 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
@@ -15,6 +15,7 @@
*/
package com.android.server.devicepolicy;
+import android.accounts.Account;
import android.annotation.NonNull;
import android.annotation.UserIdInt;
import android.app.admin.DevicePolicyDrawableResource;
@@ -30,6 +31,7 @@ import android.util.Slog;
import com.android.server.SystemService;
+import java.util.Collections;
import java.util.List;
/**
@@ -138,6 +140,11 @@ abstract class BaseIDevicePolicyManager extends IDevicePolicyManager.Stub {
return null;
}
+ public void finalizeWorkProfileProvisioning(
+ UserHandle managedProfileUser, Account migratedAccount) {
+
+ }
+
public void provisionFullyManagedDevice(
FullyManagedDeviceProvisioningParams provisioningParams, String callerPackage) {
}
@@ -171,7 +178,7 @@ abstract class BaseIDevicePolicyManager extends IDevicePolicyManager.Stub {
public void setDrawables(@NonNull List<DevicePolicyDrawableResource> drawables){}
@Override
- public void resetDrawables(@NonNull String[] drawableIds){}
+ public void resetDrawables(@NonNull List<String> drawableIds){}
@Override
public ParcelableResource getDrawable(
@@ -183,10 +190,20 @@ abstract class BaseIDevicePolicyManager extends IDevicePolicyManager.Stub {
public void setStrings(@NonNull List<DevicePolicyStringResource> strings){}
@Override
- public void resetStrings(String[] stringIds){}
+ public void resetStrings(@NonNull List<String> stringIds){}
@Override
public ParcelableResource getString(String stringId) {
return null;
}
+
+ @Override
+ public boolean shouldAllowBypassingDevicePolicyManagementRoleQualification() {
+ return false;
+ }
+
+ @Override
+ public List<UserHandle> getPolicyManagedProfiles(UserHandle userHandle) {
+ return Collections.emptyList();
+ }
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceManagementResourcesProvider.java b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceManagementResourcesProvider.java
index e70c071183ce..bf78c67d5b57 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceManagementResourcesProvider.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceManagementResourcesProvider.java
@@ -16,17 +16,14 @@
package com.android.server.devicepolicy;
-import static android.app.admin.DevicePolicyResources.Drawables.Source.UPDATABLE_DRAWABLE_SOURCES;
import static android.app.admin.DevicePolicyResources.Drawables.Style;
-import static android.app.admin.DevicePolicyResources.Drawables.Style.UPDATABLE_DRAWABLE_STYLES;
-import static android.app.admin.DevicePolicyResources.Drawables.UPDATABLE_DRAWABLE_IDS;
-import static android.app.admin.DevicePolicyResources.Strings.UPDATABLE_STRING_IDS;
import static java.util.Objects.requireNonNull;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.admin.DevicePolicyDrawableResource;
+import android.app.admin.DevicePolicyResources;
import android.app.admin.DevicePolicyResources.Drawables;
import android.app.admin.DevicePolicyStringResource;
import android.app.admin.ParcelableResource;
@@ -113,7 +110,7 @@ class DeviceManagementResourcesProvider {
Objects.requireNonNull(drawableSource, "drawableSource must be provided.");
Objects.requireNonNull(resource, "ParcelableResource must be provided.");
- if (Drawables.Source.UNDEFINED.equals(drawableSource)) {
+ if (DevicePolicyResources.UNDEFINED.equals(drawableSource)) {
updated |= updateDrawable(drawableId, drawableStyle, resource);
} else {
updated |= updateDrawableForSource(drawableId, drawableSource, resource);
@@ -130,12 +127,6 @@ class DeviceManagementResourcesProvider {
private boolean updateDrawable(
String drawableId, String drawableStyle, ParcelableResource updatableResource) {
- if (!UPDATABLE_DRAWABLE_IDS.contains(drawableId)) {
- Log.w(TAG, "Updating a resource for an unknown drawable id " + drawableId);
- }
- if (!UPDATABLE_DRAWABLE_STYLES.contains(drawableStyle)) {
- Log.w(TAG, "Updating a resource for an unknown style id " + drawableStyle);
- }
synchronized (mLock) {
if (!mUpdatedDrawablesForStyle.containsKey(drawableId)) {
mUpdatedDrawablesForStyle.put(drawableId, new HashMap<>());
@@ -153,12 +144,6 @@ class DeviceManagementResourcesProvider {
// TODO(b/214576716): change this to respect style
private boolean updateDrawableForSource(
String drawableId, String drawableSource, ParcelableResource updatableResource) {
- if (!UPDATABLE_DRAWABLE_IDS.contains(drawableId)) {
- Log.w(TAG, "Updating a resource for an unknown drawable id " + drawableId);
- }
- if (!UPDATABLE_DRAWABLE_SOURCES.contains(drawableSource)) {
- Log.w(TAG, "Updating a resource for an unknown source id " + drawableSource);
- }
synchronized (mLock) {
if (!mUpdatedDrawablesForSource.containsKey(drawableId)) {
mUpdatedDrawablesForSource.put(drawableId, new HashMap<>());
@@ -176,11 +161,11 @@ class DeviceManagementResourcesProvider {
/**
* Returns {@code false} if no resources were removed.
*/
- boolean removeDrawables(@NonNull String[] drawableIds) {
+ boolean removeDrawables(@NonNull List<String> drawableIds) {
synchronized (mLock) {
boolean removed = false;
- for (int i = 0; i < drawableIds.length; i++) {
- String drawableId = drawableIds[i];
+ for (int i = 0; i < drawableIds.size(); i++) {
+ String drawableId = drawableIds.get(i);
removed |= mUpdatedDrawablesForStyle.remove(drawableId) != null
|| mUpdatedDrawablesForSource.remove(drawableId) != null;
}
@@ -195,17 +180,6 @@ class DeviceManagementResourcesProvider {
@Nullable
ParcelableResource getDrawable(
String drawableId, String drawableStyle, String drawableSource) {
- if (!UPDATABLE_DRAWABLE_IDS.contains(drawableId)) {
- Log.w(TAG, "Getting an updated resource for an unknown drawable id " + drawableId);
- }
- if (!UPDATABLE_DRAWABLE_STYLES.contains(drawableStyle)) {
- Log.w(TAG, "Getting an updated resource for an unknown drawable style "
- + drawableStyle);
- }
- if (!UPDATABLE_DRAWABLE_SOURCES.contains(drawableSource)) {
- Log.w(TAG, "Getting an updated resource for an unknown drawable Source "
- + drawableSource);
- }
if (mUpdatedDrawablesForSource.containsKey(drawableId)
&& mUpdatedDrawablesForSource.get(drawableId).containsKey(drawableSource)) {
return mUpdatedDrawablesForSource.get(drawableId).get(drawableSource);
@@ -217,10 +191,6 @@ class DeviceManagementResourcesProvider {
if (mUpdatedDrawablesForStyle.get(drawableId).containsKey(drawableStyle)) {
return mUpdatedDrawablesForStyle.get(drawableId).get(drawableStyle);
}
-
- if (mUpdatedDrawablesForStyle.get(drawableId).containsKey(Style.DEFAULT)) {
- return mUpdatedDrawablesForStyle.get(drawableId).get(Style.DEFAULT);
- }
Log.d(TAG, "No updated drawable found for drawable id " + drawableId);
return null;
}
@@ -249,9 +219,6 @@ class DeviceManagementResourcesProvider {
}
private boolean updateString(String stringId, ParcelableResource updatableResource) {
- if (!UPDATABLE_STRING_IDS.contains(stringId)) {
- Log.w(TAG, "Updating a resource for an unknown string id " + stringId);
- }
synchronized (mLock) {
ParcelableResource current = mUpdatedStrings.get(stringId);
if (updatableResource.equals(current)) {
@@ -265,11 +232,11 @@ class DeviceManagementResourcesProvider {
/**
* Returns {@code false} if no resources were removed.
*/
- boolean removeStrings(@NonNull String[] stringIds) {
+ boolean removeStrings(@NonNull List<String> stringIds) {
synchronized (mLock) {
boolean removed = false;
- for (int i = 0; i < stringIds.length; i++) {
- String stringId = stringIds[i];
+ for (int i = 0; i < stringIds.size(); i++) {
+ String stringId = stringIds.get(i);
removed |= mUpdatedStrings.remove(stringId) != null;
}
if (!removed) {
@@ -282,10 +249,6 @@ class DeviceManagementResourcesProvider {
@Nullable
ParcelableResource getString(String stringId) {
- if (!UPDATABLE_STRING_IDS.contains(stringId)) {
- Log.w(TAG, "Getting an updated resource for an unknown string id " + stringId);
- }
-
if (mUpdatedStrings.containsKey(stringId)) {
return mUpdatedStrings.get(stringId);
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 236f663a9dd0..35f8402f71c8 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -27,6 +27,7 @@ import static android.app.admin.DeviceAdminReceiver.ACTION_COMPLIANCE_ACKNOWLEDG
import static android.app.admin.DeviceAdminReceiver.EXTRA_TRANSFER_OWNERSHIP_ADMIN_EXTRAS_BUNDLE;
import static android.app.admin.DevicePolicyManager.ACTION_CHECK_POLICY_COMPLIANCE;
import static android.app.admin.DevicePolicyManager.ACTION_DEVICE_POLICY_RESOURCE_UPDATED;
+import static android.app.admin.DevicePolicyManager.ACTION_MANAGED_PROFILE_PROVISIONED;
import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE;
import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE;
import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_USER;
@@ -45,6 +46,7 @@ import static android.app.admin.DevicePolicyManager.DELEGATION_SECURITY_LOGGING;
import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_DEFAULT;
import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_FINANCED;
import static android.app.admin.DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE_PER_USER;
+import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE;
import static android.app.admin.DevicePolicyManager.EXTRA_RESOURCE_IDS;
import static android.app.admin.DevicePolicyManager.EXTRA_RESOURCE_TYPE;
import static android.app.admin.DevicePolicyManager.EXTRA_RESOURCE_TYPE_DRAWABLE;
@@ -87,6 +89,7 @@ import static android.app.admin.DevicePolicyManager.PRIVATE_DNS_MODE_UNKNOWN;
import static android.app.admin.DevicePolicyManager.PRIVATE_DNS_SET_ERROR_FAILURE_SETTING;
import static android.app.admin.DevicePolicyManager.PRIVATE_DNS_SET_NO_ERROR;
import static android.app.admin.DevicePolicyManager.PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER;
+import static android.app.admin.DevicePolicyManager.STATE_USER_SETUP_FINALIZED;
import static android.app.admin.DevicePolicyManager.STATE_USER_UNMANAGED;
import static android.app.admin.DevicePolicyManager.STATUS_ACCOUNTS_NOT_EMPTY;
import static android.app.admin.DevicePolicyManager.STATUS_CANNOT_ADD_MANAGED_PROFILE;
@@ -132,7 +135,6 @@ import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES;
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;
-import static android.net.NetworkCapabilities.NET_ENTERPRISE_ID_1;
import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
import static android.provider.Settings.Global.PRIVATE_DNS_SPECIFIER;
import static android.provider.Settings.Secure.MANAGED_PROVISIONING_DPC_DOWNLOADED;
@@ -140,6 +142,7 @@ import static android.provider.Settings.Secure.USER_SETUP_COMPLETE;
import static android.provider.Telephony.Carriers.DPC_URI;
import static android.provider.Telephony.Carriers.ENFORCE_KEY;
import static android.provider.Telephony.Carriers.ENFORCE_MANAGED_URI;
+import static android.provider.Telephony.Carriers.INVALID_APN_ID;
import static android.security.keystore.AttestationUtils.USE_INDIVIDUAL_ATTESTATION;
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_ENTRY_POINT_ADB;
@@ -2121,7 +2124,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
+ "profile: %d", doUserId, poUserId);
Slogf.i(LOG_TAG, "Giving the PO additional power...");
- markProfileOwnerOnOrganizationOwnedDeviceUncheckedLocked(poAdminComponent, poUserId);
+ setProfileOwnerOnOrganizationOwnedDeviceUncheckedLocked(poAdminComponent, poUserId, true);
Slogf.i(LOG_TAG, "Migrating DO policies to PO...");
moveDoPoliciesToProfileParentAdminLocked(doAdmin, poAdmin.getParentActiveAdmin());
migratePersonalAppSuspensionLocked(doUserId, poUserId, poAdmin);
@@ -3356,14 +3359,14 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
updatePermissionPolicyCache(userId);
updateAdminCanGrantSensorsPermissionCache(userId);
- final PreferentialNetworkServiceConfig preferentialNetworkServiceConfig;
+ final List<PreferentialNetworkServiceConfig> preferentialNetworkServiceConfigs;
synchronized (getLockObject()) {
ActiveAdmin owner = getDeviceOrProfileOwnerAdminLocked(userId);
- preferentialNetworkServiceConfig = owner != null
- ? owner.mPreferentialNetworkServiceConfig
- : PreferentialNetworkServiceConfig.DEFAULT;
+ preferentialNetworkServiceConfigs = owner != null
+ ? owner.mPreferentialNetworkServiceConfigs
+ : List.of(PreferentialNetworkServiceConfig.DEFAULT);
}
- updateNetworkPreferenceForUser(userId, preferentialNetworkServiceConfig);
+ updateNetworkPreferenceForUser(userId, preferentialNetworkServiceConfigs);
startOwnerService(userId, "start-user");
}
@@ -3380,7 +3383,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@Override
void handleStopUser(int userId) {
- updateNetworkPreferenceForUser(userId, PreferentialNetworkServiceConfig.DEFAULT);
+ updateNetworkPreferenceForUser(userId, List.of(PreferentialNetworkServiceConfig.DEFAULT));
stopOwnerService(userId, "stop-user");
}
@@ -7029,10 +7032,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
boolean calledByProfileOwnerOnOrgOwnedDevice, boolean calledOnParentInstance) {
DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class);
return calledByProfileOwnerOnOrgOwnedDevice && !calledOnParentInstance
- ? dpm.getString(WORK_PROFILE_DELETED_ORG_OWNED_MESSAGE,
+ ? dpm.getResources().getString(WORK_PROFILE_DELETED_ORG_OWNED_MESSAGE,
() -> mContext.getString(
R.string.device_ownership_relinquished))
- : dpm.getString(WORK_PROFILE_DELETED_GENERIC_MESSAGE,
+ : dpm.getResources().getString(WORK_PROFILE_DELETED_GENERIC_MESSAGE,
() -> mContext.getString(
R.string.work_profile_deleted_description_dpm_wipe));
}
@@ -7131,7 +7134,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
private String getWorkProfileDeletedTitle() {
DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class);
- return dpm.getString(WORK_PROFILE_DELETED_TITLE,
+ return dpm.getResources().getString(WORK_PROFILE_DELETED_TITLE,
() -> mContext.getString(R.string.work_profile_deleted));
}
@@ -7447,7 +7450,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
private String getFailedPasswordAttemptWipeMessage() {
DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class);
- return dpm.getString(WORK_PROFILE_DELETED_FAILED_PASSWORD_ATTEMPTS_MESSAGE,
+ return dpm.getResources().getString(WORK_PROFILE_DELETED_FAILED_PASSWORD_ATTEMPTS_MESSAGE,
() -> mContext.getString(
R.string.work_profile_deleted_reason_maximum_password_failure));
}
@@ -9183,10 +9186,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
@Override
- public void setUserProvisioningState(int newState, int userHandle) {
+ public void setUserProvisioningState(int newState, int userId) {
if (!mHasFeature) {
logMissingFeatureAction("Cannot set provisioning state " + newState + " for user "
- + userHandle);
+ + userId);
return;
}
@@ -9196,12 +9199,24 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
final CallerIdentity caller = getCallerIdentity();
final long id = mInjector.binderClearCallingIdentity();
try {
- if (userHandle != mOwners.getDeviceOwnerUserId() && !mOwners.hasProfileOwner(userHandle)
- && getManagedUserId(userHandle) == -1
- && newState != STATE_USER_UNMANAGED) {
- // No managed device, user or profile, so setting provisioning state makes no sense.
- throw new IllegalStateException("Not allowed to change provisioning state unless a "
- + "device or profile owner is set.");
+ int deviceOwnerUserId = mOwners.getDeviceOwnerUserId();
+ // NOTE: multiple if statements are nested below so it can log more info on error
+ if (userId != deviceOwnerUserId) {
+ boolean hasProfileOwner = mOwners.hasProfileOwner(userId);
+ if (!hasProfileOwner) {
+ int managedUserId = getManagedUserId(userId);
+ if (managedUserId == -1 && newState != STATE_USER_UNMANAGED) {
+ // No managed device, user or profile, so setting provisioning state makes
+ // no sense.
+ String error = "Not allowed to change provisioning state unless a "
+ + "device or profile owner is set.";
+ Slogf.w(LOG_TAG, "setUserProvisioningState(newState=%d, userId=%d) failed: "
+ + "deviceOwnerId=%d, hasProfileOwner=%b, managedUserId=%d, err=%s",
+ newState, userId, deviceOwnerUserId, hasProfileOwner,
+ managedUserId, error);
+ throw new IllegalStateException(error);
+ }
+ }
}
synchronized (getLockObject()) {
@@ -9211,9 +9226,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
if (isAdb(caller)) {
// ADB shell can only move directly from un-managed to finalized as part of
// directly setting profile-owner or device-owner.
- if (getUserProvisioningState(userHandle)
+ if (getUserProvisioningState(userId)
!= DevicePolicyManager.STATE_USER_UNMANAGED
- || newState != DevicePolicyManager.STATE_USER_SETUP_FINALIZED) {
+ || newState != STATE_USER_SETUP_FINALIZED) {
throw new IllegalStateException("Not allowed to change provisioning state "
+ "unless current provisioning state is unmanaged, and new state"
+ "is finalized.");
@@ -9221,14 +9236,14 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
transitionCheckNeeded = false;
}
- final DevicePolicyData policyData = getUserData(userHandle);
+ final DevicePolicyData policyData = getUserData(userId);
if (transitionCheckNeeded) {
// Optional state transition check for non-ADB case.
checkUserProvisioningStateTransition(policyData.mUserProvisioningState,
newState);
}
policyData.mUserProvisioningState = newState;
- saveSettingsLocked(userHandle);
+ saveSettingsLocked(userId);
}
} finally {
mInjector.binderRestoreCallingIdentity(id);
@@ -9247,7 +9262,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
case DevicePolicyManager.STATE_USER_SETUP_INCOMPLETE:
case DevicePolicyManager.STATE_USER_SETUP_COMPLETE:
// Can only move to finalized from these states.
- if (newState == DevicePolicyManager.STATE_USER_SETUP_FINALIZED) {
+ if (newState == STATE_USER_SETUP_FINALIZED) {
return;
}
break;
@@ -9259,7 +9274,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return;
}
break;
- case DevicePolicyManager.STATE_USER_SETUP_FINALIZED:
+ case STATE_USER_SETUP_FINALIZED:
// Cannot transition out of finalized.
break;
case DevicePolicyManager.STATE_USER_PROFILE_FINALIZED:
@@ -12245,87 +12260,50 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
@Override
- public void setPreferentialNetworkServiceEnabled(boolean enabled) {
+ public void setPreferentialNetworkServiceConfigs(
+ List<PreferentialNetworkServiceConfig> preferentialNetworkServiceConfigs) {
if (!mHasFeature) {
return;
}
final CallerIdentity caller = getCallerIdentity();
- Preconditions.checkCallAuthorization(isProfileOwner(caller),
- "Caller is not profile owner;"
- + " only profile owner may control the preferential network service");
- synchronized (getLockObject()) {
- final ActiveAdmin requiredAdmin = getProfileOwnerAdminLocked(
- caller.getUserId());
- if (requiredAdmin != null
- && requiredAdmin.mPreferentialNetworkServiceEnabled != enabled) {
- requiredAdmin.mPreferentialNetworkServiceEnabled = enabled;
- saveSettingsLocked(caller.getUserId());
- }
- }
- updateNetworkPreferenceForUser(caller.getUserId(), enabled);
- DevicePolicyEventLogger
- .createEvent(DevicePolicyEnums.SET_PREFERENTIAL_NETWORK_SERVICE_ENABLED)
- .setBoolean(enabled)
- .write();
- }
-
- @Override
- public boolean isPreferentialNetworkServiceEnabled(int userHandle) {
- if (!mHasFeature) {
- return false;
- }
-
- final CallerIdentity caller = getCallerIdentity();
- Preconditions.checkCallAuthorization(isProfileOwner(caller),
- "Caller is not profile owner");
- synchronized (getLockObject()) {
- final ActiveAdmin requiredAdmin = getProfileOwnerAdminLocked(userHandle);
- if (requiredAdmin != null) {
- return requiredAdmin.mPreferentialNetworkServiceEnabled;
- } else {
- return false;
- }
- }
- }
-
- @Override
- public void setPreferentialNetworkServiceConfig(
- PreferentialNetworkServiceConfig preferentialNetworkServiceConfig) {
- if (!mHasFeature) {
- return;
- }
- final CallerIdentity caller = getCallerIdentity();
- Preconditions.checkCallAuthorization(isProfileOwner(caller),
- "Caller is not profile owner;"
- + " only profile owner may control the preferential network service");
+ Preconditions.checkCallAuthorization(isProfileOwner(caller)
+ || isDefaultDeviceOwner(caller),
+ "Caller is not profile owner or device owner;"
+ + " only profile owner or device owner may control the preferential"
+ + " network service");
synchronized (getLockObject()) {
final ActiveAdmin requiredAdmin = getProfileOwnerAdminLocked(
caller.getUserId());
- if (!requiredAdmin.mPreferentialNetworkServiceConfig.equals(
- preferentialNetworkServiceConfig)) {
- requiredAdmin.mPreferentialNetworkServiceConfig = preferentialNetworkServiceConfig;
+ if (!requiredAdmin.mPreferentialNetworkServiceConfigs.equals(
+ preferentialNetworkServiceConfigs)) {
+ requiredAdmin.mPreferentialNetworkServiceConfigs =
+ new ArrayList<>(preferentialNetworkServiceConfigs);
saveSettingsLocked(caller.getUserId());
}
}
- updateNetworkPreferenceForUser(caller.getUserId(), preferentialNetworkServiceConfig);
+ updateNetworkPreferenceForUser(caller.getUserId(), preferentialNetworkServiceConfigs);
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.SET_PREFERENTIAL_NETWORK_SERVICE_ENABLED)
- .setBoolean(preferentialNetworkServiceConfig.isEnabled())
+ .setBoolean(preferentialNetworkServiceConfigs
+ .stream().anyMatch(c -> c.isEnabled()))
.write();
}
@Override
- public PreferentialNetworkServiceConfig getPreferentialNetworkServiceConfig() {
+ public List<PreferentialNetworkServiceConfig> getPreferentialNetworkServiceConfigs() {
if (!mHasFeature) {
- return PreferentialNetworkServiceConfig.DEFAULT;
+ return List.of(PreferentialNetworkServiceConfig.DEFAULT);
}
final CallerIdentity caller = getCallerIdentity();
- Preconditions.checkCallAuthorization(isProfileOwner(caller),
- "Caller is not profile owner");
+ Preconditions.checkCallAuthorization(isProfileOwner(caller)
+ || isDefaultDeviceOwner(caller),
+ "Caller is not profile owner or device owner;"
+ + " only profile owner or device owner may retrieve the preferential"
+ + " network service configurations");
synchronized (getLockObject()) {
final ActiveAdmin requiredAdmin = getProfileOwnerAdminLocked(caller.getUserId());
- return requiredAdmin.mPreferentialNetworkServiceConfig;
+ return requiredAdmin.mPreferentialNetworkServiceConfigs;
}
}
@@ -12672,13 +12650,13 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
private String getLocationChangedTitle() {
DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class);
- return dpm.getString(LOCATION_CHANGED_TITLE,
+ return dpm.getResources().getString(LOCATION_CHANGED_TITLE,
() -> mContext.getString(R.string.location_changed_notification_title));
}
private String getLocationChangedText() {
DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class);
- return dpm.getString(LOCATION_CHANGED_MESSAGE,
+ return dpm.getResources().getString(LOCATION_CHANGED_MESSAGE,
() -> mContext.getString(R.string.location_changed_notification_text));
}
@@ -13279,7 +13257,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return null;
}
DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class);
- return dpm.getString(
+ return dpm.getResources().getString(
PRINTING_DISABLED_NAMED_ADMIN,
() -> getDefaultPrintingDisabledMsg(appLabel),
appLabel);
@@ -14796,7 +14774,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
@Override
- public void markProfileOwnerOnOrganizationOwnedDevice(ComponentName who, int userId) {
+ public void setProfileOwnerOnOrganizationOwnedDevice(ComponentName who, int userId,
+ boolean isProfileOwnerOnOrganizationOwnedDevice) {
if (!mHasFeature) {
return;
}
@@ -14828,13 +14807,14 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
// Grant access under lock.
synchronized (getLockObject()) {
- markProfileOwnerOnOrganizationOwnedDeviceUncheckedLocked(who, userId);
+ setProfileOwnerOnOrganizationOwnedDeviceUncheckedLocked(who, userId,
+ isProfileOwnerOnOrganizationOwnedDevice);
}
}
@GuardedBy("getLockObject()")
- private void markProfileOwnerOnOrganizationOwnedDeviceUncheckedLocked(
- ComponentName who, int userId) {
+ private void setProfileOwnerOnOrganizationOwnedDeviceUncheckedLocked(
+ ComponentName who, int userId, boolean isProfileOwnerOnOrganizationOwnedDevice) {
// Make sure that the user has a profile owner and that the specified
// component is the profile owner of that user.
if (!isProfileOwner(who, userId)) {
@@ -14843,7 +14823,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
who.flattenToString(), userId));
}
- Slogf.i(LOG_TAG, "Marking %s as profile owner on organization-owned device for user %d",
+ Slogf.i(LOG_TAG, "%s %s as profile owner on organization-owned device for user %d",
+ isProfileOwnerOnOrganizationOwnedDevice ? "Marking" : "Unmarking",
who.flattenToString(), userId);
// First, set restriction on removing the profile.
@@ -14860,15 +14841,18 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
+ " on user %d", parentUser.getIdentifier()));
}
- mUserManager.setUserRestriction(UserManager.DISALLOW_REMOVE_MANAGED_PROFILE, true,
+ mUserManager.setUserRestriction(UserManager.DISALLOW_REMOVE_MANAGED_PROFILE,
+ isProfileOwnerOnOrganizationOwnedDevice,
parentUser);
- mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_USER, true,
+ mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_USER,
+ isProfileOwnerOnOrganizationOwnedDevice,
parentUser);
});
- // markProfileOwnerOfOrganizationOwnedDevice will trigger writing of the profile owner
+ // setProfileOwnerOfOrganizationOwnedDevice will trigger writing of the profile owner
// data, no need to do it manually.
- mOwners.markProfileOwnerOfOrganizationOwnedDevice(userId);
+ mOwners.setProfileOwnerOfOrganizationOwnedDevice(userId,
+ isProfileOwnerOnOrganizationOwnedDevice);
}
private void pushMeteredDisabledPackagesLocked(int userId) {
@@ -15892,13 +15876,13 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
private String getNetworkLoggingTitle() {
DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class);
- return dpm.getString(NETWORK_LOGGING_TITLE,
+ return dpm.getResources().getString(NETWORK_LOGGING_TITLE,
() -> mContext.getString(R.string.network_logging_notification_title));
}
private String getNetworkLoggingText() {
DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class);
- return dpm.getString(NETWORK_LOGGING_MESSAGE,
+ return dpm.getResources().getString(NETWORK_LOGGING_MESSAGE,
() -> mContext.getString(R.string.network_logging_notification_text));
}
@@ -16446,7 +16430,12 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
Objects.requireNonNull(who, "ComponentName is null");
Objects.requireNonNull(apnSetting, "ApnSetting is null in addOverrideApn");
final CallerIdentity caller = getCallerIdentity(who);
- Preconditions.checkCallAuthorization(isDefaultDeviceOwner(caller));
+ if (apnSetting.getApnTypeBitmask() == ApnSetting.TYPE_ENTERPRISE) {
+ Preconditions.checkCallAuthorization(isDefaultDeviceOwner(caller)
+ || isProfileOwner(caller));
+ } else {
+ Preconditions.checkCallAuthorization(isDefaultDeviceOwner(caller));
+ }
TelephonyManager tm = mContext.getSystemService(TelephonyManager.class);
if (tm != null) {
@@ -16454,7 +16443,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
() -> tm.addDevicePolicyOverrideApn(mContext, apnSetting));
} else {
Slogf.w(LOG_TAG, "TelephonyManager is null when trying to add override apn");
- return Telephony.Carriers.INVALID_APN_ID;
+ return INVALID_APN_ID;
}
}
@@ -16467,7 +16456,14 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
Objects.requireNonNull(who, "ComponentName is null");
Objects.requireNonNull(apnSetting, "ApnSetting is null in updateOverrideApn");
final CallerIdentity caller = getCallerIdentity(who);
- Preconditions.checkCallAuthorization(isDefaultDeviceOwner(caller));
+ ApnSetting apn = getApnSetting(apnId);
+ if (apn != null && apn.getApnTypeBitmask() == ApnSetting.TYPE_ENTERPRISE
+ && apnSetting.getApnTypeBitmask() == ApnSetting.TYPE_ENTERPRISE) {
+ Preconditions.checkCallAuthorization(isDefaultDeviceOwner(caller)
+ || isProfileOwner(caller));
+ } else {
+ Preconditions.checkCallAuthorization(isDefaultDeviceOwner(caller));
+ }
if (apnId < 0) {
return false;
@@ -16489,7 +16485,13 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
Objects.requireNonNull(who, "ComponentName is null");
final CallerIdentity caller = getCallerIdentity(who);
- Preconditions.checkCallAuthorization(isDefaultDeviceOwner(caller));
+ ApnSetting apn = getApnSetting(apnId);
+ if (apn != null && apn.getApnTypeBitmask() == ApnSetting.TYPE_ENTERPRISE) {
+ Preconditions.checkCallAuthorization(isDefaultDeviceOwner(caller)
+ || isProfileOwner(caller));
+ } else {
+ Preconditions.checkCallAuthorization(isDefaultDeviceOwner(caller));
+ }
return removeOverrideApnUnchecked(apnId);
}
@@ -16503,6 +16505,27 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return numDeleted > 0;
}
+ private ApnSetting getApnSetting(int apnId) {
+ if (apnId < 0) {
+ return null;
+ }
+ ApnSetting apnSetting = null;
+ Cursor cursor = mInjector.binderWithCleanCallingIdentity(
+ () -> mContext.getContentResolver().query(
+ Uri.withAppendedPath(DPC_URI, Integer.toString(apnId)), null, null, null,
+ Telephony.Carriers.DEFAULT_SORT_ORDER));
+ if (cursor != null) {
+ while (cursor.moveToNext()) {
+ apnSetting = ApnSetting.makeApnSetting(cursor);
+ if (apnSetting != null) {
+ break;
+ }
+ }
+ cursor.close();
+ }
+ return apnSetting;
+ }
+
@Override
public List<ApnSetting> getOverrideApns(@NonNull ComponentName who) {
if (!mHasFeature || !mHasTelephonyFeature) {
@@ -17448,25 +17471,25 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
private String getPersonalAppSuspensionButtonText() {
DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class);
- return dpm.getString(PERSONAL_APP_SUSPENSION_TURN_ON_PROFILE,
+ return dpm.getResources().getString(PERSONAL_APP_SUSPENSION_TURN_ON_PROFILE,
() -> mContext.getString(R.string.personal_apps_suspended_turn_profile_on));
}
private String getPersonalAppSuspensionTitle() {
DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class);
- return dpm.getString(PERSONAL_APP_SUSPENSION_TITLE,
+ return dpm.getResources().getString(PERSONAL_APP_SUSPENSION_TITLE,
() -> mContext.getString(R.string.personal_apps_suspension_title));
}
private String getPersonalAppSuspensionText() {
DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class);
- return dpm.getString(PERSONAL_APP_SUSPENSION_TITLE,
+ return dpm.getResources().getString(PERSONAL_APP_SUSPENSION_TITLE,
() -> mContext.getString(R.string.personal_apps_suspension_text));
}
private String getPersonalAppSuspensionSoonText(String date, String time, int maxDays) {
DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class);
- return dpm.getString(PERSONAL_APP_SUSPENSION_TITLE,
+ return dpm.getResources().getString(PERSONAL_APP_SUSPENSION_TITLE,
() -> mContext.getString(
R.string.personal_apps_suspension_soon_text, date, time, maxDays),
date, time, maxDays);
@@ -17474,7 +17497,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
private String getWorkProfileContentDescription() {
DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class);
- return dpm.getString(NOTIFICATION_WORK_PROFILE_CONTENT_DESCRIPTION,
+ return dpm.getResources().getString(NOTIFICATION_WORK_PROFILE_CONTENT_DESCRIPTION,
() -> mContext.getString(R.string.notification_work_profile_content_description));
}
@@ -17766,7 +17789,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
if (provisioningParams.isOrganizationOwnedProvisioning()) {
synchronized (getLockObject()) {
- markProfileOwnerOnOrganizationOwnedDeviceUncheckedLocked(admin, userInfo.id);
+ setProfileOwnerOnOrganizationOwnedDeviceUncheckedLocked(admin, userInfo.id,
+ true);
}
}
@@ -17793,6 +17817,35 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
}
+ @Override
+ public void finalizeWorkProfileProvisioning(UserHandle managedProfileUser,
+ Account migratedAccount) {
+ Preconditions.checkCallAuthorization(
+ hasCallingOrSelfPermission(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS));
+
+ if (!isManagedProfile(managedProfileUser.getIdentifier())) {
+ throw new IllegalStateException("Given user is not a managed profile");
+ }
+ ComponentName profileOwnerComponent =
+ mOwners.getProfileOwnerComponent(managedProfileUser.getIdentifier());
+ if (profileOwnerComponent == null) {
+ throw new IllegalStateException("There is no profile owner on the given profile");
+ }
+ Intent primaryProfileSuccessIntent = new Intent(ACTION_MANAGED_PROFILE_PROVISIONED);
+ primaryProfileSuccessIntent.setPackage(profileOwnerComponent.getPackageName());
+ primaryProfileSuccessIntent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES
+ | Intent.FLAG_RECEIVER_FOREGROUND);
+ primaryProfileSuccessIntent.putExtra(Intent.EXTRA_USER, managedProfileUser);
+
+ if (migratedAccount != null) {
+ primaryProfileSuccessIntent.putExtra(EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE,
+ migratedAccount);
+ }
+
+ mContext.sendBroadcastAsUser(primaryProfileSuccessIntent,
+ UserHandle.of(getProfileParentId(managedProfileUser.getIdentifier())));
+ }
+
/**
* Callback called at the beginning of {@link #createAndProvisionManagedProfile(
* ManagedProfileProvisioningParams, String)} after the relevant prechecks have passed.
@@ -18080,7 +18133,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
final CallerIdentity caller = getCallerIdentity();
Preconditions.checkCallAuthorization(
- hasCallingOrSelfPermission(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS));
+ hasCallingOrSelfPermission(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS)
+ || (hasCallingOrSelfPermission(permission.PROVISION_DEMO_DEVICE)
+ && provisioningParams.isDemoDevice()));
provisioningParams.logParams(callerPackage);
@@ -18117,8 +18172,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
disallowAddUser();
- setAdminCanGrantSensorsPermissionForUserUnchecked(deviceOwnerUserId,
- provisioningParams.canDeviceOwnerGrantSensorsPermissions());
+ setAdminCanGrantSensorsPermissionForUserUnchecked(
+ deviceOwnerUserId, provisioningParams.canDeviceOwnerGrantSensorsPermissions());
+ setDemoDeviceStateUnchecked(deviceOwnerUserId, provisioningParams.isDemoDevice());
onProvisionFullyManagedDeviceCompleted(provisioningParams);
sendProvisioningCompletedBroadcast(
deviceOwnerUserId,
@@ -18317,6 +18373,19 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
}
+ private void setDemoDeviceStateUnchecked(@UserIdInt int userId, boolean isDemoDevice) {
+ Slogf.d(LOG_TAG, "setDemoDeviceStateUnchecked(%d, %b)",
+ userId, isDemoDevice);
+ if (!isDemoDevice) {
+ return;
+ }
+ synchronized (getLockObject()) {
+ mInjector.settingsGlobalPutStringForUser(
+ Settings.Global.DEVICE_DEMO_MODE, Integer.toString(/* value= */ 1), userId);
+ }
+ setUserProvisioningState(STATE_USER_SETUP_FINALIZED, userId);
+ }
+
private void updateAdminCanGrantSensorsPermissionCache(@UserIdInt int userId) {
synchronized (getLockObject()) {
@@ -18334,54 +18403,32 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
private void updateNetworkPreferenceForUser(int userId,
- boolean preferentialNetworkServiceEnabled) {
+ List<PreferentialNetworkServiceConfig> preferentialNetworkServiceConfigs) {
if (!isManagedProfile(userId)) {
return;
}
- ProfileNetworkPreference.Builder preferenceBuilder =
- new ProfileNetworkPreference.Builder();
- if (preferentialNetworkServiceEnabled) {
- preferenceBuilder.setPreference(PROFILE_NETWORK_PREFERENCE_ENTERPRISE);
- preferenceBuilder.setPreferenceEnterpriseId(NET_ENTERPRISE_ID_1);
- } else {
- preferenceBuilder.setPreference(PROFILE_NETWORK_PREFERENCE_DEFAULT);
- }
List<ProfileNetworkPreference> preferences = new ArrayList<>();
- preferences.add(preferenceBuilder.build());
- mInjector.binderWithCleanCallingIdentity(() ->
- mInjector.getConnectivityManager().setProfileNetworkPreferences(
- UserHandle.of(userId), preferences,
- null /* executor */, null /* listener */));
- }
-
- private void updateNetworkPreferenceForUser(int userId,
- PreferentialNetworkServiceConfig preferentialNetworkServiceConfig) {
- if (!isManagedProfile(userId)) {
- return;
- }
- ProfileNetworkPreference.Builder preferenceBuilder =
- new ProfileNetworkPreference.Builder();
- if (preferentialNetworkServiceConfig.isEnabled()) {
- if (preferentialNetworkServiceConfig.isFallbackToDefaultConnectionAllowed()) {
- preferenceBuilder.setPreference(PROFILE_NETWORK_PREFERENCE_ENTERPRISE);
+ for (PreferentialNetworkServiceConfig preferentialNetworkServiceConfig :
+ preferentialNetworkServiceConfigs) {
+ ProfileNetworkPreference.Builder preferenceBuilder =
+ new ProfileNetworkPreference.Builder();
+ if (preferentialNetworkServiceConfig.isEnabled()) {
+ if (preferentialNetworkServiceConfig.isFallbackToDefaultConnectionAllowed()) {
+ preferenceBuilder.setPreference(PROFILE_NETWORK_PREFERENCE_ENTERPRISE);
+ } else {
+ preferenceBuilder.setPreference(
+ PROFILE_NETWORK_PREFERENCE_ENTERPRISE_NO_FALLBACK);
+ }
} else {
- preferenceBuilder.setPreference(PROFILE_NETWORK_PREFERENCE_ENTERPRISE_NO_FALLBACK);
+ preferenceBuilder.setPreference(PROFILE_NETWORK_PREFERENCE_DEFAULT);
}
- } else {
- preferenceBuilder.setPreference(PROFILE_NETWORK_PREFERENCE_DEFAULT);
- }
- List<Integer> allowedUids = Arrays.stream(
- preferentialNetworkServiceConfig.getIncludedUids()).boxed().collect(
- Collectors.toList());
- List<Integer> excludedUids = Arrays.stream(
- preferentialNetworkServiceConfig.getExcludedUids()).boxed().collect(
- Collectors.toList());
- preferenceBuilder.setIncludedUids(allowedUids);
- preferenceBuilder.setExcludedUids(excludedUids);
- preferenceBuilder.setPreferenceEnterpriseId(
- preferentialNetworkServiceConfig.getNetworkId());
- List<ProfileNetworkPreference> preferences = new ArrayList<>();
- preferences.add(preferenceBuilder.build());
+ preferenceBuilder.setIncludedUids(preferentialNetworkServiceConfig.getIncludedUids());
+ preferenceBuilder.setExcludedUids(preferentialNetworkServiceConfig.getExcludedUids());
+ preferenceBuilder.setPreferenceEnterpriseId(
+ preferentialNetworkServiceConfig.getNetworkId());
+
+ preferences.add(preferenceBuilder.build());
+ }
mInjector.binderWithCleanCallingIdentity(() ->
mInjector.getConnectivityManager().setProfileNetworkPreferences(
UserHandle.of(userId), preferences,
@@ -18673,13 +18720,14 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
mInjector.binderWithCleanCallingIdentity(() -> {
if (mDeviceManagementResourcesProvider.updateDrawables(drawables)) {
sendDrawableUpdatedBroadcast(
- drawables.stream().map(s -> s.getDrawableId()).toArray(String[]::new));
+ drawables.stream().map(s -> s.getDrawableId()).collect(
+ Collectors.toList()));
}
});
}
@Override
- public void resetDrawables(@NonNull String[] drawableIds) {
+ public void resetDrawables(@NonNull List<String> drawableIds) {
Preconditions.checkCallAuthorization(hasCallingOrSelfPermission(
android.Manifest.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES));
@@ -18700,7 +18748,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
drawableId, drawableStyle, drawableSource));
}
- private void sendDrawableUpdatedBroadcast(String[] drawableIds) {
+ private void sendDrawableUpdatedBroadcast(List<String> drawableIds) {
sendResourceUpdatedBroadcast(EXTRA_RESOURCE_TYPE_DRAWABLE, drawableIds);
}
@@ -18714,12 +18762,12 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
mInjector.binderWithCleanCallingIdentity(() -> {
if (mDeviceManagementResourcesProvider.updateStrings(strings))
sendStringsUpdatedBroadcast(
- strings.stream().map(s -> s.getStringId()).toArray(String[]::new));
+ strings.stream().map(s -> s.getStringId()).collect(Collectors.toList()));
});
}
@Override
- public void resetStrings(String[] stringIds) {
+ public void resetStrings(@NonNull List<String> stringIds) {
Preconditions.checkCallAuthorization(hasCallingOrSelfPermission(
android.Manifest.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES));
@@ -18736,13 +18784,13 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
mDeviceManagementResourcesProvider.getString(stringId));
}
- private void sendStringsUpdatedBroadcast(String[] stringIds) {
+ private void sendStringsUpdatedBroadcast(List<String> stringIds) {
sendResourceUpdatedBroadcast(EXTRA_RESOURCE_TYPE_STRING, stringIds);
}
- private void sendResourceUpdatedBroadcast(int resourceType, String[] resourceIds) {
+ private void sendResourceUpdatedBroadcast(int resourceType, List<String> resourceIds) {
final Intent intent = new Intent(ACTION_DEVICE_POLICY_RESOURCE_UPDATED);
- intent.putExtra(EXTRA_RESOURCE_IDS, resourceIds);
+ intent.putExtra(EXTRA_RESOURCE_IDS, resourceIds.toArray(String[]::new));
intent.putExtra(EXTRA_RESOURCE_TYPE, resourceType);
intent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
@@ -18775,4 +18823,36 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
mInjector.binderWithCleanCallingIdentity(() -> Settings.Secure.putInt(
mContext.getContentResolver(), MANAGED_PROVISIONING_DPC_DOWNLOADED, setTo));
}
+
+ @Override
+ public boolean shouldAllowBypassingDevicePolicyManagementRoleQualification() {
+ Preconditions.checkCallAuthorization(hasCallingOrSelfPermission(
+ android.Manifest.permission.MANAGE_ROLE_HOLDERS));
+ return mInjector.binderWithCleanCallingIdentity(() -> {
+ if (mUserManager.getUserCount() > 1) {
+ return false;
+ }
+ AccountManager am = AccountManager.get(mContext);
+ Account[] accounts = am.getAccounts();
+ return accounts.length == 0;
+ });
+ }
+
+ @Override
+ public List<UserHandle> getPolicyManagedProfiles(@NonNull UserHandle user) {
+ Preconditions.checkCallAuthorization(hasCallingOrSelfPermission(
+ android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS));
+ int userId = user.getIdentifier();
+ return mInjector.binderWithCleanCallingIdentity(() -> {
+ List<UserInfo> userProfiles = mUserManager.getProfiles(userId);
+ List<UserHandle> result = new ArrayList<>();
+ for (int i = 0; i < userProfiles.size(); i++) {
+ UserInfo userInfo = userProfiles.get(i);
+ if (userInfo.isManagedProfile() && hasProfileOwner(userInfo.id)) {
+ result.add(new UserHandle(userInfo.id));
+ }
+ }
+ return result;
+ });
+ }
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java
index e1d720ca25c8..1fa2f53bea17 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java
@@ -340,7 +340,7 @@ final class DevicePolicyManagerServiceShellCommand extends ShellCommand {
private int runMarkProfileOwnerOnOrganizationOwnedDevice(PrintWriter pw) {
parseArgs(/* canHaveName= */ false);
- mService.markProfileOwnerOnOrganizationOwnedDevice(mComponent, mUserId);
+ mService.setProfileOwnerOnOrganizationOwnedDevice(mComponent, mUserId, true);
pw.printf("Success\n");
return 0;
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
index fe8f2235ed63..b0fdd723347f 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
@@ -620,18 +620,15 @@ class Owners {
}
}
- /**
- * Sets the indicator that the profile owner manages an organization-owned device,
- * then write to file.
- */
- void markProfileOwnerOfOrganizationOwnedDevice(int userId) {
+ /** Set whether the profile owner manages an organization-owned device, then write to file. */
+ void setProfileOwnerOfOrganizationOwnedDevice(int userId, boolean isOrganizationOwnedDevice) {
synchronized (mLock) {
OwnerInfo profileOwner = mProfileOwners.get(userId);
if (profileOwner != null) {
- profileOwner.isOrganizationOwnedDevice = true;
+ profileOwner.isOrganizationOwnedDevice = isOrganizationOwnedDevice;
} else {
Slog.e(TAG, String.format(
- "No profile owner for user %d to set as org-owned.", userId));
+ "No profile owner for user %d to set org-owned flag.", userId));
}
writeProfileOwner(userId);
}
diff --git a/services/incremental/IncrementalService.cpp b/services/incremental/IncrementalService.cpp
index 0e96567dbfad..a49577b21957 100644
--- a/services/incremental/IncrementalService.cpp
+++ b/services/incremental/IncrementalService.cpp
@@ -111,6 +111,11 @@ static bool getAlwaysEnableReadTimeoutsForSystemDataLoaders() {
true);
}
+static bool getEnableReadTimeoutsAfterInstall() {
+ return android::base::GetBoolProperty("debug.incremental.enable_read_timeouts_after_install",
+ true);
+}
+
static bool getEnforceReadLogsMaxIntervalForSystemDataLoaders() {
return android::base::GetBoolProperty("debug.incremental.enforce_readlogs_max_interval_for_"
"system_dataloaders",
@@ -853,7 +858,7 @@ void IncrementalService::onInstallationComplete(StorageId storage) {
// Always enable long read timeouts after installation is complete.
std::unique_lock l(ifs->lock);
- ifs->setReadTimeoutsRequested(true);
+ ifs->setReadTimeoutsRequested(getEnableReadTimeoutsAfterInstall());
applyStorageParamsLocked(*ifs);
}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 294dc8941983..f7c66c5cff69 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -41,6 +41,7 @@ import android.app.usage.UsageStatsManagerInternal;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.IPackageManager;
import android.content.pm.PackageItemInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
@@ -292,8 +293,6 @@ public final class SystemServer implements Dumpable {
"com.android.server.wifi.p2p.WifiP2pService";
private static final String LOWPAN_SERVICE_CLASS =
"com.android.server.lowpan.LowpanService";
- private static final String ETHERNET_SERVICE_CLASS =
- "com.android.server.ethernet.EthernetService";
private static final String JOB_SCHEDULER_SERVICE_CLASS =
"com.android.server.job.JobSchedulerService";
private static final String LOCK_SETTINGS_SERVICE_CLASS =
@@ -422,6 +421,8 @@ public final class SystemServer implements Dumpable {
private static final String SDK_SANDBOX_MANAGER_SERVICE_CLASS =
"com.android.server.sdksandbox.SdkSandboxManagerService$Lifecycle";
+ private static final String AD_SERVICES_MANAGER_SERVICE_CLASS =
+ "com.android.server.adservices.AdServicesManagerService$Lifecycle";
private static final String TETHERING_CONNECTOR_CLASS = "android.net.ITetheringConnector";
@@ -1225,12 +1226,15 @@ public final class SystemServer implements Dumpable {
mSystemServiceManager.startService(domainVerificationService);
t.traceEnd();
+ IPackageManager iPackageManager;
t.traceBegin("StartPackageManagerService");
try {
Watchdog.getInstance().pauseWatchingCurrentThread("packagemanagermain");
- mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
- domainVerificationService, mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF,
- mOnlyCore);
+ Pair<PackageManagerService, IPackageManager> pmsPair = PackageManagerService.main(
+ mSystemContext, installer, domainVerificationService,
+ mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
+ mPackageManagerService = pmsPair.first;
+ iPackageManager = pmsPair.second;
} finally {
Watchdog.getInstance().resumeWatchingCurrentThread("packagemanagermain");
}
@@ -1238,7 +1242,7 @@ public final class SystemServer implements Dumpable {
// Now that the package manager has started, register the dex load reporter to capture any
// dex files loaded by system server.
// These dex files will be optimized by the BackgroundDexOptService.
- SystemServerDexLoadReporter.configureSystemServerDexReporter(mPackageManagerService);
+ SystemServerDexLoadReporter.configureSystemServerDexReporter(iPackageManager);
mFirstBoot = mPackageManagerService.isFirstBoot();
mPackageManager = mSystemContext.getPackageManager();
@@ -1989,13 +1993,6 @@ public final class SystemServer implements Dumpable {
t.traceEnd();
}
- if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_ETHERNET) ||
- mPackageManager.hasSystemFeature(PackageManager.FEATURE_USB_HOST)) {
- t.traceBegin("StartEthernet");
- mSystemServiceManager.startService(ETHERNET_SERVICE_CLASS);
- t.traceEnd();
- }
-
t.traceBegin("StartPacProxyService");
try {
pacProxyService = new PacProxyService(context);
@@ -2604,6 +2601,11 @@ public final class SystemServer implements Dumpable {
mSystemServiceManager.startService(SDK_SANDBOX_MANAGER_SERVICE_CLASS);
t.traceEnd();
+ // AdServicesManagerService (PP API service)
+ t.traceBegin("StartAdServicesManagerService");
+ mSystemServiceManager.startService(AD_SERVICES_MANAGER_SERVICE_CLASS);
+ t.traceEnd();
+
if (safeMode) {
mActivityManagerService.enterSafeMode();
}
diff --git a/services/midi/java/com/android/server/midi/MidiService.java b/services/midi/java/com/android/server/midi/MidiService.java
index ca67bcb7f38c..e1fe1d8433ef 100644
--- a/services/midi/java/com/android/server/midi/MidiService.java
+++ b/services/midi/java/com/android/server/midi/MidiService.java
@@ -18,6 +18,7 @@ package com.android.server.midi;
import android.annotation.NonNull;
import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothUuid;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
@@ -151,6 +152,8 @@ public class MidiService extends IMidiManager.Stub {
private static final UUID MIDI_SERVICE = UUID.fromString(
"03B80E5A-EDE8-4B33-A751-6CE34EC4C700");
+ private final HashSet<ParcelUuid> mNonMidiUUIDs = new HashSet<ParcelUuid>();
+
// PackageMonitor for listening to package changes
private final PackageMonitor mPackageMonitor = new PackageMonitor() {
@Override
@@ -643,6 +646,55 @@ public class MidiService extends IMidiManager.Stub {
return false;
}
+ private static void dumpIntentExtras(Intent intent) {
+ String action = intent.getAction();
+ Log.d(TAG, "Intent: " + action);
+ Bundle bundle = intent.getExtras();
+ if (bundle != null) {
+ for (String key : bundle.keySet()) {
+ Log.d(TAG, " " + key + " : "
+ + (bundle.get(key) != null ? bundle.get(key) : "NULL"));
+ }
+ }
+ }
+
+ private static boolean isBleTransport(Intent intent) {
+ Bundle bundle = intent.getExtras();
+ boolean isBle = false;
+ if (bundle != null) {
+ isBle = bundle.getInt(BluetoothDevice.EXTRA_TRANSPORT, BluetoothDevice.TRANSPORT_AUTO)
+ == BluetoothDevice.TRANSPORT_LE;
+ }
+ return isBle;
+ }
+
+ private void dumpUuids(BluetoothDevice btDevice) {
+ Log.d(TAG, "UUIDs for " + btDevice);
+
+ ParcelUuid[] uuidParcels = btDevice.getUuids();
+ if (uuidParcels == null) {
+ Log.d(TAG, "No UUID Parcels");
+ return;
+ }
+
+ for (ParcelUuid parcel : uuidParcels) {
+ UUID uuid = parcel.getUuid();
+ Log.d(TAG, " uuid:" + uuid);
+ }
+ }
+
+ private boolean hasNonMidiUuids(BluetoothDevice btDevice) {
+ ParcelUuid[] uuidParcels = btDevice.getUuids();
+ // The assumption is that these services are indicative of devices that
+ // ARE NOT MIDI devices.
+ for (ParcelUuid parcel : uuidParcels) {
+ if (mNonMidiUUIDs.contains(parcel)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
private final BroadcastReceiver mBleMidiReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -655,10 +707,27 @@ public class MidiService extends IMidiManager.Stub {
switch (action) {
case BluetoothDevice.ACTION_ACL_CONNECTED: {
Log.d(TAG, "ACTION_ACL_CONNECTED");
+ dumpIntentExtras(intent);
+ // BLE-MIDI controllers are by definition BLE, so if this device
+ // isn't, it CAN'T be a midi device
+ if (!isBleTransport(intent)) {
+ Log.i(TAG, "No BLE transport - NOT MIDI");
+ break;
+ }
+
+ Log.d(TAG, "BLE Device");
BluetoothDevice btDevice =
intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
- // We can't determine here if this is a BLD-MIDI device, so go ahead and try
- // to open as a MIDI device, further down it will get figured out.
+ dumpUuids(btDevice);
+
+ // See if there are any service UUIDs and if so do any of them indicate a
+ // Non-MIDI device (headset, headphones, QWERTY keyboard....)
+ if (hasNonMidiUuids(btDevice)) {
+ Log.d(TAG, "Non-MIDI service UUIDs found. NOT MIDI");
+ break;
+ }
+
+ Log.d(TAG, "Potential MIDI Device.");
openBluetoothDevice(btDevice);
}
break;
@@ -689,6 +758,17 @@ public class MidiService extends IMidiManager.Stub {
context.registerReceiver(mBleMidiReceiver, filter);
mBluetoothServiceUid = -1;
+
+ mNonMidiUUIDs.add(BluetoothUuid.A2DP_SINK); // Headphones?
+ mNonMidiUUIDs.add(BluetoothUuid.A2DP_SOURCE); // Headset?
+ mNonMidiUUIDs.add(BluetoothUuid.ADV_AUDIO_DIST);
+ mNonMidiUUIDs.add(BluetoothUuid.AVRCP_CONTROLLER);
+ mNonMidiUUIDs.add(BluetoothUuid.HFP);
+ mNonMidiUUIDs.add(BluetoothUuid.HSP);
+ mNonMidiUUIDs.add(BluetoothUuid.HID);
+ mNonMidiUUIDs.add(BluetoothUuid.LE_AUDIO);
+ mNonMidiUUIDs.add(BluetoothUuid.HOGP);
+ mNonMidiUUIDs.add(BluetoothUuid.HEARING_AID);
}
private void onUnlockUser() {
diff --git a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
index c5f990d52b82..66e840b5120b 100644
--- a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
+++ b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
@@ -112,7 +112,7 @@ public final class ProfcollectForwardingService extends SystemService {
try {
mIProfcollect.registerProviderStatusCallback(mProviderStatusCallback);
} catch (RemoteException e) {
- Log.e(LOG_TAG, e.getMessage());
+ Log.e(LOG_TAG, "Failed to register provider status callback: " + e.getMessage());
}
}
@@ -123,7 +123,7 @@ public final class ProfcollectForwardingService extends SystemService {
try {
return !mIProfcollect.get_supported_provider().isEmpty();
} catch (RemoteException e) {
- Log.e(LOG_TAG, e.getMessage());
+ Log.e(LOG_TAG, "Failed to get supported provider: " + e.getMessage());
return false;
}
}
@@ -219,7 +219,8 @@ public final class ProfcollectForwardingService extends SystemService {
try {
sSelfService.mIProfcollect.process();
} catch (RemoteException e) {
- Log.e(LOG_TAG, e.getMessage());
+ Log.e(LOG_TAG, "Failed to process profiles in background: "
+ + e.getMessage());
}
});
return true;
@@ -234,8 +235,11 @@ public final class ProfcollectForwardingService extends SystemService {
// Event observers
private void registerObservers() {
- registerAppLaunchObserver();
- registerOTAObserver();
+ BackgroundThread.get().getThreadHandler().post(
+ () -> {
+ registerAppLaunchObserver();
+ registerOTAObserver();
+ });
}
private final AppLaunchObserver mAppLaunchObserver = new AppLaunchObserver();
@@ -264,7 +268,7 @@ public final class ProfcollectForwardingService extends SystemService {
try {
mIProfcollect.trace_once("applaunch");
} catch (RemoteException e) {
- Log.e(LOG_TAG, e.getMessage());
+ Log.e(LOG_TAG, "Failed to initiate trace: " + e.getMessage());
}
});
}
@@ -348,7 +352,7 @@ public final class ProfcollectForwardingService extends SystemService {
.putExtra("filename", reportName);
context.sendBroadcast(intent);
} catch (RemoteException e) {
- Log.e(LOG_TAG, e.getMessage());
+ Log.e(LOG_TAG, "Failed to upload report: " + e.getMessage());
}
});
}
diff --git a/services/robotests/backup/src/com/android/server/backup/TransportManagerTest.java b/services/robotests/backup/src/com/android/server/backup/TransportManagerTest.java
index b7f8c00896d4..8a9845b1c2d2 100644
--- a/services/robotests/backup/src/com/android/server/backup/TransportManagerTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/TransportManagerTest.java
@@ -16,6 +16,10 @@
package com.android.server.backup;
+import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
+import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
+import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
+
import static com.android.server.backup.testing.TransportData.genericTransport;
import static com.android.server.backup.testing.TransportTestUtils.mockTransport;
import static com.android.server.backup.testing.TransportTestUtils.setUpTransportsForTransportManager;
@@ -312,6 +316,86 @@ public class TransportManagerTest {
}
@Test
+ public void testOnPackageChanged_whenPackageChanged_packageDisabledUnregistersTransport()
+ throws Exception {
+ TransportManager transportManager =
+ createTransportManagerWithRegisteredTransports(mTransportA1, mTransportB1);
+ reset(mListener);
+
+ mContext.getPackageManager()
+ .setApplicationEnabledSetting(
+ PACKAGE_A,
+ Integer.valueOf(COMPONENT_ENABLED_STATE_DISABLED),
+ 0 /*flags*/);
+ transportManager.onPackageChanged(PACKAGE_A, PACKAGE_A);
+
+ assertRegisteredTransports(transportManager, singletonList(mTransportB1));
+ verify(mListener, never()).onTransportRegistered(any(), any());
+ }
+
+ @Test
+ public void testOnPackageChanged_whenPackageChanged_packageEnabledRegistersTransport()
+ throws Exception {
+ TransportManager transportManager =
+ createTransportManagerWithRegisteredTransports(mTransportA1, mTransportB1);
+ reset(mListener);
+
+ mContext.getPackageManager()
+ .setApplicationEnabledSetting(
+ PACKAGE_A,
+ Integer.valueOf(COMPONENT_ENABLED_STATE_DISABLED),
+ 0 /*flags*/);
+ transportManager.onPackageChanged(PACKAGE_A, PACKAGE_A);
+
+ assertRegisteredTransports(transportManager, singletonList(mTransportB1));
+ verify(mListener, never()).onTransportRegistered(any(), any());
+
+ mContext.getPackageManager()
+ .setApplicationEnabledSetting(
+ PACKAGE_A,
+ Integer.valueOf(COMPONENT_ENABLED_STATE_ENABLED),
+ 0 /*flags*/);
+ transportManager.onPackageChanged(PACKAGE_A, PACKAGE_A);
+
+ assertRegisteredTransports(transportManager, asList(mTransportA1, mTransportB1));
+ verify(mListener)
+ .onTransportRegistered(mTransportA1.transportName, mTransportA1.transportDirName);
+ }
+
+ @Test
+ public void testOnPackageChanged_whenPackageChanged_unknownComponentStateIsIgnored()
+ throws Exception {
+ TransportManager transportManager =
+ createTransportManagerWithRegisteredTransports(mTransportA1, mTransportB1);
+ reset(mListener);
+
+ mContext.getPackageManager()
+ .setApplicationEnabledSetting(
+ PACKAGE_A,
+ Integer.valueOf(COMPONENT_ENABLED_STATE_DEFAULT),
+ 0 /*flags*/);
+ transportManager.onPackageChanged(PACKAGE_A, PACKAGE_A);
+
+ assertRegisteredTransports(transportManager, asList(mTransportA1, mTransportB1));
+ verify(mListener, never()).onTransportRegistered(any(), any());
+ }
+
+ @Test
+ public void testOnPackageChanged_whenPackageChanged_unknownPackageExceptionIsIgnored()
+ throws Exception {
+ TransportManager transportManager =
+ createTransportManagerWithRegisteredTransports(mTransportA1, mTransportB1);
+ reset(mListener);
+
+ // empty packageName triggers Robolectric ApplicationPackageManager to throw
+ // exception as if package does not exist.
+ transportManager.onPackageChanged("", "");
+
+ assertRegisteredTransports(transportManager, asList(mTransportA1, mTransportB1));
+ verify(mListener, never()).onTransportRegistered(any(), any());
+ }
+
+ @Test
public void testRegisterAndSelectTransport_whenTransportRegistered() throws Exception {
TransportManager transportManager =
createTransportManagerWithRegisteredTransports(null, mTransportA1);
diff --git a/services/robotests/src/com/android/server/testing/shadows/ShadowApplicationPackageManager.java b/services/robotests/src/com/android/server/testing/shadows/ShadowApplicationPackageManager.java
index aea36e555ad7..4a9948668bc4 100644
--- a/services/robotests/src/com/android/server/testing/shadows/ShadowApplicationPackageManager.java
+++ b/services/robotests/src/com/android/server/testing/shadows/ShadowApplicationPackageManager.java
@@ -16,6 +16,7 @@
package com.android.server.testing.shadows;
+import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
import static android.content.pm.PackageManager.NameNotFoundException;
import android.app.ApplicationPackageManager;
@@ -44,6 +45,7 @@ public class ShadowApplicationPackageManager
private static final List<PackageInfo> sInstalledPackages = new ArrayList<>();
private static final Map<String, Integer> sPackageUids = new ArrayMap<>();
private static final Map<Integer, Map<String, Integer>> sUserPackageUids = new ArrayMap<>();
+ private static final Map<String, Integer> sPackageAppEnabledStates = new ArrayMap<>();
/**
* Registers the package {@code packageName} to be returned when invoking {@link
@@ -53,6 +55,7 @@ public class ShadowApplicationPackageManager
public static void addInstalledPackage(String packageName, PackageInfo packageInfo) {
sPackageInfos.put(packageName, packageInfo);
sInstalledPackages.add(packageInfo);
+ sPackageAppEnabledStates.put(packageName, Integer.valueOf(COMPONENT_ENABLED_STATE_DEFAULT));
}
/**
@@ -77,6 +80,22 @@ public class ShadowApplicationPackageManager
}
@Override
+ protected int getApplicationEnabledSetting(String packageName) {
+ if (packageName.isEmpty()) {
+ throw new IllegalArgumentException("Robo: Package '' does not exist.");
+ }
+ if (!sPackageAppEnabledStates.containsKey(packageName)) {
+ return COMPONENT_ENABLED_STATE_DEFAULT;
+ }
+ return sPackageAppEnabledStates.get(packageName);
+ }
+
+ @Override
+ protected void setApplicationEnabledSetting(String packageName, int newState, int flags) {
+ sPackageAppEnabledStates.put(packageName, Integer.valueOf(newState)); // flags unused here.
+ }
+
+ @Override
protected PackageInfo getPackageInfoAsUser(String packageName, int flags, int userId)
throws NameNotFoundException {
if (!sPackageInfos.containsKey(packageName)) {
@@ -115,6 +134,7 @@ public class ShadowApplicationPackageManager
public static void reset() {
sPackageInfos.clear();
sInstalledPackages.clear();
+ sPackageAppEnabledStates.clear();
org.robolectric.shadows.ShadowApplicationPackageManager.reset();
}
}
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 dcc461be0015..7017440a86bb 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
@@ -221,11 +221,14 @@ class PackageManagerComponentLabelIconOverrideTest {
@After
fun verifyExpectedResult() {
assertServiceInitialized() ?: return
- if (params.componentName != null) {
- val activityInfo = service.getActivityInfo(params.componentName, 0, userId)
- if (activityInfo != null) {
- assertThat(activityInfo.nonLocalizedLabel).isEqualTo(params.expectedLabel)
- assertThat(activityInfo.icon).isEqualTo(params.expectedIcon)
+ if (params.componentName != null && params.result !is Result.Exception) {
+ // Suppress so that failures in @After don't override the actual test failure
+ @Suppress("UNNECESSARY_SAFE_CALL")
+ service?.let {
+ val activityInfo = it.snapshotComputer()
+ .getActivityInfo(params.componentName, 0, userId)
+ assertThat(activityInfo?.nonLocalizedLabel).isEqualTo(params.expectedLabel)
+ assertThat(activityInfo?.icon).isEqualTo(params.expectedIcon)
}
}
}
@@ -237,9 +240,12 @@ class PackageManagerComponentLabelIconOverrideTest {
Result.Changed, Result.ChangedWithoutNotify -> {
// Suppress so that failures in @After don't override the actual test failure
@Suppress("UNNECESSARY_SAFE_CALL")
- val activityInfo = service?.getActivityInfo(params.componentName, 0, userIdDifferent)
- assertThat(activityInfo?.nonLocalizedLabel).isEqualTo(DEFAULT_LABEL)
- assertThat(activityInfo?.icon).isEqualTo(DEFAULT_ICON)
+ service?.let {
+ val activityInfo = it.snapshotComputer()
+ ?.getActivityInfo(params.componentName, 0, userIdDifferent)
+ assertThat(activityInfo?.nonLocalizedLabel).isEqualTo(DEFAULT_LABEL)
+ assertThat(activityInfo?.icon).isEqualTo(DEFAULT_ICON)
+ }
}
Result.NotChanged, is Result.Exception -> {}
}.run { /*exhaust*/ }
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
index 83ccabf03935..7a9c41256d61 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
@@ -143,6 +143,7 @@ class AndroidPackageTest : ParcelableComponentTest(AndroidPackage::class, Packag
AndroidPackage::getLogo,
AndroidPackage::getLocaleConfigRes,
AndroidPackage::getManageSpaceActivityName,
+ AndroidPackage::getMaxSdkVersion,
AndroidPackage::getMemtagMode,
AndroidPackage::getMinSdkVersion,
AndroidPackage::getNativeHeapZeroInitialized,
@@ -505,11 +506,6 @@ class AndroidPackageTest : ParcelableComponentTest(AndroidPackage::class, Packag
)
}
),
- getSetByValue(
- AndroidPackage::shouldInheritKeyStoreKeys,
- ParsingPackage::setInheritKeyStoreKeys,
- true
- ),
getter(AndroidPackage::getKnownActivityEmbeddingCerts, setOf("TESTEMBEDDINGCERT")),
getSetByValue(
AndroidPackage::isOnBackInvokedCallbackEnabled,
diff --git a/services/tests/mockingservicestests/AndroidManifest.xml b/services/tests/mockingservicestests/AndroidManifest.xml
index 3cab5ecd3de1..7714cf0ca094 100644
--- a/services/tests/mockingservicestests/AndroidManifest.xml
+++ b/services/tests/mockingservicestests/AndroidManifest.xml
@@ -31,6 +31,7 @@
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission
android:name="android.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD"/>
+ <uses-permission android:name="android.permission.STATUS_BAR_SERVICE" />
<!-- needed by MasterClearReceiverTest to display a system dialog -->
<uses-permission android:name="android.permission.INTERNAL_SYSTEM_WINDOW"/>
diff --git a/services/tests/mockingservicestests/src/android/service/games/GameSessionTest.java b/services/tests/mockingservicestests/src/android/service/games/GameSessionTest.java
index e89c812ba1fb..4fe9cd30e4ff 100644
--- a/services/tests/mockingservicestests/src/android/service/games/GameSessionTest.java
+++ b/services/tests/mockingservicestests/src/android/service/games/GameSessionTest.java
@@ -28,7 +28,6 @@ import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
-import android.graphics.Bitmap;
import android.platform.test.annotations.Presubmit;
import android.service.games.GameSession.ScreenshotCallback;
import android.testing.AndroidTestingRunner;
@@ -61,7 +60,6 @@ import java.util.concurrent.TimeUnit;
@TestableLooper.RunWithLooper(setAsMainLooper = true)
public final class GameSessionTest {
private static final long WAIT_FOR_CALLBACK_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(1);
- private static final Bitmap TEST_BITMAP = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
@Mock
private IGameSessionController mMockGameSessionController;
@@ -101,7 +99,7 @@ public final class GameSessionTest {
}
@Override
- public void onSuccess(Bitmap bitmap) {
+ public void onSuccess() {
fail();
}
});
@@ -131,7 +129,7 @@ public final class GameSessionTest {
}
@Override
- public void onSuccess(Bitmap bitmap) {
+ public void onSuccess() {
fail();
}
});
@@ -160,7 +158,7 @@ public final class GameSessionTest {
}
@Override
- public void onSuccess(Bitmap bitmap) {
+ public void onSuccess() {
fail();
}
});
@@ -170,10 +168,10 @@ public final class GameSessionTest {
}
@Test
- public void takeScreenshot_gameManagerSuccess_returnsBitmap() throws Exception {
+ public void takeScreenshot_gameManagerSuccess() throws Exception {
doAnswer(invocation -> {
AndroidFuture result = invocation.getArgument(1);
- result.complete(GameScreenshotResult.createSuccessResult(TEST_BITMAP));
+ result.complete(GameScreenshotResult.createSuccessResult());
return null;
}).when(mMockGameSessionController).takeScreenshot(anyInt(), any());
@@ -187,8 +185,7 @@ public final class GameSessionTest {
}
@Override
- public void onSuccess(Bitmap bitmap) {
- assertEquals(TEST_BITMAP, bitmap);
+ public void onSuccess() {
countDownLatch.countDown();
}
});
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 f05658bf6b0b..e09668756f10 100644
--- a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
@@ -494,9 +494,9 @@ public class AlarmManagerServiceTest {
final ArgumentCaptor<AlarmManagerService.UninstallReceiver> packageReceiverCaptor =
ArgumentCaptor.forClass(AlarmManagerService.UninstallReceiver.class);
- verify(mMockContext).registerReceiver(packageReceiverCaptor.capture(),
+ verify(mMockContext).registerReceiverForAllUsers(packageReceiverCaptor.capture(),
argThat((filter) -> filter.hasAction(Intent.ACTION_PACKAGE_ADDED)
- && filter.hasAction(Intent.ACTION_PACKAGE_REMOVED)));
+ && filter.hasAction(Intent.ACTION_PACKAGE_REMOVED)), isNull(), isNull());
mPackageChangesReceiver = packageReceiverCaptor.getValue();
assertEquals(mService.mExactAlarmCandidates, Collections.emptySet());
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 053551309661..47d4c8d9af46 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/BackgroundRestrictionTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/BackgroundRestrictionTest.java
@@ -19,6 +19,8 @@ package com.android.server.am;
import static android.Manifest.permission.ACCESS_BACKGROUND_LOCATION;
import static android.Manifest.permission.ACCESS_COARSE_LOCATION;
import static android.Manifest.permission.ACCESS_FINE_LOCATION;
+import static android.Manifest.permission.CAMERA;
+import static android.Manifest.permission.RECORD_AUDIO;
import static android.app.ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
import static android.app.ActivityManager.PROCESS_STATE_TOP;
import static android.app.ActivityManager.RESTRICTION_LEVEL_ADAPTIVE_BUCKET;
@@ -26,6 +28,14 @@ import static android.app.ActivityManager.RESTRICTION_LEVEL_BACKGROUND_RESTRICTE
import static android.app.ActivityManager.RESTRICTION_LEVEL_EXEMPTED;
import static android.app.ActivityManager.RESTRICTION_LEVEL_RESTRICTED_BUCKET;
import static android.app.ActivityManager.isLowRamDeviceStatic;
+import static android.app.AppOpsManager.MODE_ALLOWED;
+import static android.app.AppOpsManager.MODE_IGNORED;
+import static android.app.AppOpsManager.OP_ACTIVATE_PLATFORM_VPN;
+import static android.app.AppOpsManager.OP_ACTIVATE_VPN;
+import static android.app.AppOpsManager.OP_CAMERA;
+import static android.app.AppOpsManager.OP_FINE_LOCATION;
+import static android.app.AppOpsManager.OP_NONE;
+import static android.app.AppOpsManager.OP_RECORD_AUDIO;
import static android.app.usage.UsageStatsManager.REASON_MAIN_FORCED_BY_SYSTEM;
import static android.app.usage.UsageStatsManager.REASON_MAIN_FORCED_BY_USER;
import static android.app.usage.UsageStatsManager.REASON_MAIN_USAGE;
@@ -51,6 +61,7 @@ import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentat
import static com.android.internal.notification.SystemNotificationChannels.ABUSIVE_BACKGROUND_APPS;
import static com.android.server.am.AppBatteryTracker.AppBatteryPolicy.getFloatArray;
import static com.android.server.am.AppBatteryTracker.BatteryUsage.BATTERY_USAGE_INDEX_BACKGROUND;
+import static com.android.server.am.AppBatteryTracker.BatteryUsage.BATTERY_USAGE_INDEX_CACHED;
import static com.android.server.am.AppBatteryTracker.BatteryUsage.BATTERY_USAGE_INDEX_FOREGROUND;
import static com.android.server.am.AppBatteryTracker.BatteryUsage.BATTERY_USAGE_INDEX_FOREGROUND_SERVICE;
import static com.android.server.am.AppBatteryTracker.BatteryUsage.BATT_DIMENS;
@@ -58,6 +69,7 @@ import static com.android.server.am.AppPermissionTracker.AppPermissionPolicy;
import static com.android.server.am.AppRestrictionController.STOCK_PM_FLAGS;
import static com.android.server.am.BaseAppStateTracker.STATE_TYPE_FGS_LOCATION;
import static com.android.server.am.BaseAppStateTracker.STATE_TYPE_FGS_MEDIA_PLAYBACK;
+import static com.android.server.am.BaseAppStateTracker.STATE_TYPE_FGS_WITH_NOTIFICATION;
import static com.android.server.am.BaseAppStateTracker.STATE_TYPE_MEDIA_SESSION;
import static com.android.server.am.BaseAppStateTracker.STATE_TYPE_PERMISSION;
@@ -112,6 +124,7 @@ import android.os.UidBatteryConsumer;
import android.os.UserHandle;
import android.permission.PermissionManager;
import android.provider.DeviceConfig;
+import android.service.notification.StatusBarNotification;
import android.telephony.TelephonyManager;
import android.util.Log;
import android.util.Pair;
@@ -119,6 +132,7 @@ import android.util.Pair;
import androidx.test.runner.AndroidJUnit4;
import com.android.internal.R;
+import com.android.internal.app.IAppOpsService;
import com.android.server.AppStateTracker;
import com.android.server.DeviceIdleInternal;
import com.android.server.am.AppBatteryExemptionTracker.AppBatteryExemptionPolicy;
@@ -231,6 +245,7 @@ public final class BackgroundRestrictionTest {
@Mock private MediaSessionManager mMediaSessionManager;
@Mock private RoleManager mRoleManager;
@Mock private TelephonyManager mTelephonyManager;
+ @Mock private IAppOpsService mIAppOpsService;
private long mCurrentTimeMillis;
@@ -296,21 +311,21 @@ public final class BackgroundRestrictionTest {
doReturn(new String[]{packageName})
.when(mPackageManager)
.getPackagesForUid(eq(uid));
- doReturn(AppOpsManager.MODE_IGNORED)
- .when(mAppOpsManager)
- .checkOpNoThrow(AppOpsManager.OP_ACTIVATE_VPN, uid, packageName);
- doReturn(AppOpsManager.MODE_IGNORED)
- .when(mAppOpsManager)
- .checkOpNoThrow(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN, uid, packageName);
+ final int[] ops = new int[] {
+ OP_ACTIVATE_VPN,
+ OP_ACTIVATE_PLATFORM_VPN,
+ OP_FINE_LOCATION,
+ OP_CAMERA,
+ OP_RECORD_AUDIO,
+ };
+ for (int op : ops) {
+ setAppOpState(packageName, uid, op, false);
+ }
final String[] permissions = new String[] {ACCESS_BACKGROUND_LOCATION,
- ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION};
+ ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION, CAMERA, RECORD_AUDIO,
+ };
for (String permission : permissions) {
- doReturn(PERMISSION_DENIED)
- .when(mPermissionManagerServiceInternal)
- .checkUidPermission(uid, permission);
- doReturn(PERMISSION_DENIED)
- .when(mPermissionManagerServiceInternal)
- .checkPermission(packageName, permission, userId);
+ setPermissionState(packageName, uid, permission, false);
}
}
doReturn(appStandbyInfoList).when(mAppStandbyInternal).getAppStandbyBuckets(userId);
@@ -563,6 +578,7 @@ public final class BackgroundRestrictionTest {
DeviceConfigSession<Float> bgCurrentDrainBgRestrictedThreshold = null;
DeviceConfigSession<Boolean> bgPromptFgsWithNotiToBgRestricted = null;
DeviceConfigSession<Long> bgNotificationMinInterval = null;
+ DeviceConfigSession<Integer> bgBatteryExemptionTypes = null;
mBgRestrictionController.addAppBackgroundRestrictionListener(listener);
@@ -624,20 +640,29 @@ public final class BackgroundRestrictionTest {
ConstantsObserver.DEFAULT_BG_ABUSIVE_NOTIFICATION_MINIMAL_INTERVAL_MS);
bgNotificationMinInterval.set(windowMs);
+ bgBatteryExemptionTypes = new DeviceConfigSession<>(
+ DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ AppBatteryPolicy.KEY_BG_CURRENT_DRAIN_EXEMPTED_TYPES,
+ DeviceConfig::getInt,
+ mContext.getResources().getInteger(
+ R.integer.config_bg_current_drain_exempted_types));
+ bgBatteryExemptionTypes.set(0);
+
mCurrentTimeMillis = 10_000L;
doReturn(mCurrentTimeMillis - windowMs).when(stats).getStatsStartTimestamp();
doReturn(mCurrentTimeMillis).when(stats).getStatsEndTimestamp();
doReturn(statsList).when(mBatteryStatsInternal).getBatteryUsageStats(anyObject());
- doReturn(true).when(mNotificationManagerInternal).isNotificationShown(
- testPkgName, null, notificationId, testUser);
mAppFGSTracker.onForegroundServiceStateChanged(testPkgName, testUid,
testPid, true);
mAppFGSTracker.onForegroundServiceNotificationUpdated(
testPkgName, testUid, notificationId);
+ mAppFGSTracker.mNotificationListener.onNotificationPosted(new StatusBarNotification(
+ testPkgName, null, notificationId, null, testUid, testPid,
+ new Notification(), UserHandle.of(testUser), null, mCurrentTimeMillis), null);
runTestBgCurrentDrainMonitorOnce(listener, stats, uids,
new double[]{restrictBucketThresholdMah - 1, 0},
- new double[]{0, restrictBucketThresholdMah - 1}, zeros,
+ new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
() -> {
doReturn(mCurrentTimeMillis).when(stats).getStatsStartTimestamp();
doReturn(mCurrentTimeMillis + windowMs)
@@ -654,7 +679,7 @@ public final class BackgroundRestrictionTest {
runTestBgCurrentDrainMonitorOnce(listener, stats, uids,
new double[]{restrictBucketThresholdMah + 1, 0},
- new double[]{0, restrictBucketThresholdMah - 1}, zeros,
+ new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
() -> {
doReturn(mCurrentTimeMillis).when(stats).getStatsStartTimestamp();
doReturn(mCurrentTimeMillis + windowMs)
@@ -672,7 +697,7 @@ public final class BackgroundRestrictionTest {
runTestBgCurrentDrainMonitorOnce(listener, stats, uids,
new double[]{restrictBucketThresholdMah - 1, 0},
- new double[]{0, restrictBucketThresholdMah - 1}, zeros,
+ new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
() -> {
doReturn(mCurrentTimeMillis).when(stats).getStatsStartTimestamp();
doReturn(mCurrentTimeMillis + windowMs)
@@ -696,7 +721,7 @@ public final class BackgroundRestrictionTest {
// Trigger user interaction.
runTestBgCurrentDrainMonitorOnce(listener, stats, uids,
new double[]{restrictBucketThresholdMah - 1, 0},
- new double[]{0, restrictBucketThresholdMah - 1}, zeros,
+ new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
() -> {
doReturn(mCurrentTimeMillis).when(stats).getStatsStartTimestamp();
doReturn(mCurrentTimeMillis + windowMs)
@@ -719,8 +744,8 @@ public final class BackgroundRestrictionTest {
clearInvocations(mInjector.getAppStandbyInternal());
runTestBgCurrentDrainMonitorOnce(listener, stats, uids,
- new double[]{restrictBucketThresholdMah + 1, 0},
- new double[]{0, restrictBucketThresholdMah - 1}, zeros,
+ zeros, new double[]{0, restrictBucketThresholdMah - 1},
+ zeros, new double[]{restrictBucketThresholdMah + 1, 0},
() -> {
doReturn(mCurrentTimeMillis).when(stats).getStatsStartTimestamp();
doReturn(mCurrentTimeMillis + windowMs)
@@ -738,8 +763,8 @@ public final class BackgroundRestrictionTest {
clearInvocations(mInjector.getAppStandbyInternal());
// Drain a bit more, there shouldn't be any level changes.
runTestBgCurrentDrainMonitorOnce(listener, stats, uids,
- new double[]{restrictBucketThresholdMah + 2, 0},
- new double[]{0, restrictBucketThresholdMah - 1}, zeros,
+ zeros, new double[]{0, restrictBucketThresholdMah - 1},
+ zeros, new double[]{restrictBucketThresholdMah + 2, 0},
() -> {
doReturn(mCurrentTimeMillis).when(stats).getStatsStartTimestamp();
doReturn(mCurrentTimeMillis + windowMs)
@@ -771,7 +796,7 @@ public final class BackgroundRestrictionTest {
runTestBgCurrentDrainMonitorOnce(listener, stats, uids,
new double[]{bgRestrictedThresholdMah + 1, 0},
- new double[]{0, restrictBucketThresholdMah - 1}, zeros,
+ new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
() -> {
doReturn(mCurrentTimeMillis).when(stats).getStatsStartTimestamp();
doReturn(mCurrentTimeMillis + windowMs)
@@ -809,7 +834,7 @@ public final class BackgroundRestrictionTest {
runTestBgCurrentDrainMonitorOnce(listener, stats, uids,
new double[]{bgRestrictedThresholdMah + 1, 0},
- new double[]{0, restrictBucketThresholdMah - 1}, zeros,
+ new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
() -> {
doReturn(mCurrentTimeMillis).when(stats).getStatsStartTimestamp();
doReturn(mCurrentTimeMillis + windowMs)
@@ -848,7 +873,7 @@ public final class BackgroundRestrictionTest {
runTestBgCurrentDrainMonitorOnce(listener, stats, uids,
new double[]{bgRestrictedThresholdMah + 1, 0},
- new double[]{0, restrictBucketThresholdMah - 1}, zeros,
+ new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
() -> {
doReturn(mCurrentTimeMillis).when(stats).getStatsStartTimestamp();
doReturn(mCurrentTimeMillis + windowMs)
@@ -912,6 +937,7 @@ public final class BackgroundRestrictionTest {
closeIfNotNull(bgCurrentDrainBgRestrictedThreshold);
closeIfNotNull(bgPromptFgsWithNotiToBgRestricted);
closeIfNotNull(bgNotificationMinInterval);
+ closeIfNotNull(bgBatteryExemptionTypes);
}
}
@@ -1129,51 +1155,51 @@ public final class BackgroundRestrictionTest {
// Long-running FGS with type "location", but ran for a very short time.
runTestLongFGSExemptionOnce(testPkgName1, testUid1, testPid1,
- FOREGROUND_SERVICE_TYPE_LOCATION, 0, null, null, null,
+ FOREGROUND_SERVICE_TYPE_LOCATION, 0, null, OP_NONE, null, null,
timeout(windowMs * 2).times(2));
// Long-running FGS with type "location", and ran for a while.
// We shouldn't see notifications in this case.
runTestLongFGSExemptionOnce(testPkgName1, testUid1, testPid1,
- FOREGROUND_SERVICE_TYPE_LOCATION, thresholdMs * 2, null, null, null,
+ FOREGROUND_SERVICE_TYPE_LOCATION, thresholdMs * 2, null, OP_NONE, null, null,
timeout(windowMs * 2).times(0));
// Long-running FGS with background location permission.
runTestLongFGSExemptionOnce(testPkgName1, testUid1, testPid1,
- FOREGROUND_SERVICE_TYPE_LOCATION, 0, ACCESS_BACKGROUND_LOCATION, null, null,
- timeout(windowMs * 2).times(0));
+ FOREGROUND_SERVICE_TYPE_LOCATION, 0, ACCESS_BACKGROUND_LOCATION, OP_NONE,
+ null, null, timeout(windowMs * 2).times(0));
// Long-running FGS with type "mediaPlayback", but ran for a very short time.
runTestLongFGSExemptionOnce(testPkgName1, testUid1, testPid1,
- FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK, 0, null, null, null,
+ FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK, 0, null, OP_NONE, null, null,
timeout(windowMs * 2).times(2));
// Long-running FGS with type "mediaPlayback", and ran for a while.
// We shouldn't see notifications in this case.
runTestLongFGSExemptionOnce(testPkgName1, testUid1, testPid1,
- FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK, thresholdMs * 2, null, null, null,
- timeout(windowMs * 2).times(0));
+ FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK, thresholdMs * 2, null, OP_NONE,
+ null, null, timeout(windowMs * 2).times(0));
// Long-running FGS with type "camera", and ran for a while.
// We shouldn't see notifications in this case.
runTestLongFGSExemptionOnce(testPkgName1, testUid1, testPid1,
- FOREGROUND_SERVICE_TYPE_CAMERA, thresholdMs * 2, null, null, null,
+ FOREGROUND_SERVICE_TYPE_CAMERA, thresholdMs * 2, null, OP_NONE, null, null,
timeout(windowMs * 2).times(0));
// Long-running FGS with type "location|mediaPlayback", but ran for a very short time.
runTestLongFGSExemptionOnce(testPkgName1, testUid1, testPid1,
FOREGROUND_SERVICE_TYPE_LOCATION | FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK,
- 0, null, null, null, timeout(windowMs * 2).times(2));
+ 0, null, OP_NONE, null, null, timeout(windowMs * 2).times(2));
// Long-running FGS with type "location|mediaPlayback", and ran for a while.
// We shouldn't see notifications in this case.
runTestLongFGSExemptionOnce(testPkgName1, testUid1, testPid1,
FOREGROUND_SERVICE_TYPE_LOCATION | FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK,
- thresholdMs * 2, null, null, null, timeout(windowMs * 2).times(0));
+ thresholdMs * 2, null, OP_NONE, null, null, timeout(windowMs * 2).times(0));
// Long-running FGS with a media session starts/stops right away.
runTestLongFGSExemptionOnce(testPkgName1, testUid1, testPid1,
- FOREGROUND_SERVICE_TYPE_NONE, 0, null,
+ FOREGROUND_SERVICE_TYPE_NONE, 0, null, OP_NONE,
List.of(Pair.create(createMediaControllers(
new String[] {testPkgName1}, new int[] {testUid1}), 0L)), null,
timeout(windowMs * 2).times(2));
@@ -1181,14 +1207,14 @@ public final class BackgroundRestrictionTest {
// Long-running FGS with media session, and ran for a while.
// We shouldn't see notifications in this case.
runTestLongFGSExemptionOnce(testPkgName1, testUid1, testPid1,
- FOREGROUND_SERVICE_TYPE_NONE, thresholdMs * 2, null,
+ FOREGROUND_SERVICE_TYPE_NONE, thresholdMs * 2, null, OP_NONE,
List.of(Pair.create(createMediaControllers(new String[] {testPkgName1},
new int[] {testUid1}), thresholdMs * 2)), null,
timeout(windowMs * 2).times(0));
// Long-running FGS with 2 media sessions start/stop right away
runTestLongFGSExemptionOnce(testPkgName1, testUid1, testPid1,
- FOREGROUND_SERVICE_TYPE_NONE, 0, null,
+ FOREGROUND_SERVICE_TYPE_NONE, 0, null, OP_NONE,
List.of(Pair.create(createMediaControllers(
new String[] {testPkgName1, testPkgName2},
new int[] {testUid1, testUid2}), 0L)), null,
@@ -1196,7 +1222,7 @@ public final class BackgroundRestrictionTest {
// Long-running FGS with 2 media sessions start/stop interlaced.
runTestLongFGSExemptionOnce(testPkgName1, testUid1, testPid1,
- FOREGROUND_SERVICE_TYPE_NONE, 0, null,
+ FOREGROUND_SERVICE_TYPE_NONE, 0, null, OP_NONE,
List.of(Pair.create(createMediaControllers(
new String[] {testPkgName1, testPkgName2},
new int[] {testUid1, testUid2}), thresholdMs),
@@ -1214,17 +1240,17 @@ public final class BackgroundRestrictionTest {
// Long-running FGS with top state for a very short time.
runTestLongFGSExemptionOnce(testPkgName1, testUid1, testPid1,
- FOREGROUND_SERVICE_TYPE_NONE, 0, null, null, List.of(0L),
+ FOREGROUND_SERVICE_TYPE_NONE, 0, null, OP_NONE, null, List.of(0L),
timeout(windowMs * 2).times(2));
// Long-running FGS with top state for extended time.
runTestLongFGSExemptionOnce(testPkgName1, testUid1, testPid1,
- FOREGROUND_SERVICE_TYPE_NONE, 0, null, null, List.of(0L, windowMs * 2, 0L),
- timeout(windowMs * 2).times(0));
+ FOREGROUND_SERVICE_TYPE_NONE, 0, null, OP_NONE, null,
+ List.of(0L, windowMs * 2, 0L), timeout(windowMs * 2).times(0));
// Long-running FGS with top state, on and off frequently.
runTestLongFGSExemptionOnce(testPkgName1, testUid1, testPid1,
- FOREGROUND_SERVICE_TYPE_NONE, 0, null, null,
+ FOREGROUND_SERVICE_TYPE_NONE, 0, null, OP_NONE, null,
List.of(0L, thresholdMs / 10, thresholdMs / 10, thresholdMs / 10,
thresholdMs / 10, thresholdMs / 10, thresholdMs / 10),
timeout(windowMs * 2).times(2));
@@ -1243,18 +1269,19 @@ public final class BackgroundRestrictionTest {
}
private void runTestLongFGSExemptionOnce(String packageName, int uid, int pid,
- int serviceType, long sleepMs, String perm,
+ int serviceType, long sleepMs, String perm, int op,
List<Pair<List<MediaController>, Long>> mediaControllers, List<Long> topStateChanges,
VerificationMode mode) throws Exception {
runExemptionTestOnce(
- packageName, uid, pid, serviceType, sleepMs, true, perm, mediaControllers,
- topStateChanges, true, true,
+ packageName, uid, pid, serviceType, sleepMs, true, false, perm, op,
+ mediaControllers, topStateChanges, true, true,
() -> checkNotificationShown(new String[] {packageName}, mode, false)
);
}
private void runExemptionTestOnce(String packageName, int uid, int pid,
- int serviceType, long sleepMs, boolean stopAfterSleep, String perm,
+ int serviceType, long sleepMs, boolean stopAfterSleep,
+ boolean withNotification, String perm, int op,
List<Pair<List<MediaController>, Long>> mediaControllers,
List<Long> topStateChanges, boolean resetFGSTracker, boolean resetController,
RunnableWithException r) throws Exception {
@@ -1299,14 +1326,25 @@ public final class BackgroundRestrictionTest {
FOREGROUND_SERVICE_TYPE_NONE);
}
}
-
+ if (withNotification) {
+ final int notificationId = 1000;
+ mAppFGSTracker.onForegroundServiceNotificationUpdated(
+ packageName, uid, notificationId);
+ final StatusBarNotification noti = new StatusBarNotification(
+ packageName, null, notificationId, null, uid, pid,
+ new Notification(), UserHandle.of(UserHandle.getUserId(uid)),
+ null, mCurrentTimeMillis);
+ mAppFGSTracker.mNotificationListener.onNotificationPosted(noti, null);
+ Thread.sleep(sleepMs);
+ if (stopAfterSleep) {
+ mAppFGSTracker.mNotificationListener.onNotificationRemoved(noti, null, 0);
+ }
+ }
if (perm != null) {
- doReturn(PERMISSION_GRANTED)
- .when(mPermissionManagerServiceInternal)
- .checkPermission(packageName, perm, UserHandle.getUserId(uid));
- doReturn(PERMISSION_GRANTED)
- .when(mPermissionManagerServiceInternal)
- .checkUidPermission(uid, perm);
+ setPermissionState(packageName, uid, perm, true);
+ if (op != OP_NONE) {
+ setAppOpState(packageName, uid, op, true);
+ }
mInjector.getAppPermissionTracker().onPermissionsChanged(uid);
}
@@ -1327,12 +1365,10 @@ public final class BackgroundRestrictionTest {
mAppFGSTracker.onForegroundServiceStateChanged(packageName, uid, pid, false);
if (perm != null) {
- doReturn(PERMISSION_DENIED)
- .when(mPermissionManagerServiceInternal)
- .checkPermission(packageName, perm, UserHandle.getUserId(uid));
- doReturn(PERMISSION_DENIED)
- .when(mPermissionManagerServiceInternal)
- .checkUidPermission(uid, perm);
+ setPermissionState(packageName, uid, perm, false);
+ if (op != OP_NONE) {
+ setAppOpState(packageName, uid, op, false);
+ }
mInjector.getAppPermissionTracker().onPermissionsChanged(uid);
}
if (topStateThread != null) {
@@ -1510,7 +1546,8 @@ public final class BackgroundRestrictionTest {
mContext.getResources().getInteger(
R.integer.config_bg_current_drain_exempted_types));
bgBatteryExemptionTypes.set(STATE_TYPE_MEDIA_SESSION | STATE_TYPE_FGS_MEDIA_PLAYBACK
- | STATE_TYPE_FGS_LOCATION | STATE_TYPE_PERMISSION);
+ | STATE_TYPE_FGS_LOCATION | STATE_TYPE_PERMISSION
+ | STATE_TYPE_FGS_WITH_NOTIFICATION);
bgPermissionMonitorEnabled = new DeviceConfigSession<>(
DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
@@ -1543,19 +1580,19 @@ public final class BackgroundRestrictionTest {
// Run with a media playback service which starts/stops immediately, we should
// goto the restricted bucket.
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
- FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK, 0, true,
- null, null, null, listener, stats, uids,
+ FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK, 0, true, false,
+ null, OP_NONE, null, null, listener, stats, uids,
new double[]{restrictBucketThresholdMah + 1, 0},
- new double[]{0, restrictBucketThresholdMah - 1}, zeros,
+ new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
false, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, true,
- null, windowMs, null, null, null);
+ null, windowMs, null, null, null, null);
// Run with a media playback service with extended time. We should be back to normal.
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK, bgMediaPlaybackMinDuration * 2, false,
- null, null, null, listener, stats, uids,
+ false, null, OP_NONE, null, null, listener, stats, uids,
new double[]{restrictBucketThresholdMah + 1, 0},
- new double[]{0, restrictBucketThresholdMah - 1}, zeros,
+ new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
true, RESTRICTION_LEVEL_ADAPTIVE_BUCKET, timeout, false,
() -> {
// A user interaction will bring it back to normal.
@@ -1572,116 +1609,119 @@ public final class BackgroundRestrictionTest {
eq(REASON_SUB_FORCED_SYSTEM_FLAG_ABUSE),
eq(REASON_MAIN_USAGE),
eq(REASON_SUB_USAGE_USER_INTERACTION));
- }, windowMs, null, null, null);
+ }, windowMs, null, null, null, null);
// Start over.
resetBgRestrictionController();
- setUidBatteryConsumptions(stats, uids, zeros, zeros, zeros);
+ setUidBatteryConsumptions(stats, uids, zeros, zeros, zeros, zeros);
mAppBatteryPolicy.reset();
// Run with a media playback service with extended time, with higher current drain.
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK, bgMediaPlaybackMinDuration * 2, false,
- null, null, null, listener, stats, uids,
+ false, null, OP_NONE, null, null, listener, stats, uids,
new double[]{restrictBucketHighThresholdMah - 1, 0},
- new double[]{0, restrictBucketThresholdMah - 1}, zeros,
+ new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
true, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, true,
- null, windowMs, null, null, null);
+ null, windowMs, null, null, null, null);
// Run with a media playback service with extended time, with even higher current drain.
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK, bgMediaPlaybackMinDuration * 2, false,
- null, null, null, listener, stats, uids,
+ false, null, OP_NONE, null, null, listener, stats, uids,
new double[]{restrictBucketHighThresholdMah + 1, 0},
- new double[]{0, restrictBucketThresholdMah - 1}, zeros,
+ new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
false, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, false,
- null, windowMs, null, null, null);
+ null, windowMs, null, null, null, null);
// Start over.
resetBgRestrictionController();
- setUidBatteryConsumptions(stats, uids, zeros, zeros, zeros);
+ setUidBatteryConsumptions(stats, uids, zeros, zeros, zeros, zeros);
mAppBatteryPolicy.reset();
// Run with a media session with extended time, with higher current drain.
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
- FOREGROUND_SERVICE_TYPE_NONE, bgMediaPlaybackMinDuration * 2, false, null,
+ FOREGROUND_SERVICE_TYPE_NONE, bgMediaPlaybackMinDuration * 2, false, false,
+ null, OP_NONE,
List.of(Pair.create(createMediaControllers(new String[] {testPkgName1},
- new int[] {testUid1}), bgMediaPlaybackMinDuration * 2)),
+ new int[] {testUid1}), bgMediaPlaybackMinDuration * 2)),
null, listener, stats, uids,
new double[]{restrictBucketHighThresholdMah - 1, 0},
- new double[]{0, restrictBucketThresholdMah - 1}, zeros,
+ new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
true, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, true,
- null, windowMs, null, null, null);
+ null, windowMs, null, null, null, null);
// Run with a media session with extended time, with even higher current drain.
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
- FOREGROUND_SERVICE_TYPE_NONE, bgMediaPlaybackMinDuration * 2, false, null,
+ FOREGROUND_SERVICE_TYPE_NONE, bgMediaPlaybackMinDuration * 2, false, false,
+ null, OP_NONE,
List.of(Pair.create(createMediaControllers(new String[] {testPkgName1},
- new int[] {testUid1}), bgMediaPlaybackMinDuration * 2)),
+ new int[] {testUid1}), bgMediaPlaybackMinDuration * 2)),
null, listener, stats, uids,
new double[]{restrictBucketHighThresholdMah + 1, 0},
- new double[]{0, restrictBucketThresholdMah - 1}, zeros,
+ new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
false, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, false,
- null, windowMs, null, null, null);
+ null, windowMs, null, null, null, null);
// Start over.
resetBgRestrictionController();
- setUidBatteryConsumptions(stats, uids, zeros, zeros, zeros);
+ setUidBatteryConsumptions(stats, uids, zeros, zeros, zeros, zeros);
mAppBatteryPolicy.reset();
// Run with a media session with extended time, with moderate current drain,
// but it ran on the top when the location service is active.
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
- FOREGROUND_SERVICE_TYPE_NONE, bgMediaPlaybackMinDuration * 2, false, null,
+ FOREGROUND_SERVICE_TYPE_NONE, bgMediaPlaybackMinDuration * 2, false, false,
+ null, OP_NONE,
List.of(Pair.create(createMediaControllers(new String[] {testPkgName1},
- new int[] {testUid1}), bgMediaPlaybackMinDuration * 2)),
+ new int[] {testUid1}), bgMediaPlaybackMinDuration * 2)),
List.of(0L, timeout * 2), listener, stats, uids,
new double[]{restrictBucketThresholdMah + 1, 0},
- new double[]{0, restrictBucketThresholdMah - 1}, zeros,
+ new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
false, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, true,
- null, windowMs, null, null, null);
+ null, windowMs, null, null, null, null);
// Start over.
resetBgRestrictionController();
- setUidBatteryConsumptions(stats, uids, zeros, zeros, zeros);
+ setUidBatteryConsumptions(stats, uids, zeros, zeros, zeros, zeros);
mAppBatteryPolicy.reset();
// Run with a location service with extended time, with higher current drain.
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
- FOREGROUND_SERVICE_TYPE_LOCATION, bgMediaPlaybackMinDuration * 2, false,
- null, null, null, listener, stats, uids,
+ FOREGROUND_SERVICE_TYPE_LOCATION, bgMediaPlaybackMinDuration * 2, false, false,
+ null, OP_NONE, null, null, listener, stats, uids,
new double[]{restrictBucketHighThresholdMah - 1, 0},
- new double[]{0, restrictBucketThresholdMah - 1}, zeros,
+ new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
true, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, true,
- null, windowMs, null, null, null);
+ null, windowMs, null, null, null, null);
// Run with a location service with extended time, with even higher current drain.
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
- FOREGROUND_SERVICE_TYPE_LOCATION, bgMediaPlaybackMinDuration * 2, false,
- null, null, null, listener, stats, uids,
+ FOREGROUND_SERVICE_TYPE_LOCATION, bgMediaPlaybackMinDuration * 2, false, false,
+ null, OP_NONE, null, null, listener, stats, uids,
new double[]{restrictBucketHighThresholdMah + 1, 0},
- new double[]{0, restrictBucketThresholdMah - 1}, zeros,
+ new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
false, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, false,
- null, windowMs, null, null, null);
+ null, windowMs, null, null, null, null);
// Start over.
resetBgRestrictionController();
- setUidBatteryConsumptions(stats, uids, zeros, zeros, zeros);
+ setUidBatteryConsumptions(stats, uids, zeros, zeros, zeros, zeros);
mAppBatteryPolicy.reset();
// Run with a location service with extended time, with moderate current drain,
// but it ran on the top when the location service is active.
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
- FOREGROUND_SERVICE_TYPE_LOCATION, bgMediaPlaybackMinDuration * 2, false,
- null, null, List.of(0L, timeout * 2), listener, stats, uids,
+ FOREGROUND_SERVICE_TYPE_LOCATION, bgMediaPlaybackMinDuration * 2, false, false,
+ null, OP_NONE, null, List.of(0L, timeout * 2), listener, stats, uids,
new double[]{restrictBucketThresholdMah + 1, 0},
- new double[]{0, restrictBucketThresholdMah - 1}, zeros,
+ new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
false, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, true,
- null, windowMs, null, null, null);
+ null, windowMs, null, null, null, null);
// Start over.
resetBgRestrictionController();
- setUidBatteryConsumptions(stats, uids, zeros, zeros, zeros);
+ setUidBatteryConsumptions(stats, uids, zeros, zeros, zeros, zeros);
mAppBatteryPolicy.reset();
// Turn off the higher threshold for bg location access.
@@ -1689,25 +1729,25 @@ public final class BackgroundRestrictionTest {
// Run with bg location permission, with moderate current drain.
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
- FOREGROUND_SERVICE_TYPE_NONE, 0, false,
- ACCESS_BACKGROUND_LOCATION, null, null, listener, stats, uids,
+ FOREGROUND_SERVICE_TYPE_NONE, 0, false, false,
+ ACCESS_BACKGROUND_LOCATION, OP_NONE, null, null, listener, stats, uids,
new double[]{restrictBucketThresholdMah - 1, 0},
- new double[]{0, restrictBucketThresholdMah - 1}, zeros,
+ new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
true, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, true,
- null, windowMs, null, null, null);
+ null, windowMs, null, null, null, null);
// Run with bg location permission, with a bit higher current drain.
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
- FOREGROUND_SERVICE_TYPE_NONE, 0, false,
- ACCESS_BACKGROUND_LOCATION, null, null, listener, stats, uids,
+ FOREGROUND_SERVICE_TYPE_NONE, 0, false, false,
+ ACCESS_BACKGROUND_LOCATION, OP_NONE, null, null, listener, stats, uids,
new double[]{restrictBucketThresholdMah + 1, 0},
- new double[]{0, restrictBucketThresholdMah - 1}, zeros,
+ new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
false, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, true,
- null, windowMs, null, null, null);
+ null, windowMs, null, null, null, null);
// Start over.
resetBgRestrictionController();
- setUidBatteryConsumptions(stats, uids, zeros, zeros, zeros);
+ setUidBatteryConsumptions(stats, uids, zeros, zeros, zeros, zeros);
mAppBatteryPolicy.reset();
// Turn on the higher threshold for bg location access.
@@ -1715,21 +1755,21 @@ public final class BackgroundRestrictionTest {
// Run with bg location permission, with higher current drain.
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
- FOREGROUND_SERVICE_TYPE_NONE, 0, false,
- ACCESS_BACKGROUND_LOCATION , null, null, listener, stats, uids,
+ FOREGROUND_SERVICE_TYPE_NONE, 0, false, false,
+ ACCESS_BACKGROUND_LOCATION, OP_NONE, null, null, listener, stats, uids,
new double[]{restrictBucketHighThresholdMah - 1, 0},
- new double[]{0, restrictBucketThresholdMah - 1}, zeros,
+ new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
true , RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, false,
- null, windowMs, null, null, null);
+ null, windowMs, null, null, null, null);
// Run with bg location permission, with even higher current drain.
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
- FOREGROUND_SERVICE_TYPE_NONE, 0, false,
- ACCESS_BACKGROUND_LOCATION , null, null, listener, stats, uids,
+ FOREGROUND_SERVICE_TYPE_NONE, 0, false, false,
+ ACCESS_BACKGROUND_LOCATION, OP_NONE, null, null, listener, stats, uids,
new double[]{restrictBucketHighThresholdMah + 1, 0},
- new double[]{0, restrictBucketThresholdMah - 1}, zeros,
+ new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
false, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, false,
- null, windowMs, null, null, null);
+ null, windowMs, null, null, null, null);
// Now turn off the event duration based feature flag.
bgCurrentDrainEventDurationBasedThresholdEnabled.set(false);
@@ -1738,7 +1778,7 @@ public final class BackgroundRestrictionTest {
// Start over.
resetBgRestrictionController();
- setUidBatteryConsumptions(stats, uids, zeros, zeros, zeros);
+ setUidBatteryConsumptions(stats, uids, zeros, zeros, zeros, zeros);
mAppBatteryPolicy.reset();
waitForIdleHandler(mBgRestrictionController.getBackgroundHandler());
@@ -1746,19 +1786,19 @@ public final class BackgroundRestrictionTest {
// Run with a media playback service which starts/stops immediately, we should
// goto the restricted bucket.
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
- FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK, 0, true,
- null, null, null, listener, stats, uids,
+ FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK, 0, true, false,
+ null, OP_NONE, null, null, listener, stats, uids,
new double[]{restrictBucketThresholdMah + 1, 0},
- new double[]{0, restrictBucketThresholdMah - 1}, zeros,
+ new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
false, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, true,
- null, windowMs, null, null, null);
+ null, windowMs, null, null, null, null);
// Run with a media playback service with extended time. We should be back to normal.
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK, bgMediaPlaybackMinDuration * 2, false,
- null, null, null, listener, stats, uids,
+ false, null, OP_NONE, null, null, listener, stats, uids,
new double[]{restrictBucketThresholdMah + 1, 0},
- new double[]{0, restrictBucketThresholdMah - 1}, zeros,
+ new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
true, RESTRICTION_LEVEL_ADAPTIVE_BUCKET, timeout, false,
() -> {
// A user interaction will bring it back to normal.
@@ -1775,121 +1815,166 @@ public final class BackgroundRestrictionTest {
eq(REASON_SUB_FORCED_SYSTEM_FLAG_ABUSE),
eq(REASON_MAIN_USAGE),
eq(REASON_SUB_USAGE_USER_INTERACTION));
- }, windowMs, null, null, null);
+ }, windowMs, null, null, null, null);
// Start over.
resetBgRestrictionController();
- setUidBatteryConsumptions(stats, uids, zeros, zeros, zeros);
+ setUidBatteryConsumptions(stats, uids, zeros, zeros, zeros, zeros);
mAppBatteryPolicy.reset();
- final double[] initialBg = {1, 1}, initialFgs = {1, 1}, initialFg = zeros;
+ final double[] initialBg = {1, 1}, initialFgs = {1, 1}, initialFg = zeros,
+ initialCached = {1, 1};
// Run with a media playback service with extended time, with higher current drain.
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK, bgMediaPlaybackMinDuration * 2, false,
- null, null, null, listener, stats, uids,
+ false, null, OP_NONE, null, null, listener, stats, uids,
new double[]{restrictBucketHighThresholdMah - 1, 0},
- new double[]{0, restrictBucketThresholdMah - 1}, zeros,
+ new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
true, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, true,
- null, windowMs, initialBg, initialFgs, initialFg);
+ null, windowMs, initialBg, initialFgs, initialFg, initialCached);
// Run with a media playback service with extended time, with even higher current drain,
// it still should stay in the current restriction level as we exempt the media
// playback.
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK, bgMediaPlaybackMinDuration * 2, false,
- null, null, null, listener, stats, uids,
+ false, null, OP_NONE, null, null, listener, stats, uids,
new double[]{restrictBucketHighThresholdMah + 100, 0},
- new double[]{0, restrictBucketThresholdMah - 1}, zeros,
+ new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
true, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, false,
- null, windowMs, initialBg, initialFgs, initialFg);
+ null, windowMs, initialBg, initialFgs, initialFg, initialCached);
// Set the policy to exempt media session and permission.
bgBatteryExemptionTypes.set(STATE_TYPE_MEDIA_SESSION | STATE_TYPE_PERMISSION);
// Start over.
resetBgRestrictionController();
- setUidBatteryConsumptions(stats, uids, zeros, zeros, zeros);
+ setUidBatteryConsumptions(stats, uids, zeros, zeros, zeros, zeros);
mAppBatteryPolicy.reset();
// Run with coarse location permission, with high current drain.
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
- FOREGROUND_SERVICE_TYPE_NONE, 0, false,
- ACCESS_COARSE_LOCATION, null, null, listener, stats, uids,
+ FOREGROUND_SERVICE_TYPE_NONE, 0, false, false,
+ ACCESS_COARSE_LOCATION, OP_NONE, null, null, listener, stats, uids,
new double[]{restrictBucketThresholdMah + 1, 0},
- new double[]{0, restrictBucketThresholdMah - 1}, zeros,
+ new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
false, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, true,
- null, windowMs, initialBg, initialFgs, initialFg);
+ null, windowMs, initialBg, initialFgs, initialFg, initialCached);
// Start over.
resetBgRestrictionController();
- setUidBatteryConsumptions(stats, uids, zeros, zeros, zeros);
+ setUidBatteryConsumptions(stats, uids, zeros, zeros, zeros, zeros);
mAppBatteryPolicy.reset();
// Run with fine location permission, with high current drain.
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
- FOREGROUND_SERVICE_TYPE_NONE, 0, false,
- ACCESS_FINE_LOCATION, null, null, listener, stats, uids,
+ FOREGROUND_SERVICE_TYPE_NONE, 0, false, false,
+ ACCESS_FINE_LOCATION, OP_FINE_LOCATION, null, null, listener, stats, uids,
new double[]{restrictBucketThresholdMah + 1, 0},
- new double[]{0, restrictBucketThresholdMah - 1}, zeros,
+ new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
true, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, true,
- null, windowMs, initialBg, initialFgs, initialFg);
+ null, windowMs, initialBg, initialFgs, initialFg, initialCached);
// Start over.
resetBgRestrictionController();
- setUidBatteryConsumptions(stats, uids, zeros, zeros, zeros);
+ setUidBatteryConsumptions(stats, uids, zeros, zeros, zeros, zeros);
mAppBatteryPolicy.reset();
// Run with a media session with extended time, with higher current drain.
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
- FOREGROUND_SERVICE_TYPE_NONE, bgMediaPlaybackMinDuration * 2, false, null,
+ FOREGROUND_SERVICE_TYPE_NONE, bgMediaPlaybackMinDuration * 2, false, false,
+ null, OP_NONE,
List.of(Pair.create(createMediaControllers(new String[] {testPkgName1},
- new int[] {testUid1}), bgMediaPlaybackMinDuration * 2)),
+ new int[] {testUid1}), bgMediaPlaybackMinDuration * 2)),
null, listener, stats, uids,
new double[]{restrictBucketHighThresholdMah - 1, 0},
- new double[]{0, restrictBucketThresholdMah - 1}, zeros,
+ new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
true, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, true,
- null, windowMs, initialBg, initialFgs, initialFg);
+ null, windowMs, initialBg, initialFgs, initialFg, initialCached);
// Run with a media session with extended time, with even higher current drain.
// it still should stay in the current restriction level as we exempt the media
// session.
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
- FOREGROUND_SERVICE_TYPE_NONE, bgMediaPlaybackMinDuration * 2, false, null,
+ FOREGROUND_SERVICE_TYPE_NONE, bgMediaPlaybackMinDuration * 2, false, false,
+ null, OP_NONE,
List.of(Pair.create(createMediaControllers(new String[] {testPkgName1},
- new int[] {testUid1}), bgMediaPlaybackMinDuration * 2)),
+ new int[] {testUid1}), bgMediaPlaybackMinDuration * 2)),
null, listener, stats, uids,
new double[]{restrictBucketHighThresholdMah + 100, 0},
- new double[]{0, restrictBucketThresholdMah - 1}, zeros,
+ new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
true, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, true,
- null, windowMs, initialBg, initialFgs, initialFg);
+ null, windowMs, initialBg, initialFgs, initialFg, initialCached);
+
+ // Set the policy to exempt fgs with notifications.
+ bgBatteryExemptionTypes.set(STATE_TYPE_FGS_WITH_NOTIFICATION);
+ // Start over.
+ resetBgRestrictionController();
+ setUidBatteryConsumptions(stats, uids, zeros, zeros, zeros, zeros);
+ mAppBatteryPolicy.reset();
+
+ // Run with a FGS with notification posted/removed immediately, we should
+ // goto the restricted bucket.
+ runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
+ FOREGROUND_SERVICE_TYPE_NONE, 0, true, true,
+ null, OP_NONE, null, null, listener, stats, uids,
+ new double[]{restrictBucketThresholdMah + 1, 0},
+ new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
+ false, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, true,
+ null, windowMs, null, null, null, null);
+
+ // Run with a service with notification for extended time. We should be back to normal.
+ runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
+ FOREGROUND_SERVICE_TYPE_NONE, bgMediaPlaybackMinDuration * 2, false,
+ true, null, OP_NONE, null, null, listener, stats, uids,
+ new double[]{restrictBucketThresholdMah + 1, 0},
+ new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
+ true, RESTRICTION_LEVEL_ADAPTIVE_BUCKET, timeout, false,
+ () -> {
+ // A user interaction will bring it back to normal.
+ mIdleStateListener.onUserInteractionStarted(testPkgName1,
+ UserHandle.getUserId(testUid1));
+ waitForIdleHandler(mBgRestrictionController.getBackgroundHandler());
+ // It should have been back to normal.
+ listener.verify(timeout, testUid1, testPkgName1,
+ RESTRICTION_LEVEL_ADAPTIVE_BUCKET);
+ verify(mInjector.getAppStandbyInternal(), times(1)).maybeUnrestrictApp(
+ eq(testPkgName1),
+ eq(UserHandle.getUserId(testUid1)),
+ eq(REASON_MAIN_FORCED_BY_SYSTEM),
+ eq(REASON_SUB_FORCED_SYSTEM_FLAG_ABUSE),
+ eq(REASON_MAIN_USAGE),
+ eq(REASON_SUB_USAGE_USER_INTERACTION));
+ }, windowMs, null, null, null, null);
// Set the policy to exempt all.
bgBatteryExemptionTypes.set(STATE_TYPE_MEDIA_SESSION | STATE_TYPE_FGS_MEDIA_PLAYBACK
- | STATE_TYPE_FGS_LOCATION | STATE_TYPE_PERMISSION);
+ | STATE_TYPE_FGS_LOCATION | STATE_TYPE_PERMISSION
+ | STATE_TYPE_FGS_WITH_NOTIFICATION);
// Start over.
resetBgRestrictionController();
- setUidBatteryConsumptions(stats, uids, zeros, zeros, zeros);
+ setUidBatteryConsumptions(stats, uids, zeros, zeros, zeros, zeros);
mAppBatteryPolicy.reset();
// Run with a location service with extended time, with higher current drain.
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
- FOREGROUND_SERVICE_TYPE_LOCATION, bgMediaPlaybackMinDuration * 2, false,
- null, null, null, listener, stats, uids,
+ FOREGROUND_SERVICE_TYPE_LOCATION, bgMediaPlaybackMinDuration * 2, false, false,
+ null, OP_NONE, null, null, listener, stats, uids,
new double[]{restrictBucketHighThresholdMah - 1, 0},
- new double[]{0, restrictBucketThresholdMah - 1}, zeros,
+ new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
true, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, true,
- null, windowMs, initialBg, initialFgs, initialFg);
+ null, windowMs, initialBg, initialFgs, initialFg, initialCached);
// Run with a location service with extended time, with even higher current drain.
// it still should stay in the current restriction level as we exempt the location.
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
- FOREGROUND_SERVICE_TYPE_LOCATION, bgMediaPlaybackMinDuration * 2, false,
- null, null, null, listener, stats, uids,
+ FOREGROUND_SERVICE_TYPE_LOCATION, bgMediaPlaybackMinDuration * 2, false, false,
+ null, OP_NONE, null, null, listener, stats, uids,
new double[]{restrictBucketHighThresholdMah + 100, 0},
- new double[]{0, restrictBucketThresholdMah - 1}, zeros,
+ new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
true, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, false,
- null, windowMs, initialBg, initialFgs, initialFg);
+ null, windowMs, initialBg, initialFgs, initialFg, initialCached);
} finally {
closeIfNotNull(bgCurrentDrainMonitor);
closeIfNotNull(bgCurrentDrainWindow);
@@ -1909,40 +1994,39 @@ public final class BackgroundRestrictionTest {
}
private void runTestBgCurrentDrainExemptionOnce(String packageName, int uid, int pid,
- int serviceType, long sleepMs, boolean stopAfterSleep, String perm,
- List<Pair<List<MediaController>, Long>> mediaControllers,
+ int serviceType, long sleepMs, boolean stopAfterSleep, boolean withNotification,
+ String perm, int op, List<Pair<List<MediaController>, Long>> mediaControllers,
List<Long> topStateChanges, TestAppRestrictionLevelListener listener,
BatteryUsageStats stats, int[] uids, double[] bg, double[] fgs, double[] fg,
- boolean expectingTimeout, int expectingLevel, long timeout, boolean resetFGSTracker,
- RunnableWithException extraVerifiers, long windowMs,
- double[] initialBg, double[] initialFgs, double[] initialFg) throws Exception {
+ double[] cached, boolean expectingTimeout, int expectingLevel, long timeout,
+ boolean resetFGSTracker, RunnableWithException extraVerifiers, long windowMs,
+ double[] initialBg, double[] initialFgs, double[] initialFg, double[] initialCached)
+ throws Exception {
listener.mLatchHolder[0] = new CountDownLatch(1);
if (initialBg != null) {
doReturn(mCurrentTimeMillis).when(stats).getStatsStartTimestamp();
doReturn(mCurrentTimeMillis + windowMs).when(stats).getStatsEndTimestamp();
mCurrentTimeMillis += windowMs + 1;
- setUidBatteryConsumptions(stats, uids, initialBg, initialFgs, initialFg);
+ setUidBatteryConsumptions(stats, uids, initialBg, initialFgs, initialFg, initialCached);
mAppBatteryExemptionTracker.reset();
mAppBatteryPolicy.reset();
}
if (perm != null) {
- doReturn(PERMISSION_GRANTED)
- .when(mPermissionManagerServiceInternal)
- .checkPermission(packageName, perm, UserHandle.getUserId(uid));
- doReturn(PERMISSION_GRANTED)
- .when(mPermissionManagerServiceInternal)
- .checkUidPermission(uid, perm);
+ setPermissionState(packageName, uid, perm, true);
+ if (op != OP_NONE) {
+ setAppOpState(packageName, uid, op, true);
+ }
mInjector.getAppPermissionTracker().onPermissionsChanged(uid);
}
waitForIdleHandler(mBgRestrictionController.getBackgroundHandler());
runExemptionTestOnce(
- packageName, uid, pid, serviceType, sleepMs, stopAfterSleep,
- perm, mediaControllers, topStateChanges, resetFGSTracker, false,
+ packageName, uid, pid, serviceType, sleepMs, stopAfterSleep, withNotification,
+ perm, op, mediaControllers, topStateChanges, resetFGSTracker, false,
() -> {
clearInvocations(mInjector.getAppStandbyInternal());
clearInvocations(mBgRestrictionController);
- runTestBgCurrentDrainMonitorOnce(listener, stats, uids, bg, fgs, fg, false,
- () -> {
+ runTestBgCurrentDrainMonitorOnce(listener, stats, uids, bg, fgs, fg, cached,
+ false, () -> {
doReturn(mCurrentTimeMillis).when(stats).getStatsStartTimestamp();
doReturn(mCurrentTimeMillis + windowMs)
.when(stats).getStatsEndTimestamp();
@@ -1985,16 +2069,36 @@ public final class BackgroundRestrictionTest {
}
);
if (perm != null) {
- doReturn(PERMISSION_DENIED)
- .when(mPermissionManagerServiceInternal)
- .checkPermission(packageName, perm, UserHandle.getUserId(uid));
- doReturn(PERMISSION_DENIED)
- .when(mPermissionManagerServiceInternal)
- .checkUidPermission(uid, perm);
+ setPermissionState(packageName, uid, perm, false);
+ if (op != OP_NONE) {
+ setAppOpState(packageName, uid, op, false);
+ }
mInjector.getAppPermissionTracker().onPermissionsChanged(uid);
}
}
+ private void setPermissionState(String packageName, int uid, String perm, boolean granted) {
+ doReturn(granted ? PERMISSION_GRANTED : PERMISSION_DENIED)
+ .when(mPermissionManagerServiceInternal)
+ .checkUidPermission(uid, perm);
+ doReturn(granted ? PERMISSION_GRANTED : PERMISSION_DENIED)
+ .when(mPermissionManagerServiceInternal)
+ .checkPermission(packageName, perm, UserHandle.getUserId(uid));
+ }
+
+ private void setAppOpState(String packageName, int uid, int op, boolean granted) {
+ try {
+ doReturn(granted ? MODE_ALLOWED : MODE_IGNORED)
+ .when(mAppOpsManager)
+ .checkOpNoThrow(op, uid, packageName);
+ doReturn(granted ? MODE_ALLOWED : MODE_IGNORED)
+ .when(mIAppOpsService)
+ .checkOperation(op, uid, packageName);
+ } catch (RemoteException e) {
+ // Ignore.
+ }
+ }
+
@Test
public void testExcessiveBroadcasts() throws Exception {
final long windowMs = 5_000;
@@ -2180,30 +2284,33 @@ public final class BackgroundRestrictionTest {
private void runTestBgCurrentDrainMonitorOnce(TestAppRestrictionLevelListener listener,
BatteryUsageStats stats, int[] uids, double[] bg, double[] fgs, double[] fg,
- RunnableWithException runnable) throws Exception {
- runTestBgCurrentDrainMonitorOnce(listener, stats, uids, bg, fgs, fg, true, runnable);
+ double[] cached, RunnableWithException runnable) throws Exception {
+ runTestBgCurrentDrainMonitorOnce(listener, stats, uids, bg, fgs, fg, cached, true,
+ runnable);
}
private void runTestBgCurrentDrainMonitorOnce(TestAppRestrictionLevelListener listener,
BatteryUsageStats stats, int[] uids, double[] bg, double[] fgs, double[] fg,
- boolean resetListener, RunnableWithException runnable) throws Exception {
+ double[] cached, boolean resetListener, RunnableWithException runnable)
+ throws Exception {
if (resetListener) {
listener.mLatchHolder[0] = new CountDownLatch(1);
}
- setUidBatteryConsumptions(stats, uids, bg, fgs, fg);
+ setUidBatteryConsumptions(stats, uids, bg, fgs, fg, cached);
runnable.run();
}
private void setUidBatteryConsumptions(BatteryUsageStats stats, int[] uids, double[] bg,
- double[] fgs, double[] fg) {
+ double[] fgs, double[] fg, double[] cached) {
ArrayList<UidBatteryConsumer> consumers = new ArrayList<>();
for (int i = 0; i < uids.length; i++) {
- consumers.add(mockUidBatteryConsumer(uids[i], bg[i], fgs[i], fg[i]));
+ consumers.add(mockUidBatteryConsumer(uids[i], bg[i], fgs[i], fg[i], cached[i]));
}
doReturn(consumers).when(stats).getUidBatteryConsumers();
}
- private UidBatteryConsumer mockUidBatteryConsumer(int uid, double bg, double fgs, double fg) {
+ private UidBatteryConsumer mockUidBatteryConsumer(int uid, double bg, double fgs, double fg,
+ double cached) {
UidBatteryConsumer uidConsumer = mock(UidBatteryConsumer.class);
doReturn(uid).when(uidConsumer).getUid();
doReturn(bg).when(uidConsumer).getConsumedPower(
@@ -2212,6 +2319,8 @@ public final class BackgroundRestrictionTest {
eq(BATT_DIMENS[BATTERY_USAGE_INDEX_FOREGROUND_SERVICE]));
doReturn(fg).when(uidConsumer).getConsumedPower(
eq(BATT_DIMENS[BATTERY_USAGE_INDEX_FOREGROUND]));
+ doReturn(cached).when(uidConsumer).getConsumedPower(
+ eq(BATT_DIMENS[BATTERY_USAGE_INDEX_CACHED]));
return uidConsumer;
}
@@ -2512,7 +2621,7 @@ public final class BackgroundRestrictionTest {
final LinkedList<UidStateEventWithBattery> result = new LinkedList<>();
for (int i = 0; i < isStart.length; i++) {
result.add(new UidStateEventWithBattery(isStart[i], timestamps[i],
- new ImmutableBatteryUsage(0.0d, 0.0d, batteryUsage[i], 0.0d), null));
+ new ImmutableBatteryUsage(0.0d, 0.0d, batteryUsage[i], 0.0d, 0.0d), null));
}
return result;
}
@@ -2748,6 +2857,11 @@ public final class BackgroundRestrictionTest {
RoleManager getRoleManager() {
return BackgroundRestrictionTest.this.mRoleManager;
}
+
+ @Override
+ IAppOpsService getIAppOpsService() {
+ return BackgroundRestrictionTest.this.mIAppOpsService;
+ }
}
private class TestAppBatteryTrackerInjector extends TestBaseTrackerInjector<AppBatteryPolicy> {
diff --git a/services/tests/mockingservicestests/src/com/android/server/app/GameServiceProviderInstanceImplTest.java b/services/tests/mockingservicestests/src/com/android/server/app/GameServiceProviderInstanceImplTest.java
index 32a31d0e57f7..319a769bb1de 100644
--- a/services/tests/mockingservicestests/src/com/android/server/app/GameServiceProviderInstanceImplTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/app/GameServiceProviderInstanceImplTest.java
@@ -19,6 +19,7 @@ package com.android.server.app;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.verifyNoMoreInteractions;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
import static com.android.server.app.GameServiceProviderInstanceImplTest.FakeGameService.GameServiceState;
@@ -26,19 +27,21 @@ import static com.google.common.collect.Iterables.getOnlyElement;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.verifyZeroInteractions;
import android.Manifest;
import android.annotation.Nullable;
import android.app.ActivityManager.RunningTaskInfo;
+import android.app.ActivityManagerInternal;
import android.app.ActivityTaskManager;
import android.app.IActivityManager;
import android.app.IActivityTaskManager;
+import android.app.IProcessObserver;
import android.app.ITaskStackListener;
import android.content.ComponentName;
import android.content.Context;
@@ -46,7 +49,12 @@ import android.content.ContextWrapper;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Picture;
import android.graphics.Rect;
+import android.net.Uri;
import android.os.RemoteException;
import android.os.UserHandle;
import android.platform.test.annotations.Presubmit;
@@ -71,6 +79,7 @@ import com.android.internal.infra.AndroidFuture;
import com.android.internal.util.ConcurrentUtils;
import com.android.internal.util.FunctionalUtils.ThrowingConsumer;
import com.android.internal.util.Preconditions;
+import com.android.internal.util.ScreenshotHelper;
import com.android.server.wm.WindowManagerInternal;
import com.android.server.wm.WindowManagerInternal.TaskSystemBarsListener;
import com.android.server.wm.WindowManagerService;
@@ -87,6 +96,7 @@ import org.mockito.quality.Strictness;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Objects;
+import java.util.function.Consumer;
/**
@@ -114,11 +124,22 @@ public final class GameServiceProviderInstanceImplTest {
new ComponentName(GAME_B_PACKAGE, "com.package.game.b.MainActivity");
- private static final Bitmap TEST_BITMAP = Bitmap.createBitmap(32, 32, Bitmap.Config.ARGB_8888);
+ private static final Bitmap TEST_BITMAP;
+ static {
+ Picture picture = new Picture();
+ Canvas canvas = picture.beginRecording(200, 100);
+ Paint p = new Paint();
+ p.setColor(Color.BLACK);
+ canvas.drawCircle(10, 10, 10, p);
+ picture.endRecording();
+ TEST_BITMAP = Bitmap.createBitmap(picture);
+ }
private MockitoSession mMockingSession;
private GameServiceProviderInstance mGameServiceProviderInstance;
@Mock
+ private ActivityManagerInternal mMockActivityManagerInternal;
+ @Mock
private IActivityTaskManager mMockActivityTaskManager;
@Mock
private WindowManagerService mMockWindowManagerService;
@@ -126,6 +147,8 @@ public final class GameServiceProviderInstanceImplTest {
private WindowManagerInternal mMockWindowManagerInternal;
@Mock
private IActivityManager mMockActivityManager;
+ @Mock
+ private ScreenshotHelper mMockScreenshotHelper;
private MockContext mMockContext;
private FakeGameClassifier mFakeGameClassifier;
private FakeGameService mFakeGameService;
@@ -133,6 +156,7 @@ public final class GameServiceProviderInstanceImplTest {
private FakeGameSessionService mFakeGameSessionService;
private FakeServiceConnector<IGameSessionService> mFakeGameSessionServiceConnector;
private ArrayList<ITaskStackListener> mTaskStackListeners;
+ private ArrayList<IProcessObserver> mProcessObservers;
private ArrayList<TaskSystemBarsListener> mTaskSystemBarsListeners;
private ArrayList<RunningTaskInfo> mRunningTaskInfos;
@@ -167,6 +191,16 @@ public final class GameServiceProviderInstanceImplTest {
return null;
}).when(mMockActivityTaskManager).unregisterTaskStackListener(any());
+ mProcessObservers = new ArrayList<>();
+ doAnswer(invocation -> {
+ mProcessObservers.add(invocation.getArgument(0));
+ return null;
+ }).when(mMockActivityManager).registerProcessObserver(any());
+ doAnswer(invocation -> {
+ mProcessObservers.remove(invocation.getArgument(0));
+ return null;
+ }).when(mMockActivityManager).unregisterProcessObserver(any());
+
mTaskSystemBarsListeners = new ArrayList<>();
doAnswer(invocation -> {
mTaskSystemBarsListeners.add(invocation.getArgument(0));
@@ -188,11 +222,13 @@ public final class GameServiceProviderInstanceImplTest {
mMockContext,
mFakeGameClassifier,
mMockActivityManager,
+ mMockActivityManagerInternal,
mMockActivityTaskManager,
mMockWindowManagerService,
mMockWindowManagerInternal,
mFakeGameServiceConnector,
- mFakeGameSessionServiceConnector);
+ mFakeGameSessionServiceConnector,
+ mMockScreenshotHelper);
}
@After
@@ -410,6 +446,214 @@ public final class GameServiceProviderInstanceImplTest {
}
@Test
+ public void gameProcessStopped_soleProcess_destroysGameSession() throws Exception {
+ int gameProcessId = 1000;
+
+ mGameServiceProviderInstance.start();
+
+ startTask(10, GAME_A_MAIN_ACTIVITY);
+ startProcessForPackage(gameProcessId, GAME_A_PACKAGE);
+
+ mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY);
+ mFakeGameService.requestCreateGameSession(10);
+
+ FakeGameSession gameSession10 = new FakeGameSession();
+ SurfacePackage mockSurfacePackage10 = Mockito.mock(SurfacePackage.class);
+ mFakeGameSessionService.removePendingFutureForTaskId(10)
+ .complete(new CreateGameSessionResult(gameSession10, mockSurfacePackage10));
+ assertThat(gameSession10.mIsDestroyed).isFalse();
+
+ // Death of the sole game process destroys the game session.
+ dispatchProcessDied(gameProcessId);
+ assertThat(gameSession10.mIsDestroyed).isTrue();
+ }
+
+ @Test
+ public void gameProcessStopped_soleProcess_destroysMultipleGameSessionsForSamePackage()
+ throws Exception {
+ int gameProcessId = 1000;
+
+ mGameServiceProviderInstance.start();
+
+ // Multiple tasks exist for the same package.
+ startTask(10, GAME_A_MAIN_ACTIVITY);
+ startTask(11, GAME_A_MAIN_ACTIVITY);
+ startProcessForPackage(gameProcessId, GAME_A_PACKAGE);
+
+ mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY);
+ mFakeGameService.requestCreateGameSession(10);
+ mFakeGameService.requestCreateGameSession(11);
+
+ FakeGameSession gameSession10 = new FakeGameSession();
+ SurfacePackage mockSurfacePackage10 = Mockito.mock(SurfacePackage.class);
+ mFakeGameSessionService.removePendingFutureForTaskId(10)
+ .complete(new CreateGameSessionResult(gameSession10, mockSurfacePackage10));
+ FakeGameSession gameSession11 = new FakeGameSession();
+ SurfacePackage mockSurfacePackage11 = Mockito.mock(SurfacePackage.class);
+ mFakeGameSessionService.removePendingFutureForTaskId(11)
+ .complete(new CreateGameSessionResult(gameSession11, mockSurfacePackage11));
+
+ assertThat(gameSession10.mIsDestroyed).isFalse();
+ assertThat(gameSession11.mIsDestroyed).isFalse();
+
+ // Death of the sole game process destroys both game sessions.
+ dispatchProcessDied(gameProcessId);
+ assertThat(gameSession10.mIsDestroyed).isTrue();
+ assertThat(gameSession11.mIsDestroyed).isTrue();
+ }
+
+ @Test
+ public void gameProcessStopped_multipleProcesses_gameSessionDestroyedWhenAllDead()
+ throws Exception {
+ int firstGameProcessId = 1000;
+ int secondGameProcessId = 1001;
+
+ mGameServiceProviderInstance.start();
+
+ startTask(10, GAME_A_MAIN_ACTIVITY);
+ startProcessForPackage(firstGameProcessId, GAME_A_PACKAGE);
+ startProcessForPackage(secondGameProcessId, GAME_A_PACKAGE);
+
+ mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY);
+ mFakeGameService.requestCreateGameSession(10);
+
+ FakeGameSession gameSession10 = new FakeGameSession();
+ SurfacePackage mockSurfacePackage10 = Mockito.mock(SurfacePackage.class);
+ mFakeGameSessionService.removePendingFutureForTaskId(10)
+ .complete(new CreateGameSessionResult(gameSession10, mockSurfacePackage10));
+ assertThat(gameSession10.mIsDestroyed).isFalse();
+
+ // Death of the first process (with the second one still alive) does not destroy the game
+ // session.
+ dispatchProcessDied(firstGameProcessId);
+ assertThat(gameSession10.mIsDestroyed).isFalse();
+
+ // Death of the second process does destroy the game session.
+ dispatchProcessDied(secondGameProcessId);
+ assertThat(gameSession10.mIsDestroyed).isTrue();
+ }
+
+ @Test
+ public void gameProcessCreatedAfterInitialProcessDead_newGameSessionCreated() throws Exception {
+ int firstGameProcessId = 1000;
+ int secondGameProcessId = 1000;
+
+ mGameServiceProviderInstance.start();
+
+ startTask(10, GAME_A_MAIN_ACTIVITY);
+ startProcessForPackage(firstGameProcessId, GAME_A_PACKAGE);
+
+ mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY);
+ mFakeGameService.requestCreateGameSession(10);
+
+ FakeGameSession gameSession10 = new FakeGameSession();
+ SurfacePackage mockSurfacePackage10 = Mockito.mock(SurfacePackage.class);
+ mFakeGameSessionService.removePendingFutureForTaskId(10)
+ .complete(new CreateGameSessionResult(gameSession10, mockSurfacePackage10));
+ assertThat(gameSession10.mIsDestroyed).isFalse();
+
+ // After the first game process dies, the game session should be destroyed.
+ dispatchProcessDied(firstGameProcessId);
+ assertThat(gameSession10.mIsDestroyed).isTrue();
+
+ // However, when a new process for the game starts, a new game session should be created.
+ startProcessForPackage(secondGameProcessId, GAME_A_PACKAGE);
+ // Verify that a new pending game session is created for the game's taskId.
+ assertNotNull(mFakeGameSessionService.removePendingFutureForTaskId(10));
+ }
+
+ @Test
+ public void gameProcessCreatedAfterInitialProcessDead_multipleGameSessionsCreatedSamePackage()
+ throws Exception {
+ int firstGameProcessId = 1000;
+ int secondGameProcessId = 1000;
+
+ mGameServiceProviderInstance.start();
+
+ // Multiple tasks exist for the same package.
+ startTask(10, GAME_A_MAIN_ACTIVITY);
+ startTask(11, GAME_A_MAIN_ACTIVITY);
+ startProcessForPackage(firstGameProcessId, GAME_A_PACKAGE);
+
+ mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY);
+
+ mFakeGameService.requestCreateGameSession(10);
+ mFakeGameService.requestCreateGameSession(11);
+
+ FakeGameSession gameSession10 = new FakeGameSession();
+ SurfacePackage mockSurfacePackage10 = Mockito.mock(SurfacePackage.class);
+ mFakeGameSessionService.removePendingFutureForTaskId(10)
+ .complete(new CreateGameSessionResult(gameSession10, mockSurfacePackage10));
+ FakeGameSession gameSession11 = new FakeGameSession();
+ SurfacePackage mockSurfacePackage11 = Mockito.mock(SurfacePackage.class);
+ mFakeGameSessionService.removePendingFutureForTaskId(11)
+ .complete(new CreateGameSessionResult(gameSession11, mockSurfacePackage11));
+
+ assertThat(gameSession10.mIsDestroyed).isFalse();
+ assertThat(gameSession11.mIsDestroyed).isFalse();
+
+ // After the first game process dies, both game sessions for the package should be
+ // destroyed.
+ dispatchProcessDied(firstGameProcessId);
+ assertThat(gameSession10.mIsDestroyed).isTrue();
+ assertThat(gameSession11.mIsDestroyed).isTrue();
+
+ // However, when a new process for the game starts, new game sessions for the same
+ // package should be created.
+ startProcessForPackage(secondGameProcessId, GAME_A_PACKAGE);
+ // Verify that new pending game sessions were created for each of the game's taskIds.
+ assertNotNull(mFakeGameSessionService.removePendingFutureForTaskId(10));
+ assertNotNull(mFakeGameSessionService.removePendingFutureForTaskId(11));
+ }
+
+ @Test
+ public void gameProcessStarted_gameSessionNotRequested_doesNothing() throws Exception {
+ int gameProcessId = 1000;
+
+ mGameServiceProviderInstance.start();
+
+ // A game task and process are started, but requestCreateGameSession is never called.
+ startTask(10, GAME_A_MAIN_ACTIVITY);
+ startProcessForPackage(gameProcessId, GAME_A_PACKAGE);
+
+ mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY);
+
+ // No game session should be created.
+ assertThat(mFakeGameSessionService.getCapturedCreateInvocations()).isEmpty();
+ }
+
+ @Test
+ public void processActivityAndDeath_notForGame_gameSessionUnaffected() throws Exception {
+ mGameServiceProviderInstance.start();
+
+ startTask(10, GAME_A_MAIN_ACTIVITY);
+
+ mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY);
+ mFakeGameService.requestCreateGameSession(10);
+
+ FakeGameSession gameSession10 = new FakeGameSession();
+ SurfacePackage mockSurfacePackage10 = Mockito.mock(SurfacePackage.class);
+ mFakeGameSessionService.removePendingFutureForTaskId(10)
+ .complete(new CreateGameSessionResult(gameSession10, mockSurfacePackage10));
+
+ // Process activity for a process without a known package is ignored.
+ startProcessForPackage(1000, /*packageName=*/ null);
+ dispatchProcessActivity(1000);
+ dispatchProcessDied(1000);
+
+ // Process activity for a process with a different package is ignored
+ startProcessForPackage(1001, GAME_B_PACKAGE);
+ dispatchProcessActivity(1001);
+ dispatchProcessDied(1001);
+
+ // Death of a process for which there was no activity is ignored
+ dispatchProcessDied(1002);
+
+ // Despite all the process activity and death, the game session is not destroyed.
+ assertThat(gameSession10.mIsDestroyed).isFalse();
+ }
+
+ @Test
public void taskSystemBarsListenerChanged_noAssociatedGameSession_doesNothing() {
mGameServiceProviderInstance.start();
@@ -425,6 +669,7 @@ public final class GameServiceProviderInstanceImplTest {
public void systemBarsTransientShownDueToGesture_hasGameSession_propagatesToGameSession() {
mGameServiceProviderInstance.start();
startTask(10, GAME_A_MAIN_ACTIVITY);
+ mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY);
mFakeGameService.requestCreateGameSession(10);
FakeGameSession gameSession10 = new FakeGameSession();
@@ -446,6 +691,7 @@ public final class GameServiceProviderInstanceImplTest {
public void systemBarsTransientShownButNotGesture_hasGameSession_notPropagatedToGameSession() {
mGameServiceProviderInstance.start();
startTask(10, GAME_A_MAIN_ACTIVITY);
+ mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY);
mFakeGameService.requestCreateGameSession(10);
FakeGameSession gameSession10 = new FakeGameSession();
@@ -799,27 +1045,32 @@ public final class GameServiceProviderInstanceImplTest {
SurfaceControl mockOverlaySurfaceControl = Mockito.mock(SurfaceControl.class);
SurfaceControl[] excludeLayers = new SurfaceControl[1];
excludeLayers[0] = mockOverlaySurfaceControl;
+ int taskId = 10;
when(mMockWindowManagerService.captureTaskBitmap(eq(10), any())).thenReturn(TEST_BITMAP);
-
+ doAnswer(invocation -> {
+ Consumer<Uri> consumer = invocation.getArgument(invocation.getArguments().length - 1);
+ consumer.accept(Uri.parse("a/b.png"));
+ return null;
+ }).when(mMockScreenshotHelper).provideScreenshot(
+ any(), any(), any(), anyInt(), anyInt(), any(), anyInt(), any(), any());
mGameServiceProviderInstance.start();
- startTask(10, GAME_A_MAIN_ACTIVITY);
+ startTask(taskId, GAME_A_MAIN_ACTIVITY);
mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY);
- mFakeGameService.requestCreateGameSession(10);
+ mFakeGameService.requestCreateGameSession(taskId);
FakeGameSession gameSession10 = new FakeGameSession();
SurfacePackage mockOverlaySurfacePackage = Mockito.mock(SurfacePackage.class);
when(mockOverlaySurfacePackage.getSurfaceControl()).thenReturn(mockOverlaySurfaceControl);
- mFakeGameSessionService.removePendingFutureForTaskId(10)
+ mFakeGameSessionService.removePendingFutureForTaskId(taskId)
.complete(new CreateGameSessionResult(gameSession10, mockOverlaySurfacePackage));
IGameSessionController gameSessionController = getOnlyElement(
mFakeGameSessionService.getCapturedCreateInvocations()).mGameSessionController;
AndroidFuture<GameScreenshotResult> resultFuture = new AndroidFuture<>();
- gameSessionController.takeScreenshot(10, resultFuture);
+ gameSessionController.takeScreenshot(taskId, resultFuture);
GameScreenshotResult result = resultFuture.get();
assertEquals(GameScreenshotResult.GAME_SCREENSHOT_SUCCESS, result.getStatus());
- assertEquals(TEST_BITMAP, result.getBitmap());
}
@Test
@@ -874,7 +1125,8 @@ public final class GameServiceProviderInstanceImplTest {
mFakeGameSessionService.getCapturedCreateInvocations())
.mGameSessionController.restartGame(11);
- verifyZeroInteractions(mMockActivityManager);
+ verify(mMockActivityManager).registerProcessObserver(any());
+ verifyNoMoreInteractions(mMockActivityManager);
assertThat(mMockContext.getLastStartedIntent()).isNull();
}
@@ -906,7 +1158,6 @@ public final class GameServiceProviderInstanceImplTest {
dispatchTaskRemoved(taskId);
}
-
private void dispatchTaskRemoved(int taskId) {
dispatchTaskChangeEvent(taskStackListener -> {
taskStackListener.onTaskRemoved(taskId);
@@ -932,6 +1183,37 @@ public final class GameServiceProviderInstanceImplTest {
}
}
+ private void startProcessForPackage(int processId, @Nullable String packageName) {
+ if (packageName != null) {
+ when(mMockActivityManagerInternal.getPackageNameByPid(processId)).thenReturn(
+ packageName);
+ }
+
+ dispatchProcessActivity(processId);
+ }
+
+ private void dispatchProcessActivity(int processId) {
+ dispatchProcessChangedEvent(processObserver -> {
+ // Neither uid nor foregroundActivities are used by the implementation being tested.
+ processObserver.onForegroundActivitiesChanged(processId, /*uid=*/
+ 0, /*foregroundActivities=*/ false);
+ });
+ }
+
+ private void dispatchProcessDied(int processId) {
+ dispatchProcessChangedEvent(processObserver -> {
+ // The uid param is not used by the implementation being tested.
+ processObserver.onProcessDied(processId, /*uid=*/ 0);
+ });
+ }
+
+ private void dispatchProcessChangedEvent(
+ ThrowingConsumer<IProcessObserver> processObserverConsumer) {
+ for (IProcessObserver processObserver : mProcessObservers) {
+ processObserverConsumer.accept(processObserver);
+ }
+ }
+
private void mockPermissionGranted(String permission) {
mMockContext.setPermission(permission, PackageManager.PERMISSION_GRANTED);
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
index b5ad459d29f7..8d6269c93764 100644
--- a/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
@@ -118,6 +118,7 @@ public class LocalDisplayAdapterTest {
LocalServices.removeServiceForTest(LightsManager.class);
LocalServices.addService(LightsManager.class, mMockedLightsManager);
mInjector = new Injector();
+ when(mSurfaceControlProxy.getBootDisplayModeSupport()).thenReturn(true);
mAdapter = new LocalDisplayAdapter(mMockedSyncRoot, mMockedContext, mHandler,
mListener, mInjector);
spyOn(mAdapter);
@@ -754,6 +755,57 @@ public class LocalDisplayAdapterTest {
verify(mMockedBacklight, never()).setBrightness(anyFloat());
}
+ @Test
+ public void testGetSystemPreferredDisplayMode() throws Exception {
+ SurfaceControl.DisplayMode displayMode1 = createFakeDisplayMode(0, 1920, 1080, 60f);
+ // preferred mode
+ SurfaceControl.DisplayMode displayMode2 = createFakeDisplayMode(1, 3840, 2160, 60f);
+
+ SurfaceControl.DisplayMode[] modes =
+ new SurfaceControl.DisplayMode[]{displayMode1, displayMode2};
+ FakeDisplay display = new FakeDisplay(PORT_A, modes, 0, 1);
+ setUpDisplay(display);
+ updateAvailableDisplays();
+ mAdapter.registerLocked();
+ waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS);
+
+ assertThat(mListener.addedDisplays.size()).isEqualTo(1);
+ assertThat(mListener.changedDisplays).isEmpty();
+
+ DisplayDeviceInfo displayDeviceInfo = mListener.addedDisplays.get(
+ 0).getDisplayDeviceInfoLocked();
+
+ assertThat(displayDeviceInfo.supportedModes.length).isEqualTo(modes.length);
+
+ Display.Mode defaultMode = getModeById(displayDeviceInfo, displayDeviceInfo.defaultModeId);
+ assertThat(matches(defaultMode, displayMode2)).isTrue();
+
+ // Change the display and add new preferred mode
+ SurfaceControl.DisplayMode addedDisplayInfo = createFakeDisplayMode(2, 2340, 1080, 60f);
+ modes = new SurfaceControl.DisplayMode[]{displayMode1, displayMode2, addedDisplayInfo};
+ display.dynamicInfo.supportedDisplayModes = modes;
+ display.dynamicInfo.preferredBootDisplayMode = 2;
+ setUpDisplay(display);
+ mInjector.getTransmitter().sendHotplug(display, /* connected */ true);
+ waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS);
+
+ assertTrue(mListener.traversalRequested);
+ assertThat(mListener.addedDisplays.size()).isEqualTo(1);
+ assertThat(mListener.changedDisplays.size()).isEqualTo(1);
+
+ DisplayDevice displayDevice = mListener.changedDisplays.get(0);
+ displayDevice.applyPendingDisplayDeviceInfoChangesLocked();
+ displayDeviceInfo = displayDevice.getDisplayDeviceInfoLocked();
+
+ assertThat(displayDeviceInfo.supportedModes.length).isEqualTo(modes.length);
+ assertModeIsSupported(displayDeviceInfo.supportedModes, displayMode1);
+ assertModeIsSupported(displayDeviceInfo.supportedModes, displayMode2);
+ assertModeIsSupported(displayDeviceInfo.supportedModes, addedDisplayInfo);
+
+ assertThat(matches(displayDevice.getSystemPreferredDisplayModeLocked(), addedDisplayInfo))
+ .isTrue();
+ }
+
private void assertDisplayDpi(DisplayDeviceInfo info, int expectedPort,
float expectedXdpi,
float expectedYDpi,
@@ -831,6 +883,16 @@ public class LocalDisplayAdapterTest {
dynamicInfo.supportedDisplayModes = modes;
dynamicInfo.activeDisplayModeId = activeMode;
}
+
+ private FakeDisplay(int port, SurfaceControl.DisplayMode[] modes, int activeMode,
+ int preferredMode) {
+ address = createDisplayAddress(port);
+ info = createFakeDisplayInfo();
+ dynamicInfo.supportedDisplayModes = modes;
+ dynamicInfo.activeDisplayModeId = activeMode;
+ dynamicInfo.preferredBootDisplayMode = preferredMode;
+ }
+
}
private void setUpDisplay(FakeDisplay display) {
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/BackgroundDexOptServiceUnitTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/BackgroundDexOptServiceUnitTest.java
index 8223b8c86c5b..444db9128662 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/BackgroundDexOptServiceUnitTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/BackgroundDexOptServiceUnitTest.java
@@ -19,7 +19,9 @@ package com.android.server.pm;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.times;
@@ -36,23 +38,21 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.os.HandlerThread;
import android.os.PowerManager;
-import android.util.ArraySet;
import com.android.server.LocalServices;
import com.android.server.PinnerService;
import com.android.server.pm.dex.DexManager;
-import com.android.server.pm.dex.DexoptOptions;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
+import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import java.util.Arrays;
-import java.util.HashMap;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.stream.Collectors;
@@ -66,9 +66,8 @@ public final class BackgroundDexOptServiceUnitTest {
private static final long TEST_WAIT_TIMEOUT_MS = 10_000;
- private static final ArraySet<String> DEFAULT_PACKAGE_LIST = new ArraySet<>(
- Arrays.asList("aaa", "bbb"));
- private static final ArraySet<String> EMPTY_PACKAGE_LIST = new ArraySet<>();
+ private static final List<String> DEFAULT_PACKAGE_LIST = List.of("aaa", "bbb");
+ private static final List<String> EMPTY_PACKAGE_LIST = List.of();
@Mock
private Context mContext;
@@ -116,9 +115,11 @@ public final class BackgroundDexOptServiceUnitTest {
when(mInjector.getDataDirStorageLowBytes()).thenReturn(STORAGE_LOW_BYTES);
when(mInjector.getDexOptThermalCutoff()).thenReturn(PowerManager.THERMAL_STATUS_CRITICAL);
when(mInjector.getCurrentThermalStatus()).thenReturn(PowerManager.THERMAL_STATUS_NONE);
- when(mDexOptHelper.getOptimizablePackages()).thenReturn(DEFAULT_PACKAGE_LIST);
+ when(mInjector.supportSecondaryDex()).thenReturn(true);
+ when(mDexOptHelper.getOptimizablePackages(any())).thenReturn(DEFAULT_PACKAGE_LIST);
when(mDexOptHelper.performDexOptWithStatus(any())).thenReturn(
PackageDexOptimizer.DEX_OPT_PERFORMED);
+ when(mDexOptHelper.performDexOpt(any())).thenReturn(true);
mService = new BackgroundDexOptService(mInjector);
}
@@ -158,7 +159,7 @@ public final class BackgroundDexOptServiceUnitTest {
@Test
public void testNoExecutionForNoOptimizablePackages() {
initUntilBootCompleted();
- when(mDexOptHelper.getOptimizablePackages()).thenReturn(EMPTY_PACKAGE_LIST);
+ when(mDexOptHelper.getOptimizablePackages(any())).thenReturn(EMPTY_PACKAGE_LIST);
assertThat(mService.onStartJob(mJobServiceForPostBoot,
mJobParametersForPostBoot)).isFalse();
@@ -418,26 +419,16 @@ public final class BackgroundDexOptServiceUnitTest {
verifyPerformDexOpt(DEFAULT_PACKAGE_LIST, totalJobRuns);
}
- private void verifyPerformDexOpt(ArraySet<String> pkgs, int expectedRuns) {
- ArgumentCaptor<DexoptOptions> dexOptOptions = ArgumentCaptor.forClass(DexoptOptions.class);
- verify(mDexOptHelper, atLeastOnce()).performDexOptWithStatus(dexOptOptions.capture());
- HashMap<String, Integer> primaryPkgs = new HashMap<>(); // K: pkg, V: dexopt runs left
- for (String pkg : pkgs) {
- primaryPkgs.put(pkg, expectedRuns);
- }
-
- for (DexoptOptions opt : dexOptOptions.getAllValues()) {
- assertThat(pkgs).contains(opt.getPackageName());
- assertThat(opt.isDexoptOnlySecondaryDex()).isFalse();
- Integer count = primaryPkgs.get(opt.getPackageName());
- assertThat(count).isNotNull();
- if (count == 1) {
- primaryPkgs.remove(opt.getPackageName());
- } else {
- primaryPkgs.put(opt.getPackageName(), count - 1);
+ private void verifyPerformDexOpt(List<String> pkgs, int expectedRuns) {
+ InOrder inOrder = inOrder(mDexOptHelper);
+ for (int i = 0; i < expectedRuns; i++) {
+ for (String pkg : pkgs) {
+ inOrder.verify(mDexOptHelper, times(1)).performDexOptWithStatus(argThat((option) ->
+ option.getPackageName().equals(pkg) && !option.isDexoptOnlySecondaryDex()));
+ inOrder.verify(mDexOptHelper, times(1)).performDexOpt(argThat((option) ->
+ option.getPackageName().equals(pkg) && option.isDexoptOnlySecondaryDex()));
}
}
- assertThat(primaryPkgs).isEmpty();
}
private static class StartAndWaitThread extends Thread {
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/OWNERS b/services/tests/mockingservicestests/src/com/android/server/pm/OWNERS
index 46b797b83f1d..5181af14ff65 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/OWNERS
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/OWNERS
@@ -1,3 +1,4 @@
include /services/core/java/com/android/server/pm/OWNERS
+per-file BackgroundDexOptServiceUnitTest.java = file:/services/core/java/com/android/server/pm/dex/OWNERS
per-file StagingManagerTest.java = dariofreni@google.com, ioffe@google.com, olilan@google.com
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/PackageFreezerTest.kt b/services/tests/mockingservicestests/src/com/android/server/pm/PackageFreezerTest.kt
index ccfeb4c9df51..fbbb814388f7 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/PackageFreezerTest.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/PackageFreezerTest.kt
@@ -74,6 +74,10 @@ class PackageFreezerTest {
assertThat(assertFailsWith(exceptionClass, block).message).contains(message)
}
+ private fun checkPackageStartable() {
+ pms.checkPackageStartable(pms.snapshotComputer(), TEST_PACKAGE, TEST_USER_ID)
+ }
+
@Before
@Throws(Exception::class)
fun setup() {
@@ -89,11 +93,11 @@ class PackageFreezerTest {
.killApplication(eq(TEST_PACKAGE), any(), eq(TEST_USER_ID), eq(TEST_REASON))
assertThrowContainsMessage(SecurityException::class, frozenMessage(TEST_PACKAGE)) {
- pms.checkPackageStartable(TEST_PACKAGE, TEST_USER_ID)
+ checkPackageStartable()
}
freezer.close()
- pms.checkPackageStartable(TEST_PACKAGE, TEST_USER_ID)
+ checkPackageStartable()
}
@Test
@@ -104,16 +108,16 @@ class PackageFreezerTest {
.killApplication(eq(TEST_PACKAGE), any(), eq(TEST_USER_ID), eq(TEST_REASON))
assertThrowContainsMessage(SecurityException::class, frozenMessage(TEST_PACKAGE)) {
- pms.checkPackageStartable(TEST_PACKAGE, TEST_USER_ID)
+ checkPackageStartable()
}
freezer1.close()
assertThrowContainsMessage(SecurityException::class, frozenMessage(TEST_PACKAGE)) {
- pms.checkPackageStartable(TEST_PACKAGE, TEST_USER_ID)
+ checkPackageStartable()
}
freezer2.close()
- pms.checkPackageStartable(TEST_PACKAGE, TEST_USER_ID)
+ checkPackageStartable()
}
@Test
@@ -123,13 +127,13 @@ class PackageFreezerTest {
.killApplication(eq(TEST_PACKAGE), any(), eq(TEST_USER_ID), eq(TEST_REASON))
assertThrowContainsMessage(SecurityException::class, frozenMessage(TEST_PACKAGE)) {
- pms.checkPackageStartable(TEST_PACKAGE, TEST_USER_ID)
+ checkPackageStartable()
}
freezer = null
System.gc()
System.runFinalization()
- pms.checkPackageStartable(TEST_PACKAGE, TEST_USER_ID)
+ checkPackageStartable()
}
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/PackageManagerServiceHibernationTests.kt b/services/tests/mockingservicestests/src/com/android/server/pm/PackageManagerServiceHibernationTests.kt
index a6c7bfb456be..537a0280e24b 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/PackageManagerServiceHibernationTests.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/PackageManagerServiceHibernationTests.kt
@@ -107,7 +107,7 @@ class PackageManagerServiceHibernationTests {
whenever(appHibernationManager.isHibernatingForUser(TEST_PACKAGE_NAME, TEST_USER_ID))
.thenReturn(true)
- pm.setPackageStoppedState(TEST_PACKAGE_NAME, false, TEST_USER_ID)
+ pm.setPackageStoppedState(pm.snapshotComputer(), TEST_PACKAGE_NAME, false, TEST_USER_ID)
TestableLooper.get(this).processAllMessages()
@@ -133,7 +133,8 @@ class PackageManagerServiceHibernationTests {
.thenReturn(true)
try {
- pm.setPackageStoppedState(TEST_PACKAGE_NAME, false, TEST_USER_ID)
+ pm.setPackageStoppedState(pm.snapshotComputer(), TEST_PACKAGE_NAME, false,
+ TEST_USER_ID)
TestableLooper.get(this).processAllMessages()
} catch (e: Exception) {
Assert.fail("Method throws exception when AppHibernationManager is not ready.\n$e")
@@ -156,7 +157,7 @@ class PackageManagerServiceHibernationTests {
rule.system().validateFinalState()
whenever(appHibernationManager.isHibernatingGlobally(TEST_PACKAGE_2_NAME)).thenReturn(true)
- val optimizablePkgs = DexOptHelper(pm).optimizablePackages
+ val optimizablePkgs = DexOptHelper(pm).getOptimizablePackages(pm.snapshotComputer())
assertTrue(optimizablePkgs.contains(TEST_PACKAGE_NAME))
assertFalse(optimizablePkgs.contains(TEST_PACKAGE_2_NAME))
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 b063d22de2bb..97b52a98b266 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/SharedLibrariesImplTest.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/SharedLibrariesImplTest.kt
@@ -24,7 +24,6 @@ import android.os.Build
import android.os.storage.StorageManager
import android.util.ArrayMap
import android.util.PackageUtils
-import com.android.internal.util.FunctionalUtils
import com.android.server.SystemConfig.SharedLibraryEntry
import com.android.server.compat.PlatformCompat
import com.android.server.extendedtestutils.wheneverStatic
@@ -35,7 +34,6 @@ import com.android.server.pm.parsing.pkg.ParsedPackage
import com.android.server.testutils.any
import com.android.server.testutils.eq
import com.android.server.testutils.mock
-import com.android.server.testutils.mockThrowOnUnmocked
import com.android.server.testutils.nullable
import com.android.server.testutils.spy
import com.android.server.testutils.whenever
@@ -59,6 +57,7 @@ import kotlin.test.assertFailsWith
import kotlin.test.assertFalse
import kotlin.test.assertTrue
+@Ignore("b/216603387")
@RunWith(JUnit4::class)
class SharedLibrariesImplTest {
@@ -85,6 +84,7 @@ class SharedLibrariesImplTest {
private lateinit var mSharedLibrariesImpl: SharedLibrariesImpl
private lateinit var mPms: PackageManagerService
private lateinit var mSettings: Settings
+ private lateinit var mComputer: Computer
@Mock
private lateinit var mDeletePackageHelper: DeletePackageHelper
@@ -114,22 +114,16 @@ class SharedLibrariesImplTest {
mSharedLibrariesImpl.setDeletePackageHelper(mDeletePackageHelper)
addExistingSharedLibraries()
+ mComputer = mock {
+ whenever(sharedLibraries) { mSharedLibrariesImpl.sharedLibraries }
+ whenever(resolveInternalPackageName(anyString(), anyLong())) { arguments[0] }
+ }
+
whenever(mSettings.getPackageLPr(any())) { mExistingSettings[arguments[0]] }
whenever(mRule.mocks().injector.getSystemService(StorageManager::class.java))
.thenReturn(mStorageManager)
whenever(mStorageManager.findPathForUuid(nullable())).thenReturn(mFile)
- doAnswer { it.arguments[0] }.`when`(mPms).resolveInternalPackageName(any(), any())
- doAnswer {
- mockThrowOnUnmocked<Computer> {
- whenever(sharedLibraries) { mSharedLibrariesImpl.sharedLibraries }
- whenever(resolveInternalPackageName(anyString(), anyLong())) {
- mPms.resolveInternalPackageName(getArgument(0), getArgument(1))
- }
- whenever(getPackageStateInternal(anyString())) {
- mPms.getPackageStateInternal(getArgument(0))
- }
- }
- }.`when`(mPms).snapshotComputer()
+ doAnswer { mComputer }.`when`(mPms).snapshotComputer()
whenever(mDeletePackageHelper.deletePackageX(any(), any(), any(), any(), any()))
.thenReturn(PackageManager.DELETE_SUCCEEDED)
whenever(mRule.mocks().injector.compatibility).thenReturn(mPlatformCompat)
@@ -189,7 +183,8 @@ class SharedLibrariesImplTest {
@Test
fun removeSharedLibrary() {
- doAnswer { mutableListOf(VersionedPackage(CONSUMER_PACKAGE_NAME, 1L)) }.`when`(mPms)
+ doAnswer { mutableListOf(VersionedPackage(CONSUMER_PACKAGE_NAME, 1L)) }
+ .`when`(mComputer)
.getPackagesUsingSharedLibrary(any(), any(), any(), any())
val staticInfo = mSharedLibrariesImpl
.getSharedLibraryInfo(STATIC_LIB_NAME, STATIC_LIB_VERSION)!!
@@ -253,7 +248,6 @@ class SharedLibrariesImplTest {
assertThat(testPackageSetting.usesLibraryFiles).contains(builtinLibPath(BUILTIN_LIB_NAME))
}
- @Ignore("b/216603387")
@Test
fun updateSharedLibraries_withStaticLibPackage() {
val testPackageSetting = mExistingSettings[STATIC_LIB_PACKAGE_NAME]!!
@@ -266,7 +260,6 @@ class SharedLibrariesImplTest {
assertThat(testPackageSetting.usesLibraryFiles).contains(apkPath(DYNAMIC_LIB_PACKAGE_NAME))
}
- @Ignore("b/216603387")
@Test
fun updateSharedLibraries_withConsumerPackage() {
val testPackageSetting = mExistingSettings[CONSUMER_PACKAGE_NAME]!!
@@ -280,7 +273,6 @@ class SharedLibrariesImplTest {
assertThat(testPackageSetting.usesLibraryFiles).contains(apkPath(STATIC_LIB_PACKAGE_NAME))
}
- @Ignore("b/216603387")
@Test
fun updateAllSharedLibraries() {
mExistingSettings.forEach {
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/StagingManagerTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/StagingManagerTest.java
index f7b1dd5219d6..1464405cca08 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/StagingManagerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/StagingManagerTest.java
@@ -39,8 +39,7 @@ import android.content.Context;
import android.content.pm.ApexStagedEvent;
import android.content.pm.IStagedApexObserver;
import android.content.pm.PackageInstaller;
-import android.content.pm.PackageInstaller.SessionInfo;
-import android.content.pm.PackageInstaller.SessionInfo.SessionErrorCode;
+import android.content.pm.PackageManager;
import android.content.pm.StagedApexInfo;
import android.os.SystemProperties;
import android.os.storage.IStorageManager;
@@ -158,10 +157,10 @@ public class StagingManagerTest {
mStagingManager.restoreSessions(Arrays.asList(session1, session2), true);
- assertThat(session1.getErrorCode()).isEqualTo(SessionInfo.SESSION_ACTIVATION_FAILED);
+ assertThat(session1.getErrorCode()).isEqualTo(PackageManager.INSTALL_ACTIVATION_FAILED);
assertThat(session1.getErrorMessage()).isEqualTo("Build fingerprint has changed");
- assertThat(session2.getErrorCode()).isEqualTo(SessionInfo.SESSION_ACTIVATION_FAILED);
+ assertThat(session2.getErrorCode()).isEqualTo(PackageManager.INSTALL_ACTIVATION_FAILED);
assertThat(session2.getErrorMessage()).isEqualTo("Build fingerprint has changed");
}
@@ -247,12 +246,12 @@ public class StagingManagerTest {
verify(mStorageManager, never()).abortChanges(eq("abort-staged-install"), eq(false));
assertThat(apexSession.getErrorCode())
- .isEqualTo(SessionInfo.SESSION_ACTIVATION_FAILED);
+ .isEqualTo(PackageManager.INSTALL_ACTIVATION_FAILED);
assertThat(apexSession.getErrorMessage()).isEqualTo("apexd did not know anything about a "
+ "staged session supposed to be activated");
assertThat(apkSession.getErrorCode())
- .isEqualTo(SessionInfo.SESSION_ACTIVATION_FAILED);
+ .isEqualTo(PackageManager.INSTALL_ACTIVATION_FAILED);
assertThat(apkSession.getErrorMessage()).isEqualTo("Another apex session failed");
}
@@ -303,22 +302,22 @@ public class StagingManagerTest {
verify(mStorageManager, never()).abortChanges(eq("abort-staged-install"), eq(false));
assertThat(apexSession1.getErrorCode())
- .isEqualTo(SessionInfo.SESSION_ACTIVATION_FAILED);
+ .isEqualTo(PackageManager.INSTALL_ACTIVATION_FAILED);
assertThat(apexSession1.getErrorMessage()).isEqualTo("APEX activation failed. "
+ "Error: Failed for test");
assertThat(apexSession2.getErrorCode())
- .isEqualTo(SessionInfo.SESSION_ACTIVATION_FAILED);
+ .isEqualTo(PackageManager.INSTALL_ACTIVATION_FAILED);
assertThat(apexSession2.getErrorMessage()).isEqualTo("Staged session 101 at boot didn't "
+ "activate nor fail. Marking it as failed anyway.");
assertThat(apexSession3.getErrorCode())
- .isEqualTo(SessionInfo.SESSION_ACTIVATION_FAILED);
+ .isEqualTo(PackageManager.INSTALL_ACTIVATION_FAILED);
assertThat(apexSession3.getErrorMessage()).isEqualTo("apexd did not know anything about a "
+ "staged session supposed to be activated");
assertThat(apkSession.getErrorCode())
- .isEqualTo(SessionInfo.SESSION_ACTIVATION_FAILED);
+ .isEqualTo(PackageManager.INSTALL_ACTIVATION_FAILED);
assertThat(apkSession.getErrorMessage()).isEqualTo("Another apex session failed");
}
@@ -351,12 +350,12 @@ public class StagingManagerTest {
verify(mStorageManager, never()).abortChanges(eq("abort-staged-install"), eq(false));
assertThat(apexSession.getErrorCode())
- .isEqualTo(SessionInfo.SESSION_ACTIVATION_FAILED);
+ .isEqualTo(PackageManager.INSTALL_ACTIVATION_FAILED);
assertThat(apexSession.getErrorMessage()).isEqualTo("Staged session 1543 at boot didn't "
+ "activate nor fail. Marking it as failed anyway.");
assertThat(apkSession.getErrorCode())
- .isEqualTo(SessionInfo.SESSION_ACTIVATION_FAILED);
+ .isEqualTo(PackageManager.INSTALL_ACTIVATION_FAILED);
assertThat(apkSession.getErrorMessage()).isEqualTo("Another apex session failed");
}
@@ -445,11 +444,11 @@ public class StagingManagerTest {
verify(mStorageManager, never()).abortChanges(eq("abort-staged-install"), eq(false));
assertThat(apexSession.getErrorCode())
- .isEqualTo(SessionInfo.SESSION_ACTIVATION_FAILED);
+ .isEqualTo(PackageManager.INSTALL_ACTIVATION_FAILED);
assertThat(apexSession.getErrorMessage()).isEqualTo("Impossible state");
assertThat(apkSession.getErrorCode())
- .isEqualTo(SessionInfo.SESSION_ACTIVATION_FAILED);
+ .isEqualTo(PackageManager.INSTALL_ACTIVATION_FAILED);
assertThat(apkSession.getErrorMessage()).isEqualTo("Another apex session failed");
}
@@ -755,7 +754,7 @@ public class StagingManagerTest {
/* isReady */ false,
/* isFailed */ false,
/* isApplied */false,
- /* stagedSessionErrorCode */ PackageInstaller.SessionInfo.SESSION_NO_ERROR,
+ /* stagedSessionErrorCode */ PackageManager.INSTALL_UNKNOWN,
/* stagedSessionErrorMessage */ "no error");
StagingManager.StagedSession stagedSession = spy(session.mStagedSession);
@@ -775,7 +774,7 @@ public class StagingManagerTest {
private boolean mIsReady = false;
private boolean mIsApplied = false;
private boolean mIsFailed = false;
- private @SessionErrorCode int mErrorCode = -1;
+ private int mErrorCode = -1;
private String mErrorMessage;
private boolean mIsDestroyed = false;
private int mParentSessionId = -1;
@@ -828,7 +827,7 @@ public class StagingManagerTest {
return this;
}
- private @SessionErrorCode int getErrorCode() {
+ private int getErrorCode() {
return mErrorCode;
}
@@ -940,7 +939,7 @@ public class StagingManagerTest {
}
@Override
- public void setSessionFailed(@SessionErrorCode int errorCode, String errorMessage) {
+ public void setSessionFailed(int errorCode, String errorMessage) {
Preconditions.checkState(!mIsApplied, "Already marked as applied");
mIsFailed = true;
mErrorCode = errorCode;
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 5230ea7304c8..4818573e9ae5 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/SuspendPackageHelperTest.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/SuspendPackageHelperTest.kt
@@ -104,9 +104,9 @@ class SuspendPackageHelperTest {
pms, rule.mocks().injector, broadcastHelper, protectedPackages)
defaultAppProvider = rule.mocks().defaultAppProvider
testHandler = rule.mocks().handler
- packageSetting1 = pms.getPackageStateInternal(TEST_PACKAGE_1)!!
- packageSetting2 = pms.getPackageStateInternal(TEST_PACKAGE_2)!!
- ownerSetting = pms.getPackageStateInternal(DEVICE_OWNER_PACKAGE)!!
+ 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)
@@ -270,7 +270,7 @@ class SuspendPackageHelperTest {
testHandler.flush()
assertThat(failedNames).isEmpty()
- val result = suspendPackageHelper.getSuspendedPackageAppExtras(
+ val result = suspendPackageHelper.getSuspendedPackageAppExtras(pms.snapshotComputer(),
TEST_PACKAGE_1, TEST_USER_ID, deviceOwnerUid)!!
assertThat(result.getString(TEST_PACKAGE_1)).isEqualTo(TEST_PACKAGE_1)
@@ -286,13 +286,13 @@ class SuspendPackageHelperTest {
null /* dialogInfo */, DEVICE_OWNER_PACKAGE, TEST_USER_ID, deviceOwnerUid)
testHandler.flush()
assertThat(failedNames).isEmpty()
- assertThat(suspendPackageHelper.getSuspendingPackage(
+ assertThat(suspendPackageHelper.getSuspendingPackage(pms.snapshotComputer(),
TEST_PACKAGE_1, TEST_USER_ID, deviceOwnerUid)).isEqualTo(DEVICE_OWNER_PACKAGE)
- assertThat(suspendPackageHelper.getSuspendingPackage(
+ assertThat(suspendPackageHelper.getSuspendingPackage(pms.snapshotComputer(),
TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)).isEqualTo(DEVICE_OWNER_PACKAGE)
- assertThat(suspendPackageHelper.getSuspendedPackageAppExtras(
+ assertThat(suspendPackageHelper.getSuspendedPackageAppExtras(pms.snapshotComputer(),
TEST_PACKAGE_1, TEST_USER_ID, deviceOwnerUid)).isNotNull()
- assertThat(suspendPackageHelper.getSuspendedPackageAppExtras(
+ assertThat(suspendPackageHelper.getSuspendedPackageAppExtras(pms.snapshotComputer(),
TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)).isNotNull()
suspendPackageHelper.removeSuspensionsBySuspendingPackage(pms.snapshotComputer(),
@@ -311,13 +311,13 @@ class SuspendPackageHelperTest {
nullable(), nullable(), any(), eq(TEST_PACKAGE_2), nullable(), any(), any(),
nullable(), nullable())
- assertThat(suspendPackageHelper.getSuspendingPackage(
+ assertThat(suspendPackageHelper.getSuspendingPackage(pms.snapshotComputer(),
TEST_PACKAGE_1, TEST_USER_ID, deviceOwnerUid)).isNull()
- assertThat(suspendPackageHelper.getSuspendingPackage(
+ assertThat(suspendPackageHelper.getSuspendingPackage(pms.snapshotComputer(),
TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)).isNull()
- assertThat(suspendPackageHelper.getSuspendedPackageAppExtras(
+ assertThat(suspendPackageHelper.getSuspendedPackageAppExtras(pms.snapshotComputer(),
TEST_PACKAGE_1, TEST_USER_ID, deviceOwnerUid)).isNull()
- assertThat(suspendPackageHelper.getSuspendedPackageAppExtras(
+ assertThat(suspendPackageHelper.getSuspendedPackageAppExtras(pms.snapshotComputer(),
TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)).isNull()
}
@@ -331,7 +331,7 @@ class SuspendPackageHelperTest {
testHandler.flush()
assertThat(failedNames).isEmpty()
- val result = suspendPackageHelper.getSuspendedPackageLauncherExtras(
+ val result = suspendPackageHelper.getSuspendedPackageLauncherExtras(pms.snapshotComputer(),
TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)!!
assertThat(result.getString(TEST_PACKAGE_2)).isEqualTo(TEST_PACKAGE_2)
@@ -346,7 +346,7 @@ class SuspendPackageHelperTest {
testHandler.flush()
assertThat(failedNames).isEmpty()
- assertThat(suspendPackageHelper.isPackageSuspended(
+ assertThat(suspendPackageHelper.isPackageSuspended(pms.snapshotComputer(),
TEST_PACKAGE_1, TEST_USER_ID, deviceOwnerUid)).isTrue()
}
@@ -360,7 +360,7 @@ class SuspendPackageHelperTest {
testHandler.flush()
assertThat(failedNames).isEmpty()
- assertThat(suspendPackageHelper.getSuspendingPackage(
+ assertThat(suspendPackageHelper.getSuspendingPackage(pms.snapshotComputer(),
TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)).isEqualTo(DEVICE_OWNER_PACKAGE)
}
@@ -375,7 +375,7 @@ class SuspendPackageHelperTest {
testHandler.flush()
assertThat(failedNames).isEmpty()
- val result = suspendPackageHelper.getSuspendedDialogInfo(
+ val result = suspendPackageHelper.getSuspendedDialogInfo(pms.snapshotComputer(),
TEST_PACKAGE_1, DEVICE_OWNER_PACKAGE, TEST_USER_ID, deviceOwnerUid)!!
assertThat(result.title).isEqualTo(TEST_PACKAGE_1)
@@ -387,8 +387,8 @@ class SuspendPackageHelperTest {
mockAllowList(packageSetting1, allowList(10001, 10002, 10003))
mockAllowList(packageSetting2, allowList(10001, 10002, 10003))
- suspendPackageHelper.sendPackagesSuspendedForUser(Intent.ACTION_PACKAGES_SUSPENDED,
- packagesToSuspend, uidsToSuspend, TEST_USER_ID)
+ suspendPackageHelper.sendPackagesSuspendedForUser(pms.snapshotComputer(),
+ Intent.ACTION_PACKAGES_SUSPENDED, packagesToSuspend, uidsToSuspend, TEST_USER_ID)
testHandler.flush()
verify(broadcastHelper).sendPackageBroadcast(any(), nullable(), bundleCaptor.capture(),
anyInt(), nullable(), nullable(), any(), nullable(), any(), nullable())
@@ -406,8 +406,8 @@ class SuspendPackageHelperTest {
mockAllowList(packageSetting1, allowList(10001, 10002, 10003))
mockAllowList(packageSetting2, allowList(10001, 10002, 10007))
- suspendPackageHelper.sendPackagesSuspendedForUser(Intent.ACTION_PACKAGES_SUSPENDED,
- packagesToSuspend, uidsToSuspend, TEST_USER_ID)
+ suspendPackageHelper.sendPackagesSuspendedForUser(pms.snapshotComputer(),
+ Intent.ACTION_PACKAGES_SUSPENDED, packagesToSuspend, uidsToSuspend, TEST_USER_ID)
testHandler.flush()
verify(broadcastHelper, times(2)).sendPackageBroadcast(
any(), nullable(), bundleCaptor.capture(), anyInt(), nullable(), nullable(), any(),
@@ -429,8 +429,8 @@ class SuspendPackageHelperTest {
mockAllowList(packageSetting1, allowList(10001, 10002, 10003))
mockAllowList(packageSetting2, null)
- suspendPackageHelper.sendPackagesSuspendedForUser(Intent.ACTION_PACKAGES_SUSPENDED,
- packagesToSuspend, uidsToSuspend, TEST_USER_ID)
+ suspendPackageHelper.sendPackagesSuspendedForUser(pms.snapshotComputer(),
+ Intent.ACTION_PACKAGES_SUSPENDED, packagesToSuspend, uidsToSuspend, TEST_USER_ID)
testHandler.flush()
verify(broadcastHelper, times(2)).sendPackageBroadcast(
any(), nullable(), bundleCaptor.capture(), anyInt(), nullable(), nullable(), any(),
@@ -449,8 +449,9 @@ class SuspendPackageHelperTest {
@Test
@Throws(Exception::class)
fun sendPackagesSuspendModifiedForUser() {
- suspendPackageHelper.sendPackagesSuspendedForUser(Intent.ACTION_PACKAGES_SUSPENSION_CHANGED,
- packagesToSuspend, uidsToSuspend, TEST_USER_ID)
+ suspendPackageHelper.sendPackagesSuspendedForUser(pms.snapshotComputer(),
+ Intent.ACTION_PACKAGES_SUSPENSION_CHANGED, packagesToSuspend, uidsToSuspend,
+ TEST_USER_ID)
testHandler.flush()
verify(broadcastHelper).sendPackageBroadcast(
eq(Intent.ACTION_PACKAGES_SUSPENSION_CHANGED), nullable(), bundleCaptor.capture(),
@@ -483,13 +484,13 @@ class SuspendPackageHelperTest {
Mockito.doReturn(DIALER_PACKAGE).`when`(defaultAppProvider)
.getDefaultDialer(eq(TEST_USER_ID))
Mockito.doReturn(arrayOf(INSTALLER_PACKAGE)).`when`(pms).getKnownPackageNamesInternal(
- eq(PackageManagerInternal.PACKAGE_INSTALLER), eq(TEST_USER_ID))
+ any(), eq(PackageManagerInternal.PACKAGE_INSTALLER), eq(TEST_USER_ID))
Mockito.doReturn(arrayOf(UNINSTALLER_PACKAGE)).`when`(pms).getKnownPackageNamesInternal(
- eq(PackageManagerInternal.PACKAGE_UNINSTALLER), eq(TEST_USER_ID))
+ any(), eq(PackageManagerInternal.PACKAGE_UNINSTALLER), eq(TEST_USER_ID))
Mockito.doReturn(arrayOf(VERIFIER_PACKAGE)).`when`(pms).getKnownPackageNamesInternal(
- eq(PackageManagerInternal.PACKAGE_VERIFIER), eq(TEST_USER_ID))
+ any(), eq(PackageManagerInternal.PACKAGE_VERIFIER), eq(TEST_USER_ID))
Mockito.doReturn(arrayOf(PERMISSION_CONTROLLER_PACKAGE)).`when`(pms)
- .getKnownPackageNamesInternal(
+ .getKnownPackageNamesInternal(any(),
eq(PackageManagerInternal.PACKAGE_PERMISSION_CONTROLLER), eq(TEST_USER_ID))
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/dex/DexManagerTests.java b/services/tests/mockingservicestests/src/com/android/server/pm/dex/DexManagerTests.java
index 8abe46fab1d6..9d269719db64 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/dex/DexManagerTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/dex/DexManagerTests.java
@@ -159,8 +159,8 @@ public class DexManagerTests {
.when(mockContext)
.getSystemService(PowerManager.class);
- mDexManager = new DexManager(mockContext, mPM, /*PackageDexOptimizer*/ null,
- mInstaller, mInstallLock);
+ mDexManager = new DexManager(mockContext, /*PackageDexOptimizer*/ null,
+ mInstaller, mInstallLock, mPM);
// Foo and Bar are available to user0.
// Only Bar is available to user1;
diff --git a/services/tests/mockingservicestests/src/com/android/server/tare/AgentTest.java b/services/tests/mockingservicestests/src/com/android/server/tare/AgentTest.java
index 41d46f223f4b..534d0a1bc76f 100644
--- a/services/tests/mockingservicestests/src/com/android/server/tare/AgentTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/tare/AgentTest.java
@@ -21,7 +21,6 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSess
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
import android.app.AlarmManager;
import android.content.Context;
@@ -71,10 +70,10 @@ public class AgentTest {
.strictness(Strictness.LENIENT)
.mockStatic(LocalServices.class)
.startMocking();
- when(mIrs.getContext()).thenReturn(mContext);
- when(mIrs.getCompleteEconomicPolicyLocked()).thenReturn(mEconomicPolicy);
- when(mIrs.getLock()).thenReturn(mIrs);
- when(mContext.getSystemService(Context.ALARM_SERVICE)).thenReturn(mock(AlarmManager.class));
+ doReturn(mContext).when(mIrs).getContext();
+ doReturn(mEconomicPolicy).when(mIrs).getCompleteEconomicPolicyLocked();
+ doReturn(mIrs).when(mIrs).getLock();
+ doReturn(mock(AlarmManager.class)).when(mContext).getSystemService(Context.ALARM_SERVICE);
mScribe = new MockScribe(mIrs);
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/tare/ScribeTest.java b/services/tests/mockingservicestests/src/com/android/server/tare/ScribeTest.java
index ab29e5903f02..c2cf2ff439ca 100644
--- a/services/tests/mockingservicestests/src/com/android/server/tare/ScribeTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/tare/ScribeTest.java
@@ -109,6 +109,7 @@ public class ScribeTest {
long lastReclamationTime = System.currentTimeMillis();
long remainingConsumableNarcs = 2000L;
long consumptionLimit = 500_000L;
+ when(mIrs.getConsumptionLimitLocked()).thenReturn(consumptionLimit);
Ledger ledger = mScribeUnderTest.getLedgerLocked(TEST_USER_ID, TEST_PACKAGE);
ledger.recordTransaction(new Ledger.Transaction(0, 1000L, 1, null, 2000, 0));
@@ -119,8 +120,13 @@ public class ScribeTest {
mScribeUnderTest.setConsumptionLimitLocked(consumptionLimit);
mScribeUnderTest.adjustRemainingConsumableNarcsLocked(
remainingConsumableNarcs - consumptionLimit);
- mScribeUnderTest.writeImmediatelyForTesting();
+ assertEquals(lastReclamationTime, mScribeUnderTest.getLastReclamationTimeLocked());
+ assertEquals(remainingConsumableNarcs,
+ mScribeUnderTest.getRemainingConsumableNarcsLocked());
+ assertEquals(consumptionLimit, mScribeUnderTest.getSatiatedConsumptionLimitLocked());
+
+ mScribeUnderTest.writeImmediatelyForTesting();
mScribeUnderTest.loadFromDiskLocked();
assertEquals(lastReclamationTime, mScribeUnderTest.getLastReclamationTimeLocked());
diff --git a/services/tests/mockingservicestests/src/com/android/server/utils/TimingsTraceAndSlogTest.java b/services/tests/mockingservicestests/src/com/android/server/utils/TimingsTraceAndSlogTest.java
new file mode 100644
index 000000000000..52cd29cabb94
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/utils/TimingsTraceAndSlogTest.java
@@ -0,0 +1,165 @@
+/*
+ * 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 static android.os.Trace.TRACE_TAG_APP;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.contains;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Matchers.matches;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+
+import android.os.Trace;
+import android.util.Slog;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.dx.mockito.inline.extended.MockedVoidMethod;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.MockitoSession;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Tests for {@link TimingsTraceAndSlog}.
+ *
+ * <p>Usage: {@code atest FrameworksMockingServicesTests:TimingsTraceAndSlogTest}
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class TimingsTraceAndSlogTest {
+
+ private static final String TAG = "TEST";
+
+ private MockitoSession mSession;
+
+ @Before
+ public final void startMockSession() {
+ mSession = mockitoSession()
+ .spyStatic(Slog.class)
+ .spyStatic(Trace.class)
+ .startMocking();
+ }
+
+ @After
+ public final void finishMockSession() {
+ mSession.finishMocking();
+ }
+
+ @Test
+ public void testDifferentThreads() throws Exception {
+ TimingsTraceAndSlog log = new TimingsTraceAndSlog(TAG, TRACE_TAG_APP);
+ // Should be able to log on the same thread
+ log.traceBegin("test");
+ log.traceEnd();
+ final List<String> errors = new ArrayList<>();
+ // Calling from a different thread should fail
+ Thread t = new Thread(() -> {
+ try {
+ log.traceBegin("test");
+ errors.add("traceBegin should fail on a different thread");
+ } catch (IllegalStateException expected) {
+ }
+ try {
+ log.traceEnd();
+ errors.add("traceEnd should fail on a different thread");
+ } catch (IllegalStateException expected) {
+ }
+ // Verify that creating a new log will work
+ TimingsTraceAndSlog log2 = new TimingsTraceAndSlog(TAG, TRACE_TAG_APP);
+ log2.traceBegin("test");
+ log2.traceEnd();
+
+ });
+ t.start();
+ t.join();
+ assertThat(errors).isEmpty();
+ }
+
+ @Test
+ public void testGetUnfinishedTracesForDebug() {
+ TimingsTraceAndSlog log = new TimingsTraceAndSlog(TAG, TRACE_TAG_APP);
+ assertThat(log.getUnfinishedTracesForDebug()).isEmpty();
+
+ log.traceBegin("One");
+ assertThat(log.getUnfinishedTracesForDebug()).containsExactly("One").inOrder();
+
+ log.traceBegin("Two");
+ assertThat(log.getUnfinishedTracesForDebug()).containsExactly("One", "Two").inOrder();
+
+ log.traceEnd();
+ assertThat(log.getUnfinishedTracesForDebug()).containsExactly("One").inOrder();
+
+ log.traceEnd();
+ assertThat(log.getUnfinishedTracesForDebug()).isEmpty();
+ }
+
+ @Test
+ public void testLogDuration() throws Exception {
+ TimingsTraceAndSlog log = new TimingsTraceAndSlog(TAG, TRACE_TAG_APP);
+ log.logDuration("logro", 42);
+ verify((MockedVoidMethod) () -> Slog.v(eq(TAG), contains("logro took to complete: 42ms")));
+ }
+
+ @Test
+ public void testOneLevel() throws Exception {
+ TimingsTraceAndSlog log = new TimingsTraceAndSlog(TAG, TRACE_TAG_APP);
+ log.traceBegin("test");
+ log.traceEnd();
+
+ verify((MockedVoidMethod) () -> Trace.traceBegin(TRACE_TAG_APP, "test"));
+ verify((MockedVoidMethod) () -> Trace.traceEnd(TRACE_TAG_APP));
+ verify((MockedVoidMethod) () -> Slog.v(eq(TAG), matches("test took to complete: \\dms")));
+ }
+
+ @Test
+ public void testMultipleLevels() throws Exception {
+ TimingsTraceAndSlog log = new TimingsTraceAndSlog(TAG, TRACE_TAG_APP);
+ log.traceBegin("L1");
+ log.traceBegin("L2");
+ log.traceEnd();
+ log.traceEnd();
+
+ verify((MockedVoidMethod) () -> Trace.traceBegin(TRACE_TAG_APP, "L1"));
+ verify((MockedVoidMethod) () -> Trace.traceBegin(TRACE_TAG_APP, "L2"));
+ verify((MockedVoidMethod) () -> Trace.traceEnd(TRACE_TAG_APP), times(2)); // L1 and L2
+
+ verify((MockedVoidMethod) () -> Slog.v(eq(TAG), matches("L2 took to complete: \\d+ms")));
+ verify((MockedVoidMethod) () -> Slog.v(eq(TAG), matches("L1 took to complete: \\d+ms")));
+ }
+
+ @Test
+ public void testEndNoBegin() throws Exception {
+ TimingsTraceAndSlog log = new TimingsTraceAndSlog(TAG, TRACE_TAG_APP);
+ log.traceEnd();
+ verify((MockedVoidMethod) () -> Trace.traceEnd(TRACE_TAG_APP));
+ verify((MockedVoidMethod) () -> Slog.d(eq(TAG), anyString()), never());
+ verify((MockedVoidMethod) () -> Slog.w(TAG, "traceEnd called more times than traceBegin"));
+ }
+}
diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp
index 152f3b3abd13..e3be3a792549 100644
--- a/services/tests/servicestests/Android.bp
+++ b/services/tests/servicestests/Android.bp
@@ -64,6 +64,7 @@ android_test {
"testng",
"junit",
"platform-compat-test-rules",
+ "ActivityContext",
],
aidl: {
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
index 1f016fb6f017..56c51507606f 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
@@ -28,6 +28,8 @@ import static com.android.internal.accessibility.AccessibilityShortcutController
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.doCallRealMethod;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -61,10 +63,12 @@ import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import com.android.compatibility.common.util.TestUtils;
+import com.android.internal.compat.IPlatformCompat;
import com.android.server.LocalServices;
import com.android.server.accessibility.AccessibilityManagerService.AccessibilityDisplayListener;
import com.android.server.accessibility.magnification.FullScreenMagnificationController;
import com.android.server.accessibility.magnification.MagnificationController;
+import com.android.server.accessibility.magnification.MagnificationProcessor;
import com.android.server.accessibility.magnification.WindowMagnificationManager;
import com.android.server.accessibility.test.MessageCapturingHandler;
import com.android.server.pm.UserManagerInternal;
@@ -185,7 +189,7 @@ public class AccessibilityManagerServiceTest {
mA11yms.mUserStates.put(mA11yms.getCurrentUserIdLocked(), userState);
}
- private void setupAccessibilityServiceConnection() {
+ private void setupAccessibilityServiceConnection(int serviceInfoFlag) {
final AccessibilityUserState userState = mA11yms.mUserStates.get(
mA11yms.getCurrentUserIdLocked());
when(mMockServiceInfo.getResolveInfo()).thenReturn(mMockResolveInfo);
@@ -193,7 +197,12 @@ public class AccessibilityManagerServiceTest {
mMockResolveInfo.serviceInfo.applicationInfo = mock(ApplicationInfo.class);
when(mMockBinder.queryLocalInterface(any())).thenReturn(mMockServiceClient);
+ when(mMockSystemSupport.getKeyEventDispatcher()).thenReturn(mock(KeyEventDispatcher.class));
+ when(mMockSystemSupport.getMagnificationProcessor()).thenReturn(
+ mock(MagnificationProcessor.class));
mTestableContext.addMockService(COMPONENT_NAME, mMockBinder);
+
+ mMockServiceInfo.flags = serviceInfoFlag;
mAccessibilityServiceConnection = new AccessibilityServiceConnection(
userState,
mTestableContext,
@@ -256,7 +265,7 @@ public class AccessibilityManagerServiceTest {
@SmallTest
@Test
public void testOnSystemActionsChanged() throws Exception {
- setupAccessibilityServiceConnection();
+ setupAccessibilityServiceConnection(0);
final AccessibilityUserState userState = mA11yms.mUserStates.get(
mA11yms.getCurrentUserIdLocked());
@@ -376,7 +385,7 @@ public class AccessibilityManagerServiceTest {
@SmallTest
@Test
public void testOnClientChange_boundServiceCanControlMagnification_requestConnection() {
- setupAccessibilityServiceConnection();
+ setupAccessibilityServiceConnection(0);
when(mMockSecurityPolicy.canControlMagnification(any())).thenReturn(true);
// Invokes client change to trigger onUserStateChanged.
@@ -385,6 +394,29 @@ public class AccessibilityManagerServiceTest {
verify(mMockWindowMagnificationMgr).requestConnection(true);
}
+ @Test
+ public void testUnbindIme_whenServiceUnbinds() {
+ setupAccessibilityServiceConnection(AccessibilityServiceInfo.FLAG_INPUT_METHOD_EDITOR);
+ mAccessibilityServiceConnection.unbindLocked();
+ verify(mMockSystemSupport, atLeastOnce()).unbindImeLocked(mAccessibilityServiceConnection);
+ }
+
+ @Test
+ public void testUnbindIme_whenServiceCrashed() {
+ setupAccessibilityServiceConnection(AccessibilityServiceInfo.FLAG_INPUT_METHOD_EDITOR);
+ mAccessibilityServiceConnection.binderDied();
+ verify(mMockSystemSupport).unbindImeLocked(mAccessibilityServiceConnection);
+ }
+
+ @Test
+ public void testUnbindIme_whenServiceStopsRequestingIme() {
+ setupAccessibilityServiceConnection(AccessibilityServiceInfo.FLAG_INPUT_METHOD_EDITOR);
+ doCallRealMethod().when(mMockServiceInfo).updateDynamicallyConfigurableProperties(
+ any(IPlatformCompat.class), any(AccessibilityServiceInfo.class));
+ mAccessibilityServiceConnection.setServiceInfo(new AccessibilityServiceInfo());
+ verify(mMockSystemSupport).unbindImeLocked(mAccessibilityServiceConnection);
+ }
+
public static class FakeInputFilter extends AccessibilityInputFilter {
FakeInputFilter(Context context,
AccessibilityManagerService service) {
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java
index f3a0b7fa1ea7..0780d219dc80 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java
@@ -28,6 +28,7 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
@@ -45,13 +46,16 @@ import android.content.IntentFilter;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.Region;
+import android.hardware.display.DisplayManagerInternal;
import android.os.Looper;
+import android.view.DisplayInfo;
import android.view.MagnificationSpec;
import android.view.accessibility.MagnificationAnimationCallback;
import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
+import com.android.server.LocalServices;
import com.android.server.accessibility.AccessibilityTraceManager;
import com.android.server.accessibility.test.MessageCapturingHandler;
import com.android.server.wm.WindowManagerInternal;
@@ -113,6 +117,8 @@ public class FullScreenMagnificationControllerTest {
FullScreenMagnificationController mFullScreenMagnificationController;
+ public DisplayManagerInternal mDisplayManagerInternalMock = mock(DisplayManagerInternal.class);
+
@Before
public void setUp() {
Looper looper = InstrumentationRegistry.getContext().getMainLooper();
@@ -125,6 +131,12 @@ public class FullScreenMagnificationControllerTest {
when(mMockControllerCtx.getAnimationDuration()).thenReturn(1000L);
initMockWindowManager();
+ final DisplayInfo displayInfo = new DisplayInfo();
+ displayInfo.logicalDensityDpi = 300;
+ doReturn(displayInfo).when(mDisplayManagerInternalMock).getDisplayInfo(anyInt());
+ LocalServices.removeServiceForTest(DisplayManagerInternal.class);
+ LocalServices.addService(DisplayManagerInternal.class, mDisplayManagerInternalMock);
+
mFullScreenMagnificationController = new FullScreenMagnificationController(
mMockControllerCtx, new Object(), mRequestObserver, mScaleProvider);
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerOperationTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerOperationTest.java
index eab96c09a00a..c17347320f52 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerOperationTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerOperationTest.java
@@ -72,9 +72,11 @@ public class BiometricSchedulerOperationTest {
@Mock
private ClientMonitorCallback mClientCallback;
@Mock
+ private ClientMonitorCallback mOnStartCallback;
+ @Mock
private FakeHal mHal;
@Captor
- ArgumentCaptor<ClientMonitorCallback> mStartCallback;
+ ArgumentCaptor<ClientMonitorCallback> mStartedCallbackCaptor;
private Handler mHandler;
private BiometricSchedulerOperation mOperation;
@@ -91,17 +93,17 @@ public class BiometricSchedulerOperationTest {
when(mClientMonitor.getCookie()).thenReturn(cookie);
when(mClientMonitor.getFreshDaemon()).thenReturn(mHal);
- assertThat(mOperation.isReadyToStart()).isEqualTo(cookie);
+ assertThat(mOperation.isReadyToStart(mOnStartCallback)).isEqualTo(cookie);
assertThat(mOperation.isStarted()).isFalse();
assertThat(mOperation.isCanceling()).isFalse();
assertThat(mOperation.isFinished()).isFalse();
+ verify(mClientMonitor).waitForCookie(any());
- final boolean started = mOperation.startWithCookie(
- mock(ClientMonitorCallback.class), cookie);
+ final boolean started = mOperation.startWithCookie(mOnStartCallback, cookie);
assertThat(started).isTrue();
- verify(mClientMonitor).start(mStartCallback.capture());
- mStartCallback.getValue().onClientStarted(mClientMonitor);
+ verify(mClientMonitor).start(mStartedCallbackCaptor.capture());
+ mStartedCallbackCaptor.getValue().onClientStarted(mClientMonitor);
assertThat(mOperation.isStarted()).isTrue();
}
@@ -112,14 +114,15 @@ public class BiometricSchedulerOperationTest {
when(mClientMonitor.getCookie()).thenReturn(goodCookie);
when(mClientMonitor.getFreshDaemon()).thenReturn(mHal);
- assertThat(mOperation.isReadyToStart()).isEqualTo(goodCookie);
- final boolean started = mOperation.startWithCookie(
- mock(ClientMonitorCallback.class), badCookie);
+ assertThat(mOperation.isReadyToStart(mOnStartCallback)).isEqualTo(goodCookie);
+ final boolean started = mOperation.startWithCookie(mOnStartCallback, badCookie);
assertThat(started).isFalse();
assertThat(mOperation.isStarted()).isFalse();
assertThat(mOperation.isCanceling()).isFalse();
assertThat(mOperation.isFinished()).isFalse();
+ verify(mClientMonitor).waitForCookie(any());
+ verify(mClientMonitor, never()).start(any());
}
@Test
@@ -127,26 +130,25 @@ public class BiometricSchedulerOperationTest {
when(mClientMonitor.getCookie()).thenReturn(0);
when(mClientMonitor.getFreshDaemon()).thenReturn(mHal);
- final ClientMonitorCallback cb = mock(ClientMonitorCallback.class);
- mOperation.start(cb);
- verify(mClientMonitor).start(mStartCallback.capture());
- mStartCallback.getValue().onClientStarted(mClientMonitor);
+ mOperation.start(mOnStartCallback);
+ verify(mClientMonitor).start(mStartedCallbackCaptor.capture());
+ mStartedCallbackCaptor.getValue().onClientStarted(mClientMonitor);
assertThat(mOperation.isStarted()).isTrue();
assertThat(mOperation.isCanceling()).isFalse();
assertThat(mOperation.isFinished()).isFalse();
verify(mClientCallback).onClientStarted(eq(mClientMonitor));
- verify(cb).onClientStarted(eq(mClientMonitor));
+ verify(mOnStartCallback).onClientStarted(eq(mClientMonitor));
verify(mClientCallback, never()).onClientFinished(any(), anyBoolean());
- verify(cb, never()).onClientFinished(any(), anyBoolean());
+ verify(mOnStartCallback, never()).onClientFinished(any(), anyBoolean());
- mStartCallback.getValue().onClientFinished(mClientMonitor, true);
+ mStartedCallbackCaptor.getValue().onClientFinished(mClientMonitor, true);
assertThat(mOperation.isFinished()).isTrue();
assertThat(mOperation.isCanceling()).isFalse();
verify(mClientMonitor).destroy();
- verify(cb).onClientFinished(eq(mClientMonitor), eq(true));
+ verify(mOnStartCallback).onClientFinished(eq(mClientMonitor), eq(true));
}
@Test
@@ -154,8 +156,7 @@ public class BiometricSchedulerOperationTest {
when(mClientMonitor.getCookie()).thenReturn(0);
when(mClientMonitor.getFreshDaemon()).thenReturn(null);
- final ClientMonitorCallback cb = mock(ClientMonitorCallback.class);
- mOperation.start(cb);
+ mOperation.start(mOnStartCallback);
verify(mClientMonitor, never()).start(any());
assertThat(mOperation.isStarted()).isFalse();
@@ -163,9 +164,9 @@ public class BiometricSchedulerOperationTest {
assertThat(mOperation.isFinished()).isTrue();
verify(mClientCallback, never()).onClientStarted(eq(mClientMonitor));
- verify(cb, never()).onClientStarted(eq(mClientMonitor));
+ verify(mOnStartCallback, never()).onClientStarted(eq(mClientMonitor));
verify(mClientCallback).onClientFinished(eq(mClientMonitor), eq(false));
- verify(cb).onClientFinished(eq(mClientMonitor), eq(false));
+ verify(mOnStartCallback).onClientFinished(eq(mClientMonitor), eq(false));
}
@Test
@@ -179,7 +180,7 @@ public class BiometricSchedulerOperationTest {
public void cannotRestart() {
when(mClientMonitor.getFreshDaemon()).thenReturn(mHal);
- mOperation.start(mock(ClientMonitorCallback.class));
+ mOperation.start(mOnStartCallback);
assertThrows(IllegalStateException.class,
() -> mOperation.start(mock(ClientMonitorCallback.class)));
@@ -202,7 +203,7 @@ public class BiometricSchedulerOperationTest {
public void cannotAbortRunning() {
when(mClientMonitor.getFreshDaemon()).thenReturn(mHal);
- mOperation.start(mock(ClientMonitorCallback.class));
+ mOperation.start(mOnStartCallback);
assertThrows(IllegalStateException.class, () -> mOperation.abort());
}
@@ -211,11 +212,10 @@ public class BiometricSchedulerOperationTest {
public void cancel() {
when(mClientMonitor.getFreshDaemon()).thenReturn(mHal);
- final ClientMonitorCallback startCb = mock(ClientMonitorCallback.class);
final ClientMonitorCallback cancelCb = mock(ClientMonitorCallback.class);
- mOperation.start(startCb);
- verify(mClientMonitor).start(mStartCallback.capture());
- mStartCallback.getValue().onClientStarted(mClientMonitor);
+ mOperation.start(mOnStartCallback);
+ verify(mClientMonitor).start(mStartedCallbackCaptor.capture());
+ mStartedCallbackCaptor.getValue().onClientStarted(mClientMonitor);
mOperation.cancel(mHandler, cancelCb);
assertThat(mOperation.isCanceling()).isTrue();
@@ -223,7 +223,7 @@ public class BiometricSchedulerOperationTest {
verify(mClientMonitor, never()).cancelWithoutStarting(any());
verify(mClientMonitor, never()).destroy();
- mStartCallback.getValue().onClientFinished(mClientMonitor, true);
+ mStartedCallbackCaptor.getValue().onClientFinished(mClientMonitor, true);
assertThat(mOperation.isFinished()).isTrue();
assertThat(mOperation.isCanceling()).isFalse();
@@ -315,12 +315,10 @@ public class BiometricSchedulerOperationTest {
private void cancelWatchdog(boolean start) {
when(mClientMonitor.getFreshDaemon()).thenReturn(mHal);
- final ClientMonitorCallback opStartCallback = mock(ClientMonitorCallback.class);
- mOperation.start(opStartCallback);
+ mOperation.start(mOnStartCallback);
if (start) {
- verify(mClientMonitor).start(mStartCallback.capture());
- mStartCallback.getValue().onClientStarted(mClientMonitor);
- verify(opStartCallback).onClientStarted(eq(mClientMonitor));
+ verify(mClientMonitor).start(mStartedCallbackCaptor.capture());
+ mStartedCallbackCaptor.getValue().onClientStarted(mClientMonitor);
}
mOperation.cancel(mHandler, mock(ClientMonitorCallback.class));
@@ -331,7 +329,7 @@ public class BiometricSchedulerOperationTest {
assertThat(mOperation.isFinished()).isTrue();
assertThat(mOperation.isCanceling()).isFalse();
- verify(opStartCallback).onClientFinished(eq(mClientMonitor), eq(false));
+ verify(mOnStartCallback).onClientFinished(eq(mClientMonitor), eq(false));
verify(mClientMonitor).destroy();
}
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
index 0fa2b41e8b32..45e3b4373266 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
@@ -196,7 +196,8 @@ public class BiometricSchedulerTest {
// Schedule a BiometricPrompt authentication request
mScheduler.scheduleClientMonitor(client1, callback1);
- assertNotEquals(0, mScheduler.mCurrentOperation.isReadyToStart());
+ assertNotEquals(0, mScheduler.mCurrentOperation.isReadyToStart(
+ mock(ClientMonitorCallback.class)));
assertEquals(client1, mScheduler.mCurrentOperation.getClientMonitor());
assertEquals(0, mScheduler.mPendingOperations.size());
@@ -436,7 +437,8 @@ public class BiometricSchedulerTest {
if (started || isEnroll) { // prep'd auth clients and enroll clients
assertTrue(mScheduler.mCurrentOperation.isStarted());
} else {
- assertNotEquals(0, mScheduler.mCurrentOperation.isReadyToStart());
+ assertNotEquals(0, mScheduler.mCurrentOperation.isReadyToStart(
+ mock(ClientMonitorCallback.class)));
}
}
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/SensorOverlaysTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/SensorOverlaysTest.java
index dc39b6d573db..5012335b533f 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/SensorOverlaysTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/SensorOverlaysTest.java
@@ -21,6 +21,7 @@ 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.verify;
+import static org.mockito.Mockito.when;
import android.hardware.biometrics.BiometricOverlayConstants;
import android.hardware.fingerprint.ISidefpsController;
@@ -29,6 +30,7 @@ import android.platform.test.annotations.Presubmit;
import androidx.test.filters.SmallTest;
+import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.mockito.Mock;
@@ -43,6 +45,7 @@ import java.util.List;
public class SensorOverlaysTest {
private static final int SENSOR_ID = 11;
+ private static final long REQUEST_ID = 8;
@Rule public final MockitoRule mockito = MockitoJUnit.rule();
@@ -50,6 +53,12 @@ public class SensorOverlaysTest {
@Mock private ISidefpsController mSidefpsController;
@Mock private AcquisitionClient<?> mAcquisitionClient;
+ @Before
+ public void setup() {
+ when(mAcquisitionClient.getRequestId()).thenReturn(REQUEST_ID);
+ when(mAcquisitionClient.hasRequestId()).thenReturn(true);
+ }
+
@Test
public void noopWhenBothNull() {
final SensorOverlays useless = new SensorOverlays(null, null);
@@ -92,7 +101,8 @@ public class SensorOverlaysTest {
sensorOverlays.show(SENSOR_ID, reason, mAcquisitionClient);
if (udfps != null) {
- verify(mUdfpsOverlayController).showUdfpsOverlay(eq(SENSOR_ID), eq(reason), any());
+ verify(mUdfpsOverlayController).showUdfpsOverlay(
+ eq(REQUEST_ID), eq(SENSOR_ID), eq(reason), any());
}
if (sidefps != null) {
verify(mSidefpsController).show(eq(SENSOR_ID), eq(reason));
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/UserAwareBiometricSchedulerTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/UserAwareBiometricSchedulerTest.java
index 52eee9a55cc7..8391914a0bb6 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/UserAwareBiometricSchedulerTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/UserAwareBiometricSchedulerTest.java
@@ -18,9 +18,8 @@ package com.android.server.biometrics.sensors;
import static android.testing.TestableLooper.RunWithLooper;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertSame;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -45,11 +44,15 @@ import com.android.server.biometrics.log.BiometricContext;
import com.android.server.biometrics.log.BiometricLogger;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+import java.util.ArrayList;
+import java.util.List;
import java.util.function.Supplier;
@Presubmit
@@ -61,9 +64,12 @@ public class UserAwareBiometricSchedulerTest {
private static final String TAG = "UserAwareBiometricSchedulerTest";
private static final int TEST_SENSOR_ID = 0;
+ @Rule
+ public final MockitoRule mockito = MockitoJUnit.rule();
+
private Handler mHandler;
private UserAwareBiometricScheduler mScheduler;
- private IBinder mToken = new Binder();
+ private final IBinder mToken = new Binder();
@Mock
private Context mContext;
@@ -74,15 +80,14 @@ public class UserAwareBiometricSchedulerTest {
@Mock
private BiometricContext mBiometricContext;
- private TestUserStartedCallback mUserStartedCallback = new TestUserStartedCallback();
- private TestUserStoppedCallback mUserStoppedCallback = new TestUserStoppedCallback();
+ private final TestUserStartedCallback mUserStartedCallback = new TestUserStartedCallback();
+ private final TestUserStoppedCallback mUserStoppedCallback = new TestUserStoppedCallback();
private int mCurrentUserId = UserHandle.USER_NULL;
private boolean mStartOperationsFinish = true;
private int mStartUserClientCount = 0;
@Before
public void setUp() {
- MockitoAnnotations.initMocks(this);
mHandler = new Handler(TestableLooper.get(this).getLooper());
mScheduler = new UserAwareBiometricScheduler(TAG,
mHandler,
@@ -121,8 +126,8 @@ public class UserAwareBiometricSchedulerTest {
mScheduler.scheduleClientMonitor(nextClient);
waitForIdle();
- assertEquals(0, mUserStoppedCallback.numInvocations);
- assertEquals(1, mUserStartedCallback.numInvocations);
+ assertThat(mUserStoppedCallback.mNumInvocations).isEqualTo(0);
+ assertThat(mUserStartedCallback.mStartedUsers).containsExactly(0);
verify(nextClient).start(any());
}
@@ -142,9 +147,9 @@ public class UserAwareBiometricSchedulerTest {
waitForIdle();
}
- assertEquals(0, mUserStoppedCallback.numInvocations);
- assertEquals(0, mUserStartedCallback.numInvocations);
- assertEquals(1, mStartUserClientCount);
+ assertThat(mUserStoppedCallback.mNumInvocations).isEqualTo(0);
+ assertThat(mUserStartedCallback.mStartedUsers).isEmpty();
+ assertThat(mStartUserClientCount).isEqualTo(1);
for (BaseClientMonitor client : nextClients) {
verify(client, never()).start(any());
}
@@ -163,13 +168,13 @@ public class UserAwareBiometricSchedulerTest {
final TestStartUserClient startUserClient =
(TestStartUserClient) mScheduler.mCurrentOperation.getClientMonitor();
mScheduler.reset();
- assertNull(mScheduler.mCurrentOperation);
+ assertThat(mScheduler.mCurrentOperation).isNull();
final BiometricSchedulerOperation fakeOperation = new BiometricSchedulerOperation(
mock(BaseClientMonitor.class), new ClientMonitorCallback() {});
mScheduler.mCurrentOperation = fakeOperation;
startUserClient.mCallback.onClientFinished(startUserClient, true);
- assertSame(fakeOperation, mScheduler.mCurrentOperation);
+ assertThat(fakeOperation).isSameInstanceAs(mScheduler.mCurrentOperation);
}
@Test
@@ -184,8 +189,8 @@ public class UserAwareBiometricSchedulerTest {
waitForIdle();
verify(nextClient).start(any());
- assertEquals(0, mUserStoppedCallback.numInvocations);
- assertEquals(0, mUserStartedCallback.numInvocations);
+ assertThat(mUserStoppedCallback.mNumInvocations).isEqualTo(0);
+ assertThat(mUserStartedCallback.mStartedUsers).isEmpty();
}
@Test
@@ -199,36 +204,67 @@ public class UserAwareBiometricSchedulerTest {
mScheduler.scheduleClientMonitor(nextClient);
waitForIdle();
- assertEquals(1, mUserStoppedCallback.numInvocations);
+ assertThat(mUserStoppedCallback.mNumInvocations).isEqualTo(1);
waitForIdle();
- assertEquals(1, mUserStartedCallback.numInvocations);
+ assertThat(mUserStartedCallback.mStartedUsers).containsExactly(nextUserId);
waitForIdle();
verify(nextClient).start(any());
}
+ @Test
+ public void testStartUser_alwaysStartsNextOperation() {
+ BaseClientMonitor nextClient = mock(BaseClientMonitor.class);
+ when(nextClient.getTargetUserId()).thenReturn(10);
+
+ mScheduler.scheduleClientMonitor(nextClient);
+
+ waitForIdle();
+ verify(nextClient).start(any());
+
+ // finish first operation
+ mScheduler.getInternalCallback().onClientFinished(nextClient, true /* success */);
+ waitForIdle();
+
+ // schedule second operation but swap out the current operation
+ // before it runs so that it's not current when it's completion callback runs
+ nextClient = mock(BaseClientMonitor.class);
+ when(nextClient.getTargetUserId()).thenReturn(11);
+ mUserStartedCallback.mAfterStart = () -> mScheduler.mCurrentOperation = null;
+ mScheduler.scheduleClientMonitor(nextClient);
+
+ waitForIdle();
+ verify(nextClient).start(any());
+ assertThat(mUserStartedCallback.mStartedUsers).containsExactly(10, 11).inOrder();
+ assertThat(mUserStoppedCallback.mNumInvocations).isEqualTo(1);
+ }
+
private void waitForIdle() {
TestableLooper.get(this).processAllMessages();
}
private class TestUserStoppedCallback implements StopUserClient.UserStoppedCallback {
- int numInvocations;
+ int mNumInvocations;
@Override
public void onUserStopped() {
- numInvocations++;
+ mNumInvocations++;
mCurrentUserId = UserHandle.USER_NULL;
}
}
private class TestUserStartedCallback implements StartUserClient.UserStartedCallback<Object> {
- int numInvocations;
+ final List<Integer> mStartedUsers = new ArrayList<>();
+ Runnable mAfterStart = null;
@Override
public void onUserStarted(int newUserId, Object newObject, int halInterfaceVersion) {
- numInvocations++;
+ mStartedUsers.add(newUserId);
mCurrentUserId = newUserId;
+ if (mAfterStart != null) {
+ mAfterStart.run();
+ }
}
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java
index de0f038e8ec5..6c50ca35be79 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java
@@ -71,6 +71,7 @@ public class FingerprintAuthenticationClientTest {
private static final int USER_ID = 8;
private static final long OP_ID = 7;
+ private static final long REQUEST_ID = 88;
private static final int POINTER_ID = 0;
private static final int TOUCH_X = 8;
private static final int TOUCH_Y = 20;
@@ -259,7 +260,7 @@ public class FingerprintAuthenticationClientTest {
client.start(mCallback);
- verify(mUdfpsOverlayController).showUdfpsOverlay(anyInt(), anyInt(), any());
+ verify(mUdfpsOverlayController).showUdfpsOverlay(eq(REQUEST_ID), anyInt(), anyInt(), any());
verify(mSideFpsController).show(anyInt(), anyInt());
block.accept(client);
@@ -277,7 +278,7 @@ public class FingerprintAuthenticationClientTest {
final AidlSession aidl = new AidlSession(version, mHal, USER_ID, mHalSessionCallback);
return new FingerprintAuthenticationClient(mContext, () -> aidl, mToken,
- 2 /* requestId */, mClientMonitorCallbackConverter, 5 /* targetUserId */, OP_ID,
+ REQUEST_ID, mClientMonitorCallbackConverter, 5 /* targetUserId */, OP_ID,
false /* restricted */, "test-owner", 4 /* cookie */, false /* requireConfirmation */,
9 /* sensorId */, mBiometricLogger, mBiometricContext,
true /* isStrongBiometric */,
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java
index 5a96f5cca52a..f77eb0bcc59f 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java
@@ -72,6 +72,7 @@ public class FingerprintEnrollClientTest {
private static final byte[] HAT = new byte[69];
private static final int USER_ID = 8;
+ private static final long REQUEST_ID = 9;
private static final int POINTER_ID = 0;
private static final int TOUCH_X = 8;
private static final int TOUCH_Y = 20;
@@ -256,7 +257,7 @@ public class FingerprintEnrollClientTest {
client.start(mCallback);
- verify(mUdfpsOverlayController).showUdfpsOverlay(anyInt(), anyInt(), any());
+ verify(mUdfpsOverlayController).showUdfpsOverlay(eq(REQUEST_ID), anyInt(), anyInt(), any());
verify(mSideFpsController).show(anyInt(), anyInt());
block.accept(client);
@@ -273,7 +274,7 @@ public class FingerprintEnrollClientTest {
when(mHal.getInterfaceVersion()).thenReturn(version);
final AidlSession aidl = new AidlSession(version, mHal, USER_ID, mHalSessionCallback);
- return new FingerprintEnrollClient(mContext, () -> aidl, mToken, 6 /* requestId */,
+ return new FingerprintEnrollClient(mContext, () -> aidl, mToken, REQUEST_ID,
mClientMonitorCallbackConverter, 0 /* userId */,
HAT, "owner", mBiometricUtils, 8 /* sensorId */,
mBiometricLogger, mBiometricContext, mSensorProps, mUdfpsOverlayController,
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 b601d14f1f58..89bd10fdcdc3 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -158,6 +158,7 @@ import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.junit.After;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.mockito.Mockito;
import org.mockito.internal.util.collections.Sets;
@@ -186,6 +187,7 @@ import java.util.concurrent.TimeUnit;
*/
@SmallTest
@Presubmit
+@Ignore("b/225415867")
public class DevicePolicyManagerTest extends DpmTestBase {
private static final String TAG = DevicePolicyManagerTest.class.getSimpleName();
@@ -4157,8 +4159,8 @@ public class DevicePolicyManagerTest extends DpmTestBase {
@Test
public void testSetPreferentialNetworkServiceConfig_noProfileOwner() throws Exception {
assertExpectException(SecurityException.class, null,
- () -> dpm.setPreferentialNetworkServiceConfig(
- PreferentialNetworkServiceConfig.DEFAULT));
+ () -> dpm.setPreferentialNetworkServiceConfigs(
+ List.of(PreferentialNetworkServiceConfig.DEFAULT)));
}
@Test
@@ -4198,10 +4200,10 @@ public class DevicePolicyManagerTest extends DpmTestBase {
addManagedProfile(admin1, managedProfileAdminUid, admin1);
mContext.binder.callingUid = managedProfileAdminUid;
- dpm.setPreferentialNetworkServiceConfig(PreferentialNetworkServiceConfig.DEFAULT);
+ dpm.setPreferentialNetworkServiceConfigs(
+ List.of(PreferentialNetworkServiceConfig.DEFAULT));
assertThat(dpm.isPreferentialNetworkServiceEnabled()).isFalse();
- assertThat(dpm.getPreferentialNetworkServiceConfig()
- .isEnabled()).isFalse();
+ assertThat(dpm.getPreferentialNetworkServiceConfigs().get(0).isEnabled()).isFalse();
ProfileNetworkPreference preferenceDetails =
new ProfileNetworkPreference.Builder()
@@ -4227,8 +4229,8 @@ public class DevicePolicyManagerTest extends DpmTestBase {
addManagedProfile(admin1, managedProfileAdminUid, admin1);
mContext.binder.callingUid = managedProfileAdminUid;
- dpm.setPreferentialNetworkServiceConfig(preferentialNetworkServiceConfigEnabled);
- assertThat(dpm.getPreferentialNetworkServiceConfig()
+ dpm.setPreferentialNetworkServiceConfigs(List.of(preferentialNetworkServiceConfigEnabled));
+ assertThat(dpm.getPreferentialNetworkServiceConfigs().get(0)
.isEnabled()).isTrue();
ProfileNetworkPreference preferenceDetails =
new ProfileNetworkPreference.Builder()
@@ -4257,17 +4259,14 @@ public class DevicePolicyManagerTest extends DpmTestBase {
.setFallbackToDefaultConnectionAllowed(false)
.setIncludedUids(new int[]{1, 2})
.build();
- dpm.setPreferentialNetworkServiceConfig(preferentialNetworkServiceConfigEnabled);
- assertThat(dpm.getPreferentialNetworkServiceConfig()
+ dpm.setPreferentialNetworkServiceConfigs(List.of(preferentialNetworkServiceConfigEnabled));
+ assertThat(dpm.getPreferentialNetworkServiceConfigs().get(0)
.isEnabled()).isTrue();
- List<Integer> includedList = new ArrayList<>();
- includedList.add(1);
- includedList.add(2);
ProfileNetworkPreference preferenceDetails =
new ProfileNetworkPreference.Builder()
.setPreference(PROFILE_NETWORK_PREFERENCE_ENTERPRISE_NO_FALLBACK)
.setPreferenceEnterpriseId(NET_ENTERPRISE_ID_1)
- .setIncludedUids(includedList)
+ .setIncludedUids(new int[]{1, 2})
.build();
List<ProfileNetworkPreference> preferences = new ArrayList<>();
preferences.add(preferenceDetails);
@@ -4292,17 +4291,14 @@ public class DevicePolicyManagerTest extends DpmTestBase {
.setExcludedUids(new int[]{1, 2})
.build();
- dpm.setPreferentialNetworkServiceConfig(preferentialNetworkServiceConfigEnabled);
- assertThat(dpm.getPreferentialNetworkServiceConfig()
+ dpm.setPreferentialNetworkServiceConfigs(List.of(preferentialNetworkServiceConfigEnabled));
+ assertThat(dpm.getPreferentialNetworkServiceConfigs().get(0)
.isEnabled()).isTrue();
- List<Integer> excludedUids = new ArrayList<>();
- excludedUids.add(1);
- excludedUids.add(2);
ProfileNetworkPreference preferenceDetails =
new ProfileNetworkPreference.Builder()
.setPreference(PROFILE_NETWORK_PREFERENCE_ENTERPRISE_NO_FALLBACK)
.setPreferenceEnterpriseId(NET_ENTERPRISE_ID_1)
- .setExcludedUids(excludedUids)
+ .setExcludedUids(new int[]{1, 2})
.build();
List<ProfileNetworkPreference> preferences = new ArrayList<>();
preferences.clear();
@@ -6671,7 +6667,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
configureContextForAccess(mContext, false);
assertExpectException(SecurityException.class, /* messageRegex= */ null,
- () -> dpm.markProfileOwnerOnOrganizationOwnedDevice(admin2));
+ () -> dpm.setProfileOwnerOnOrganizationOwnedDevice(admin2, true));
}
@Test
@@ -6680,7 +6676,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
configureContextForAccess(mContext, false);
assertExpectException(SecurityException.class, /* messageRegex= */ null,
- () -> dpm.markProfileOwnerOnOrganizationOwnedDevice(admin1));
+ () -> dpm.setProfileOwnerOnOrganizationOwnedDevice(admin1, true));
}
@Test
@@ -6715,7 +6711,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
DpmMockContext.CALLER_MANAGED_PROVISIONING_UID);
try {
runAsCaller(mServiceContext, dpms, dpm -> {
- dpm.markProfileOwnerOnOrganizationOwnedDevice(admin1);
+ dpm.setProfileOwnerOnOrganizationOwnedDevice(admin1, true);
});
} finally {
mServiceContext.binder.restoreCallingIdentity(ident);
@@ -7050,7 +7046,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
configureContextForAccess(mServiceContext, true);
runAsCaller(mServiceContext, dpms, dpm -> {
- dpm.markProfileOwnerOnOrganizationOwnedDevice(who);
+ dpm.setProfileOwnerOnOrganizationOwnedDevice(who, true);
});
mServiceContext.binder.restoreCallingIdentity(ident);
}
diff --git a/services/tests/servicestests/src/com/android/server/display/ColorFadeTest.java b/services/tests/servicestests/src/com/android/server/display/ColorFadeTest.java
new file mode 100644
index 000000000000..26a83a23de33
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/display/ColorFadeTest.java
@@ -0,0 +1,75 @@
+/*
+ * 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.display;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import static org.junit.Assert.assertFalse;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.hardware.display.DisplayManagerInternal;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.server.LocalServices;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class ColorFadeTest {
+ private static final int DISPLAY_ID = 123;
+
+ private Context mContext;
+
+ @Mock private DisplayManagerInternal mDisplayManagerInternalMock;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ addLocalServiceMock(DisplayManagerInternal.class, mDisplayManagerInternalMock);
+ mContext = getInstrumentation().getTargetContext();
+ }
+
+ @After
+ public void tearDown() {
+ LocalServices.removeServiceForTest(DisplayManagerInternal.class);
+ }
+
+ @Test
+ public void testPrepareColorFadeForInvalidDisplay() {
+ when(mDisplayManagerInternalMock.getDisplayInfo(eq(DISPLAY_ID))).thenReturn(null);
+ ColorFade colorFade = new ColorFade(DISPLAY_ID);
+ assertFalse(colorFade.prepare(mContext, ColorFade.MODE_FADE));
+ }
+
+ private static <T> void addLocalServiceMock(Class<T> clazz, T mock) {
+ LocalServices.removeServiceForTest(clazz);
+ LocalServices.addService(clazz, mock);
+ }
+
+}
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 a9812ab9bb03..d104871f488a 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
@@ -89,6 +89,7 @@ public class HdmiCecLocalDeviceTvTest {
private ArrayList<HdmiCecLocalDevice> mLocalDevices = new ArrayList<>();
private int mTvPhysicalAddress;
private int mTvLogicalAddress;
+ private boolean mWokenUp;
@Mock
private AudioManager mAudioManager;
@@ -104,6 +105,11 @@ public class HdmiCecLocalDeviceTvTest {
new HdmiControlService(InstrumentationRegistry.getTargetContext(),
Collections.emptyList()) {
@Override
+ void wakeUp() {
+ mWokenUp = true;
+ super.wakeUp();
+ }
+ @Override
boolean isControlEnabled() {
return true;
}
@@ -308,6 +314,22 @@ public class HdmiCecLocalDeviceTvTest {
}
@Test
+ public void handleTextViewOn_Dreaming() {
+ mHdmiCecLocalDeviceTv.mService.getHdmiCecConfig().setIntValue(
+ HdmiControlManager.CEC_SETTING_NAME_TV_WAKE_ON_ONE_TOUCH_PLAY,
+ HdmiControlManager.TV_WAKE_ON_ONE_TOUCH_PLAY_ENABLED);
+ mTestLooper.dispatchAll();
+ mPowerManager.setInteractive(true);
+ mWokenUp = false;
+ HdmiCecMessage textViewOn = HdmiCecMessageBuilder.buildTextViewOn(ADDR_PLAYBACK_1,
+ mTvLogicalAddress);
+ assertThat(mHdmiCecLocalDeviceTv.dispatchMessage(textViewOn)).isEqualTo(Constants.HANDLED);
+ mTestLooper.dispatchAll();
+ assertThat(mPowerManager.isInteractive()).isTrue();
+ assertThat(mWokenUp).isTrue();
+ }
+
+ @Test
public void tvSendStandbyOnSleep_Enabled() {
mHdmiCecLocalDeviceTv.mService.getHdmiCecConfig().setIntValue(
HdmiControlManager.CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP,
diff --git a/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java b/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java
index 4de15c87dcc1..928c76d07d7c 100644
--- a/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java
+++ b/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java
@@ -330,11 +330,12 @@ public class JobStoreTest {
@Test
public void testPriorityPersisted() throws Exception {
- final JobInfo.Builder b = new Builder(92, mComponent)
+ final JobInfo job = new Builder(92, mComponent)
.setOverrideDeadline(5000)
.setPriority(JobInfo.PRIORITY_MIN)
- .setPersisted(true);
- final JobStatus js = JobStatus.createFromJobInfo(b.build(), SOME_UID, null, -1, null);
+ .setPersisted(true)
+ .build();
+ final JobStatus js = JobStatus.createFromJobInfo(job, SOME_UID, null, -1, null);
mTaskStoreUnderTest.add(js);
waitForPendingIo();
@@ -342,7 +343,7 @@ public class JobStoreTest {
mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet, true);
final JobStatus loaded = jobStatusSet.getAllJobs().iterator().next();
assertEquals("Priority not correctly persisted.",
- JobInfo.PRIORITY_MIN, loaded.getEffectivePriority());
+ JobInfo.PRIORITY_MIN, job.getPriority());
}
/**
diff --git a/services/tests/servicestests/src/com/android/server/job/PendingJobQueueTest.java b/services/tests/servicestests/src/com/android/server/job/PendingJobQueueTest.java
new file mode 100644
index 000000000000..150e3c60b91e
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/job/PendingJobQueueTest.java
@@ -0,0 +1,452 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.job;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import android.app.job.JobInfo;
+import android.content.ComponentName;
+import android.platform.test.annotations.LargeTest;
+import android.util.Log;
+import android.util.SparseArray;
+import android.util.SparseBooleanArray;
+import android.util.SparseIntArray;
+import android.util.SparseLongArray;
+
+import com.android.server.job.controllers.JobStatus;
+
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+
+public class PendingJobQueueTest {
+ private static final String TAG = PendingJobQueueTest.class.getSimpleName();
+
+ private static final int[] sRegJobPriorities = {
+ JobInfo.PRIORITY_HIGH, JobInfo.PRIORITY_DEFAULT,
+ JobInfo.PRIORITY_LOW, JobInfo.PRIORITY_MIN
+ };
+
+ private static JobInfo.Builder createJobInfo(int jobId) {
+ return new JobInfo.Builder(jobId, new ComponentName("foo", "bar"));
+ }
+
+ private JobStatus createJobStatus(String testTag, JobInfo.Builder jobInfoBuilder,
+ int callingUid) {
+ return JobStatus.createFromJobInfo(
+ jobInfoBuilder.build(), callingUid, "com.android.test", 0, testTag);
+ }
+
+ @Test
+ public void testAdd() {
+ List<JobStatus> jobs = new ArrayList<>();
+ jobs.add(createJobStatus("testAdd", createJobInfo(1), 1));
+ jobs.add(createJobStatus("testAdd", createJobInfo(2), 2));
+ jobs.add(createJobStatus("testAdd", createJobInfo(3).setExpedited(true), 3));
+ jobs.add(createJobStatus("testAdd", createJobInfo(4), 4));
+ jobs.add(createJobStatus("testAdd", createJobInfo(5).setExpedited(true), 5));
+
+ PendingJobQueue jobQueue = new PendingJobQueue();
+ for (int i = 0; i < jobs.size(); ++i) {
+ jobQueue.add(jobs.get(i));
+ assertEquals(i + 1, jobQueue.size());
+ }
+
+ JobStatus job;
+ while ((job = jobQueue.next()) != null) {
+ jobs.remove(job);
+ }
+ assertEquals(0, jobs.size());
+ }
+
+ @Test
+ public void testAddAll() {
+ List<JobStatus> jobs = new ArrayList<>();
+ jobs.add(createJobStatus("testAddAll", createJobInfo(1), 1));
+ jobs.add(createJobStatus("testAddAll", createJobInfo(2), 2));
+ jobs.add(createJobStatus("testAddAll", createJobInfo(3).setExpedited(true), 3));
+ jobs.add(createJobStatus("testAddAll", createJobInfo(4), 4));
+ jobs.add(createJobStatus("testAddAll", createJobInfo(5).setExpedited(true), 5));
+
+ PendingJobQueue jobQueue = new PendingJobQueue();
+ jobQueue.addAll(jobs);
+ assertEquals(jobs.size(), jobQueue.size());
+
+ JobStatus job;
+ while ((job = jobQueue.next()) != null) {
+ jobs.remove(job);
+ }
+ assertEquals(0, jobs.size());
+ }
+
+ @Test
+ public void testClear() {
+ List<JobStatus> jobs = new ArrayList<>();
+ jobs.add(createJobStatus("testClear", createJobInfo(1), 1));
+ jobs.add(createJobStatus("testClear", createJobInfo(2), 2));
+ jobs.add(createJobStatus("testClear", createJobInfo(3).setExpedited(true), 3));
+ jobs.add(createJobStatus("testClear", createJobInfo(4), 4));
+ jobs.add(createJobStatus("testClear", createJobInfo(5).setExpedited(true), 5));
+
+ PendingJobQueue jobQueue = new PendingJobQueue();
+ jobQueue.addAll(jobs);
+ assertEquals(jobs.size(), jobQueue.size());
+ assertNotNull(jobQueue.next());
+
+ jobQueue.clear();
+ assertEquals(0, jobQueue.size());
+ assertNull(jobQueue.next());
+ }
+
+ @Test
+ public void testRemove() {
+ List<JobStatus> jobs = new ArrayList<>();
+ jobs.add(createJobStatus("testRemove", createJobInfo(1), 1));
+ jobs.add(createJobStatus("testRemove", createJobInfo(2), 2));
+ jobs.add(createJobStatus("testRemove", createJobInfo(3).setExpedited(true), 3));
+ jobs.add(createJobStatus("testRemove", createJobInfo(4), 4));
+ jobs.add(createJobStatus("testRemove", createJobInfo(5).setExpedited(true), 5));
+
+ PendingJobQueue jobQueue = new PendingJobQueue();
+ jobQueue.addAll(jobs);
+
+ for (int i = 0; i < jobs.size(); ++i) {
+ jobQueue.remove(jobs.get(i));
+ assertEquals(jobs.size() - i - 1, jobQueue.size());
+ }
+ assertNull(jobQueue.next());
+ }
+
+ @Test
+ public void testPendingJobSorting() {
+ PendingJobQueue jobQueue = new PendingJobQueue();
+
+ // First letter in job variable name indicate regular (r) or expedited (e).
+ // Capital letters in job variable name indicate the app/UID.
+ // Numbers in job variable name indicate the enqueue time.
+ // Expected sort order:
+ // eA7 > rA1 > eB6 > rB2 > eC3 > rD4 > eE5 > eF9 > rF8 > eC11 > rC10 > rG12 > rG13 > eE14
+ // Intentions:
+ // * A jobs let us test skipping both regular and expedited jobs of other apps
+ // * B jobs let us test skipping only regular job of another app without going too far
+ // * C jobs test that regular jobs don't skip over other app's jobs and that EJs only
+ // skip up to level of the earliest regular job
+ // * E jobs test that expedited jobs don't skip the line when the app has no regular jobs
+ // * F jobs test correct expedited/regular ordering doesn't push jobs too high in list
+ // * G jobs test correct ordering for regular jobs
+ // * H job tests correct behavior when enqueue times are the same
+ JobStatus rA1 = createJobStatus("testPendingJobSorting", createJobInfo(1), 1);
+ JobStatus rB2 = createJobStatus("testPendingJobSorting", createJobInfo(2), 2);
+ JobStatus eC3 = createJobStatus("testPendingJobSorting",
+ createJobInfo(3).setExpedited(true), 3);
+ JobStatus rD4 = createJobStatus("testPendingJobSorting", createJobInfo(4), 4);
+ JobStatus eE5 = createJobStatus("testPendingJobSorting",
+ createJobInfo(5).setExpedited(true), 5);
+ JobStatus eB6 = createJobStatus("testPendingJobSorting",
+ createJobInfo(6).setExpedited(true), 2);
+ JobStatus eA7 = createJobStatus("testPendingJobSorting",
+ createJobInfo(7).setExpedited(true), 1);
+ JobStatus rH8 = createJobStatus("testPendingJobSorting", createJobInfo(8), 8);
+ JobStatus rF8 = createJobStatus("testPendingJobSorting", createJobInfo(8), 6);
+ JobStatus eF9 = createJobStatus("testPendingJobSorting",
+ createJobInfo(9).setExpedited(true), 6);
+ JobStatus rC10 = createJobStatus("testPendingJobSorting", createJobInfo(10), 3);
+ JobStatus eC11 = createJobStatus("testPendingJobSorting",
+ createJobInfo(11).setExpedited(true), 3);
+ JobStatus rG12 = createJobStatus("testPendingJobSorting", createJobInfo(12), 7);
+ JobStatus rG13 = createJobStatus("testPendingJobSorting", createJobInfo(13), 7);
+ JobStatus eE14 = createJobStatus("testPendingJobSorting",
+ createJobInfo(14).setExpedited(true), 5);
+
+ rA1.enqueueTime = 10;
+ rB2.enqueueTime = 20;
+ eC3.enqueueTime = 30;
+ rD4.enqueueTime = 40;
+ eE5.enqueueTime = 50;
+ eB6.enqueueTime = 60;
+ eA7.enqueueTime = 70;
+ rF8.enqueueTime = 80;
+ rH8.enqueueTime = 80;
+ eF9.enqueueTime = 90;
+ rC10.enqueueTime = 100;
+ eC11.enqueueTime = 110;
+ rG12.enqueueTime = 120;
+ rG13.enqueueTime = 130;
+ eE14.enqueueTime = 140;
+
+ // Add in random order so sorting is apparent.
+ jobQueue.add(eC3);
+ jobQueue.add(eE5);
+ jobQueue.add(rA1);
+ jobQueue.add(rG13);
+ jobQueue.add(rD4);
+ jobQueue.add(eA7);
+ jobQueue.add(rG12);
+ jobQueue.add(rH8);
+ jobQueue.add(rF8);
+ jobQueue.add(eB6);
+ jobQueue.add(eE14);
+ jobQueue.add(eF9);
+ jobQueue.add(rB2);
+ jobQueue.add(rC10);
+ jobQueue.add(eC11);
+
+ checkPendingJobInvariants(jobQueue);
+ final JobStatus[] expectedOrder = new JobStatus[]{
+ eA7, rA1, eB6, rB2, eC3, rD4, eE5, eF9, rH8, rF8, eC11, rC10, rG12, rG13, eE14};
+ int idx = 0;
+ JobStatus job;
+ while ((job = jobQueue.next()) != null) {
+ assertEquals("List wasn't correctly sorted @ index " + idx,
+ expectedOrder[idx].getJobId(), job.getJobId());
+ idx++;
+ }
+ }
+
+ @Test
+ public void testPendingJobSorting_Random() {
+ PendingJobQueue jobQueue = new PendingJobQueue();
+ Random random = new Random(1); // Always use the same series of pseudo random values.
+
+ for (int i = 0; i < 5000; ++i) {
+ JobStatus job = createJobStatus("testPendingJobSorting_Random",
+ createJobInfo(i).setExpedited(random.nextBoolean()), random.nextInt(250));
+ job.enqueueTime = random.nextInt(1_000_000);
+ jobQueue.add(job);
+ }
+
+ checkPendingJobInvariants(jobQueue);
+ }
+
+ @Test
+ public void testPendingJobSortingTransitivity() {
+ PendingJobQueue jobQueue = new PendingJobQueue();
+ // Always use the same series of pseudo random values.
+ for (int seed : new int[]{1337, 7357, 606, 6357, 41106010, 3, 2, 1}) {
+ Random random = new Random(seed);
+
+ jobQueue.clear();
+
+ for (int i = 0; i < 300; ++i) {
+ JobStatus job = createJobStatus("testPendingJobSortingTransitivity",
+ createJobInfo(i).setExpedited(random.nextBoolean()), random.nextInt(50));
+ job.enqueueTime = random.nextInt(1_000_000);
+ job.overrideState = random.nextInt(4);
+ jobQueue.add(job);
+ }
+
+ checkPendingJobInvariants(jobQueue);
+ }
+ }
+
+ @Test
+ @LargeTest
+ public void testPendingJobSortingTransitivity_Concentrated() {
+ PendingJobQueue jobQueue = new PendingJobQueue();
+ // Always use the same series of pseudo random values.
+ for (int seed : new int[]{1337, 6000, 637739, 6357, 1, 7, 13}) {
+ Random random = new Random(seed);
+
+ jobQueue.clear();
+
+ for (int i = 0; i < 300; ++i) {
+ JobStatus job = createJobStatus("testPendingJobSortingTransitivity_Concentrated",
+ createJobInfo(i).setExpedited(random.nextFloat() < .03),
+ random.nextInt(20));
+ job.enqueueTime = random.nextInt(250);
+ job.overrideState = random.nextFloat() < .01
+ ? JobStatus.OVERRIDE_SORTING : JobStatus.OVERRIDE_NONE;
+ jobQueue.add(job);
+ Log.d(TAG, testJobToString(job));
+ }
+
+ checkPendingJobInvariants(jobQueue);
+ }
+ }
+
+ @Test
+ public void testPendingJobSorting_Random_WithPriority() {
+ PendingJobQueue jobQueue = new PendingJobQueue();
+ Random random = new Random(1); // Always use the same series of pseudo random values.
+
+ for (int i = 0; i < 5000; ++i) {
+ final boolean isEj = random.nextBoolean();
+ final int priority;
+ if (isEj) {
+ priority = random.nextBoolean() ? JobInfo.PRIORITY_MAX : JobInfo.PRIORITY_HIGH;
+ } else {
+ priority = sRegJobPriorities[random.nextInt(sRegJobPriorities.length)];
+ }
+ JobStatus job = createJobStatus("testPendingJobSorting_Random_WithPriority",
+ createJobInfo(i).setExpedited(isEj).setPriority(priority),
+ random.nextInt(250));
+ job.enqueueTime = random.nextInt(1_000_000);
+ jobQueue.add(job);
+ }
+
+ checkPendingJobInvariants(jobQueue);
+ }
+
+ @Test
+ public void testPendingJobSortingTransitivity_WithPriority() {
+ PendingJobQueue jobQueue = new PendingJobQueue();
+ // Always use the same series of pseudo random values.
+ for (int seed : new int[]{1337, 7357, 606, 6357, 41106010, 3, 2, 1}) {
+ Random random = new Random(seed);
+
+ jobQueue.clear();
+
+ for (int i = 0; i < 300; ++i) {
+ final boolean isEj = random.nextBoolean();
+ final int priority;
+ if (isEj) {
+ priority = random.nextBoolean() ? JobInfo.PRIORITY_MAX : JobInfo.PRIORITY_HIGH;
+ } else {
+ priority = sRegJobPriorities[random.nextInt(sRegJobPriorities.length)];
+ }
+ JobStatus job = createJobStatus("testPendingJobSortingTransitivity_WithPriority",
+ createJobInfo(i).setExpedited(isEj).setPriority(priority),
+ random.nextInt(50));
+ job.enqueueTime = random.nextInt(1_000_000);
+ job.overrideState = random.nextInt(4);
+ jobQueue.add(job);
+ }
+
+ checkPendingJobInvariants(jobQueue);
+ }
+ }
+
+ @Test
+ @LargeTest
+ public void testPendingJobSortingTransitivity_Concentrated_WithPriority() {
+ PendingJobQueue jobQueue = new PendingJobQueue();
+ // Always use the same series of pseudo random values.
+ for (int seed : new int[]{1337, 6000, 637739, 6357, 1, 7, 13}) {
+ Random random = new Random(seed);
+
+ jobQueue.clear();
+
+ for (int i = 0; i < 300; ++i) {
+ final boolean isEj = random.nextFloat() < .03;
+ final int priority;
+ if (isEj) {
+ priority = random.nextBoolean() ? JobInfo.PRIORITY_MAX : JobInfo.PRIORITY_HIGH;
+ } else {
+ priority = sRegJobPriorities[random.nextInt(sRegJobPriorities.length)];
+ }
+ JobStatus job = createJobStatus(
+ "testPendingJobSortingTransitivity_Concentrated_WithPriority",
+ createJobInfo(i).setExpedited(isEj).setPriority(priority),
+ random.nextInt(20));
+ job.enqueueTime = random.nextInt(250);
+ job.overrideState = random.nextFloat() < .01
+ ? JobStatus.OVERRIDE_SORTING : JobStatus.OVERRIDE_NONE;
+ jobQueue.add(job);
+ Log.d(TAG, testJobToString(job));
+ }
+
+ checkPendingJobInvariants(jobQueue);
+ }
+ }
+
+ private void checkPendingJobInvariants(PendingJobQueue jobQueue) {
+ final SparseBooleanArray regJobSeen = new SparseBooleanArray();
+ final SparseIntArray lastOverrideStateSeen = new SparseIntArray();
+ // Latest priority enqueue times seen for each priority for each app.
+ final SparseArray<SparseLongArray> latestPriorityRegEnqueueTimesPerUid =
+ new SparseArray<>();
+ final SparseArray<SparseLongArray> latestPriorityEjEnqueueTimesPerUid = new SparseArray<>();
+ final int noEntry = -1;
+
+ JobStatus job;
+ jobQueue.resetIterator();
+ while ((job = jobQueue.next()) != null) {
+ final int uid = job.getSourceUid();
+
+ // Invariant #1: All jobs (for a UID) are sorted by override state
+ // Invariant #2: All jobs (for a UID) are sorted by priority order
+ // Invariant #3: Jobs (for a UID) with the same priority are sorted by enqueue time.
+ // Invariant #4: EJs (for a UID) should be before regular jobs
+
+ final int prevOverrideState = lastOverrideStateSeen.get(uid, noEntry);
+ lastOverrideStateSeen.put(uid, job.overrideState);
+ if (prevOverrideState == noEntry) {
+ // First job for UID
+ continue;
+ }
+
+ // Invariant 1
+ if (prevOverrideState != job.overrideState) {
+ assertTrue(prevOverrideState > job.overrideState);
+ // Override state can make ordering weird. Clear the other cached states for this
+ // UID to avoid confusion in the other checks.
+ latestPriorityEjEnqueueTimesPerUid.remove(uid);
+ latestPriorityRegEnqueueTimesPerUid.remove(uid);
+ regJobSeen.delete(uid);
+ }
+
+ final int priority = job.getEffectivePriority();
+ final SparseArray<SparseLongArray> latestPriorityEnqueueTimesPerUid =
+ job.isRequestedExpeditedJob()
+ ? latestPriorityEjEnqueueTimesPerUid
+ : latestPriorityRegEnqueueTimesPerUid;
+ SparseLongArray latestPriorityEnqueueTimes = latestPriorityEnqueueTimesPerUid.get(uid);
+ if (latestPriorityEnqueueTimes != null) {
+ // Invariant 2
+ for (int p = priority - 1; p >= JobInfo.PRIORITY_MIN; --p) {
+ // If we haven't seen the priority, there shouldn't be an entry in the array.
+ assertEquals("Jobs not properly sorted by priority for uid " + uid,
+ noEntry, latestPriorityEnqueueTimes.get(p, noEntry));
+ }
+
+ // Invariant 3
+ final long lastSeenPriorityEnqueueTime =
+ latestPriorityEnqueueTimes.get(priority, noEntry);
+ if (lastSeenPriorityEnqueueTime != noEntry) {
+ assertTrue("Jobs with same priority not sorted by enqueue time: "
+ + lastSeenPriorityEnqueueTime + " vs " + job.enqueueTime,
+ lastSeenPriorityEnqueueTime <= job.enqueueTime);
+ }
+ } else {
+ latestPriorityEnqueueTimes = new SparseLongArray();
+ latestPriorityEnqueueTimesPerUid.put(uid, latestPriorityEnqueueTimes);
+ }
+ latestPriorityEnqueueTimes.put(priority, job.enqueueTime);
+
+ // Invariant 4
+ if (!job.isRequestedExpeditedJob()) {
+ regJobSeen.put(uid, true);
+ } else if (regJobSeen.get(uid)) {
+ fail("UID " + uid + " had an EJ ordered after a regular job");
+ }
+ }
+ }
+
+ private static String testJobToString(JobStatus job) {
+ return "testJob " + job.getSourceUid() + "/" + job.getJobId()
+ + "/o" + job.overrideState
+ + "/p" + job.getEffectivePriority()
+ + "/b" + job.lastEvaluatedBias
+ + "/" + job.isRequestedExpeditedJob() + "@" + job.enqueueTime;
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/locales/SystemAppUpdateTrackerTest.java b/services/tests/servicestests/src/com/android/server/locales/SystemAppUpdateTrackerTest.java
index 5185e15a8557..db602ca83f30 100644
--- a/services/tests/servicestests/src/com/android/server/locales/SystemAppUpdateTrackerTest.java
+++ b/services/tests/servicestests/src/com/android/server/locales/SystemAppUpdateTrackerTest.java
@@ -98,11 +98,8 @@ public class SystemAppUpdateTrackerTest {
private ActivityTaskManagerInternal mMockActivityTaskManager;
@Mock
private ActivityManagerInternal mMockActivityManager;
- @Mock
- private LocaleManagerBackupHelper mMockLocaleManagerBackupHelper;
- @Mock
- PackageMonitor mMockPackageMonitor;
+ PackageMonitor mPackageMonitor;
private LocaleManagerService mLocaleManagerService;
// Object under test.
@@ -114,11 +111,14 @@ public class SystemAppUpdateTrackerTest {
mMockActivityTaskManager = mock(ActivityTaskManagerInternal.class);
mMockActivityManager = mock(ActivityManagerInternal.class);
mMockPackageManagerInternal = mock(PackageManagerInternal.class);
- mMockPackageMonitor = mock(PackageMonitor.class);
- mMockLocaleManagerBackupHelper = mock(ShadowLocaleManagerBackupHelper.class);
+ LocaleManagerBackupHelper mockLocaleManagerBackupHelper =
+ mock(ShadowLocaleManagerBackupHelper.class);
+ // PackageMonitor is not needed in LocaleManagerService for these tests hence it is
+ // passed as null.
mLocaleManagerService = new LocaleManagerService(mMockContext,
mMockActivityTaskManager, mMockActivityManager,
- mMockPackageManagerInternal, mMockLocaleManagerBackupHelper, mMockPackageMonitor);
+ mMockPackageManagerInternal, mockLocaleManagerBackupHelper,
+ /* mPackageMonitor= */ null);
doReturn(DEFAULT_USER_ID).when(mMockActivityManager)
.handleIncomingUser(anyInt(), anyInt(), eq(DEFAULT_USER_ID), anyBoolean(), anyInt(),
@@ -134,6 +134,9 @@ public class SystemAppUpdateTrackerTest {
mSystemAppUpdateTracker = new SystemAppUpdateTracker(mMockContext,
mLocaleManagerService, mStoragefile);
+
+ mPackageMonitor = new LocaleManagerServicePackageMonitor(
+ mockLocaleManagerBackupHelper, mSystemAppUpdateTracker);
}
@After
@@ -148,7 +151,7 @@ public class SystemAppUpdateTrackerTest {
.when(mMockPackageManager).getApplicationInfo(eq(DEFAULT_PACKAGE_NAME_1), any());
// Updates the app once so that it writes to the file.
- mSystemAppUpdateTracker.onPackageUpdateFinished(DEFAULT_PACKAGE_NAME_1,
+ mPackageMonitor.onPackageUpdateFinished(DEFAULT_PACKAGE_NAME_1,
Binder.getCallingUid());
// Clear the in-memory data of updated apps
mSystemAppUpdateTracker.getUpdatedApps().clear();
@@ -167,7 +170,7 @@ public class SystemAppUpdateTrackerTest {
DEFAULT_LOCALES)).when(mMockActivityTaskManager)
.getApplicationConfig(anyString(), anyInt());
- mSystemAppUpdateTracker.onPackageUpdateFinished(DEFAULT_PACKAGE_NAME_1,
+ mPackageMonitor.onPackageUpdateFinished(DEFAULT_PACKAGE_NAME_1,
Binder.getCallingUid());
assertBroadcastSentToInstaller(DEFAULT_PACKAGE_NAME_1, DEFAULT_LOCALES);
@@ -186,7 +189,7 @@ public class SystemAppUpdateTrackerTest {
.getApplicationConfig(anyString(), anyInt());
// first update
- mSystemAppUpdateTracker.onPackageUpdateFinished(DEFAULT_PACKAGE_NAME_1,
+ mPackageMonitor.onPackageUpdateFinished(DEFAULT_PACKAGE_NAME_1,
Binder.getCallingUid());
assertBroadcastSentToInstaller(DEFAULT_PACKAGE_NAME_1, DEFAULT_LOCALES);
@@ -195,7 +198,7 @@ public class SystemAppUpdateTrackerTest {
verifyStorageFileContents(expectedAppList);
// second update
- mSystemAppUpdateTracker.onPackageUpdateFinished(DEFAULT_PACKAGE_NAME_1,
+ mPackageMonitor.onPackageUpdateFinished(DEFAULT_PACKAGE_NAME_1,
Binder.getCallingUid());
// getApplicationLocales should be invoked only once on the first update.
verify(mMockActivityTaskManager, times(1))
@@ -212,7 +215,7 @@ public class SystemAppUpdateTrackerTest {
/* isUpdatedSystemApp = */false))
.when(mMockPackageManager).getApplicationInfo(eq(DEFAULT_PACKAGE_NAME_2), any());
- mSystemAppUpdateTracker.onPackageUpdateFinished(DEFAULT_PACKAGE_NAME_2,
+ mPackageMonitor.onPackageUpdateFinished(DEFAULT_PACKAGE_NAME_2,
Binder.getCallingUid());
assertTrue(!mSystemAppUpdateTracker.getUpdatedApps().contains(DEFAULT_PACKAGE_NAME_2));
@@ -231,7 +234,7 @@ public class SystemAppUpdateTrackerTest {
.when(mMockPackageManager).getApplicationInfo(eq(DEFAULT_PACKAGE_NAME_1), any());
doReturn(null).when(mMockPackageManager).getInstallSourceInfo(anyString());
- mSystemAppUpdateTracker.onPackageUpdateFinished(DEFAULT_PACKAGE_NAME_1,
+ mPackageMonitor.onPackageUpdateFinished(DEFAULT_PACKAGE_NAME_1,
Binder.getCallingUid());
// getApplicationLocales should be never be invoked if not installer is not present.
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java
index 21c09a09e10f..1d10b8aa3f5a 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java
@@ -217,7 +217,7 @@ public class LockSettingsServiceTestable extends LockSettingsService {
}
@Override
- protected boolean isCredentialSharedWithParent(int userId) {
+ protected boolean isCredentialSharableWithParent(int userId) {
UserInfo userInfo = mUserManager.getUserInfo(userId);
return userInfo.isCloneProfile() || userInfo.isManagedProfile();
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/CrossProfileAppsServiceImplTest.java b/services/tests/servicestests/src/com/android/server/pm/CrossProfileAppsServiceImplTest.java
index 3cb5d5f92810..ce322f7cb6e6 100644
--- a/services/tests/servicestests/src/com/android/server/pm/CrossProfileAppsServiceImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/CrossProfileAppsServiceImplTest.java
@@ -20,6 +20,7 @@ import static org.testng.Assert.assertThrows;
import android.Manifest;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
+import android.app.ActivityOptions;
import android.app.AppOpsManager;
import android.app.IApplicationThread;
import android.app.admin.DevicePolicyManagerInternal;
@@ -46,6 +47,7 @@ import android.permission.PermissionManager;
import android.platform.test.annotations.Presubmit;
import android.util.SparseArray;
+import com.android.activitycontext.ActivityContext;
import com.android.internal.util.FunctionalUtils.ThrowingRunnable;
import com.android.internal.util.FunctionalUtils.ThrowingSupplier;
import com.android.server.LocalServices;
@@ -240,7 +242,9 @@ public class CrossProfileAppsServiceImplTest {
FEATURE_ID,
ACTIVITY_COMPONENT,
UserHandle.of(PRIMARY_USER).getIdentifier(),
- true));
+ true,
+ /* targetTask */ null,
+ /* options */ null));
verify(mActivityTaskManagerInternal, never())
.startActivityAsUser(
@@ -265,7 +269,9 @@ public class CrossProfileAppsServiceImplTest {
FEATURE_ID,
ACTIVITY_COMPONENT,
UserHandle.of(PRIMARY_USER).getIdentifier(),
- false));
+ false,
+ /* targetTask */ null,
+ /* options */ null));
verify(mActivityTaskManagerInternal, never())
.startActivityAsUser(
@@ -292,7 +298,9 @@ public class CrossProfileAppsServiceImplTest {
FEATURE_ID,
ACTIVITY_COMPONENT,
UserHandle.of(PROFILE_OF_PRIMARY_USER).getIdentifier(),
- true));
+ true,
+ /* targetTask */ null,
+ /* options */ null));
verify(mActivityTaskManagerInternal, never())
.startActivityAsUser(
@@ -319,7 +327,9 @@ public class CrossProfileAppsServiceImplTest {
FEATURE_ID,
ACTIVITY_COMPONENT,
UserHandle.of(PROFILE_OF_PRIMARY_USER).getIdentifier(),
- false));
+ false,
+ /* targetTask */ null,
+ /* options */ null));
verify(mActivityTaskManagerInternal, never())
.startActivityAsUser(
@@ -344,7 +354,9 @@ public class CrossProfileAppsServiceImplTest {
FEATURE_ID,
ACTIVITY_COMPONENT,
UserHandle.of(PROFILE_OF_PRIMARY_USER).getIdentifier(),
- true));
+ true,
+ /* targetTask */ null,
+ /* options */ null));
verify(mActivityTaskManagerInternal, never())
.startActivityAsUser(
@@ -369,7 +381,9 @@ public class CrossProfileAppsServiceImplTest {
FEATURE_ID,
ACTIVITY_COMPONENT,
UserHandle.of(PROFILE_OF_PRIMARY_USER).getIdentifier(),
- false));
+ false,
+ /* targetTask */ null,
+ /* options */ null));
verify(mActivityTaskManagerInternal, never())
.startActivityAsUser(
@@ -396,7 +410,9 @@ public class CrossProfileAppsServiceImplTest {
FEATURE_ID,
ACTIVITY_COMPONENT,
UserHandle.of(PROFILE_OF_PRIMARY_USER).getIdentifier(),
- true));
+ true,
+ /* targetTask */ null,
+ /* options */ null));
verify(mActivityTaskManagerInternal, never())
.startActivityAsUser(
@@ -440,7 +456,9 @@ public class CrossProfileAppsServiceImplTest {
FEATURE_ID,
ACTIVITY_COMPONENT,
UserHandle.of(PROFILE_OF_PRIMARY_USER).getIdentifier(),
- false));
+ false,
+ /* targetTask */ null,
+ /* options */ null));
verify(mActivityTaskManagerInternal, never())
.startActivityAsUser(
@@ -465,7 +483,9 @@ public class CrossProfileAppsServiceImplTest {
FEATURE_ID,
new ComponentName(PACKAGE_TWO, "test"),
UserHandle.of(PROFILE_OF_PRIMARY_USER).getIdentifier(),
- true));
+ true,
+ /* targetTask */ null,
+ /* options */ null));
verify(mActivityTaskManagerInternal, never())
.startActivityAsUser(
@@ -490,7 +510,9 @@ public class CrossProfileAppsServiceImplTest {
FEATURE_ID,
new ComponentName(PACKAGE_TWO, "test"),
UserHandle.of(PROFILE_OF_PRIMARY_USER).getIdentifier(),
- false));
+ false,
+ /* targetTask */ null,
+ /* options */ null));
verify(mActivityTaskManagerInternal, never())
.startActivityAsUser(
@@ -515,7 +537,9 @@ public class CrossProfileAppsServiceImplTest {
FEATURE_ID,
ACTIVITY_COMPONENT,
UserHandle.of(SECONDARY_USER).getIdentifier(),
- true));
+ true,
+ /* targetTask */ null,
+ /* options */ null));
verify(mActivityTaskManagerInternal, never())
.startActivityAsUser(
@@ -540,7 +564,9 @@ public class CrossProfileAppsServiceImplTest {
FEATURE_ID,
ACTIVITY_COMPONENT,
UserHandle.of(SECONDARY_USER).getIdentifier(),
- false));
+ false,
+ /* targetTask */ null,
+ /* options */ null));
verify(mActivityTaskManagerInternal, never())
.startActivityAsUser(
@@ -564,7 +590,9 @@ public class CrossProfileAppsServiceImplTest {
FEATURE_ID,
ACTIVITY_COMPONENT,
UserHandle.of(PRIMARY_USER).getIdentifier(),
- true);
+ true,
+ /* targetTask */ null,
+ /* options */ null);
verify(mActivityTaskManagerInternal)
.startActivityAsUser(
@@ -578,6 +606,44 @@ public class CrossProfileAppsServiceImplTest {
eq(PRIMARY_USER));
}
+ @Test
+ public void startActivityAsUser_sameTask_fromProfile_success() throws Exception {
+ mTestInjector.setCallingUserId(PROFILE_OF_PRIMARY_USER);
+
+ Bundle options = ActivityOptions.makeOpenCrossProfileAppsAnimation().toBundle();
+ IBinder result = ActivityContext.getWithContext(activity -> {
+ try {
+ IBinder targetTask = activity.getActivityToken();
+ mCrossProfileAppsServiceImpl.startActivityAsUser(
+ mIApplicationThread,
+ PACKAGE_ONE,
+ FEATURE_ID,
+ ACTIVITY_COMPONENT,
+ UserHandle.of(PRIMARY_USER).getIdentifier(),
+ true,
+ targetTask,
+ options);
+ return targetTask;
+ } catch (Exception re) {
+ return null;
+ }
+ });
+ if (result == null) {
+ throw new Exception();
+ }
+
+ verify(mActivityTaskManagerInternal)
+ .startActivityAsUser(
+ nullable(IApplicationThread.class),
+ eq(PACKAGE_ONE),
+ eq(FEATURE_ID),
+ any(Intent.class),
+ eq(result),
+ anyInt(),
+ eq(options),
+ eq(PRIMARY_USER));
+ }
+
private void mockAppsInstalled(String packageName, int user, boolean installed) {
when(mPackageManagerInternal.getPackageInfo(
eq(packageName),
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java
index 3d21b74825f0..27c3ca46cb20 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java
@@ -20,10 +20,15 @@ import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.when;
import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
import static org.xmlpull.v1.XmlPullParser.START_TAG;
import android.content.pm.PackageInstaller;
+import android.content.pm.PackageManager;
import android.platform.test.annotations.Presubmit;
import android.util.AtomicFile;
import android.util.Slog;
@@ -68,12 +73,17 @@ public class PackageInstallerSessionTest {
@Mock
PackageManagerService mMockPackageManagerInternal;
+ @Mock
+ Computer mSnapshot;
+
@Before
public void setUp() throws Exception {
mTmpDir = mTemporaryFolder.newFolder("PackageInstallerSessionTest");
mSessionsFile = new AtomicFile(
new File(mTmpDir.getAbsolutePath() + "/sessions.xml"), "package-session");
MockitoAnnotations.initMocks(this);
+ when(mSnapshot.getPackageUid(anyString(), anyLong(), anyInt())).thenReturn(0);
+ when(mMockPackageManagerInternal.snapshotComputer()).thenReturn(mSnapshot);
}
@Test
@@ -188,7 +198,7 @@ public class PackageInstallerSessionTest {
/* isFailed */ false,
/* isApplied */false,
/* stagedSessionErrorCode */
- PackageInstaller.SessionInfo.SESSION_VERIFICATION_FAILED,
+ PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE,
/* stagedSessionErrorMessage */ "some error");
}
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 050b224bf7f7..946108d607db 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java
@@ -23,11 +23,10 @@ import static com.google.common.truth.Truth.assertWithMessage;
import static org.junit.Assert.fail;
import static java.lang.reflect.Modifier.isFinal;
-import static java.lang.reflect.Modifier.isPrivate;
-import static java.lang.reflect.Modifier.isProtected;
import static java.lang.reflect.Modifier.isPublic;
import static java.lang.reflect.Modifier.isStatic;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.AppGlobals;
import android.content.IIntentReceiver;
@@ -63,7 +62,6 @@ import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
-import java.util.HashMap;
import java.util.List;
import java.util.regex.Pattern;
@@ -101,7 +99,7 @@ public class PackageManagerServiceTest {
@Nullable Bundle bOptions) {
}
- public void sendPackageAddedForNewUsers(String packageName,
+ public void sendPackageAddedForNewUsers(@NonNull Computer snapshot, String packageName,
boolean sendBootComplete, boolean includeStopped, int appId,
int[] userIds, int[] instantUserIds, int dataLoaderType) {
}
@@ -456,147 +454,6 @@ public class PackageManagerServiceTest {
return null;
}
- // Return the boolean locked value. A null return means the annotation was not
- // found. This method will fail if the annotation is found but is not one of the
- // known constants.
- private Boolean getOverride(Method m) {
- final String name = "Computer." + displayName(m);
- final Computer.LiveImplementation annotation =
- m.getAnnotation(Computer.LiveImplementation.class);
- if (annotation == null) {
- return null;
- }
- final int override = annotation.override();
- if (override == Computer.LiveImplementation.MANDATORY) {
- return true;
- } else if (override == Computer.LiveImplementation.NOT_ALLOWED) {
- return false;
- } else {
- flag(name, "invalid Live value: " + override);
- return null;
- }
- }
-
- @Test
- public void testComputerStructure() {
- // Verify that Copmuter methods are properly annotated and that ComputerLocked is
- // properly populated per annotations.
- // Call PackageManagerService.validateComputer();
- Class base = Computer.class;
-
- HashMap<Method, Boolean> methodType = new HashMap<>();
-
- // Verify that all Computer methods are annotated and that the annotation
- // parameter locked() is valid.
- for (Method m : base.getDeclaredMethods()) {
- final String name = "Computer." + displayName(m);
- Boolean override = getOverride(m);
- if (override == null) {
- flag(name, "missing required Live annotation");
- }
- methodType.put(m, override);
- }
-
- Class coreClass = ComputerEngine.class;
- final Method[] coreMethods = coreClass.getDeclaredMethods();
-
- // Examine every method in the core. If it inherits from a base method it must be
- // "public final" if the base is NOT_ALLOWED or "public" if the base is MANDATORY.
- // If the core method does not inherit from the base then it must be either
- // private or protected.
- for (Method m : base.getDeclaredMethods()) {
- String name = "Computer." + displayName(m);
- final boolean locked = methodType.get(m);
- final Method core = matchMethod(m, coreMethods);
- if (core == null) {
- flag(name, "not overridden in ComputerEngine");
- continue;
- }
- name = "ComputerEngine." + displayName(m);
- final int modifiers = core.getModifiers();
- if (!locked) {
- if (!isPublic(modifiers)) {
- flag(name, "is not public");
- }
- if (!isFinal(modifiers)) {
- flag(name, "is not final");
- }
- }
- }
- // Any methods left in the coreMethods array must be private or protected.
- // Protected methods must be overridden (and final) in the live list.
- Method[] coreHelpers = new Method[coreMethods.length];
- int coreIndex = 0;
- for (Method m : coreMethods) {
- if (m != null) {
- final String name = "ComputerEngine." + displayName(m);
- if (name.contains(".lambda$static")) {
- // skip static lambda function
- continue;
- }
-
- final int modifiers = m.getModifiers();
- if (isPrivate(modifiers)) {
- // Okay
- } else if (isProtected(modifiers)) {
- coreHelpers[coreIndex++] = m;
- } else {
- flag(name, "is neither private nor protected");
- }
- }
- }
-
- Class liveClass = ComputerLocked.class;
- final Method[] liveMethods = liveClass.getDeclaredMethods();
-
- // Examine every method in the live list. Every method must be final and must
- // inherit either from base or core. If the method inherits from a base method
- // then the base must be MANDATORY.
- for (Method m : base.getDeclaredMethods()) {
- String name = "Computer." + displayName(m);
- final boolean locked = methodType.get(m);
- final Method live = matchMethod(m, liveMethods);
- if (live == null) {
- if (locked) {
- flag(name, "not overridden in ComputerLocked");
- }
- continue;
- }
- if (!locked) {
- flag(name, "improperly overridden in ComputerLocked");
- continue;
- }
-
- name = "ComputerLocked." + displayName(m);
- final int modifiers = live.getModifiers();
- if (!locked) {
- if (!isPublic(modifiers)) {
- flag(name, "is not public");
- }
- if (!isFinal(modifiers)) {
- flag(name, "is not final");
- }
- }
- }
- for (Method m : coreHelpers) {
- if (m == null) {
- continue;
- }
- String name = "ComputerLocked." + displayName(m);
- final Method live = matchMethod(m, liveMethods);
- if (live == null) {
- flag(name, "is not overridden in ComputerLocked");
- continue;
- }
- }
- for (Method m : liveMethods) {
- if (m != null) {
- String name = "ComputerLocked." + displayName(m);
- flag(name, "illegal local method");
- }
- }
- }
-
private static PerPackageReadTimeouts[] getPerPackageReadTimeouts(String knownDigestersList) {
final String defaultTimeouts = "3600000001:3600000002:3600000003";
List<PerPackageReadTimeouts> result = PerPackageReadTimeouts.parseDigestersList(
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
index 2b34bc2ef28d..f4ab3db3c917 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
@@ -31,11 +31,11 @@ import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
-import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import android.annotation.NonNull;
@@ -1103,6 +1103,59 @@ public class PackageManagerSettingsTests {
assertThat(countDownLatch.getCount(), is(0L));
}
+ @Test
+ public void testRegisterAndRemoveAppId() throws PackageManagerException {
+ // Test that the first new app UID should start from FIRST_APPLICATION_UID
+ final Settings settings = makeSettings();
+ final PackageSetting ps = createPackageSetting("com.foo");
+ assertTrue(settings.registerAppIdLPw(ps, false));
+ assertEquals(10000, ps.getAppId());
+ // Set up existing app IDs: 10000, 10001, 10003
+ final PackageSetting ps1 = createPackageSetting("com.foo1");
+ ps1.setAppId(10001);
+ final PackageSetting ps2 = createPackageSetting("com.foo2");
+ ps2.setAppId(10003);
+ final PackageSetting ps3 = createPackageSetting("com.foo3");
+ assertEquals(0, ps3.getAppId());
+ assertTrue(settings.registerAppIdLPw(ps1, false));
+ assertTrue(settings.registerAppIdLPw(ps2, false));
+ assertTrue(settings.registerAppIdLPw(ps3, false));
+ assertEquals(10001, ps1.getAppId());
+ assertEquals(10003, ps2.getAppId());
+ // Expecting the new one to start with the next available uid
+ assertEquals(10002, ps3.getAppId());
+ // Remove and insert a new one and the new one should not reuse the same uid
+ settings.removeAppIdLPw(10002);
+ final PackageSetting ps4 = createPackageSetting("com.foo4");
+ assertTrue(settings.registerAppIdLPw(ps4, false));
+ assertEquals(10004, ps4.getAppId());
+ // Keep adding more
+ final PackageSetting ps5 = createPackageSetting("com.foo5");
+ assertTrue(settings.registerAppIdLPw(ps5, false));
+ assertEquals(10005, ps5.getAppId());
+ // Remove the last one and the new one should use incremented uid
+ settings.removeAppIdLPw(10005);
+ final PackageSetting ps6 = createPackageSetting("com.foo6");
+ assertTrue(settings.registerAppIdLPw(ps6, false));
+ assertEquals(10006, ps6.getAppId());
+ }
+
+ /**
+ * Test replacing a PackageSetting with a SharedUserSetting in mAppIds
+ */
+ @Test
+ public void testAddPackageSetting() throws PackageManagerException {
+ final Settings settings = makeSettings();
+ final SharedUserSetting sus1 = new SharedUserSetting(
+ "TestUser", 0 /*pkgFlags*/, 0 /*pkgPrivateFlags*/);
+ sus1.mAppId = 10001;
+ final PackageSetting ps1 = createPackageSetting("com.foo");
+ ps1.setAppId(10001);
+ assertTrue(settings.registerAppIdLPw(ps1, false));
+ settings.addPackageSettingLPw(ps1, sus1);
+ assertSame(sus1, settings.getSharedUserSettingLPr(ps1));
+ }
+
private void verifyUserState(PackageUserState userState,
boolean notLaunched, boolean stopped, boolean installed) {
assertThat(userState.getEnabledState(), is(0));
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
index 99edecfeed30..c78678431dac 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
@@ -16,7 +16,6 @@
package com.android.server.pm;
import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertBundlesEqual;
-import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertEmpty;
import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertExpectException;
import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertWith;
import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.list;
@@ -37,6 +36,8 @@ import android.app.Person;
import android.content.ComponentName;
import android.content.Intent;
import android.content.LocusId;
+import android.content.pm.Capability;
+import android.content.pm.CapabilityParams;
import android.content.pm.ShortcutInfo;
import android.content.res.Resources;
import android.graphics.BitmapFactory;
@@ -258,10 +259,15 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest {
.setLongLived(true)
.setExtras(pb)
.setStartingTheme(android.R.style.Theme_Black_NoTitleBar_Fullscreen)
- .addCapabilityBinding("action.intent.START_EXERCISE",
- "exercise.type", list("running", "jogging"))
- .addCapabilityBinding("action.intent.START_EXERCISE",
- "exercise.duration", list("10m"))
+ .addCapabilityBinding(
+ new Capability.Builder("action.intent.START_EXERCISE").build(),
+ new CapabilityParams.Builder("exercise.type", "running")
+ .addAlias("jogging")
+ .build())
+ .addCapabilityBinding(
+ new Capability.Builder("action.intent.START_EXERCISE").build(),
+ new CapabilityParams.Builder("exercise.duration", "10m")
+ .build())
.build();
si.addFlags(ShortcutInfo.FLAG_PINNED);
si.setBitmapPath("abc");
@@ -299,13 +305,14 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest {
assertEquals(null, si.getDisabledMessageResName());
assertEquals("android:style/Theme.Black.NoTitleBar.Fullscreen",
si.getStartingThemeResName());
- assertTrue(si.hasCapability("action.intent.START_EXERCISE"));
- assertFalse(si.hasCapability(""));
- assertFalse(si.hasCapability("random"));
- assertEquals(list("running", "jogging"), si.getCapabilityParameterValues(
- "action.intent.START_EXERCISE", "exercise.type"));
- assertEmpty(si.getCapabilityParameterValues("action.intent.START_EXERCISE", ""));
- assertEmpty(si.getCapabilityParameterValues("action.intent.START_EXERCISE", "random"));
+ assertEquals(list(new Capability.Builder("action.intent.START_EXERCISE").build()),
+ si.getCapabilities());
+ assertEquals(list(
+ new CapabilityParams.Builder("exercise.type", "running")
+ .addAlias("jogging").build(),
+ new CapabilityParams.Builder("exercise.duration", "10m").build()),
+ si.getCapabilityParams(
+ new Capability.Builder("action.intent.START_EXERCISE").build()));
}
public void testShortcutInfoParcel_resId() {
@@ -959,10 +966,15 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest {
.setRank(123)
.setExtras(pb)
.setLocusId(new LocusId("1.2.3.4.5"))
- .addCapabilityBinding("action.intent.START_EXERCISE",
- "exercise.type", list("running", "jogging"))
- .addCapabilityBinding("action.intent.START_EXERCISE",
- "exercise.duration", list("10m"))
+ .addCapabilityBinding(
+ new Capability.Builder("action.intent.START_EXERCISE").build(),
+ new CapabilityParams.Builder("exercise.type", "running")
+ .addAlias("jogging")
+ .build())
+ .addCapabilityBinding(
+ new Capability.Builder("action.intent.START_EXERCISE").build(),
+ new CapabilityParams.Builder("exercise.duration", "10m")
+ .build())
.build();
sorig.setTimestamp(mInjectedCurrentTimeMillis);
@@ -1024,13 +1036,14 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest {
assertNull(si.getIconUri());
assertTrue(si.getLastChangedTimestamp() < now);
- assertTrue(si.hasCapability("action.intent.START_EXERCISE"));
- assertFalse(si.hasCapability(""));
- assertFalse(si.hasCapability("random"));
- assertEquals(list("running", "jogging"), si.getCapabilityParameterValues(
- "action.intent.START_EXERCISE", "exercise.type"));
- assertEmpty(si.getCapabilityParameterValues("action.intent.START_EXERCISE", ""));
- assertEmpty(si.getCapabilityParameterValues("action.intent.START_EXERCISE", "random"));
+ assertEquals(list(new Capability.Builder("action.intent.START_EXERCISE").build()),
+ si.getCapabilities());
+ assertEquals(list(
+ new CapabilityParams.Builder("exercise.type", "running")
+ .addAlias("jogging").build(),
+ new CapabilityParams.Builder("exercise.duration", "10m").build()),
+ si.getCapabilityParams(
+ new Capability.Builder("action.intent.START_EXERCISE").build()));
// Make sure ranks are saved too. Because of the auto-adjusting, we need two shortcuts
// to test it.
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
index c7b5547170d0..06b711251c0f 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
@@ -316,7 +316,8 @@ public final class UserManagerTest {
asHandle(currentUser));
try {
assertThat(mUserManager.removeUserWhenPossible(user1.getUserHandle(),
- /* overrideDevicePolicy= */ false)).isEqualTo(UserManager.REMOVE_RESULT_ERROR);
+ /* overrideDevicePolicy= */ false))
+ .isEqualTo(UserManager.REMOVE_RESULT_ERROR_USER_RESTRICTION);
} finally {
mUserManager.setUserRestriction(UserManager.DISALLOW_REMOVE_USER, /* value= */ false,
asHandle(currentUser));
@@ -353,7 +354,8 @@ public final class UserManagerTest {
@Test
public void testRemoveUserWhenPossible_systemUserReturnsError() throws Exception {
assertThat(mUserManager.removeUserWhenPossible(UserHandle.SYSTEM,
- /* overrideDevicePolicy= */ false)).isEqualTo(UserManager.REMOVE_RESULT_ERROR);
+ /* overrideDevicePolicy= */ false))
+ .isEqualTo(UserManager.REMOVE_RESULT_ERROR_SYSTEM_USER);
assertThat(hasUser(UserHandle.USER_SYSTEM)).isTrue();
}
@@ -363,7 +365,8 @@ public final class UserManagerTest {
public void testRemoveUserWhenPossible_invalidUserReturnsError() throws Exception {
assertThat(hasUser(Integer.MAX_VALUE)).isFalse();
assertThat(mUserManager.removeUserWhenPossible(UserHandle.of(Integer.MAX_VALUE),
- /* overrideDevicePolicy= */ false)).isEqualTo(UserManager.REMOVE_RESULT_ERROR);
+ /* overrideDevicePolicy= */ false))
+ .isEqualTo(UserManager.REMOVE_RESULT_ERROR_USER_NOT_FOUND);
}
@MediumTest
diff --git a/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImplTest.java b/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImplTest.java
index 0eba6a335d00..0187e34cbc5f 100644
--- a/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImplTest.java
@@ -224,6 +224,11 @@ public class SoundTriggerMiddlewareImplTest {
// Stop the recognition.
stopRecognition(module, handle, hwHandle);
+ ArgumentCaptor<RecognitionEvent> eventCaptor = ArgumentCaptor.forClass(
+ RecognitionEvent.class);
+ verify(callback).onRecognition(eq(handle), eventCaptor.capture(), eq(101));
+ assertEquals(RecognitionStatus.ABORTED, eventCaptor.getValue().status);
+
// Unload the model.
unloadModel(module, handle, hwHandle);
module.detach();
@@ -268,6 +273,11 @@ public class SoundTriggerMiddlewareImplTest {
// Stop the recognition.
stopRecognition(module, handle, hwHandle);
+ ArgumentCaptor<PhraseRecognitionEvent> eventCaptor = ArgumentCaptor.forClass(
+ PhraseRecognitionEvent.class);
+ verify(callback).onPhraseRecognition(eq(handle), eventCaptor.capture(), eq(101));
+ assertEquals(RecognitionStatus.ABORTED, eventCaptor.getValue().common.status);
+
// Unload the model.
unloadModel(module, handle, hwHandle);
module.detach();
diff --git a/services/tests/servicestests/src/com/android/server/statusbar/StatusBarManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/statusbar/StatusBarManagerServiceTest.java
index 1442f1c82d42..83139b02430a 100644
--- a/services/tests/servicestests/src/com/android/server/statusbar/StatusBarManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/statusbar/StatusBarManagerServiceTest.java
@@ -23,9 +23,11 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.anyLong;
import static org.mockito.Mockito.anyString;
import static org.mockito.Mockito.argThat;
import static org.mockito.Mockito.eq;
@@ -37,6 +39,7 @@ import static org.mockito.Mockito.when;
import android.Manifest;
import android.app.ActivityManagerInternal;
import android.app.StatusBarManager;
+import android.compat.testing.PlatformCompatChangeRule;
import android.content.ComponentName;
import android.content.Intent;
import android.content.om.IOverlayManager;
@@ -62,10 +65,13 @@ import com.android.server.LocalServices;
import com.android.server.policy.GlobalActionsProvider;
import com.android.server.wm.ActivityTaskManagerInternal;
+import libcore.junit.util.compat.CoreCompatChangeRule;
+
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.TestRule;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import org.mockito.ArgumentCaptor;
@@ -73,6 +79,7 @@ import org.mockito.ArgumentMatcher;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import org.mockito.stubbing.Answer;
@RunWith(JUnit4.class)
public class StatusBarManagerServiceTest {
@@ -88,6 +95,9 @@ public class StatusBarManagerServiceTest {
public final TestableContext mContext =
new NoBroadcastContextWrapper(InstrumentationRegistry.getContext());
+ @Rule
+ public TestRule mCompatChangeRule = new PlatformCompatChangeRule();
+
@Mock
private ActivityTaskManagerInternal mActivityTaskManagerInternal;
@Mock
@@ -127,6 +137,7 @@ public class StatusBarManagerServiceTest {
when(mMockStatusBar.asBinder()).thenReturn(mMockStatusBar);
when(mApplicationInfo.loadLabel(any())).thenReturn(APP_NAME);
+ mockHandleIncomingUser();
mStatusBarManagerService = new StatusBarManagerService(mContext);
LocalServices.removeServiceForTest(StatusBarManagerInternal.class);
@@ -142,6 +153,80 @@ public class StatusBarManagerServiceTest {
}
@Test
+ @CoreCompatChangeRule.EnableCompatChanges(
+ {StatusBarManagerService.REQUEST_LISTENING_MUST_MATCH_PACKAGE})
+ public void testRequestActive_changeEnabled_OKCall() throws RemoteException {
+ int user = 0;
+ mockEverything(user);
+ mStatusBarManagerService.requestTileServiceListeningState(TEST_COMPONENT, user);
+
+ verify(mMockStatusBar).requestTileServiceListeningState(TEST_COMPONENT);
+ }
+
+ @Test
+ @CoreCompatChangeRule.EnableCompatChanges(
+ {StatusBarManagerService.REQUEST_LISTENING_MUST_MATCH_PACKAGE})
+ public void testRequestActive_changeEnabled_differentPackage_fail() throws RemoteException {
+ when(mPackageManagerInternal.getPackageUid(TEST_PACKAGE, 0L, mContext.getUserId()))
+ .thenReturn(Binder.getCallingUid() + 1);
+ try {
+ mStatusBarManagerService.requestTileServiceListeningState(TEST_COMPONENT, 0);
+ fail("Should cause security exception");
+ } catch (SecurityException e) { }
+ verify(mMockStatusBar, never()).requestTileServiceListeningState(TEST_COMPONENT);
+ }
+
+ @Test
+ @CoreCompatChangeRule.EnableCompatChanges(
+ {StatusBarManagerService.REQUEST_LISTENING_MUST_MATCH_PACKAGE})
+ public void testRequestActive_changeEnabled_notCurrentUser_fail() throws RemoteException {
+ mockUidCheck();
+ int user = 0;
+ mockCurrentUserCheck(user);
+ try {
+ mStatusBarManagerService.requestTileServiceListeningState(TEST_COMPONENT, user + 1);
+ fail("Should cause illegal argument exception");
+ } catch (IllegalArgumentException e) { }
+
+ // Do not call into SystemUI
+ verify(mMockStatusBar, never()).requestTileServiceListeningState(TEST_COMPONENT);
+ }
+
+ @Test
+ @CoreCompatChangeRule.DisableCompatChanges(
+ {StatusBarManagerService.REQUEST_LISTENING_MUST_MATCH_PACKAGE})
+ public void testRequestActive_changeDisabled_pass() throws RemoteException {
+ int user = 0;
+ mockEverything(user);
+ mStatusBarManagerService.requestTileServiceListeningState(TEST_COMPONENT, user);
+
+ verify(mMockStatusBar).requestTileServiceListeningState(TEST_COMPONENT);
+ }
+
+ @Test
+ @CoreCompatChangeRule.DisableCompatChanges(
+ {StatusBarManagerService.REQUEST_LISTENING_MUST_MATCH_PACKAGE})
+ public void testRequestActive_changeDisabled_differentPackage_pass() throws RemoteException {
+ when(mPackageManagerInternal.getPackageUid(TEST_PACKAGE, 0L, mContext.getUserId()))
+ .thenReturn(Binder.getCallingUid() + 1);
+ mStatusBarManagerService.requestTileServiceListeningState(TEST_COMPONENT, 0);
+
+ verify(mMockStatusBar).requestTileServiceListeningState(TEST_COMPONENT);
+ }
+
+ @Test
+ @CoreCompatChangeRule.DisableCompatChanges(
+ {StatusBarManagerService.REQUEST_LISTENING_MUST_MATCH_PACKAGE})
+ public void testRequestActive_changeDisabled_notCurrentUser_pass() throws RemoteException {
+ mockUidCheck();
+ int user = 0;
+ mockCurrentUserCheck(user);
+ mStatusBarManagerService.requestTileServiceListeningState(TEST_COMPONENT, user + 1);
+
+ verify(mMockStatusBar).requestTileServiceListeningState(TEST_COMPONENT);
+ }
+
+ @Test
public void testHandleIncomingUserCalled() {
int fakeUser = 17;
try {
@@ -252,7 +337,7 @@ public class StatusBarManagerServiceTest {
mockCurrentUserCheck(user);
IntentMatcher im = new IntentMatcher(
new Intent(TileService.ACTION_QS_TILE).setComponent(TEST_COMPONENT));
- when(mPackageManagerInternal.resolveService(argThat(im), nullable(String.class), eq(0),
+ when(mPackageManagerInternal.resolveService(argThat(im), nullable(String.class), eq(0L),
eq(user), anyInt())).thenReturn(null);
Callback callback = new Callback();
@@ -272,7 +357,7 @@ public class StatusBarManagerServiceTest {
IntentMatcher im = new IntentMatcher(
new Intent(TileService.ACTION_QS_TILE).setComponent(TEST_COMPONENT));
- when(mPackageManagerInternal.resolveService(argThat(im), nullable(String.class), eq(0),
+ when(mPackageManagerInternal.resolveService(argThat(im), nullable(String.class), eq(0L),
eq(user), anyInt())).thenReturn(r);
when(mPackageManagerInternal.getComponentEnabledSetting(TEST_COMPONENT,
Binder.getCallingUid(), user)).thenReturn(
@@ -294,7 +379,7 @@ public class StatusBarManagerServiceTest {
IntentMatcher im = new IntentMatcher(
new Intent(TileService.ACTION_QS_TILE).setComponent(TEST_COMPONENT));
- when(mPackageManagerInternal.resolveService(argThat(im), nullable(String.class), eq(0),
+ when(mPackageManagerInternal.resolveService(argThat(im), nullable(String.class), eq(0L),
eq(user), anyInt())).thenReturn(r);
when(mPackageManagerInternal.getComponentEnabledSetting(TEST_COMPONENT,
Binder.getCallingUid(), user)).thenReturn(
@@ -318,7 +403,7 @@ public class StatusBarManagerServiceTest {
IntentMatcher im = new IntentMatcher(
new Intent(TileService.ACTION_QS_TILE).setComponent(TEST_COMPONENT));
- when(mPackageManagerInternal.resolveService(argThat(im), nullable(String.class), eq(0),
+ when(mPackageManagerInternal.resolveService(argThat(im), nullable(String.class), eq(0L),
eq(user), anyInt())).thenReturn(r);
when(mPackageManagerInternal.getComponentEnabledSetting(TEST_COMPONENT,
Binder.getCallingUid(), user)).thenReturn(
@@ -342,7 +427,7 @@ public class StatusBarManagerServiceTest {
IntentMatcher im = new IntentMatcher(
new Intent(TileService.ACTION_QS_TILE).setComponent(TEST_COMPONENT));
- when(mPackageManagerInternal.resolveService(argThat(im), nullable(String.class), eq(0),
+ when(mPackageManagerInternal.resolveService(argThat(im), nullable(String.class), eq(0L),
eq(user), anyInt())).thenReturn(r);
when(mPackageManagerInternal.getComponentEnabledSetting(TEST_COMPONENT,
Binder.getCallingUid(), user)).thenReturn(
@@ -607,23 +692,12 @@ public class StatusBarManagerServiceTest {
public void testSetNavBarMode_invalidInputThrowsError() throws RemoteException {
int navBarModeInvalid = -1;
- assertThrows(UnsupportedOperationException.class,
+ assertThrows(IllegalArgumentException.class,
() -> mStatusBarManagerService.setNavBarMode(navBarModeInvalid));
verify(mOverlayManager, never()).setEnabledExclusiveInCategory(anyString(), anyInt());
}
@Test
- public void testSetNavBarMode_noOverlayManagerDoesNotEnable() throws RemoteException {
- mOverlayManager = null;
- int navBarModeKids = StatusBarManager.NAV_BAR_MODE_KIDS;
-
- mStatusBarManagerService.setNavBarMode(navBarModeKids);
-
- assertEquals(navBarModeKids, mStatusBarManagerService.getNavBarMode());
- verify(mOverlayManager, never()).setEnabledExclusiveInCategory(anyString(), anyInt());
- }
-
- @Test
public void testSetNavBarMode_noPackageDoesNotEnable() throws Exception {
mContext.setMockPackageManager(mPackageManager);
when(mPackageManager.getPackageInfo(anyString(),
@@ -641,7 +715,7 @@ public class StatusBarManagerServiceTest {
}
private void mockUidCheck(String packageName) {
- when(mPackageManagerInternal.getPackageUid(eq(packageName), anyInt(), anyInt()))
+ when(mPackageManagerInternal.getPackageUid(eq(packageName), anyLong(), anyInt()))
.thenReturn(Binder.getCallingUid());
}
@@ -667,7 +741,7 @@ public class StatusBarManagerServiceTest {
IntentMatcher im = new IntentMatcher(
new Intent(TileService.ACTION_QS_TILE).setComponent(componentName));
- when(mPackageManagerInternal.resolveService(argThat(im), nullable(String.class), eq(0),
+ when(mPackageManagerInternal.resolveService(argThat(im), nullable(String.class), eq(0L),
eq(user), anyInt())).thenReturn(r);
when(mPackageManagerInternal.getComponentEnabledSetting(componentName,
Binder.getCallingUid(), user)).thenReturn(
@@ -679,6 +753,15 @@ public class StatusBarManagerServiceTest {
PROCESS_STATE_TOP);
}
+ private void mockHandleIncomingUser() {
+ when(mActivityManagerInternal.handleIncomingUser(anyInt(), anyInt(), anyInt(), anyBoolean(),
+ anyInt(), anyString(), anyString())).thenAnswer(
+ (Answer<Integer>) invocation -> {
+ return invocation.getArgument(2); // same user
+ }
+ );
+ }
+
private void mockEverything(int user) {
mockUidCheck();
mockCurrentUserCheck(user);
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 18d3f3d0e805..210d2faf44d6 100644
--- a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
@@ -62,7 +62,10 @@ import static org.mockito.AdditionalMatchers.not;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Matchers.intThat;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
@@ -76,11 +79,13 @@ import android.app.usage.UsageStatsManagerInternal;
import android.appwidget.AppWidgetManager;
import android.content.Context;
import android.content.ContextWrapper;
+import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
+import android.content.pm.ResolveInfo;
import android.hardware.display.DisplayManager;
import android.os.Handler;
import android.os.Looper;
@@ -118,6 +123,7 @@ import java.util.Random;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
/**
* Unit test for AppStandbyController.
@@ -421,8 +427,31 @@ public class AppStandbyControllerTests {
pib.packageName = PACKAGE_BACKGROUND_LOCATION;
packages.add(pib);
- doReturn(packages).when(mockPm).getInstalledPackagesAsUser(anyInt(), anyInt());
+ // Set up getInstalledPackagesAsUser().
+ doReturn(packages).when(mockPm).getInstalledPackagesAsUser(anyInt(),
+ anyInt());
+
+ // Set up getInstalledPackagesAsUser() for "MATCH_ONLY_SYSTEM"
+ doReturn(
+ packages.stream().filter(pinfo -> pinfo.applicationInfo.isSystemApp())
+ .collect(Collectors.toList())
+ ).when(mockPm).getInstalledPackagesAsUser(
+ intThat(i -> (i & PackageManager.MATCH_SYSTEM_ONLY) != 0),
+ anyInt());
+
+ // Set up queryIntentActivitiesAsUser()
+ final ArrayList<ResolveInfo> systemFrontDoorActivities = new ArrayList<>();
+ final ResolveInfo frontDoorActivity = new ResolveInfo();
+ frontDoorActivity.activityInfo = new ActivityInfo();
+ frontDoorActivity.activityInfo.packageName = pis.packageName;
+ systemFrontDoorActivities.add(frontDoorActivity);
+ doReturn(systemFrontDoorActivities).when(mockPm)
+ .queryIntentActivitiesAsUser(any(Intent.class),
+ intThat(i -> (i & PackageManager.MATCH_SYSTEM_ONLY) != 0),
+ anyInt());
+
+ // Set up other APIs.
try {
for (int i = 0; i < packages.size(); ++i) {
PackageInfo pkg = packages.get(i);
@@ -489,6 +518,7 @@ public class AppStandbyControllerTests {
@Before
public void setUp() throws Exception {
+ LocalServices.removeServiceForTest(UsageStatsManagerInternal.class);
LocalServices.addService(
UsageStatsManagerInternal.class, mock(UsageStatsManagerInternal.class));
MyContextWrapper myContext = new MyContextWrapper(InstrumentationRegistry.getContext());
diff --git a/services/tests/servicestests/src/com/android/server/vibrator/VibrationSettingsTest.java b/services/tests/servicestests/src/com/android/server/vibrator/VibrationSettingsTest.java
index 3cda2a554e48..ec16188bfc1d 100644
--- a/services/tests/servicestests/src/com/android/server/vibrator/VibrationSettingsTest.java
+++ b/services/tests/servicestests/src/com/android/server/vibrator/VibrationSettingsTest.java
@@ -288,7 +288,7 @@ public class VibrationSettingsTest {
}
@Test
- public void shouldIgnoreVibration_withRingerModeSilent_ignoresRingtoneOnly() {
+ public void shouldIgnoreVibration_withRingerModeSilent_ignoresRingtoneAndNotification() {
// Vibrating settings on are overruled by ringer mode.
setUserSetting(Settings.System.HAPTIC_FEEDBACK_ENABLED, 1);
setUserSetting(Settings.System.VIBRATE_WHEN_RINGING, 1);
@@ -296,7 +296,7 @@ public class VibrationSettingsTest {
setRingerMode(AudioManager.RINGER_MODE_SILENT);
for (int usage : ALL_USAGES) {
- if (usage == USAGE_RINGTONE) {
+ if (usage == USAGE_RINGTONE || usage == USAGE_NOTIFICATION) {
assertVibrationIgnoredForUsage(usage, Vibration.Status.IGNORED_FOR_RINGER_MODE);
} else {
assertVibrationNotIgnoredForUsage(usage);
@@ -305,6 +305,16 @@ public class VibrationSettingsTest {
}
@Test
+ public void shouldIgnoreVibration_withRingerModeSilentAndBypassFlag_allowsAllVibrations() {
+ setRingerMode(AudioManager.RINGER_MODE_SILENT);
+
+ for (int usage : ALL_USAGES) {
+ assertVibrationNotIgnoredForUsageAndFlags(usage,
+ VibrationAttributes.FLAG_BYPASS_INTERRUPTION_POLICY);
+ }
+ }
+
+ @Test
public void shouldIgnoreVibration_withRingerModeVibrate_allowsAllVibrations() {
setRingerMode(AudioManager.RINGER_MODE_VIBRATE);
diff --git a/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java
index e46e28199d5a..92736c517782 100644
--- a/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java
@@ -1136,19 +1136,23 @@ public class VibratorManagerServiceTest {
}
@Test
- public void onExternalVibration_setsExternalControl() {
+ public void onExternalVibration_setsExternalControl() throws Exception {
mockVibrators(1);
mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_EXTERNAL_CONTROL);
createSystemReadyService();
+ IBinder binderToken = mock(IBinder.class);
ExternalVibration externalVibration = new ExternalVibration(UID, PACKAGE_NAME, AUDIO_ATTRS,
- mock(IExternalVibrationController.class));
+ mock(IExternalVibrationController.class), binderToken);
int scale = mExternalVibratorService.onExternalVibrationStart(externalVibration);
mExternalVibratorService.onExternalVibrationStop(externalVibration);
assertNotEquals(IExternalVibratorService.SCALE_MUTE, scale);
assertEquals(Arrays.asList(false, true, false),
mVibratorProviders.get(1).getExternalControlStates());
+
+ verify(binderToken).linkToDeath(any(), eq(0));
+ verify(binderToken).unlinkToDeath(any(), eq(0));
}
@Test
@@ -1160,17 +1164,19 @@ public class VibratorManagerServiceTest {
setUserSetting(Settings.System.VIBRATE_WHEN_RINGING, 1);
createSystemReadyService();
+ IBinder firstToken = mock(IBinder.class);
+ IBinder secondToken = mock(IBinder.class);
IExternalVibrationController firstController = mock(IExternalVibrationController.class);
IExternalVibrationController secondController = mock(IExternalVibrationController.class);
ExternalVibration firstVibration = new ExternalVibration(UID, PACKAGE_NAME, AUDIO_ATTRS,
- firstController);
+ firstController, firstToken);
int firstScale = mExternalVibratorService.onExternalVibrationStart(firstVibration);
AudioAttributes ringtoneAudioAttrs = new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE)
.build();
ExternalVibration secondVibration = new ExternalVibration(UID, PACKAGE_NAME,
- ringtoneAudioAttrs, secondController);
+ ringtoneAudioAttrs, secondController, secondToken);
int secondScale = mExternalVibratorService.onExternalVibrationStart(secondVibration);
assertNotEquals(IExternalVibratorService.SCALE_MUTE, firstScale);
@@ -1180,6 +1186,17 @@ public class VibratorManagerServiceTest {
// Set external control called only once.
assertEquals(Arrays.asList(false, true),
mVibratorProviders.get(1).getExternalControlStates());
+
+ mExternalVibratorService.onExternalVibrationStop(secondVibration);
+ mExternalVibratorService.onExternalVibrationStop(firstVibration);
+ assertEquals(Arrays.asList(false, true, false),
+ mVibratorProviders.get(1).getExternalControlStates());
+
+ verify(firstToken).linkToDeath(any(), eq(0));
+ verify(firstToken).unlinkToDeath(any(), eq(0));
+
+ verify(secondToken).linkToDeath(any(), eq(0));
+ verify(secondToken).unlinkToDeath(any(), eq(0));
}
@Test
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 71f8b8de032b..67382bfacab4 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -18,6 +18,7 @@ package com.android.server.notification;
import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
+import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.app.AppOpsManager.MODE_ALLOWED;
import static android.app.AppOpsManager.MODE_IGNORED;
import static android.app.Notification.FLAG_AUTO_CANCEL;
@@ -432,8 +433,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
when(mUgmInternal.newUriPermissionOwner(anyString())).thenReturn(mPermOwner);
when(mPackageManager.getPackagesForUid(mUid)).thenReturn(new String[]{PKG});
when(mPackageManagerClient.getPackagesForUid(anyInt())).thenReturn(new String[]{PKG});
- when(mPermissionPolicyInternal.canShowPermissionPromptForTask(
- any(ActivityManager.RecentTaskInfo.class))).thenReturn(false);
+ when(mAtm.getTaskToShowPermissionDialogOn(anyString(), anyInt()))
+ .thenReturn(INVALID_TASK_ID);
mContext.addMockSystemService(AppOpsManager.class, mock(AppOpsManager.class));
when(mUm.getProfileIds(0, false)).thenReturn(new int[]{0});
@@ -971,8 +972,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
@Test
public void testCreateNotificationChannels_FirstChannelWithFgndTaskStartsPermDialog()
throws Exception {
- when(mPermissionPolicyInternal.canShowPermissionPromptForTask(any(
- ActivityManager.RecentTaskInfo.class))).thenReturn(true);
+ when(mAtm.getTaskToShowPermissionDialogOn(anyString(), anyInt())).thenReturn(TEST_TASK_ID);
final NotificationChannel channel =
new NotificationChannel("id", "name", IMPORTANCE_DEFAULT);
mBinderService.createNotificationChannels(PKG_NO_CHANNELS,
@@ -985,8 +985,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
@Test
public void testCreateNotificationChannels_SecondChannelWithFgndTaskDoesntStartPermDialog()
throws Exception {
- when(mPermissionPolicyInternal.canShowPermissionPromptForTask(any(
- ActivityManager.RecentTaskInfo.class))).thenReturn(true);
+ when(mAtm.getTaskToShowPermissionDialogOn(anyString(), anyInt())).thenReturn(TEST_TASK_ID);
assertTrue(mBinderService.getNumNotificationChannelsForPackage(PKG, mUid, true) > 0);
final NotificationChannel channel =
@@ -1001,8 +1000,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
public void testCreateNotificationChannels_FirstChannelWithBgndTaskDoesntStartPermDialog()
throws Exception {
reset(mPermissionPolicyInternal);
- when(mPermissionPolicyInternal.canShowPermissionPromptForTask(any(
- ActivityManager.RecentTaskInfo.class))).thenReturn(false);
+ when(mAtm.getTaskToShowPermissionDialogOn(anyString(), anyInt())).thenReturn(TEST_TASK_ID);
final NotificationChannel channel =
new NotificationChannel("id", "name", IMPORTANCE_DEFAULT);
@@ -2707,13 +2705,10 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
@Test
public void testUpdateAppNotifyCreatorBlock() throws Exception {
mService.setPreferencesHelper(mPreferencesHelper);
-
- // should not trigger a broadcast
- when(mAppOpsManager.checkOpNoThrow(anyInt(), eq(mUid), eq(PKG))).thenReturn(MODE_IGNORED);
- mService.mAppOpsCallback.opChanged(0, mUid, PKG);
+ when(mPreferencesHelper.getImportance(PKG, mUid)).thenReturn(IMPORTANCE_DEFAULT);
// should trigger a broadcast
- mBinderService.setNotificationsEnabledForPackage(PKG, 0, true);
+ mBinderService.setNotificationsEnabledForPackage(PKG, mUid, false);
Thread.sleep(500);
waitForIdle();
ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
@@ -2722,7 +2717,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
assertEquals(NotificationManager.ACTION_APP_BLOCK_STATE_CHANGED,
captor.getValue().getAction());
assertEquals(PKG, captor.getValue().getPackage());
- assertFalse(captor.getValue().getBooleanExtra(EXTRA_BLOCKED_STATE, true));
+ assertTrue(captor.getValue().getBooleanExtra(EXTRA_BLOCKED_STATE, true));
}
@Test
@@ -2739,7 +2734,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
// should not trigger a broadcast
when(mAppOpsManager.checkOpNoThrow(anyInt(), eq(mUid), eq(PKG))).thenReturn(MODE_ALLOWED);
- mService.mAppOpsCallback.opChanged(0, mUid, PKG);
// should trigger a broadcast
mBinderService.setNotificationsEnabledForPackage(PKG, 0, true);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationPermissionMigrationTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationPermissionMigrationTest.java
index a83887202a7d..2ba587d21163 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationPermissionMigrationTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationPermissionMigrationTest.java
@@ -606,9 +606,9 @@ public class NotificationPermissionMigrationTest extends UiServiceTestCase {
@Test
public void testUpdateAppNotifyCreatorBlock() throws Exception {
- when(mAppOpsManager.checkOpNoThrow(anyInt(), eq(mUid), eq(PKG))).thenReturn(MODE_IGNORED);
+ when(mPermissionHelper.hasPermission(mUid)).thenReturn(true);
- mService.mAppOpsCallback.opChanged(0, mUid, PKG);
+ mBinderService.setNotificationsEnabledForPackage(PKG, mUid, false);
Thread.sleep(500);
waitForIdle();
@@ -618,14 +618,14 @@ public class NotificationPermissionMigrationTest extends UiServiceTestCase {
assertEquals(NotificationManager.ACTION_APP_BLOCK_STATE_CHANGED,
captor.getValue().getAction());
assertEquals(PKG, captor.getValue().getPackage());
- assertFalse(captor.getValue().getBooleanExtra(EXTRA_BLOCKED_STATE, true));
+ assertTrue(captor.getValue().getBooleanExtra(EXTRA_BLOCKED_STATE, true));
}
@Test
public void testUpdateAppNotifyCreatorUnblock() throws Exception {
- when(mAppOpsManager.checkOpNoThrow(anyInt(), eq(mUid), eq(PKG))).thenReturn(MODE_ALLOWED);
+ when(mPermissionHelper.hasPermission(mUid)).thenReturn(false);
- mService.mAppOpsCallback.opChanged(0, mUid, PKG);
+ mBinderService.setNotificationsEnabledForPackage(PKG, mUid, true);
Thread.sleep(500);
waitForIdle();
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PermissionHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PermissionHelperTest.java
index a24ba0d1e1c2..46b47f4dcfdd 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PermissionHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PermissionHelperTest.java
@@ -88,7 +88,11 @@ public class PermissionHelperTest extends UiServiceTestCase {
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
- mPermissionHelper = new PermissionHelper(mPmi, mPackageManager, mPermManager, true);
+ mPermissionHelper = new PermissionHelper(mPmi, mPackageManager, mPermManager, true, false);
+ PackageInfo testPkgInfo = new PackageInfo();
+ testPkgInfo.requestedPermissions = new String[]{ Manifest.permission.POST_NOTIFICATIONS };
+ when(mPackageManager.getPackageInfo(anyString(), anyLong(), anyInt()))
+ .thenReturn(testPkgInfo);
}
// TODO (b/194833441): Remove when the migration is enabled
@@ -96,7 +100,7 @@ public class PermissionHelperTest extends UiServiceTestCase {
public void testMethodsThrowIfMigrationDisabled() throws IllegalAccessException,
InvocationTargetException {
PermissionHelper permHelper =
- new PermissionHelper(mPmi, mPackageManager, mPermManager, false);
+ new PermissionHelper(mPmi, mPackageManager, mPermManager, false, false);
Method[] allMethods = PermissionHelper.class.getDeclaredMethods();
for (Method method : allMethods) {
@@ -298,6 +302,26 @@ public class PermissionHelperTest extends UiServiceTestCase {
}
@Test
+ public void testSetNotificationPermission_pkgPerm_grantedByDefaultPermSet_allUserSet()
+ throws Exception {
+ mPermissionHelper = new PermissionHelper(mPmi, mPackageManager, mPermManager, true, true);
+ when(mPmi.checkPermission(anyString(), anyString(), anyInt()))
+ .thenReturn(PERMISSION_DENIED);
+ when(mPermManager.getPermissionFlags(anyString(),
+ eq(Manifest.permission.POST_NOTIFICATIONS),
+ anyInt())).thenReturn(FLAG_PERMISSION_GRANTED_BY_DEFAULT);
+ PermissionHelper.PackagePermission pkgPerm = new PermissionHelper.PackagePermission(
+ "pkg", 10, true, false);
+
+ mPermissionHelper.setNotificationPermission(pkgPerm);
+ verify(mPermManager).grantRuntimePermission(
+ "pkg", Manifest.permission.POST_NOTIFICATIONS, 10);
+ verify(mPermManager).updatePermissionFlags("pkg", Manifest.permission.POST_NOTIFICATIONS,
+ FLAG_PERMISSION_USER_SET | FLAG_PERMISSION_REVIEW_REQUIRED,
+ FLAG_PERMISSION_USER_SET, true, 10);
+ }
+
+ @Test
public void testSetNotificationPermission_revokeUserSet() throws Exception {
when(mPmi.checkPermission(anyString(), anyString(), anyInt()))
.thenReturn(PERMISSION_GRANTED);
@@ -384,6 +408,22 @@ public class PermissionHelperTest extends UiServiceTestCase {
}
@Test
+ public void testSetNotificationPermission_doesntRequestNotChanged() throws Exception {
+ when(mPmi.checkPermission(anyString(), anyString(), anyInt()))
+ .thenReturn(PERMISSION_GRANTED);
+ PackageInfo testPkgInfo = new PackageInfo();
+ testPkgInfo.requestedPermissions = new String[]{ Manifest.permission.RECORD_AUDIO };
+ when(mPackageManager.getPackageInfo(anyString(), anyLong(), anyInt()))
+ .thenReturn(testPkgInfo);
+ mPermissionHelper.setNotificationPermission("pkg", 10, false, false);
+
+ verify(mPmi, never()).checkPermission(
+ eq("pkg"), eq(Manifest.permission.POST_NOTIFICATIONS), eq(10));
+ verify(mPermManager, never()).revokeRuntimePermission(
+ eq("pkg"), eq(Manifest.permission.POST_NOTIFICATIONS), eq(10), anyString());
+ }
+
+ @Test
public void testIsPermissionFixed() throws Exception {
when(mPermManager.getPermissionFlags(anyString(),
eq(Manifest.permission.POST_NOTIFICATIONS),
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
index 8f1eed89647c..7d5a0d0bf84d 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
@@ -1870,46 +1870,46 @@ public class PreferencesHelperTest extends UiServiceTestCase {
@Test
public void testGetChannelsBypassingDndCount_noChannelsBypassing() throws Exception {
assertEquals(0, mHelper.getNotificationChannelsBypassingDnd(PKG_N_MR1,
- USER.getIdentifier()).getList().size());
+ UID_N_MR1).getList().size());
}
@Test
- public void testGetChannelsBypassingDnd_noChannelsForUserIdBypassing()
+ public void testGetChannelsBypassingDnd_noChannelsForUidBypassing()
throws Exception {
- int user = 9;
+ int uid = 222;
NotificationChannel channel = new NotificationChannel("id", "name",
NotificationManager.IMPORTANCE_MAX);
channel.setBypassDnd(true);
mHelper.createNotificationChannel(PKG_N_MR1, 111, channel, true, true);
assertEquals(0, mHelper.getNotificationChannelsBypassingDnd(PKG_N_MR1,
- user).getList().size());
+ uid).getList().size());
}
@Test
public void testGetChannelsBypassingDndCount_oneChannelBypassing_groupBlocked() {
- int user = USER.getIdentifier();
+ int uid = UID_N_MR1;
NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1");
NotificationChannel channel1 = new NotificationChannel("id1", "name1",
NotificationManager.IMPORTANCE_MAX);
channel1.setBypassDnd(true);
channel1.setGroup(ncg.getId());
- mHelper.createNotificationChannelGroup(PKG_N_MR1, user, ncg, /* fromTargetApp */ true);
- mHelper.createNotificationChannel(PKG_N_MR1, user, channel1, true, /*has DND access*/ true);
+ mHelper.createNotificationChannelGroup(PKG_N_MR1, uid, ncg, /* fromTargetApp */ true);
+ mHelper.createNotificationChannel(PKG_N_MR1, uid, channel1, true, /*has DND access*/ true);
assertEquals(1, mHelper.getNotificationChannelsBypassingDnd(PKG_N_MR1,
- user).getList().size());
+ uid).getList().size());
// disable group
ncg.setBlocked(true);
- mHelper.createNotificationChannelGroup(PKG_N_MR1, user, ncg, /* fromTargetApp */ false);
+ mHelper.createNotificationChannelGroup(PKG_N_MR1, uid, ncg, /* fromTargetApp */ false);
assertEquals(0, mHelper.getNotificationChannelsBypassingDnd(PKG_N_MR1,
- user).getList().size());
+ uid).getList().size());
}
@Test
public void testGetChannelsBypassingDndCount_multipleChannelsBypassing() {
- int user = USER.getIdentifier();
+ int uid = UID_N_MR1;
NotificationChannel channel1 = new NotificationChannel("id1", "name1",
NotificationManager.IMPORTANCE_MAX);
NotificationChannel channel2 = new NotificationChannel("id2", "name2",
@@ -1920,22 +1920,22 @@ public class PreferencesHelperTest extends UiServiceTestCase {
channel2.setBypassDnd(true);
channel3.setBypassDnd(true);
// has DND access, so can set bypassDnd attribute
- mHelper.createNotificationChannel(PKG_N_MR1, user, channel1, true, /*has DND access*/ true);
- mHelper.createNotificationChannel(PKG_N_MR1, user, channel2, true, true);
- mHelper.createNotificationChannel(PKG_N_MR1, user, channel3, true, true);
+ mHelper.createNotificationChannel(PKG_N_MR1, uid, channel1, true, /*has DND access*/ true);
+ mHelper.createNotificationChannel(PKG_N_MR1, uid, channel2, true, true);
+ mHelper.createNotificationChannel(PKG_N_MR1, uid, channel3, true, true);
assertEquals(3, mHelper.getNotificationChannelsBypassingDnd(PKG_N_MR1,
- user).getList().size());
+ uid).getList().size());
// setBypassDnd false for some channels
channel1.setBypassDnd(false);
channel2.setBypassDnd(false);
assertEquals(1, mHelper.getNotificationChannelsBypassingDnd(PKG_N_MR1,
- user).getList().size());
+ uid).getList().size());
// setBypassDnd false for rest of the channels
channel3.setBypassDnd(false);
assertEquals(0, mHelper.getNotificationChannelsBypassingDnd(PKG_N_MR1,
- user).getList().size());
+ uid).getList().size());
}
@Test
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeFilteringTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeFilteringTest.java
index abcc8c1e99cb..8ac729e29424 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeFilteringTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeFilteringTest.java
@@ -121,7 +121,7 @@ public class ZenModeFilteringTest extends UiServiceTestCase {
// Create a notification record with the people String array as the
// bundled extras, and the numbers ArraySet as additional phone numbers.
- private NotificationRecord getRecordWithPeopleInfo(String[] people,
+ private NotificationRecord getCallRecordWithPeopleInfo(String[] people,
ArraySet<String> numbers) {
// set up notification record
NotificationRecord r = mock(NotificationRecord.class);
@@ -131,6 +131,8 @@ public class ZenModeFilteringTest extends UiServiceTestCase {
when(sbn.getNotification()).thenReturn(notification);
when(r.getSbn()).thenReturn(sbn);
when(r.getPhoneNumbers()).thenReturn(numbers);
+ when(r.getCriticality()).thenReturn(CriticalNotificationExtractor.NORMAL);
+ when(r.isCategory(CATEGORY_CALL)).thenReturn(true);
return r;
}
@@ -350,11 +352,41 @@ public class ZenModeFilteringTest extends UiServiceTestCase {
}
@Test
+ public void testRepeatCallers_checksPhoneNumbers() {
+ // set up telephony manager behavior
+ when(mTelephonyManager.getNetworkCountryIso()).thenReturn("us");
+
+ // first, record a phone call from a telephone number
+ String[] callNumber = new String[]{"tel:12345678910"};
+ mZenModeFiltering.recordCall(getCallRecordWithPeopleInfo(callNumber, null));
+
+ // set up policy to only allow repeat callers
+ Policy policy = new Policy(
+ PRIORITY_CATEGORY_REPEAT_CALLERS, 0, 0, 0, CONVERSATION_SENDERS_NONE);
+
+ // make sure that a record with the phone number in extras is correctly allowed through
+ NotificationRecord r = getCallRecordWithPeopleInfo(callNumber, null);
+ assertFalse(mZenModeFiltering.shouldIntercept(ZEN_MODE_IMPORTANT_INTERRUPTIONS, policy, r));
+
+ // make sure that a record with the phone number in the phone numbers array is also
+ // allowed through
+ NotificationRecord r2 = getCallRecordWithPeopleInfo(new String[]{"some_contact_uri"},
+ new ArraySet<>(new String[]{"12345678910"}));
+ assertFalse(mZenModeFiltering.shouldIntercept(
+ ZEN_MODE_IMPORTANT_INTERRUPTIONS, policy, r2));
+
+ // A record with the phone number in neither of the above should be intercepted
+ NotificationRecord r3 = getCallRecordWithPeopleInfo(new String[]{"tel:10987654321"},
+ new ArraySet<>(new String[]{"15555555555"}));
+ assertTrue(mZenModeFiltering.shouldIntercept(ZEN_MODE_IMPORTANT_INTERRUPTIONS, policy, r3));
+ }
+
+ @Test
public void testMatchesCallFilter_repeatCallers_directMatch() {
// after calls given an email with an exact string match, make sure that
// matchesCallFilter returns the right thing
String[] mailSource = new String[]{"mailto:hello.world"};
- mZenModeFiltering.recordCall(getRecordWithPeopleInfo(mailSource, null));
+ mZenModeFiltering.recordCall(getCallRecordWithPeopleInfo(mailSource, null));
// set up policy to only allow repeat callers
Policy policy = new Policy(
@@ -377,7 +409,7 @@ public class ZenModeFilteringTest extends UiServiceTestCase {
when(mTelephonyManager.getNetworkCountryIso()).thenReturn("us");
String[] telSource = new String[]{"tel:+1-617-555-1212"};
- mZenModeFiltering.recordCall(getRecordWithPeopleInfo(telSource, null));
+ mZenModeFiltering.recordCall(getCallRecordWithPeopleInfo(telSource, null));
// set up policy to only allow repeat callers
Policy policy = new Policy(
@@ -421,7 +453,7 @@ public class ZenModeFilteringTest extends UiServiceTestCase {
when(mTelephonyManager.getNetworkCountryIso()).thenReturn("us");
String[] telSource = new String[]{"tel:%2B16175551212"};
- mZenModeFiltering.recordCall(getRecordWithPeopleInfo(telSource, null));
+ mZenModeFiltering.recordCall(getCallRecordWithPeopleInfo(telSource, null));
// set up policy to only allow repeat callers
Policy policy = new Policy(
@@ -468,7 +500,7 @@ public class ZenModeFilteringTest extends UiServiceTestCase {
String[] contactSource = new String[]{"content://contacts/lookup/uri-here"};
ArraySet<String> contactNumbers = new ArraySet<>(
new String[]{"1-617-555-1212", "1-617-555-3434"});
- NotificationRecord record = getRecordWithPeopleInfo(contactSource, contactNumbers);
+ NotificationRecord record = getCallRecordWithPeopleInfo(contactSource, contactNumbers);
record.mergePhoneNumbers(contactNumbers);
mZenModeFiltering.recordCall(record);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
index 31be33e98363..fd1536c5c0f1 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
@@ -43,6 +43,7 @@ import static com.android.os.AtomsProto.DNDModeProto.ENABLED_FIELD_NUMBER;
import static com.android.os.AtomsProto.DNDModeProto.ID_FIELD_NUMBER;
import static com.android.os.AtomsProto.DNDModeProto.UID_FIELD_NUMBER;
import static com.android.os.AtomsProto.DNDModeProto.ZEN_MODE_FIELD_NUMBER;
+import static com.android.server.notification.ZenModeHelper.RULE_LIMIT_PER_PACKAGE;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
@@ -1611,6 +1612,35 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
+ public void testAddAutomaticZenRule_beyondSystemLimit() {
+ for (int i = 0; i < RULE_LIMIT_PER_PACKAGE; i++) {
+ ScheduleInfo si = new ScheduleInfo();
+ si.startHour = i;
+ AutomaticZenRule zenRule = new AutomaticZenRule("name" + i,
+ null,
+ new ComponentName("android", "ScheduleConditionProvider"),
+ ZenModeConfig.toScheduleConditionId(si),
+ new ZenPolicy.Builder().build(),
+ NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
+ String id = mZenModeHelperSpy.addAutomaticZenRule("android", zenRule, "test");
+ assertNotNull(id);
+ }
+ try {
+ AutomaticZenRule zenRule = new AutomaticZenRule("name",
+ null,
+ new ComponentName("android", "ScheduleConditionProvider"),
+ ZenModeConfig.toScheduleConditionId(new ScheduleInfo()),
+ new ZenPolicy.Builder().build(),
+ NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
+ String id = mZenModeHelperSpy.addAutomaticZenRule("android", zenRule, "test");
+ fail("allowed too many rules to be created");
+ } catch (IllegalArgumentException e) {
+ // yay
+ }
+
+ }
+
+ @Test
public void testAddAutomaticZenRule_CA() {
AutomaticZenRule zenRule = new AutomaticZenRule("name",
null,
diff --git a/services/tests/wmtests/src/com/android/server/policy/KeyCombinationTests.java b/services/tests/wmtests/src/com/android/server/policy/KeyCombinationTests.java
index 75479de26b1d..cf571815b4cb 100644
--- a/services/tests/wmtests/src/com/android/server/policy/KeyCombinationTests.java
+++ b/services/tests/wmtests/src/com/android/server/policy/KeyCombinationTests.java
@@ -36,6 +36,9 @@ import androidx.test.filters.SmallTest;
import org.junit.Before;
import org.junit.Test;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
/**
* Test class for {@link KeyCombinationManager}.
*
@@ -47,16 +50,18 @@ import org.junit.Test;
public class KeyCombinationTests {
private KeyCombinationManager mKeyCombinationManager;
- private boolean mAction1Triggered = false;
- private boolean mAction2Triggered = false;
- private boolean mAction3Triggered = false;
+ private final CountDownLatch mAction1Triggered = new CountDownLatch(1);
+ private final CountDownLatch mAction2Triggered = new CountDownLatch(1);
+ private final CountDownLatch mAction3Triggered = new CountDownLatch(1);
private boolean mPreCondition = true;
private static final long SCHEDULE_TIME = 300;
+ private Handler mHandler;
@Before
public void setUp() {
- mKeyCombinationManager = new KeyCombinationManager();
+ mHandler = new Handler(Looper.getMainLooper());
+ mKeyCombinationManager = new KeyCombinationManager(mHandler);
initKeyCombinationRules();
}
@@ -67,7 +72,7 @@ public class KeyCombinationTests {
KEYCODE_POWER) {
@Override
void execute() {
- mAction1Triggered = true;
+ mAction1Triggered.countDown();
}
@Override
@@ -86,12 +91,17 @@ public class KeyCombinationTests {
@Override
void execute() {
- mAction2Triggered = true;
+ mAction2Triggered.countDown();
}
@Override
void cancel() {
}
+
+ @Override
+ long getKeyInterceptDelayMs() {
+ return 0;
+ }
});
// Rule 3 : power + volume_up schedule and trigger action after timeout.
@@ -100,10 +110,9 @@ public class KeyCombinationTests {
final Runnable mAction = new Runnable() {
@Override
public void run() {
- mAction3Triggered = true;
+ mAction3Triggered.countDown();
}
};
- final Handler mHandler = new Handler(Looper.getMainLooper());
@Override
void execute() {
@@ -149,60 +158,74 @@ public class KeyCombinationTests {
}
@Test
- public void testTriggerRule() {
+ public void testTriggerRule() throws InterruptedException {
final long eventTime = SystemClock.uptimeMillis();
pressKeys(eventTime, KEYCODE_POWER, eventTime, KEYCODE_VOLUME_DOWN);
- assertTrue(mAction1Triggered);
+ assertTrue(mAction1Triggered.await(SCHEDULE_TIME, TimeUnit.MILLISECONDS));
pressKeys(eventTime, KEYCODE_VOLUME_UP, eventTime, KEYCODE_VOLUME_DOWN);
- assertTrue(mAction2Triggered);
+ assertTrue(mAction2Triggered.await(SCHEDULE_TIME, TimeUnit.MILLISECONDS));
pressKeys(eventTime, KEYCODE_POWER, eventTime, KEYCODE_VOLUME_UP, SCHEDULE_TIME + 50);
- assertTrue(mAction3Triggered);
+ assertTrue(mAction3Triggered.await(SCHEDULE_TIME, TimeUnit.MILLISECONDS));
}
/**
* Nothing should happen if there is no definition.
*/
@Test
- public void testNotTrigger_NoRule() {
+ public void testNotTrigger_NoRule() throws InterruptedException {
final long eventTime = SystemClock.uptimeMillis();
pressKeys(eventTime, KEYCODE_BACK, eventTime, KEYCODE_VOLUME_DOWN);
- assertFalse(mAction1Triggered);
- assertFalse(mAction2Triggered);
- assertFalse(mAction3Triggered);
+ assertFalse(mAction1Triggered.await(SCHEDULE_TIME, TimeUnit.MILLISECONDS));
+ assertFalse(mAction2Triggered.await(SCHEDULE_TIME, TimeUnit.MILLISECONDS));
+ assertFalse(mAction3Triggered.await(SCHEDULE_TIME, TimeUnit.MILLISECONDS));
}
/**
* Nothing should happen if the interval of press time is too long.
*/
@Test
- public void testNotTrigger_Interval() {
+ public void testNotTrigger_Interval() throws InterruptedException {
final long eventTime = SystemClock.uptimeMillis();
final long earlyEventTime = eventTime - 200; // COMBINE_KEY_DELAY_MILLIS = 150;
pressKeys(earlyEventTime, KEYCODE_POWER, eventTime, KEYCODE_VOLUME_DOWN);
- assertFalse(mAction1Triggered);
+ assertFalse(mAction1Triggered.await(SCHEDULE_TIME, TimeUnit.MILLISECONDS));
}
/**
* Nothing should happen if the condition is false.
*/
@Test
- public void testNotTrigger_Condition() {
+ public void testNotTrigger_Condition() throws InterruptedException {
final long eventTime = SystemClock.uptimeMillis();
// we won't trigger action 2 because the condition is false.
mPreCondition = false;
pressKeys(eventTime, KEYCODE_VOLUME_UP, eventTime, KEYCODE_VOLUME_DOWN);
- assertFalse(mAction2Triggered);
+ assertFalse(mAction2Triggered.await(SCHEDULE_TIME, TimeUnit.MILLISECONDS));
}
/**
* Nothing should happen if the keys released too early.
*/
@Test
- public void testNotTrigger_EarlyRelease() {
+ public void testNotTrigger_EarlyRelease() throws InterruptedException {
final long eventTime = SystemClock.uptimeMillis();
pressKeys(eventTime, KEYCODE_POWER, eventTime, KEYCODE_VOLUME_UP);
- assertFalse(mAction3Triggered);
+ assertFalse(mAction3Triggered.await(SCHEDULE_TIME, TimeUnit.MILLISECONDS));
+ }
+
+ /**
+ * The KeyInterceptTimeout should return the max timeout value.
+ */
+ @Test
+ public void testKeyInterceptTimeout() {
+ final long eventTime = SystemClock.uptimeMillis();
+ final KeyEvent firstKeyDown = new KeyEvent(eventTime, eventTime, ACTION_DOWN,
+ KEYCODE_VOLUME_UP, 0 /* repeat */, 0 /* metaState */);
+ // Press KEYCODE_VOLUME_UP would activate rule2 and rule3,
+ // and rule2's intercept delay is 0.
+ mKeyCombinationManager.interceptKey(firstKeyDown, true);
+ assertTrue(mKeyCombinationManager.getKeyInterceptTimeout(KEYCODE_VOLUME_UP) > eventTime);
}
-}
+} \ No newline at end of file
diff --git a/services/tests/wmtests/src/com/android/server/policy/OWNERS b/services/tests/wmtests/src/com/android/server/policy/OWNERS
new file mode 100644
index 000000000000..27891dcf64da
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/policy/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/policy/OWNERS
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
index d4d8b86850c6..7689e08bc3f3 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
@@ -256,6 +256,14 @@ public class ActivityMetricsLaunchObserverTests extends WindowTestsBase {
mActivityMetricsLogger.notifyVisibilityChanged(noDrawnActivity);
verifyAsync(mLaunchObserver).onActivityLaunchCancelled(eqProto(noDrawnActivity));
+
+ // If an activity is removed immediately before visibility update, it should cancel too.
+ final ActivityRecord removedImm = new ActivityBuilder(mAtm).setCreateTask(true).build();
+ clearInvocations(mLaunchObserver);
+ onActivityLaunched(removedImm);
+ removedImm.removeImmediately();
+ // Verify any() instead of proto because the field of record may be changed.
+ verifyAsync(mLaunchObserver).onActivityLaunchCancelled(any());
}
@Test
@@ -299,15 +307,16 @@ public class ActivityMetricsLaunchObserverTests extends WindowTestsBase {
@Test
public void testOnReportFullyDrawn() {
// Create an invisible event that should be cancelled after the next event starts.
- onActivityLaunched(mTrampolineActivity);
- mTrampolineActivity.mVisibleRequested = false;
+ final ActivityRecord prev = new ActivityBuilder(mAtm).setCreateTask(true).build();
+ onActivityLaunched(prev);
+ prev.mVisibleRequested = false;
mActivityOptions = ActivityOptions.makeBasic();
mActivityOptions.setSourceInfo(SourceInfo.TYPE_LAUNCHER, SystemClock.uptimeMillis() - 10);
onIntentStarted(mTopActivity.intent);
notifyActivityLaunched(START_SUCCESS, mTopActivity);
verifyAsync(mLaunchObserver).onActivityLaunched(eqProto(mTopActivity), anyInt());
- verifyAsync(mLaunchObserver).onActivityLaunchCancelled(eqProto(mTrampolineActivity));
+ verifyAsync(mLaunchObserver).onActivityLaunchCancelled(eqProto(prev));
// The activity reports fully drawn before windows drawn, then the fully drawn event will
// be pending (see {@link WindowingModeTransitionInfo#pendingFullyDrawn}).
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index a89c5a1fbf1f..f9d4dffd4643 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -16,6 +16,8 @@
package com.android.server.wm;
+import static android.app.AppOpsManager.MODE_ALLOWED;
+import static android.app.AppOpsManager.OP_PICTURE_IN_PICTURE;
import static android.app.TaskInfo.CAMERA_COMPAT_CONTROL_DISMISSED;
import static android.app.TaskInfo.CAMERA_COMPAT_CONTROL_HIDDEN;
import static android.app.TaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED;
@@ -110,6 +112,7 @@ import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.never;
import android.app.ActivityOptions;
+import android.app.AppOpsManager;
import android.app.ICompatCameraControlCallback;
import android.app.PictureInPictureParams;
import android.app.servertransaction.ActivityConfigurationChangeItem;
@@ -2204,6 +2207,28 @@ public class ActivityRecordTests extends WindowTestsBase {
}
@Test
+ public void testCheckEnterPictureInPictureState_displayNotSupportedPip() {
+ final Task task = new TaskBuilder(mSupervisor)
+ .setDisplay(mDisplayContent).build();
+ final ActivityRecord activity = new ActivityBuilder(mAtm)
+ .setTask(task)
+ .setResizeMode(ActivityInfo.RESIZE_MODE_UNRESIZEABLE)
+ .setActivityFlags(FLAG_SUPPORTS_PICTURE_IN_PICTURE)
+ .build();
+ mAtm.mSupportsPictureInPicture = true;
+ AppOpsManager appOpsManager = mAtm.getAppOpsManager();
+ doReturn(MODE_ALLOWED).when(appOpsManager).checkOpNoThrow(eq(OP_PICTURE_IN_PICTURE),
+ anyInt(), any());
+ doReturn(false).when(mAtm).shouldDisableNonVrUiLocked();
+
+ spyOn(mDisplayContent.mDwpcHelper);
+ doReturn(false).when(mDisplayContent.mDwpcHelper).isWindowingModeSupported(
+ WINDOWING_MODE_PINNED);
+
+ assertFalse(activity.checkEnterPictureInPictureState("TEST", false /* beforeStopping */));
+ }
+
+ @Test
public void testLaunchIntoPip() {
final PictureInPictureParams params = new PictureInPictureParams.Builder()
.build();
@@ -2217,6 +2242,19 @@ public class ActivityRecordTests extends WindowTestsBase {
assertTrue(activity.pictureInPictureArgs.isLaunchIntoPip());
}
+ @Test
+ public void testTransferLaunchCookieWhenFinishing() {
+ final ActivityRecord activity1 = createActivityWithTask();
+ final Binder launchCookie = new Binder();
+ activity1.mLaunchCookie = launchCookie;
+ final ActivityRecord activity2 = createActivityRecord(activity1.getTask());
+ activity1.setState(PAUSED, "test");
+ activity1.makeFinishingLocked();
+
+ assertEquals(launchCookie, activity2.mLaunchCookie);
+ assertNull(activity1.mLaunchCookie);
+ }
+
private void verifyProcessInfoUpdate(ActivityRecord activity, State state,
boolean shouldUpdate, boolean activityChange) {
reset(activity.app);
@@ -3073,11 +3111,11 @@ public class ActivityRecordTests extends WindowTestsBase {
// Simulate app re-start input or turning screen off/on then unlocked by un-secure
// keyguard to back to the app, expect IME insets is not frozen
+ mDisplayContent.updateImeInputAndControlTarget(app);
+ assertFalse(app.mActivityRecord.mImeInsetsFrozenUntilStartInput);
imeSource.setFrame(new Rect(100, 400, 500, 500));
app.getInsetsState().addSource(imeSource);
app.getInsetsState().setSourceVisible(ITYPE_IME, true);
- mDisplayContent.updateImeInputAndControlTarget(app);
- assertFalse(app.mActivityRecord.mImeInsetsFrozenUntilStartInput);
// Verify when IME is visible and the app can receive the right IME insets from policy.
makeWindowVisibleAndDrawn(app, mImeWindow);
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 0c8394e75fbc..24ff3f96100a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java
@@ -41,9 +41,11 @@ import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
+import android.content.pm.IPackageManager;
import android.content.pm.PackageManagerInternal;
import android.content.pm.SuspendDialogInfo;
import android.content.pm.UserInfo;
+import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
import android.platform.test.annotations.Presubmit;
@@ -58,8 +60,6 @@ import com.android.internal.app.SuspendedAppActivity;
import com.android.internal.app.UnlaunchableAppActivity;
import com.android.server.LocalServices;
import com.android.server.am.ActivityManagerService;
-import com.android.server.pm.PackageManagerService;
-import com.android.server.wm.ActivityInterceptorCallback.ActivityInterceptResult;
import org.junit.After;
import org.junit.Before;
@@ -113,7 +113,7 @@ public class ActivityStartInterceptorTest {
@Mock
private KeyguardManager mKeyguardManager;
@Mock
- private PackageManagerService mPackageManager;
+ private IPackageManager mPackageManager;
@Mock
private ActivityManagerInternal mAmInternal;
@Mock
@@ -126,7 +126,7 @@ public class ActivityStartInterceptorTest {
new SparseArray<>();
@Before
- public void setUp() {
+ public void setUp() throws RemoteException {
MockitoAnnotations.initMocks(this);
mService.mAmInternal = mAmInternal;
mInterceptor = new ActivityStartInterceptor(
@@ -279,7 +279,7 @@ public class ActivityStartInterceptorTest {
}
@Test
- public void testHarmfulAppWarning() {
+ public void testHarmfulAppWarning() throws RemoteException {
// GIVEN the package we're about to launch has a harmful app warning set
when(mPackageManager.getHarmfulAppWarning(TEST_PACKAGE_NAME, TEST_USER_ID))
.thenReturn("This app is bad");
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index 6fe2d337e4a0..9902e83c3648 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -308,12 +308,12 @@ public class ActivityStarterTests extends WindowTestsBase {
}
private ActivityStarter prepareStarter(@Intent.Flags int launchFlags) {
- return prepareStarter(launchFlags, true /* mockGetLaunchStack */, LAUNCH_MULTIPLE);
+ return prepareStarter(launchFlags, true /* mockGetRootTask */, LAUNCH_MULTIPLE);
}
private ActivityStarter prepareStarter(@Intent.Flags int launchFlags,
- boolean mockGetLaunchStack) {
- return prepareStarter(launchFlags, mockGetLaunchStack, LAUNCH_MULTIPLE);
+ boolean mockGetRootTask) {
+ return prepareStarter(launchFlags, mockGetRootTask, LAUNCH_MULTIPLE);
}
private void setupImeWindow() {
@@ -326,20 +326,20 @@ public class ActivityStarterTests extends WindowTestsBase {
* Creates a {@link ActivityStarter} with default parameters and necessary mocks.
*
* @param launchFlags The intent flags to launch activity.
- * @param mockGetLaunchStack Whether to mock {@link RootWindowContainer#getLaunchRootTask} for
+ * @param mockGetRootTask Whether to mock {@link RootWindowContainer#getOrCreateRootTask} for
* always launching to the testing stack. Set to false when allowing
* the activity can be launched to any stack that is decided by real
* implementation.
* @return A {@link ActivityStarter} with default setup.
*/
private ActivityStarter prepareStarter(@Intent.Flags int launchFlags,
- boolean mockGetLaunchStack, int launchMode) {
+ boolean mockGetRootTask, int launchMode) {
// always allow test to start activity.
doReturn(true).when(mSupervisor).checkStartAnyActivityPermission(
any(), any(), any(), anyInt(), anyInt(), anyInt(), any(), any(),
anyBoolean(), anyBoolean(), any(), any(), any());
- if (mockGetLaunchStack) {
+ if (mockGetRootTask) {
// Instrument the stack and task used.
final Task stack = mRootWindowContainer.getDefaultTaskDisplayArea()
.createRootTask(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
@@ -347,9 +347,9 @@ public class ActivityStarterTests extends WindowTestsBase {
// Direct starter to use spy stack.
doReturn(stack).when(mRootWindowContainer)
- .getLaunchRootTask(any(), any(), any(), anyBoolean());
- doReturn(stack).when(mRootWindowContainer).getLaunchRootTask(any(), any(), any(), any(),
- anyBoolean(), any(), anyInt());
+ .getOrCreateRootTask(any(), any(), any(), anyBoolean());
+ doReturn(stack).when(mRootWindowContainer).getOrCreateRootTask(any(), any(), any(),
+ any(), anyBoolean(), any(), anyInt());
}
// Set up mock package manager internal and make sure no unmocked methods are called
@@ -434,7 +434,7 @@ public class ActivityStarterTests extends WindowTestsBase {
public void testSplitScreenDeliverToTop() {
final ActivityStarter starter = prepareStarter(
FLAG_ACTIVITY_RESET_TASK_IF_NEEDED | FLAG_ACTIVITY_SINGLE_TOP,
- false /* mockGetLaunchStack */);
+ false /* mockGetRootTask */);
final Pair<ActivityRecord, ActivityRecord> activities = createActivitiesInSplit();
final ActivityRecord splitPrimaryFocusActivity = activities.first;
final ActivityRecord splitSecondReusableActivity = activities.second;
@@ -500,6 +500,23 @@ public class ActivityStarterTests extends WindowTestsBase {
return Pair.create(splitPrimaryActivity, splitSecondActivity);
}
+ @Test
+ public void testMoveVisibleTaskToFront() {
+ final ActivityRecord activity = new TaskBuilder(mSupervisor)
+ .setCreateActivity(true).build().getTopMostActivity();
+ final ActivityRecord translucentActivity = new TaskBuilder(mSupervisor)
+ .setCreateActivity(true).build().getTopMostActivity();
+ assertTrue(activity.mVisibleRequested);
+
+ final ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK,
+ false /* mockGetRootTask */);
+ starter.getIntent().setComponent(activity.mActivityComponent);
+ final int result = starter.setReason("testMoveVisibleTaskToFront").execute();
+
+ assertEquals(START_TASK_TO_FRONT, result);
+ assertEquals(1, activity.compareTo(translucentActivity));
+ }
+
/**
* Tests activity is cleaned up properly in a task mode violation.
*/
@@ -790,7 +807,7 @@ public class ActivityStarterTests extends WindowTestsBase {
finishingTopActivity.finishing = true;
// Launch the bottom task of the target root task.
- prepareStarter(FLAG_ACTIVITY_NEW_TASK, false /* mockGetLaunchStack */)
+ prepareStarter(FLAG_ACTIVITY_NEW_TASK, false /* mockGetRootTask */)
.setReason("testBringTaskToFrontWhenFocusedTaskIsFinishing")
.setIntent(activity.intent.addFlags(
FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))
@@ -809,7 +826,7 @@ public class ActivityStarterTests extends WindowTestsBase {
@Test
public void testDeliverIntentToTopActivityOfNonTopDisplay() {
final ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK,
- false /* mockGetLaunchStack */);
+ false /* mockGetRootTask */);
// Create a secondary display at bottom.
final TestDisplayContent secondaryDisplay =
@@ -849,7 +866,7 @@ public class ActivityStarterTests extends WindowTestsBase {
@Test
public void testBringTaskToFrontOnSecondaryDisplay() {
final ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK,
- false /* mockGetLaunchStack */);
+ false /* mockGetRootTask */);
// Create a secondary display with an activity.
final TestDisplayContent secondaryDisplay =
@@ -943,7 +960,7 @@ public class ActivityStarterTests extends WindowTestsBase {
@Test
public void testReparentTopFocusedActivityToSecondaryDisplay() {
final ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK,
- false /* mockGetLaunchStack */);
+ false /* mockGetRootTask */);
// Create a secondary display at bottom.
final TestDisplayContent secondaryDisplay = addNewDisplayContentAt(POSITION_BOTTOM);
@@ -1076,7 +1093,7 @@ public class ActivityStarterTests extends WindowTestsBase {
@Test
public void testTargetStackInSplitScreen() {
final ActivityStarter starter =
- prepareStarter(FLAG_ACTIVITY_LAUNCH_ADJACENT, false /* mockGetLaunchStack */);
+ prepareStarter(FLAG_ACTIVITY_LAUNCH_ADJACENT, false /* mockGetRootTask */);
final ActivityRecord top = new ActivityBuilder(mAtm).setCreateTask(true).build();
final ActivityOptions options = ActivityOptions.makeBasic();
final ActivityRecord[] outActivity = new ActivityRecord[1];
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
index 8ada97147dd3..a8571906bb06 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
@@ -355,7 +355,8 @@ public class ActivityTaskManagerServiceTests extends WindowTestsBase {
@Test
public void testUpdateSleep() {
doCallRealMethod().when(mWm.mRoot).hasAwakeDisplay();
- mSupervisor.mGoingToSleepWakeLock = mock(PowerManager.WakeLock.class);
+ mSupervisor.mGoingToSleepWakeLock =
+ mSystemServicesTestRule.createStubbedWakeLock(true /* needVerification */);
final Task rootHomeTask = mWm.mRoot.getDefaultTaskDisplayArea().getOrCreateRootHomeTask();
final ActivityRecord homeActivity = new ActivityBuilder(mAtm).setTask(rootHomeTask).build();
final ActivityRecord topActivity = new ActivityBuilder(mAtm).setCreateTask(true).build();
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
index 2ea7fdaf6348..eb6395b46120 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
@@ -36,6 +36,7 @@ import static android.view.WindowManager.TRANSIT_OPEN;
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
@@ -422,6 +423,7 @@ public class AppTransitionTests extends WindowTestsBase {
public void testActivityRecordReparentToTaskFragment() {
final ActivityRecord activity = createActivityRecord(mDc);
final SurfaceControl activityLeash = mock(SurfaceControl.class);
+ doNothing().when(activity).setDropInputMode(anyInt());
activity.setVisibility(true);
activity.setSurfaceControl(activityLeash);
final Task task = activity.getTask();
diff --git a/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
index c21a5b6ff7ea..92550a3107d5 100644
--- a/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
@@ -30,7 +30,10 @@ import static org.mockito.Mockito.when;
import android.annotation.NonNull;
import android.hardware.HardwareBuffer;
import android.platform.test.annotations.Presubmit;
+import android.window.BackEvent;
import android.window.BackNavigationInfo;
+import android.window.IOnBackInvokedCallback;
+import android.window.OnBackInvokedDispatcher;
import android.window.TaskSnapshot;
import org.junit.Before;
@@ -42,15 +45,19 @@ import org.junit.runner.RunWith;
public class BackNavigationControllerTests extends WindowTestsBase {
private BackNavigationController mBackNavigationController;
+ private IOnBackInvokedCallback mOnBackInvokedCallback;
@Before
public void setUp() throws Exception {
mBackNavigationController = new BackNavigationController();
+ mOnBackInvokedCallback = createBackCallback();
}
@Test
public void backTypeHomeWhenBackToLauncher() {
Task task = createTopTaskWithActivity();
+ registerSystemOnBackInvokedCallback();
+
BackNavigationInfo backNavigationInfo =
mBackNavigationController.startBackNavigation(task, new StubTransaction());
assertThat(backNavigationInfo).isNotNull();
@@ -63,6 +70,8 @@ public class BackNavigationControllerTests extends WindowTestsBase {
Task taskA = createTask(mDefaultDisplay);
createActivityRecord(taskA);
Task task = createTopTaskWithActivity();
+ registerSystemOnBackInvokedCallback();
+
BackNavigationInfo backNavigationInfo =
mBackNavigationController.startBackNavigation(task, new StubTransaction());
assertThat(backNavigationInfo).isNotNull();
@@ -75,6 +84,8 @@ public class BackNavigationControllerTests extends WindowTestsBase {
Task task = createTopTaskWithActivity();
mAtm.setFocusedTask(task.mTaskId,
createAppWindow(task, FIRST_APPLICATION_WINDOW, "window").mActivityRecord);
+ registerSystemOnBackInvokedCallback();
+
BackNavigationInfo backNavigationInfo =
mBackNavigationController.startBackNavigation(task, new StubTransaction());
assertThat(backNavigationInfo).isNotNull();
@@ -89,6 +100,7 @@ public class BackNavigationControllerTests extends WindowTestsBase {
public void backNavInfoFullyPopulated() {
Task task = createTopTaskWithActivity();
createAppWindow(task, FIRST_APPLICATION_WINDOW, "window");
+ registerSystemOnBackInvokedCallback();
// We need a mock screenshot so
TaskSnapshotController taskSnapshotController = createMockTaskSnapshotController();
@@ -104,6 +116,30 @@ public class BackNavigationControllerTests extends WindowTestsBase {
assertThat(backNavigationInfo.getTaskWindowConfiguration()).isNotNull();
}
+ @Test
+ public void preparesForBackToHome() {
+ Task task = createTopTaskWithActivity();
+ ActivityRecord activity = task.getTopActivity(false, false);
+ registerSystemOnBackInvokedCallback();
+
+ BackNavigationInfo backNavigationInfo =
+ mBackNavigationController.startBackNavigation(task, new StubTransaction());
+ assertThat(typeToString(backNavigationInfo.getType()))
+ .isEqualTo(typeToString(BackNavigationInfo.TYPE_RETURN_TO_HOME));
+ }
+
+ @Test
+ public void backTypeCallback() {
+ Task task = createTopTaskWithActivity();
+ ActivityRecord activity = task.getTopActivity(false, false);
+ registerApplicationOnBackInvokedCallback();
+
+ BackNavigationInfo backNavigationInfo =
+ mBackNavigationController.startBackNavigation(task, new StubTransaction());
+ assertThat(typeToString(backNavigationInfo.getType()))
+ .isEqualTo(typeToString(BackNavigationInfo.TYPE_CALLBACK));
+ }
+
@NonNull
private TaskSnapshotController createMockTaskSnapshotController() {
TaskSnapshotController taskSnapshotController = mock(TaskSnapshotController.class);
@@ -126,4 +162,30 @@ public class BackNavigationControllerTests extends WindowTestsBase {
mAtm.setFocusedTask(task.mTaskId, record);
return task;
}
+
+ private void registerSystemOnBackInvokedCallback() {
+ mWm.getFocusedWindowLocked().setOnBackInvokedCallback(
+ mOnBackInvokedCallback, OnBackInvokedDispatcher.PRIORITY_SYSTEM);
+ }
+
+ private void registerApplicationOnBackInvokedCallback() {
+ mWm.getFocusedWindowLocked().setOnBackInvokedCallback(
+ mOnBackInvokedCallback, OnBackInvokedDispatcher.PRIORITY_DEFAULT);
+ }
+
+ private IOnBackInvokedCallback createBackCallback() {
+ return new IOnBackInvokedCallback.Stub() {
+ @Override
+ public void onBackStarted() { }
+
+ @Override
+ public void onBackProgressed(BackEvent backEvent) { }
+
+ @Override
+ public void onBackCancelled() { }
+
+ @Override
+ public void onBackInvoked() { }
+ };
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java b/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java
index 50eefa066a45..c5117bb83976 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java
@@ -19,12 +19,12 @@ package com.android.server.wm;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR;
-import static android.view.ContentRecordingSession.RECORD_CONTENT_TASK;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+import static com.android.server.wm.ContentRecorder.KEY_RECORD_TASK_FEATURE;
import static com.google.common.truth.Truth.assertThat;
@@ -40,17 +40,22 @@ import android.hardware.display.VirtualDisplay;
import android.os.Binder;
import android.os.IBinder;
import android.platform.test.annotations.Presubmit;
+import android.provider.DeviceConfig;
import android.util.DisplayMetrics;
import android.view.ContentRecordingSession;
import android.view.Surface;
import android.view.SurfaceControl;
+import androidx.annotation.NonNull;
import androidx.test.filters.SmallTest;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.concurrent.CountDownLatch;
+
/**
* Tests for the {@link ContentRecorder} class.
*
@@ -62,17 +67,18 @@ import org.junit.runner.RunWith;
@RunWith(WindowTestRunner.class)
public class ContentRecorderTests extends WindowTestsBase {
private static final IBinder TEST_TOKEN = new RecordingTestToken();
- private final ContentRecordingSession mDefaultSession =
+ private static IBinder sTaskWindowContainerToken;
+ private final ContentRecordingSession mDisplaySession =
ContentRecordingSession.createDisplaySession(TEST_TOKEN);
+ private ContentRecordingSession mTaskSession;
private static Point sSurfaceSize;
private ContentRecorder mContentRecorder;
private SurfaceControl mRecordedSurface;
+ // Handle feature flag.
+ private ConfigListener mConfigListener;
+ private CountDownLatch mLatch;
@Before public void setUp() {
- // GIVEN MediaProjection has already initialized the WindowToken of the DisplayArea to
- // mirror.
- setUpDefaultTaskDisplayAreaWindowToken();
-
// GIVEN SurfaceControl can successfully mirror the provided surface.
sSurfaceSize = new Point(
mDefaultDisplay.getDefaultTaskDisplayArea().getBounds().width(),
@@ -84,12 +90,32 @@ public class ContentRecorderTests extends WindowTestsBase {
sSurfaceSize.x, sSurfaceSize.y,
DisplayMetrics.DENSITY_140, new Surface(), VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR);
final int displayId = virtualDisplay.getDisplay().getDisplayId();
- mDefaultSession.setDisplayId(displayId);
-
mWm.mRoot.onDisplayAdded(displayId);
- final DisplayContent mVirtualDisplayContent = mWm.mRoot.getDisplayContent(displayId);
- mContentRecorder = new ContentRecorder(mVirtualDisplayContent);
- spyOn(mVirtualDisplayContent);
+ final DisplayContent virtualDisplayContent = mWm.mRoot.getDisplayContent(displayId);
+ mContentRecorder = new ContentRecorder(virtualDisplayContent);
+ spyOn(virtualDisplayContent);
+
+ // GIVEN MediaProjection has already initialized the WindowToken of the DisplayArea to
+ // record.
+ setUpDefaultTaskDisplayAreaWindowToken();
+ mDisplaySession.setDisplayId(displayId);
+
+ // GIVEN there is a window token associated with a task to record.
+ sTaskWindowContainerToken = setUpTaskWindowContainerToken(virtualDisplayContent);
+ mTaskSession = ContentRecordingSession.createTaskSession(sTaskWindowContainerToken);
+ mTaskSession.setDisplayId(displayId);
+
+ mConfigListener = new ConfigListener();
+ DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_WINDOW_MANAGER,
+ mContext.getMainExecutor(), mConfigListener);
+ mLatch = new CountDownLatch(1);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_WINDOW_MANAGER, KEY_RECORD_TASK_FEATURE,
+ "true", true);
+ }
+
+ @After
+ public void teardown() {
+ DeviceConfig.removeOnPropertiesChangedListener(mConfigListener);
}
@Test
@@ -102,37 +128,79 @@ public class ContentRecorderTests extends WindowTestsBase {
@Test
public void testUpdateRecording_display() {
- mContentRecorder.setContentRecordingSession(mDefaultSession);
+ mContentRecorder.setContentRecordingSession(mDisplaySession);
mContentRecorder.updateRecording();
assertThat(mContentRecorder.isCurrentlyRecording()).isTrue();
}
@Test
- public void testUpdateRecording_task() {
- mDefaultSession.setContentToRecord(RECORD_CONTENT_TASK);
- mContentRecorder.setContentRecordingSession(mDefaultSession);
+ public void testUpdateRecording_display_nullToken() {
+ ContentRecordingSession session = ContentRecordingSession.createDisplaySession(TEST_TOKEN);
+ session.setDisplayId(mDisplaySession.getDisplayId());
+ session.setTokenToRecord(null);
+ mContentRecorder.setContentRecordingSession(session);
mContentRecorder.updateRecording();
assertThat(mContentRecorder.isCurrentlyRecording()).isFalse();
}
@Test
- public void testUpdateRecording_wasPaused() {
- mContentRecorder.setContentRecordingSession(mDefaultSession);
+ public void testUpdateRecording_display_noWindowContainer() {
+ doReturn(null).when(
+ mWm.mWindowContextListenerController).getContainer(any());
+ mContentRecorder.setContentRecordingSession(mDisplaySession);
mContentRecorder.updateRecording();
+ assertThat(mContentRecorder.isCurrentlyRecording()).isFalse();
+ }
- mContentRecorder.pauseRecording();
+ @Test
+ public void testUpdateRecording_task_featureDisabled() {
+ mLatch = new CountDownLatch(1);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_WINDOW_MANAGER, KEY_RECORD_TASK_FEATURE,
+ "false", false);
+ mContentRecorder.setContentRecordingSession(mTaskSession);
+ mContentRecorder.updateRecording();
+ assertThat(mContentRecorder.isCurrentlyRecording()).isFalse();
+ }
+
+ @Test
+ public void testUpdateRecording_task_featureEnabled() {
+ // Feature already enabled; don't need to again.
+ mContentRecorder.setContentRecordingSession(mTaskSession);
mContentRecorder.updateRecording();
assertThat(mContentRecorder.isCurrentlyRecording()).isTrue();
}
@Test
- public void testUpdateRecording_wasStopped() {
- mContentRecorder.setContentRecordingSession(mDefaultSession);
+ public void testUpdateRecording_task_nullToken() {
+ ContentRecordingSession session = ContentRecordingSession.createTaskSession(
+ sTaskWindowContainerToken);
+ session.setDisplayId(mDisplaySession.getDisplayId());
+ session.setTokenToRecord(null);
+ mContentRecorder.setContentRecordingSession(session);
mContentRecorder.updateRecording();
+ assertThat(mContentRecorder.isCurrentlyRecording()).isFalse();
+ // TODO(b/219761722) validate VirtualDisplay is torn down when can't set up task recording.
+ }
- mContentRecorder.remove();
+ @Test
+ public void testUpdateRecording_task_noWindowContainer() {
+ // Use the window container token of the DisplayContent, rather than task.
+ ContentRecordingSession invalidTaskSession = ContentRecordingSession.createTaskSession(
+ new WindowContainer.RemoteToken(mDisplayContent));
+ mContentRecorder.setContentRecordingSession(invalidTaskSession);
mContentRecorder.updateRecording();
assertThat(mContentRecorder.isCurrentlyRecording()).isFalse();
+ // TODO(b/219761722) validate VirtualDisplay is torn down when can't set up task recording.
+ }
+
+ @Test
+ public void testUpdateRecording_wasPaused() {
+ mContentRecorder.setContentRecordingSession(mDisplaySession);
+ mContentRecorder.updateRecording();
+
+ mContentRecorder.pauseRecording();
+ mContentRecorder.updateRecording();
+ assertThat(mContentRecorder.isCurrentlyRecording()).isTrue();
}
@Test
@@ -146,7 +214,7 @@ public class ContentRecorderTests extends WindowTestsBase {
@Test
public void testOnConfigurationChanged_resizesSurface() {
- mContentRecorder.setContentRecordingSession(mDefaultSession);
+ mContentRecorder.setContentRecordingSession(mDisplaySession);
mContentRecorder.updateRecording();
mContentRecorder.onConfigurationChanged(ORIENTATION_PORTRAIT);
@@ -158,7 +226,7 @@ public class ContentRecorderTests extends WindowTestsBase {
@Test
public void testPauseRecording_pausesRecording() {
- mContentRecorder.setContentRecordingSession(mDefaultSession);
+ mContentRecorder.setContentRecordingSession(mDisplaySession);
mContentRecorder.updateRecording();
mContentRecorder.pauseRecording();
@@ -173,7 +241,7 @@ public class ContentRecorderTests extends WindowTestsBase {
@Test
public void testRemove_stopsRecording() {
- mContentRecorder.setContentRecordingSession(mDefaultSession);
+ mContentRecorder.setContentRecordingSession(mDisplaySession);
mContentRecorder.updateRecording();
mContentRecorder.remove();
@@ -188,8 +256,9 @@ public class ContentRecorderTests extends WindowTestsBase {
@Test
public void testUpdateMirroredSurface_capturedAreaResized() {
- mContentRecorder.setContentRecordingSession(mDefaultSession);
+ mContentRecorder.setContentRecordingSession(mDisplaySession);
mContentRecorder.updateRecording();
+ assertThat(mContentRecorder.isCurrentlyRecording()).isTrue();
// WHEN attempting to mirror on the virtual display, and the captured content is resized.
float xScale = 0.7f;
@@ -197,13 +266,14 @@ public class ContentRecorderTests extends WindowTestsBase {
Rect displayAreaBounds = new Rect(0, 0, Math.round(sSurfaceSize.x * xScale),
Math.round(sSurfaceSize.y * yScale));
mContentRecorder.updateMirroredSurface(mTransaction, displayAreaBounds, sSurfaceSize);
+ assertThat(mContentRecorder.isCurrentlyRecording()).isTrue();
// THEN content in the captured DisplayArea is scaled to fit the surface size.
verify(mTransaction, atLeastOnce()).setMatrix(mRecordedSurface, 1.0f / yScale, 0, 0,
1.0f / yScale);
// THEN captured content is positioned in the centre of the output surface.
- float scaledWidth = displayAreaBounds.width() / xScale;
- float xInset = (sSurfaceSize.x - scaledWidth) / 2;
+ int scaledWidth = Math.round((float) displayAreaBounds.width() / xScale);
+ int xInset = (sSurfaceSize.x - scaledWidth) / 2;
verify(mTransaction, atLeastOnce()).setPosition(mRecordedSurface, xInset, 0);
}
@@ -222,6 +292,18 @@ public class ContentRecorderTests extends WindowTestsBase {
}
/**
+ * Creates a {@link android.window.WindowContainerToken} associated with a task, in order for
+ * that task to be recorded.
+ */
+ private IBinder setUpTaskWindowContainerToken(DisplayContent displayContent) {
+ final Task rootTask = createTask(displayContent);
+ final Task task = createTaskInRootTask(rootTask, 0 /* userId */);
+ // Ensure the task is not empty.
+ createActivityRecord(displayContent, task);
+ return task.getTaskInfo().token.asBinder();
+ }
+
+ /**
* SurfaceControl successfully creates a mirrored surface of the given size.
*/
private SurfaceControl surfaceControlMirrors(Point surfaceSize) {
@@ -236,4 +318,13 @@ public class ContentRecorderTests extends WindowTestsBase {
anyInt());
return mirroredSurface;
}
+
+ private class ConfigListener implements DeviceConfig.OnPropertiesChangedListener {
+ @Override
+ public void onPropertiesChanged(@NonNull DeviceConfig.Properties properties) {
+ if (mLatch != null && properties.getKeyset().contains(KEY_RECORD_TASK_FEATURE)) {
+ mLatch.countDown();
+ }
+ }
+ }
}
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 12f987dfcd8d..40b460157bc2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -77,7 +77,6 @@ import static com.android.server.wm.ActivityTaskSupervisor.ON_TOP;
import static com.android.server.wm.DisplayContent.IME_TARGET_LAYERING;
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION;
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_FIXED_TRANSFORM;
-import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS;
import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
import static com.android.server.wm.WindowContainer.POSITION_TOP;
@@ -108,6 +107,7 @@ import android.graphics.Insets;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.Region;
+import android.hardware.HardwareBuffer;
import android.hardware.display.VirtualDisplay;
import android.metrics.LogMaker;
import android.os.Binder;
@@ -1102,6 +1102,21 @@ public class DisplayContentTests extends WindowTestsBase {
assertEquals(dc.getImeContainer().getParentSurfaceControl(), dc.computeImeParent());
}
+ @UseTestDisplay(addWindows = W_ACTIVITY)
+ @Test
+ public void testComputeImeParent_inputTargetNotUpdate() throws Exception {
+ WindowState app1 = createWindow(null, TYPE_BASE_APPLICATION, "app1");
+ WindowState app2 = createWindow(null, TYPE_BASE_APPLICATION, "app2");
+ doReturn(true).when(mDisplayContent).shouldImeAttachedToApp();
+ mDisplayContent.setImeLayeringTarget(app1);
+ mDisplayContent.setImeInputTarget(app1);
+ assertEquals(app1.mActivityRecord.getSurfaceControl(), mDisplayContent.computeImeParent());
+ mDisplayContent.setImeLayeringTarget(app2);
+ // Expect null means no change IME parent when the IME layering target not yet
+ // request IME to be the input target.
+ assertNull(mDisplayContent.computeImeParent());
+ }
+
@Test
public void testInputMethodInputTarget_isClearedWhenWindowStateIsRemoved() throws Exception {
final DisplayContent dc = createNewDisplay();
@@ -1370,7 +1385,9 @@ public class DisplayContentTests extends WindowTestsBase {
ROTATION_0 /* oldRotation */, ROTATION_90 /* newRotation */,
false /* forceUpdate */));
- assertNotNull(mDisplayContent.getAsyncRotationController());
+ final AsyncRotationController asyncRotationController =
+ mDisplayContent.getAsyncRotationController();
+ assertNotNull(asyncRotationController);
assertTrue(mStatusBarWindow.isAnimating(PARENTS, ANIMATION_TYPE_FIXED_TRANSFORM));
assertTrue(mNavBarWindow.isAnimating(PARENTS, ANIMATION_TYPE_FIXED_TRANSFORM));
// Notification shade may have its own view animation in real case so do not fade out it.
@@ -1443,6 +1460,7 @@ public class DisplayContentTests extends WindowTestsBase {
mDisplayContent.setImeLayeringTarget(mAppWindow);
LocalServices.getService(WindowManagerInternal.class).onToggleImeRequested(true /* show */,
app.token, app.token, mDisplayContent.mDisplayId);
+ assertTrue(asyncRotationController.isTargetToken(mImeWindow.mToken));
assertTrue(mImeWindow.mToken.hasFixedRotationTransform());
assertTrue(mImeWindow.isAnimating(PARENTS, ANIMATION_TYPE_FIXED_TRANSFORM));
@@ -1936,12 +1954,10 @@ public class DisplayContentTests extends WindowTestsBase {
// Preparation: Simulate snapshot IME surface.
spyOn(mWm.mTaskSnapshotController);
- doReturn(mock(SurfaceControl.ScreenshotHardwareBuffer.class)).when(
- mWm.mTaskSnapshotController).snapshotImeFromAttachedTask(any());
- final SurfaceControl imeSurface = mock(SurfaceControl.class);
- spyOn(imeSurface);
- doReturn(true).when(imeSurface).isValid();
- doReturn(imeSurface).when(mDisplayContent).createImeSurface(any(), any());
+ SurfaceControl.ScreenshotHardwareBuffer mockHwBuffer = mock(
+ SurfaceControl.ScreenshotHardwareBuffer.class);
+ doReturn(mock(HardwareBuffer.class)).when(mockHwBuffer).getHardwareBuffer();
+ doReturn(mockHwBuffer).when(mWm.mTaskSnapshotController).snapshotImeFromAttachedTask(any());
// Preparation: Simulate snapshot Task.
ActivityRecord act1 = createActivityRecord(mDisplayContent);
@@ -1967,21 +1983,18 @@ public class DisplayContentTests extends WindowTestsBase {
final WindowState appWin2 = createWindow(null, TYPE_BASE_APPLICATION, act2, "appWin2");
appWin2.setHasSurface(true);
assertTrue(appWin2.canBeImeTarget());
- doReturn(true).when(appWin1).isAnimating(PARENTS | TRANSITION,
- ANIMATION_TYPE_APP_TRANSITION | ANIMATION_TYPE_RECENTS);
+ doReturn(true).when(appWin1).isClosing();
+ doReturn(true).when(appWin1).inAppOrRecentsTransition();
// Test step 3: Verify appWin2 will be the next IME target and the IME snapshot surface will
- // be shown at this time.
- final Transaction t = mDisplayContent.getPendingTransaction();
- spyOn(t);
+ // be attached and shown on the display at this time.
mDisplayContent.computeImeTarget(true);
assertEquals(appWin2, mDisplayContent.getImeTarget(IME_TARGET_LAYERING));
assertTrue(mDisplayContent.shouldImeAttachedToApp());
- verify(mDisplayContent, atLeast(1)).attachAndShowImeScreenshotOnTarget();
+ verify(mDisplayContent, atLeast(1)).showImeScreenshot();
verify(mWm.mTaskSnapshotController).snapshotImeFromAttachedTask(appWin1.getTask());
assertNotNull(mDisplayContent.mImeScreenshot);
- verify(t).show(mDisplayContent.mImeScreenshot);
}
@UseTestDisplay(addWindows = {W_INPUT_METHOD}, addAllCommonWindows = true)
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
index db22757cc4fe..45ae81a71c44 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
@@ -157,6 +157,7 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
win.getFrame().set(0, 0, 500, 100);
addWindow(win);
+ win.updateSourceFrame(win.getFrame());
InsetsStateController controller = mDisplayContent.getInsetsStateController();
controller.onPostLayout();
@@ -185,6 +186,7 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
win.getFrame().set(0, 0, 500, 100);
addWindow(win);
+ win.updateSourceFrame(win.getFrame());
mDisplayContent.getInsetsStateController().onPostLayout();
InsetsSourceProvider provider =
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowPolicyControllerHelperTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowPolicyControllerHelperTests.java
index 6e11d8cf23e1..f9689990c5e8 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowPolicyControllerHelperTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowPolicyControllerHelperTests.java
@@ -16,13 +16,18 @@
package com.android.server.wm;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyInt;
+import android.app.WindowConfiguration;
import android.content.ComponentName;
import android.content.pm.ActivityInfo;
import android.os.UserHandle;
@@ -37,6 +42,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.List;
+import java.util.Set;
/**
* Tests for the {@link DisplayWindowPolicyControllerHelper} class.
@@ -113,6 +119,39 @@ public class DisplayWindowPolicyControllerHelperTests extends WindowTestsBase {
return activity;
}
+ @Test
+ public void testIsWindowingModeSupported_noController_returnTrueForAnyWindowingMode() {
+ doReturn(null).when(mWm.mDisplayManagerInternal)
+ .getDisplayWindowPolicyController(anyInt());
+ mSecondaryDisplay = createNewDisplay();
+ assertFalse(mSecondaryDisplay.mDwpcHelper.hasController());
+
+ assertTrue(mSecondaryDisplay.mDwpcHelper.isWindowingModeSupported(WINDOWING_MODE_PINNED));
+ assertTrue(
+ mSecondaryDisplay.mDwpcHelper.isWindowingModeSupported(WINDOWING_MODE_FULLSCREEN));
+ }
+
+ @Test
+ public void testIsWindowingModeSupported_withoutSettingSupportedMode_returnFalse() {
+ assertFalse(mSecondaryDisplay.mDwpcHelper.isWindowingModeSupported(WINDOWING_MODE_PINNED));
+ }
+
+ @Test
+ public void testIsWindowingModeSupported_withoutSupportedMode_defaultSupportFullScreen() {
+ assertTrue(
+ mSecondaryDisplay.mDwpcHelper.isWindowingModeSupported(WINDOWING_MODE_FULLSCREEN));
+ }
+
+ @Test
+ public void testIsWindowingModeSupported_setPinnedMode_returnTrue() {
+ Set<Integer> supportedWindowingMode = new ArraySet<>();
+ supportedWindowingMode.add(WINDOWING_MODE_PINNED);
+
+ mDwpc.setSupportedWindowingModes(supportedWindowingMode);
+
+ assertTrue(mSecondaryDisplay.mDwpcHelper.isWindowingModeSupported(WINDOWING_MODE_PINNED));
+ }
+
private class TestDisplayWindowPolicyController extends DisplayWindowPolicyController {
ComponentName mTopActivity = null;
@@ -120,7 +159,8 @@ public class DisplayWindowPolicyControllerHelperTests extends WindowTestsBase {
ArraySet<Integer> mRunningUids = new ArraySet<>();
@Override
- public boolean canContainActivities(@NonNull List<ActivityInfo> activities) {
+ public boolean canContainActivities(@NonNull List<ActivityInfo> activities,
+ @WindowConfiguration.WindowingMode int windowingMode) {
return false;
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/HighRefreshRateDenylistTest.java b/services/tests/wmtests/src/com/android/server/wm/HighRefreshRateDenylistTest.java
index dfc2e35ffedf..38ab683f81fe 100644
--- a/services/tests/wmtests/src/com/android/server/wm/HighRefreshRateDenylistTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/HighRefreshRateDenylistTest.java
@@ -33,7 +33,6 @@ import com.android.internal.R;
import com.android.internal.util.Preconditions;
import com.android.server.testutils.FakeDeviceConfigInterface;
-import org.junit.After;
import org.junit.Test;
import java.util.concurrent.Executor;
@@ -51,11 +50,6 @@ public class HighRefreshRateDenylistTest {
private HighRefreshRateDenylist mDenylist;
- @After
- public void tearDown() {
- mDenylist.dispose();
- }
-
@Test
public void testDefaultDenylist() {
final Resources r = createResources(APP1, APP2);
diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
index 90a6918644fa..6d022262b720 100644
--- a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
@@ -280,6 +280,7 @@ public class InsetsStateControllerTest extends WindowTestsBase {
rect.set(0, 1, 2, 3)));
getController().getSourceProvider(ITYPE_IME).setWindowContainer(ime, null, null);
statusBar.setControllableInsetProvider(statusBarProvider);
+ statusBar.updateSourceFrame(statusBar.getFrame());
statusBarProvider.onPostLayout();
diff --git a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java
index 0c2de5c6031b..5265b442c968 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java
@@ -23,9 +23,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.view.Display.INVALID_DISPLAY;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
@@ -279,51 +277,6 @@ public class LaunchParamsControllerTests extends WindowTestsBase {
}
/**
- * Ensures that {@link LaunchParamsModifier} requests specifying display id during
- * layout are honored.
- */
- @Test
- public void testLayoutTaskPreferredDisplayChange() {
- final LaunchParams params = new LaunchParams();
- final TestDisplayContent display = createNewDisplayContent();
- final TaskDisplayArea preferredTaskDisplayArea = display.getDefaultTaskDisplayArea();
- params.mPreferredTaskDisplayArea = preferredTaskDisplayArea;
- final InstrumentedPositioner positioner = new InstrumentedPositioner(RESULT_DONE, params);
- final Task task = new TaskBuilder(mAtm.mTaskSupervisor).build();
-
- mController.registerModifier(positioner);
-
- doNothing().when(mRootWindowContainer).moveRootTaskToTaskDisplayArea(anyInt(), any(),
- anyBoolean());
- mController.layoutTask(task, null /* windowLayout */);
- verify(mRootWindowContainer, times(1)).moveRootTaskToTaskDisplayArea(
- eq(task.getRootTaskId()), eq(preferredTaskDisplayArea), anyBoolean());
- }
-
- /**
- * Ensures that {@link LaunchParamsModifier} requests specifying windowingMode during
- * layout are honored.
- */
- @Test
- public void testLayoutTaskWindowingModeChange() {
- final LaunchParams params = new LaunchParams();
- final int windowingMode = WINDOWING_MODE_FREEFORM;
- params.mWindowingMode = windowingMode;
- final InstrumentedPositioner positioner = new InstrumentedPositioner(RESULT_DONE, params);
- final Task task = new TaskBuilder(mAtm.mTaskSupervisor).build();
-
- mController.registerModifier(positioner);
-
- final int beforeWindowMode = task.getRootTask().getWindowingMode();
- assertNotEquals(windowingMode, beforeWindowMode);
-
- mController.layoutTask(task, null /* windowLayout */);
-
- final int afterWindowMode = task.getRootTask().getWindowingMode();
- assertEquals(windowingMode, afterWindowMode);
- }
-
- /**
* Ensures that {@link LaunchParamsModifier} doesn't alter non-root tasks' windowingMode.
*/
@Test
@@ -355,10 +308,10 @@ public class LaunchParamsControllerTests extends WindowTestsBase {
final Rect expected = new Rect(10, 20, 30, 40);
final LaunchParams params = new LaunchParams();
- params.mWindowingMode = WINDOWING_MODE_FREEFORM;
params.mBounds.set(expected);
final InstrumentedPositioner positioner = new InstrumentedPositioner(RESULT_DONE, params);
- final Task task = new TaskBuilder(mAtm.mTaskSupervisor).build();
+ final Task task = new TaskBuilder(mAtm.mTaskSupervisor)
+ .setWindowingMode(WINDOWING_MODE_FREEFORM).build();
mController.registerModifier(positioner);
@@ -380,10 +333,10 @@ public class LaunchParamsControllerTests extends WindowTestsBase {
final Rect expected = new Rect(10, 20, 30, 40);
final LaunchParams params = new LaunchParams();
- params.mWindowingMode = WINDOWING_MODE_MULTI_WINDOW;
params.mBounds.set(expected);
final InstrumentedPositioner positioner = new InstrumentedPositioner(RESULT_DONE, params);
- final Task task = new TaskBuilder(mAtm.mTaskSupervisor).build();
+ final Task task = new TaskBuilder(mAtm.mTaskSupervisor)
+ .setWindowingMode(WINDOWING_MODE_MULTI_WINDOW).build();
mController.registerModifier(positioner);
diff --git a/services/tests/wmtests/src/com/android/server/wm/MockSurfaceControlBuilder.java b/services/tests/wmtests/src/com/android/server/wm/MockSurfaceControlBuilder.java
index 66139e6b483a..6a39d5608a19 100644
--- a/services/tests/wmtests/src/com/android/server/wm/MockSurfaceControlBuilder.java
+++ b/services/tests/wmtests/src/com/android/server/wm/MockSurfaceControlBuilder.java
@@ -20,6 +20,8 @@ import static org.mockito.Mockito.mock;
import android.view.SurfaceControl;
+import org.mockito.Mockito;
+
/**
* Stubbed {@link SurfaceControl.Builder} class that returns a mocked SurfaceControl instance
* that can be used for unit testing.
@@ -32,6 +34,8 @@ class MockSurfaceControlBuilder extends SurfaceControl.Builder {
@Override
public SurfaceControl build() {
- return mock(SurfaceControl.class);
+ SurfaceControl mockSurfaceControl = mock(SurfaceControl.class);
+ Mockito.doReturn(true).when(mockSurfaceControl).isValid();
+ return mockSurfaceControl;
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/RefreshRatePolicyTest.java b/services/tests/wmtests/src/com/android/server/wm/RefreshRatePolicyTest.java
index 19247604ad10..9d2eb26f5f21 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RefreshRatePolicyTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RefreshRatePolicyTest.java
@@ -101,14 +101,63 @@ public class RefreshRatePolicyTest extends WindowTestsBase {
assertEquals(0, mPolicy.getPreferredRefreshRate(cameraUsingWindow), FLOAT_TOLERANCE);
assertEquals(0, mPolicy.getPreferredMinRefreshRate(cameraUsingWindow), FLOAT_TOLERANCE);
assertEquals(0, mPolicy.getPreferredMaxRefreshRate(cameraUsingWindow), FLOAT_TOLERANCE);
- mPolicy.addNonHighRefreshRatePackage("com.android.test");
+ mPolicy.addRefreshRateRangeForPackage("com.android.test",
+ LOW_REFRESH_RATE, LOW_REFRESH_RATE);
assertEquals(0, mPolicy.getPreferredModeId(cameraUsingWindow));
assertEquals(0, mPolicy.getPreferredRefreshRate(cameraUsingWindow), FLOAT_TOLERANCE);
assertEquals(LOW_REFRESH_RATE,
mPolicy.getPreferredMinRefreshRate(cameraUsingWindow), FLOAT_TOLERANCE);
assertEquals(LOW_REFRESH_RATE,
mPolicy.getPreferredMaxRefreshRate(cameraUsingWindow), FLOAT_TOLERANCE);
- mPolicy.removeNonHighRefreshRatePackage("com.android.test");
+ mPolicy.removeRefreshRateRangeForPackage("com.android.test");
+ assertEquals(0, mPolicy.getPreferredModeId(cameraUsingWindow));
+ assertEquals(0, mPolicy.getPreferredRefreshRate(cameraUsingWindow), FLOAT_TOLERANCE);
+ assertEquals(0, mPolicy.getPreferredMinRefreshRate(cameraUsingWindow), FLOAT_TOLERANCE);
+ assertEquals(0, mPolicy.getPreferredMaxRefreshRate(cameraUsingWindow), FLOAT_TOLERANCE);
+ }
+
+ @Test
+ public void testCameraRange() {
+ final WindowState cameraUsingWindow = createWindow("cameraUsingWindow");
+ cameraUsingWindow.mAttrs.packageName = "com.android.test";
+ parcelLayoutParams(cameraUsingWindow);
+ assertEquals(0, mPolicy.getPreferredModeId(cameraUsingWindow));
+ assertEquals(0, mPolicy.getPreferredRefreshRate(cameraUsingWindow), FLOAT_TOLERANCE);
+ assertEquals(0, mPolicy.getPreferredMinRefreshRate(cameraUsingWindow), FLOAT_TOLERANCE);
+ assertEquals(0, mPolicy.getPreferredMaxRefreshRate(cameraUsingWindow), FLOAT_TOLERANCE);
+ mPolicy.addRefreshRateRangeForPackage("com.android.test",
+ LOW_REFRESH_RATE, MID_REFRESH_RATE);
+ assertEquals(0, mPolicy.getPreferredModeId(cameraUsingWindow));
+ assertEquals(0, mPolicy.getPreferredRefreshRate(cameraUsingWindow), FLOAT_TOLERANCE);
+ assertEquals(LOW_REFRESH_RATE,
+ mPolicy.getPreferredMinRefreshRate(cameraUsingWindow), FLOAT_TOLERANCE);
+ assertEquals(MID_REFRESH_RATE,
+ mPolicy.getPreferredMaxRefreshRate(cameraUsingWindow), FLOAT_TOLERANCE);
+ mPolicy.removeRefreshRateRangeForPackage("com.android.test");
+ assertEquals(0, mPolicy.getPreferredModeId(cameraUsingWindow));
+ assertEquals(0, mPolicy.getPreferredRefreshRate(cameraUsingWindow), FLOAT_TOLERANCE);
+ assertEquals(0, mPolicy.getPreferredMinRefreshRate(cameraUsingWindow), FLOAT_TOLERANCE);
+ assertEquals(0, mPolicy.getPreferredMaxRefreshRate(cameraUsingWindow), FLOAT_TOLERANCE);
+ }
+
+ @Test
+ public void testCameraRange_OutOfRange() {
+ final WindowState cameraUsingWindow = createWindow("cameraUsingWindow");
+ cameraUsingWindow.mAttrs.packageName = "com.android.test";
+ parcelLayoutParams(cameraUsingWindow);
+ assertEquals(0, mPolicy.getPreferredModeId(cameraUsingWindow));
+ assertEquals(0, mPolicy.getPreferredRefreshRate(cameraUsingWindow), FLOAT_TOLERANCE);
+ assertEquals(0, mPolicy.getPreferredMinRefreshRate(cameraUsingWindow), FLOAT_TOLERANCE);
+ assertEquals(0, mPolicy.getPreferredMaxRefreshRate(cameraUsingWindow), FLOAT_TOLERANCE);
+ mPolicy.addRefreshRateRangeForPackage("com.android.test",
+ LOW_REFRESH_RATE - 10, HI_REFRESH_RATE + 10);
+ assertEquals(0, mPolicy.getPreferredModeId(cameraUsingWindow));
+ assertEquals(0, mPolicy.getPreferredRefreshRate(cameraUsingWindow), FLOAT_TOLERANCE);
+ assertEquals(LOW_REFRESH_RATE,
+ mPolicy.getPreferredMinRefreshRate(cameraUsingWindow), FLOAT_TOLERANCE);
+ assertEquals(HI_REFRESH_RATE,
+ mPolicy.getPreferredMaxRefreshRate(cameraUsingWindow), FLOAT_TOLERANCE);
+ mPolicy.removeRefreshRateRangeForPackage("com.android.test");
assertEquals(0, mPolicy.getPreferredModeId(cameraUsingWindow));
assertEquals(0, mPolicy.getPreferredRefreshRate(cameraUsingWindow), FLOAT_TOLERANCE);
assertEquals(0, mPolicy.getPreferredMinRefreshRate(cameraUsingWindow), FLOAT_TOLERANCE);
@@ -162,7 +211,8 @@ public class RefreshRatePolicyTest extends WindowTestsBase {
overrideWindow.mAttrs.packageName = "com.android.test";
overrideWindow.mAttrs.preferredDisplayModeId = HI_MODE_ID;
parcelLayoutParams(overrideWindow);
- mPolicy.addNonHighRefreshRatePackage("com.android.test");
+ mPolicy.addRefreshRateRangeForPackage("com.android.test",
+ LOW_REFRESH_RATE, LOW_REFRESH_RATE);
assertEquals(HI_MODE_ID, mPolicy.getPreferredModeId(overrideWindow));
assertEquals(HI_REFRESH_RATE,
mPolicy.getPreferredRefreshRate(overrideWindow), FLOAT_TOLERANCE);
@@ -178,7 +228,8 @@ public class RefreshRatePolicyTest extends WindowTestsBase {
overrideWindow.mAttrs.packageName = "com.android.test";
overrideWindow.mAttrs.preferredRefreshRate = HI_REFRESH_RATE;
parcelLayoutParams(overrideWindow);
- mPolicy.addNonHighRefreshRatePackage("com.android.test");
+ mPolicy.addRefreshRateRangeForPackage("com.android.test",
+ LOW_REFRESH_RATE, LOW_REFRESH_RATE);
assertEquals(0, mPolicy.getPreferredModeId(overrideWindow));
assertEquals(HI_REFRESH_RATE,
mPolicy.getPreferredRefreshRate(overrideWindow), FLOAT_TOLERANCE);
@@ -257,7 +308,8 @@ public class RefreshRatePolicyTest extends WindowTestsBase {
cameraUsingWindow.mAttrs.packageName = "com.android.test";
parcelLayoutParams(cameraUsingWindow);
- mPolicy.addNonHighRefreshRatePackage("com.android.test");
+ mPolicy.addRefreshRateRangeForPackage("com.android.test",
+ LOW_REFRESH_RATE, LOW_REFRESH_RATE);
assertEquals(0, mPolicy.getPreferredModeId(cameraUsingWindow));
assertEquals(0, mPolicy.getPreferredRefreshRate(cameraUsingWindow), FLOAT_TOLERANCE);
assertEquals(LOW_REFRESH_RATE,
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
index acceadf8c499..762c08f99d94 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
@@ -20,6 +20,7 @@ import static android.app.KeyguardManager.ACTION_CONFIRM_DEVICE_CREDENTIAL_WITH_
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.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
@@ -945,22 +946,25 @@ public class RootWindowContainerTests extends WindowTestsBase {
mWm, "TDA", FEATURE_VENDOR_FIRST);
display.addChild(taskDisplayArea, POSITION_BOTTOM);
- // Making sure getting the root task from the preferred TDA
+ // Making sure getting the root task from the preferred TDA and the preferred windowing mode
LaunchParamsController.LaunchParams launchParams =
new LaunchParamsController.LaunchParams();
launchParams.mPreferredTaskDisplayArea = taskDisplayArea;
- Task root = mRootWindowContainer.getLaunchRootTask(null /* r */, null /* options */,
+ launchParams.mWindowingMode = WINDOWING_MODE_FREEFORM;
+ Task root = mRootWindowContainer.getOrCreateRootTask(null /* r */, null /* options */,
null /* candidateTask */, null /* sourceTask */, true /* onTop */, launchParams,
0 /* launchParams */);
assertEquals(taskDisplayArea, root.getTaskDisplayArea());
+ assertEquals(WINDOWING_MODE_FREEFORM, root.getWindowingMode());
// Making sure still getting the root task from the preferred TDA when passing in a
// launching activity.
ActivityRecord r = new ActivityBuilder(mAtm).build();
- root = mRootWindowContainer.getLaunchRootTask(r, null /* options */,
+ root = mRootWindowContainer.getOrCreateRootTask(r, null /* options */,
null /* candidateTask */, null /* sourceTask */, true /* onTop */, launchParams,
0 /* launchParams */);
assertEquals(taskDisplayArea, root.getTaskDisplayArea());
+ assertEquals(WINDOWING_MODE_FREEFORM, root.getWindowingMode());
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java
index cb858845e03e..33b236669ec7 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java
@@ -16,6 +16,7 @@
package com.android.server.wm;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.server.wm.RunningTasks.FLAG_ALLOWED;
import static com.android.server.wm.RunningTasks.FLAG_CROSS_USERS;
import static com.android.server.wm.RunningTasks.FLAG_KEEP_INTENT_EXTRA;
@@ -81,7 +82,9 @@ public class RunningTasksTest extends WindowTestsBase {
rootTasks.add(task);
}, false /* traverseTopToBottom */);
for (int i = 0; i < numTasks; i++) {
- createTask(rootTasks.get(i % numStacks), ".Task" + i, i, activeTime++, null);
+ final Task task =
+ createTask(rootTasks.get(i % numStacks), ".Task" + i, i, activeTime++, null);
+ doReturn(false).when(task).isVisible();
}
// Ensure that the latest tasks were returned in order of decreasing last active time,
@@ -158,6 +161,36 @@ public class RunningTasksTest extends WindowTestsBase {
}
}
+ @Test
+ public void testUpdateLastActiveTimeOfVisibleTasks() {
+ final DisplayContent display = new TestDisplayContent.Builder(mAtm, 1000, 2500).build();
+ final int numTasks = 10;
+ final ArrayList<Task> tasks = new ArrayList<>();
+ for (int i = 0; i < numTasks; i++) {
+ final Task task = createTask(null, ".Task" + i, i, i, null);
+ doReturn(false).when(task).isVisible();
+ tasks.add(task);
+ }
+
+ final Task visibleTask = tasks.get(0);
+ doReturn(true).when(visibleTask).isVisible();
+
+ final Task focusedTask = tasks.get(1);
+ doReturn(true).when(focusedTask).isVisible();
+ doReturn(true).when(focusedTask).isFocused();
+
+ // Ensure that the last active time of visible tasks were updated while the focused one had
+ // the largest last active time.
+ final int numFetchTasks = 5;
+ final ArrayList<RunningTaskInfo> fetchTasks = new ArrayList<>();
+ mRunningTasks.getTasks(numFetchTasks, fetchTasks,
+ FLAG_ALLOWED | FLAG_CROSS_USERS | FLAG_KEEP_INTENT_EXTRA, mRootWindowContainer,
+ -1 /* callingUid */, PROFILE_IDS);
+ assertThat(fetchTasks).hasSize(numFetchTasks);
+ assertEquals(fetchTasks.get(0).id, focusedTask.mTaskId);
+ assertEquals(fetchTasks.get(1).id, visibleTask.mTaskId);
+ }
+
/**
* Create a task with a single activity in it, with the given last active time.
*/
diff --git a/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java b/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java
index 46ef7ed092de..d27581865e26 100644
--- a/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java
+++ b/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java
@@ -17,11 +17,13 @@
package com.android.server.wm;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.graphics.ColorSpace;
import android.graphics.GraphicBuffer;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.graphics.Region;
+import android.hardware.HardwareBuffer;
import android.os.IBinder;
import android.os.Parcel;
import android.view.InputWindowHandle;
@@ -135,6 +137,12 @@ public class StubTransaction extends SurfaceControl.Transaction {
}
@Override
+ @NonNull
+ public SurfaceControl.Transaction setCrop(@NonNull SurfaceControl sc, @Nullable Rect crop) {
+ return this;
+ }
+
+ @Override
public SurfaceControl.Transaction setCornerRadius(SurfaceControl sc, float cornerRadius) {
return this;
}
@@ -275,6 +283,13 @@ public class StubTransaction extends SurfaceControl.Transaction {
}
@Override
+ @NonNull
+ public SurfaceControl.Transaction setBuffer(@NonNull SurfaceControl sc,
+ @Nullable HardwareBuffer buffer) {
+ return this;
+ }
+
+ @Override
public SurfaceControl.Transaction setColorSpace(SurfaceControl sc, ColorSpace colorSpace) {
return this;
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
index d038fea4680b..ce861595535c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
@@ -18,6 +18,7 @@ package com.android.server.wm;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.provider.DeviceConfig.NAMESPACE_CONSTRAIN_DISPLAY_APIS;
import static android.testing.DexmakerShareClassLoaderRule.runWithDexmakerShareClassLoader;
import static android.view.Display.DEFAULT_DISPLAY;
@@ -27,6 +28,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyString;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq;
@@ -36,6 +38,9 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.nullable;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+import static org.mockito.Mockito.CALLS_REAL_METHODS;
+import static org.mockito.Mockito.withSettings;
+
import android.app.ActivityManagerInternal;
import android.app.AppOpsManager;
import android.app.usage.UsageStatsManagerInternal;
@@ -57,6 +62,7 @@ import android.os.PowerManagerInternal;
import android.os.PowerSaveState;
import android.os.StrictMode;
import android.os.UserHandle;
+import android.provider.DeviceConfig;
import android.util.Log;
import android.view.InputChannel;
import android.view.Surface;
@@ -83,10 +89,12 @@ import com.android.server.uri.UriGrantsManagerInternal;
import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
+import org.mockito.MockSettings;
import org.mockito.Mockito;
import org.mockito.quality.Strictness;
import java.io.File;
+import java.util.ArrayList;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Supplier;
@@ -101,6 +109,17 @@ public class SystemServicesTestRule implements TestRule {
static int sNextDisplayId = DEFAULT_DISPLAY + 100;
private static final int[] TEST_USER_PROFILE_IDS = {};
+ /** Use a real static object so there won't be NPE in finalize() after clearInlineMocks(). */
+ private static final PowerManager.WakeLock sWakeLock = getInstrumentation().getContext()
+ .getSystemService(PowerManager.class).newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
+ private PowerManager.WakeLock mStubbedWakeLock;
+
+ /**
+ * The captured listeners will be unregistered in {@link #tearDown()} to avoid keeping static
+ * references of test instances from DeviceConfig.
+ */
+ private final ArrayList<DeviceConfig.OnPropertiesChangedListener> mDeviceConfigListeners =
+ new ArrayList<>();
private Description mDescription;
private Context mContext;
@@ -137,20 +156,29 @@ public class SystemServicesTestRule implements TestRule {
Log.e("SystemServicesTestRule", "Suppressed: ", throwable);
t.addSuppressed(throwable);
}
- throw t;
+ throwable = t;
}
- if (throwable != null) throw throwable;
}
+ if (throwable != null) throw throwable;
}
};
}
private void setUp() {
+ // Use stubOnly() to reduce memory usage if it doesn't need verification.
+ final MockSettings spyStubOnly = withSettings().stubOnly()
+ .defaultAnswer(CALLS_REAL_METHODS);
+ final MockSettings mockStubOnly = withSettings().stubOnly();
+ // Return mocked services: LocalServices.getService
+ // Avoid real operation: SurfaceControl.mirrorSurface
+ // Avoid leakage: DeviceConfig.addOnPropertiesChangedListener, LockGuard.installLock
+ // Watchdog.getInstance/addMonitor
mMockitoSession = mockitoSession()
- .spyStatic(LocalServices.class)
- .spyStatic(SurfaceControl.class)
- .mockStatic(LockGuard.class)
- .mockStatic(Watchdog.class)
+ .mockStatic(LocalServices.class, spyStubOnly)
+ .mockStatic(DeviceConfig.class, spyStubOnly)
+ .mockStatic(SurfaceControl.class, mockStubOnly)
+ .mockStatic(LockGuard.class, mockStubOnly)
+ .mockStatic(Watchdog.class, mockStubOnly)
.strictness(Strictness.LENIENT)
.startMocking();
@@ -162,6 +190,16 @@ public class SystemServicesTestRule implements TestRule {
private void setUpSystemCore() {
doReturn(mock(Watchdog.class)).when(Watchdog::getInstance);
+ doAnswer(invocation -> {
+ // Exclude CONSTRAIN_DISPLAY_APIS because ActivityRecord#sConstrainDisplayApisConfig
+ // only registers once and it doesn't reference to outside.
+ if (!NAMESPACE_CONSTRAIN_DISPLAY_APIS.equals(invocation.getArgument(0))) {
+ mDeviceConfigListeners.add(invocation.getArgument(2));
+ }
+ // SizeCompatTests uses setNeverConstrainDisplayApisFlag, and ActivityRecordTests
+ // uses splash_screen_exception_list. So still execute real registration.
+ return invocation.callRealMethod();
+ }).when(() -> DeviceConfig.addOnPropertiesChangedListener(anyString(), any(), any()));
mContext = getInstrumentation().getTargetContext();
spyOn(mContext);
@@ -194,7 +232,8 @@ public class SystemServicesTestRule implements TestRule {
// Prevent "WakeLock finalized while still held: SCREEN_FROZEN".
final PowerManager pm = mock(PowerManager.class);
doReturn(pm).when(mContext).getSystemService(eq(Context.POWER_SERVICE));
- doReturn(mock(PowerManager.WakeLock.class)).when(pm).newWakeLock(anyInt(), anyString());
+ mStubbedWakeLock = createStubbedWakeLock(false /* needVerification */);
+ doReturn(mStubbedWakeLock).when(pm).newWakeLock(anyInt(), anyString());
// DisplayManagerInternal
final DisplayManagerInternal dmi = mock(DisplayManagerInternal.class);
@@ -340,11 +379,10 @@ public class SystemServicesTestRule implements TestRule {
// Unregister display listener from root to avoid issues with subsequent tests.
mContext.getSystemService(DisplayManager.class)
.unregisterDisplayListener(mAtmService.mRootWindowContainer);
- // The constructor of WindowManagerService registers WindowManagerConstants and
- // HighRefreshRateBlacklist with DeviceConfig. We need to undo that here to avoid
- // leaking mWmService.
- mWmService.mConstants.dispose();
- mWmService.mHighRefreshRateDenylist.dispose();
+
+ for (int i = mDeviceConfigListeners.size() - 1; i >= 0; i--) {
+ DeviceConfig.removeOnPropertiesChangedListener(mDeviceConfigListeners.get(i));
+ }
// This makes sure the posted messages without delay are processed, e.g.
// DisplayPolicy#release, WindowManagerService#setAnimationScale.
@@ -401,6 +439,16 @@ public class SystemServicesTestRule implements TestRule {
return mPowerManagerWrapper;
}
+ /** Creates a no-op wakelock object. */
+ PowerManager.WakeLock createStubbedWakeLock(boolean needVerification) {
+ if (needVerification) {
+ return mock(PowerManager.WakeLock.class, Mockito.withSettings()
+ .spiedInstance(sWakeLock).defaultAnswer(Mockito.RETURNS_DEFAULTS));
+ }
+ return mock(PowerManager.WakeLock.class, Mockito.withSettings()
+ .spiedInstance(sWakeLock).stubOnly());
+ }
+
void setSurfaceFactory(Supplier<Surface> factory) {
mSurfaceFactory = factory;
}
@@ -556,7 +604,7 @@ public class SystemServicesTestRule implements TestRule {
// unit test version does not handle launch wake lock
doNothing().when(this).acquireLaunchWakelock();
- mLaunchingActivityWakeLock = mock(PowerManager.WakeLock.class);
+ mLaunchingActivityWakeLock = mStubbedWakeLock;
initialize();
diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRuleTest.java b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRuleTest.java
index 4056c7195c9b..2e7cc2736410 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRuleTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRuleTest.java
@@ -16,59 +16,64 @@
package com.android.server.wm;
-import static junit.framework.Assert.assertTrue;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.fail;
import android.platform.test.annotations.Presubmit;
-import org.junit.Rule;
+import com.android.internal.util.GcUtils;
+
import org.junit.Test;
-import org.junit.rules.ExpectedException;
import org.junit.runners.model.Statement;
-import java.io.IOException;
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.function.Predicate;
@Presubmit
public class SystemServicesTestRuleTest {
- @Rule
- public ExpectedException mExpectedException = ExpectedException.none();
@Test
- public void testRule_rethrows_unchecked_exceptions() throws Throwable {
- final SystemServicesTestRule mWmsRule = new SystemServicesTestRule();
- Statement statement = new Statement() {
- @Override
- public void evaluate() throws Throwable {
- throw new RuntimeException("A failing test!");
- }
- };
- mExpectedException.expect(RuntimeException.class);
- mWmsRule.apply(statement, null /* Description*/).evaluate();
+ public void testRule_rethrows_throwable() {
+ assertThrows(Throwable.class, () -> applyRule(rule -> false));
}
@Test
- public void testRule_rethrows_checked_exceptions() throws Throwable {
- final SystemServicesTestRule mWmsRule = new SystemServicesTestRule();
- Statement statement = new Statement() {
- @Override
- public void evaluate() throws Throwable {
- throw new IOException("A failing test!");
+ public void testRule_ranSuccessfully() throws Throwable {
+ final int iterations = 5;
+ final ArrayList<WeakReference<WindowManagerService>> wmsRefs = new ArrayList<>();
+ for (int i = 0; i < iterations; i++) {
+ applyRule(rule -> {
+ final WindowManagerService wms = rule.getWindowManagerService();
+ assertNotNull(wms);
+ wmsRefs.add(new WeakReference<>(wms));
+ return true;
+ });
+ }
+ assertEquals(iterations, wmsRefs.size());
+
+ GcUtils.runGcAndFinalizersSync();
+ // Only ensure that at least one instance is released because some references may be kept
+ // temporally by the message of other thread or single static reference.
+ for (int i = wmsRefs.size() - 1; i >= 0; i--) {
+ if (wmsRefs.get(i).get() == null) {
+ return;
}
- };
- mExpectedException.expect(IOException.class);
- mWmsRule.apply(statement, null /* Description*/).evaluate();
+ }
+ fail("WMS instance is leaked");
}
- @Test
- public void testRule_ranSuccessfully() throws Throwable {
- final boolean[] testRan = {false};
- final SystemServicesTestRule mWmsRule = new SystemServicesTestRule();
- Statement statement = new Statement() {
+ private static void applyRule(Predicate<SystemServicesTestRule> action) throws Throwable {
+ final SystemServicesTestRule wmsRule = new SystemServicesTestRule();
+ wmsRule.apply(new Statement() {
@Override
public void evaluate() throws Throwable {
- testRan[0] = true;
+ if (!action.test(wmsRule)) {
+ throw new Throwable("A failing test!");
+ }
}
- };
- mWmsRule.apply(statement, null /* Description*/).evaluate();
- assertTrue(testRan[0]);
+ }, null /* description */).evaluate();
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
index 0debdfa3bd1a..c6158662d110 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
@@ -359,17 +359,11 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
public void testApplyTransaction_enforceHierarchyChange_createTaskFragment()
throws RemoteException {
mController.registerOrganizer(mIOrganizer);
- final ActivityRecord activity = createActivityRecord(mDisplayContent);
- final int uid = Binder.getCallingUid();
- activity.info.applicationInfo.uid = uid;
- activity.getTask().effectiveUid = uid;
+ final ActivityRecord ownerActivity = createActivityRecord(mDisplayContent);
final IBinder fragmentToken = new Binder();
- final TaskFragmentCreationParams params = new TaskFragmentCreationParams.Builder(
- mOrganizerToken, fragmentToken, activity.token).build();
- mOrganizer.applyTransaction(mTransaction);
// Allow organizer to create TaskFragment and start/reparent activity to TaskFragment.
- mTransaction.createTaskFragment(params);
+ createTaskFragmentFromOrganizer(mTransaction, ownerActivity, fragmentToken);
mTransaction.startActivityInTaskFragment(
mFragmentToken, null /* callerToken */, new Intent(), null /* activityOptions */);
mTransaction.reparentActivityToTaskFragment(mFragmentToken, mock(IBinder.class));
@@ -381,7 +375,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
final TaskFragment taskFragment = mAtm.mWindowOrganizerController
.getTaskFragment(fragmentToken);
assertNotNull(taskFragment);
- assertEquals(activity.getTask(), taskFragment.getTask());
+ assertEquals(ownerActivity.getTask(), taskFragment.getTask());
}
@Test
@@ -523,4 +517,43 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
mController.dispatchPendingEvents();
verify(mOrganizer).onTaskFragmentInfoChanged(any());
}
+
+ /**
+ * When an embedded {@link TaskFragment} is removed, we should clean up the reference in the
+ * {@link WindowOrganizerController}.
+ */
+ @Test
+ public void testTaskFragmentRemoved_cleanUpEmbeddedTaskFragment()
+ throws RemoteException {
+ mController.registerOrganizer(mIOrganizer);
+ final ActivityRecord ownerActivity = createActivityRecord(mDisplayContent);
+ final IBinder fragmentToken = new Binder();
+ createTaskFragmentFromOrganizer(mTransaction, ownerActivity, fragmentToken);
+ mAtm.getWindowOrganizerController().applyTransaction(mTransaction);
+ final TaskFragment taskFragment = mAtm.mWindowOrganizerController
+ .getTaskFragment(fragmentToken);
+
+ assertNotNull(taskFragment);
+
+ taskFragment.removeImmediately();
+
+ assertNull(mAtm.mWindowOrganizerController.getTaskFragment(fragmentToken));
+ }
+
+ /**
+ * Creates a {@link TaskFragment} with the {@link WindowContainerTransaction}. Calls
+ * {@link WindowOrganizerController#applyTransaction} to apply the transaction,
+ */
+ private void createTaskFragmentFromOrganizer(WindowContainerTransaction wct,
+ ActivityRecord ownerActivity, IBinder fragmentToken) {
+ final int uid = Binder.getCallingUid();
+ ownerActivity.info.applicationInfo.uid = uid;
+ ownerActivity.getTask().effectiveUid = uid;
+ final TaskFragmentCreationParams params = new TaskFragmentCreationParams.Builder(
+ mOrganizerToken, fragmentToken, ownerActivity.token).build();
+ mOrganizer.applyTransaction(wct);
+
+ // Allow organizer to create TaskFragment and start/reparent activity to TaskFragment.
+ wct.createTaskFragment(params);
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java
index 730275cde40b..189a1dacb891 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java
@@ -149,4 +149,25 @@ public class TaskFragmentTest extends WindowTestsBase {
assertEquals(false, info.isEmpty());
assertEquals(activity.token, info.getActivities().get(0));
}
+
+ @Test
+ public void testActivityVisibilityBehindTranslucentTaskFragment() {
+ // Having an activity covered by a translucent TaskFragment:
+ // Task
+ // - TaskFragment
+ // - Activity (Translucent)
+ // - Activity
+ ActivityRecord translucentActivity = new ActivityBuilder(mAtm)
+ .setUid(DEFAULT_TASK_FRAGMENT_ORGANIZER_UID).build();
+ mTaskFragment.addChild(translucentActivity);
+ doReturn(true).when(mTaskFragment).isTranslucent(any());
+
+ ActivityRecord activityBelow = new ActivityBuilder(mAtm).build();
+ mTaskFragment.getTask().addChild(activityBelow, 0);
+
+ // Ensure the activity below is visible
+ mTaskFragment.getTask().ensureActivitiesVisible(null /* starting */, 0 /* configChanges */,
+ false /* preserveWindows */);
+ assertEquals(true, activityBelow.isVisibleRequested());
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
index fe41734d0232..9304761fc1c9 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
@@ -146,6 +146,27 @@ public class TaskTests extends WindowTestsBase {
}
@Test
+ public void testRemoveContainer_multipleNestedTasks() {
+ final Task rootTask = createTask(mDisplayContent);
+ rootTask.mCreatedByOrganizer = true;
+ final Task task1 = new TaskBuilder(mSupervisor).setParentTaskFragment(rootTask).build();
+ final Task task2 = new TaskBuilder(mSupervisor).setParentTaskFragment(rootTask).build();
+ final ActivityRecord activity1 = createActivityRecord(task1);
+ final ActivityRecord activity2 = createActivityRecord(task2);
+ activity1.setVisible(false);
+
+ // All activities under the root task should be finishing.
+ rootTask.remove(true /* withTransition */, "test");
+ assertTrue(activity1.finishing);
+ assertTrue(activity2.finishing);
+
+ // After all activities activities are destroyed, the root task should also be removed.
+ activity1.removeImmediately();
+ activity2.removeImmediately();
+ assertFalse(rootTask.isAttached());
+ }
+
+ @Test
public void testRemoveContainer_deferRemoval() {
final Task rootTask = createTask(mDisplayContent);
final Task task = createTaskInRootTask(rootTask, 0 /* userId */);
@@ -238,6 +259,20 @@ public class TaskTests extends WindowTestsBase {
}
@Test
+ public void testPerformClearTop() {
+ final Task task = createTask(mDisplayContent);
+ final ActivityRecord activity1 = new ActivityBuilder(mAtm).setTask(task).build();
+ final ActivityRecord activity2 = new ActivityBuilder(mAtm).setTask(task).build();
+ // Detach from process so the activities can be removed from hierarchy when finishing.
+ activity1.detachFromProcess();
+ activity2.detachFromProcess();
+ assertNull(task.performClearTop(activity1, 0 /* launchFlags */));
+ assertFalse(task.hasChild());
+ // In real case, the task should be preserved for adding new activity.
+ assertTrue(task.isAttached());
+ }
+
+ @Test
public void testRemoveChildForOverlayTask() {
final Task task = createTask(mDisplayContent);
final int taskId = task.mTaskId;
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java b/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java
index 7dfb5aef7fe7..7cf4b2ebe924 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java
@@ -44,7 +44,7 @@ public class TestIWindow extends IWindow.Stub {
@Override
public void resized(ClientWindowFrames frames, boolean reportDraw,
MergedConfiguration mergedConfig, boolean forceLayout, boolean alwaysConsumeSystemBars,
- int displayId) throws RemoteException {
+ int displayId, int seqId, int resizeMode) throws RemoteException {
}
@Override
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 8474c3829827..7e5d017e2bc4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
@@ -32,6 +32,7 @@ import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.TRANSIT_TO_BACK;
import static android.window.TransitionInfo.FLAG_IS_WALLPAPER;
import static android.window.TransitionInfo.FLAG_SHOW_WALLPAPER;
+import static android.window.TransitionInfo.FLAG_TRANSLUCENT;
import static android.window.TransitionInfo.isIndependent;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
@@ -328,6 +329,7 @@ public class TransitionTests extends WindowTestsBase {
final ActivityRecord act = createActivityRecord(tasks[i]);
// alternate so that the transition doesn't get promoted to the display area
act.mVisibleRequested = (i % 2) == 0; // starts invisible
+ act.visibleIgnoringKeyguard = (i % 2) == 0;
if (i == showWallpaperTask) {
doReturn(true).when(act).showWallpaper();
}
@@ -490,6 +492,86 @@ public class TransitionTests extends WindowTestsBase {
}
@Test
+ public void testOpenOpaqueTask() {
+ final Transition transition = createTestTransition(TRANSIT_OPEN);
+ ArrayMap<WindowContainer, Transition.ChangeInfo> changes = transition.mChanges;
+ ArraySet<WindowContainer> participants = transition.mParticipants;
+
+ final Task newTask = createTask(mDisplayContent);
+ doReturn(false).when(newTask).isTranslucent(any());
+ final Task oldTask = createTask(mDisplayContent);
+ doReturn(false).when(oldTask).isTranslucent(any());
+
+ final ActivityRecord closing = createActivityRecord(oldTask);
+ closing.setOccludesParent(true);
+ final ActivityRecord opening = createActivityRecord(newTask);
+ opening.setOccludesParent(false);
+ // Start states.
+ changes.put(newTask, new Transition.ChangeInfo(false /* vis */, true /* exChg */));
+ changes.put(oldTask, new Transition.ChangeInfo(true /* vis */, false /* exChg */));
+ changes.put(opening, new Transition.ChangeInfo(false /* vis */, true /* exChg */));
+ changes.put(closing, new Transition.ChangeInfo(true /* vis */, false /* exChg */));
+ fillChangeMap(changes, newTask);
+ // End states.
+ closing.mVisibleRequested = true;
+ opening.mVisibleRequested = true;
+
+ final int transit = transition.mType;
+ int flags = 0;
+
+ // Check basic both tasks participating
+ participants.add(oldTask);
+ participants.add(newTask);
+ ArrayList<WindowContainer> targets = Transition.calculateTargets(participants, changes);
+ TransitionInfo info = Transition.calculateTransitionInfo(transit, flags, targets, changes);
+ assertEquals(2, info.getChanges().size());
+ assertEquals(transit, info.getType());
+
+ assertTrue((info.getChanges().get(0).getFlags() & FLAG_TRANSLUCENT) == 0);
+ assertTrue((info.getChanges().get(1).getFlags() & FLAG_TRANSLUCENT) == 0);
+ }
+
+ @Test
+ public void testOpenTranslucentTask() {
+ final Transition transition = createTestTransition(TRANSIT_OPEN);
+ ArrayMap<WindowContainer, Transition.ChangeInfo> changes = transition.mChanges;
+ ArraySet<WindowContainer> participants = transition.mParticipants;
+
+ final Task newTask = createTask(mDisplayContent);
+ doReturn(true).when(newTask).isTranslucent(any());
+ final Task oldTask = createTask(mDisplayContent);
+ doReturn(false).when(oldTask).isTranslucent(any());
+
+ final ActivityRecord closing = createActivityRecord(oldTask);
+ closing.setOccludesParent(true);
+ final ActivityRecord opening = createActivityRecord(newTask);
+ opening.setOccludesParent(false);
+ // Start states.
+ changes.put(newTask, new Transition.ChangeInfo(false /* vis */, true /* exChg */));
+ changes.put(oldTask, new Transition.ChangeInfo(true /* vis */, false /* exChg */));
+ changes.put(opening, new Transition.ChangeInfo(false /* vis */, true /* exChg */));
+ changes.put(closing, new Transition.ChangeInfo(true /* vis */, false /* exChg */));
+ fillChangeMap(changes, newTask);
+ // End states.
+ closing.mVisibleRequested = true;
+ opening.mVisibleRequested = true;
+
+ final int transit = transition.mType;
+ int flags = 0;
+
+ // Check basic both tasks participating
+ participants.add(oldTask);
+ participants.add(newTask);
+ ArrayList<WindowContainer> targets = Transition.calculateTargets(participants, changes);
+ TransitionInfo info = Transition.calculateTransitionInfo(transit, flags, targets, changes);
+ assertEquals(2, info.getChanges().size());
+ assertEquals(transit, info.getType());
+
+ assertTrue((info.getChanges().get(0).getFlags() & FLAG_TRANSLUCENT) != 0);
+ assertTrue((info.getChanges().get(1).getFlags() & FLAG_TRANSLUCENT) == 0);
+ }
+
+ @Test
public void testTimeout() {
final TransitionController controller = new TransitionController(mAtm,
mock(TaskSnapshotController.class));
@@ -610,7 +692,8 @@ public class TransitionTests extends WindowTestsBase {
statusBar.mWinAnimator.mDrawState = WindowStateAnimator.DRAW_PENDING;
final SurfaceControl.Transaction postDrawTransaction =
mock(SurfaceControl.Transaction.class);
- final boolean layoutNeeded = statusBar.finishDrawing(postDrawTransaction);
+ final boolean layoutNeeded = statusBar.finishDrawing(postDrawTransaction,
+ Integer.MAX_VALUE);
assertFalse(layoutNeeded);
transactionCommittedListener.onTransactionCommitted();
@@ -660,7 +743,7 @@ public class TransitionTests extends WindowTestsBase {
player.finish();
// The controller should be cleared if the target windows are drawn.
- statusBar.finishDrawing(mWm.mTransactionFactory.get());
+ statusBar.finishDrawing(mWm.mTransactionFactory.get(), Integer.MAX_VALUE);
statusBar.setOrientationChanging(false);
assertNull(mDisplayContent.getAsyncRotationController());
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerInsetsSourceProviderTest.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerInsetsSourceProviderTest.java
index 10e429250c19..e824f3d2916d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerInsetsSourceProviderTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerInsetsSourceProviderTest.java
@@ -64,6 +64,7 @@ public class WindowContainerInsetsSourceProviderTest extends WindowTestsBase {
statusBar.getFrame().set(0, 0, 500, 100);
statusBar.mHasSurface = true;
mProvider.setWindowContainer(statusBar, null, null);
+ mProvider.updateSourceFrame(statusBar.getFrame());
mProvider.onPostLayout();
assertEquals(new Rect(0, 0, 500, 100), mProvider.getSource().getFrame());
assertEquals(Insets.of(0, 100, 0, 0),
@@ -81,6 +82,7 @@ public class WindowContainerInsetsSourceProviderTest extends WindowTestsBase {
ime.mGivenVisibleInsets.set(0, 0, 0, 75);
ime.mHasSurface = true;
mProvider.setWindowContainer(ime, null, null);
+ mProvider.updateSourceFrame(ime.getFrame());
mProvider.onPostLayout();
assertEquals(new Rect(0, 0, 500, 40), mProvider.getSource().getFrame());
assertEquals(new Rect(0, 0, 500, 25), mProvider.getSource().getVisibleFrame());
@@ -96,6 +98,7 @@ public class WindowContainerInsetsSourceProviderTest extends WindowTestsBase {
final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
statusBar.getFrame().set(0, 0, 500, 100);
mProvider.setWindowContainer(statusBar, null, null);
+ mProvider.updateSourceFrame(statusBar.getFrame());
mProvider.onPostLayout();
assertEquals(Insets.NONE, mProvider.getSource().calculateInsets(new Rect(0, 0, 500, 500),
false /* ignoreVisibility */));
@@ -110,6 +113,7 @@ public class WindowContainerInsetsSourceProviderTest extends WindowTestsBase {
(displayFrames, windowState, rect) -> {
rect.set(10, 10, 20, 20);
}, null);
+ mProvider.updateSourceFrame(statusBar.getFrame());
mProvider.onPostLayout();
assertEquals(new Rect(10, 10, 20, 20), mProvider.getSource().getFrame());
}
@@ -181,7 +185,7 @@ public class WindowContainerInsetsSourceProviderTest extends WindowTestsBase {
mImeProvider.setWindowContainer(inputMethod, null, null);
mImeProvider.setServerVisible(false);
mImeSource.setVisible(true);
- mImeProvider.updateSourceFrame();
+ mImeProvider.updateSourceFrame(inputMethod.getFrame());
assertEquals(new Rect(0, 0, 0, 0), mImeSource.getFrame());
Insets insets = mImeSource.calculateInsets(new Rect(0, 0, 500, 500),
false /* ignoreVisibility */);
@@ -189,7 +193,7 @@ public class WindowContainerInsetsSourceProviderTest extends WindowTestsBase {
mImeProvider.setServerVisible(true);
mImeSource.setVisible(true);
- mImeProvider.updateSourceFrame();
+ mImeProvider.updateSourceFrame(inputMethod.getFrame());
assertEquals(inputMethod.getFrame(), mImeSource.getFrame());
insets = mImeSource.calculateInsets(new Rect(0, 0, 500, 500),
false /* ignoreVisibility */);
@@ -229,6 +233,7 @@ public class WindowContainerInsetsSourceProviderTest extends WindowTestsBase {
statusBar.getFrame().set(0, 0, 500, 100);
statusBar.mHasSurface = true;
mProvider.setWindowContainer(statusBar, null, null);
+ mProvider.updateSourceFrame(statusBar.getFrame());
mProvider.onPostLayout();
assertEquals(new Rect(0, 0, 500, 100), mProvider.getSource().getFrame());
// Still apply top insets if window overlaps even if it's top doesn't exactly match
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowLayoutTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowLayoutTests.java
index 7d2e9bf26b01..ea18e58fe999 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowLayoutTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowLayoutTests.java
@@ -45,6 +45,7 @@ import android.view.InsetsVisibilities;
import android.view.WindowInsets;
import android.view.WindowLayout;
import android.view.WindowManager;
+import android.window.ClientWindowFrames;
import androidx.test.filters.SmallTest;
@@ -71,9 +72,7 @@ public class WindowLayoutTests {
private static final Insets WATERFALL_INSETS = Insets.of(6, 0, 12, 0);
private final WindowLayout mWindowLayout = new WindowLayout();
- private final Rect mDisplayFrame = new Rect();
- private final Rect mParentFrame = new Rect();
- private final Rect mFrame = new Rect();
+ private final ClientWindowFrames mOutFrames = new ClientWindowFrames();
private WindowManager.LayoutParams mAttrs;
private InsetsState mState;
@@ -108,7 +107,7 @@ public class WindowLayoutTests {
private void computeFrames() {
mWindowLayout.computeFrames(mAttrs, mState, mDisplayCutoutSafe, mWindowBounds,
mWindowingMode, mRequestedWidth, mRequestedHeight, mRequestedVisibilities,
- mAttachedWindowFrame, mCompatScale, mDisplayFrame, mParentFrame, mFrame);
+ mAttachedWindowFrame, mCompatScale, mOutFrames);
}
private void addDisplayCutout() {
@@ -146,9 +145,9 @@ public class WindowLayoutTests {
public void defaultParams() {
computeFrames();
- assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mDisplayFrame);
- assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mParentFrame);
- assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mFrame);
+ assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mOutFrames.displayFrame);
+ assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mOutFrames.parentFrame);
+ assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mOutFrames.frame);
}
@Test
@@ -157,9 +156,9 @@ public class WindowLayoutTests {
mRequestedHeight = UNSPECIFIED_LENGTH;
computeFrames();
- assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mDisplayFrame);
- assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mParentFrame);
- assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mFrame);
+ assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mOutFrames.displayFrame);
+ assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mOutFrames.parentFrame);
+ assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mOutFrames.frame);
}
@Test
@@ -173,9 +172,9 @@ public class WindowLayoutTests {
mAttrs.gravity = Gravity.LEFT | Gravity.TOP;
computeFrames();
- assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mDisplayFrame);
- assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mParentFrame);
- assertRect(0, STATUS_BAR_HEIGHT, width, STATUS_BAR_HEIGHT + height, mFrame);
+ assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mOutFrames.displayFrame);
+ assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mOutFrames.parentFrame);
+ assertRect(0, STATUS_BAR_HEIGHT, width, STATUS_BAR_HEIGHT + height, mOutFrames.frame);
}
@Test
@@ -186,9 +185,12 @@ public class WindowLayoutTests {
mRequestedHeight = UNSPECIFIED_LENGTH;
computeFrames();
- assertRect(0, top, DISPLAY_WIDTH, DISPLAY_HEIGHT - NAVIGATION_BAR_HEIGHT, mDisplayFrame);
- assertRect(0, top, DISPLAY_WIDTH, DISPLAY_HEIGHT - NAVIGATION_BAR_HEIGHT, mParentFrame);
- assertRect(0, top, DISPLAY_WIDTH, DISPLAY_HEIGHT - NAVIGATION_BAR_HEIGHT, mFrame);
+ assertRect(0, top, DISPLAY_WIDTH, DISPLAY_HEIGHT - NAVIGATION_BAR_HEIGHT,
+ mOutFrames.displayFrame);
+ assertRect(0, top, DISPLAY_WIDTH, DISPLAY_HEIGHT - NAVIGATION_BAR_HEIGHT,
+ mOutFrames.parentFrame);
+ assertRect(0, top, DISPLAY_WIDTH, DISPLAY_HEIGHT - NAVIGATION_BAR_HEIGHT,
+ mOutFrames.frame);
}
@Test
@@ -196,9 +198,9 @@ public class WindowLayoutTests {
mAttrs.setFitInsetsTypes(WindowInsets.Type.statusBars());
computeFrames();
- assertInsetByTopBottom(STATUS_BAR_HEIGHT, 0, mDisplayFrame);
- assertInsetByTopBottom(STATUS_BAR_HEIGHT, 0, mParentFrame);
- assertInsetByTopBottom(STATUS_BAR_HEIGHT, 0, mFrame);
+ assertInsetByTopBottom(STATUS_BAR_HEIGHT, 0, mOutFrames.displayFrame);
+ assertInsetByTopBottom(STATUS_BAR_HEIGHT, 0, mOutFrames.parentFrame);
+ assertInsetByTopBottom(STATUS_BAR_HEIGHT, 0, mOutFrames.frame);
}
@Test
@@ -206,9 +208,9 @@ public class WindowLayoutTests {
mAttrs.setFitInsetsTypes(WindowInsets.Type.navigationBars());
computeFrames();
- assertInsetByTopBottom(0, NAVIGATION_BAR_HEIGHT, mDisplayFrame);
- assertInsetByTopBottom(0, NAVIGATION_BAR_HEIGHT, mParentFrame);
- assertInsetByTopBottom(0, NAVIGATION_BAR_HEIGHT, mFrame);
+ assertInsetByTopBottom(0, NAVIGATION_BAR_HEIGHT, mOutFrames.displayFrame);
+ assertInsetByTopBottom(0, NAVIGATION_BAR_HEIGHT, mOutFrames.parentFrame);
+ assertInsetByTopBottom(0, NAVIGATION_BAR_HEIGHT, mOutFrames.frame);
}
@Test
@@ -216,9 +218,9 @@ public class WindowLayoutTests {
mAttrs.setFitInsetsTypes(0);
computeFrames();
- assertInsetByTopBottom(0, 0, mDisplayFrame);
- assertInsetByTopBottom(0, 0, mParentFrame);
- assertInsetByTopBottom(0, 0, mFrame);
+ assertInsetByTopBottom(0, 0, mOutFrames.displayFrame);
+ assertInsetByTopBottom(0, 0, mOutFrames.parentFrame);
+ assertInsetByTopBottom(0, 0, mOutFrames.frame);
}
@Test
@@ -226,9 +228,9 @@ public class WindowLayoutTests {
mAttrs.setFitInsetsSides(WindowInsets.Side.all());
computeFrames();
- assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mDisplayFrame);
- assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mParentFrame);
- assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mFrame);
+ assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mOutFrames.displayFrame);
+ assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mOutFrames.parentFrame);
+ assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mOutFrames.frame);
}
@Test
@@ -236,9 +238,9 @@ public class WindowLayoutTests {
mAttrs.setFitInsetsSides(WindowInsets.Side.TOP);
computeFrames();
- assertInsetByTopBottom(STATUS_BAR_HEIGHT, 0, mDisplayFrame);
- assertInsetByTopBottom(STATUS_BAR_HEIGHT, 0, mParentFrame);
- assertInsetByTopBottom(STATUS_BAR_HEIGHT, 0, mFrame);
+ assertInsetByTopBottom(STATUS_BAR_HEIGHT, 0, mOutFrames.displayFrame);
+ assertInsetByTopBottom(STATUS_BAR_HEIGHT, 0, mOutFrames.parentFrame);
+ assertInsetByTopBottom(STATUS_BAR_HEIGHT, 0, mOutFrames.frame);
}
@Test
@@ -246,9 +248,9 @@ public class WindowLayoutTests {
mAttrs.setFitInsetsSides(0);
computeFrames();
- assertInsetByTopBottom(0, 0, mDisplayFrame);
- assertInsetByTopBottom(0, 0, mParentFrame);
- assertInsetByTopBottom(0, 0, mFrame);
+ assertInsetByTopBottom(0, 0, mOutFrames.displayFrame);
+ assertInsetByTopBottom(0, 0, mOutFrames.parentFrame);
+ assertInsetByTopBottom(0, 0, mOutFrames.frame);
}
@Test
@@ -257,9 +259,9 @@ public class WindowLayoutTests {
mState.getSource(ITYPE_NAVIGATION_BAR).setVisible(false);
computeFrames();
- assertInsetByTopBottom(0, 0, mDisplayFrame);
- assertInsetByTopBottom(0, 0, mParentFrame);
- assertInsetByTopBottom(0, 0, mFrame);
+ assertInsetByTopBottom(0, 0, mOutFrames.displayFrame);
+ assertInsetByTopBottom(0, 0, mOutFrames.parentFrame);
+ assertInsetByTopBottom(0, 0, mOutFrames.frame);
}
@Test
@@ -269,9 +271,9 @@ public class WindowLayoutTests {
mAttrs.setFitInsetsIgnoringVisibility(true);
computeFrames();
- assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mDisplayFrame);
- assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mParentFrame);
- assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mFrame);
+ assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mOutFrames.displayFrame);
+ assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mOutFrames.parentFrame);
+ assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mOutFrames.frame);
}
@Test
@@ -282,9 +284,9 @@ public class WindowLayoutTests {
mAttrs.privateFlags |= PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME;
computeFrames();
- assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mDisplayFrame);
- assertInsetByTopBottom(STATUS_BAR_HEIGHT, IME_HEIGHT, mParentFrame);
- assertInsetByTopBottom(STATUS_BAR_HEIGHT, IME_HEIGHT, mFrame);
+ assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mOutFrames.displayFrame);
+ assertInsetByTopBottom(STATUS_BAR_HEIGHT, IME_HEIGHT, mOutFrames.parentFrame);
+ assertInsetByTopBottom(STATUS_BAR_HEIGHT, IME_HEIGHT, mOutFrames.frame);
}
@Test
@@ -295,11 +297,11 @@ public class WindowLayoutTests {
computeFrames();
assertInsetBy(WATERFALL_INSETS.left, DISPLAY_CUTOUT_HEIGHT, WATERFALL_INSETS.right, 0,
- mDisplayFrame);
+ mOutFrames.displayFrame);
assertInsetBy(WATERFALL_INSETS.left, DISPLAY_CUTOUT_HEIGHT, WATERFALL_INSETS.right, 0,
- mParentFrame);
+ mOutFrames.parentFrame);
assertInsetBy(WATERFALL_INSETS.left, DISPLAY_CUTOUT_HEIGHT, WATERFALL_INSETS.right, 0,
- mFrame);
+ mOutFrames.frame);
}
@Test
@@ -310,11 +312,11 @@ public class WindowLayoutTests {
computeFrames();
assertInsetBy(WATERFALL_INSETS.left, STATUS_BAR_HEIGHT, WATERFALL_INSETS.right, 0,
- mDisplayFrame);
+ mOutFrames.displayFrame);
assertInsetBy(WATERFALL_INSETS.left, STATUS_BAR_HEIGHT, WATERFALL_INSETS.right, 0,
- mParentFrame);
+ mOutFrames.parentFrame);
assertInsetBy(WATERFALL_INSETS.left, STATUS_BAR_HEIGHT, WATERFALL_INSETS.right, 0,
- mFrame);
+ mOutFrames.frame);
}
@Test
@@ -325,9 +327,9 @@ public class WindowLayoutTests {
mAttrs.setFitInsetsTypes(0);
computeFrames();
- assertInsetBy(WATERFALL_INSETS.left, 0, WATERFALL_INSETS.right, 0, mDisplayFrame);
- assertInsetBy(WATERFALL_INSETS.left, 0, WATERFALL_INSETS.right, 0, mParentFrame);
- assertInsetBy(WATERFALL_INSETS.left, 0, WATERFALL_INSETS.right, 0, mFrame);
+ assertInsetBy(WATERFALL_INSETS.left, 0, WATERFALL_INSETS.right, 0, mOutFrames.displayFrame);
+ assertInsetBy(WATERFALL_INSETS.left, 0, WATERFALL_INSETS.right, 0, mOutFrames.parentFrame);
+ assertInsetBy(WATERFALL_INSETS.left, 0, WATERFALL_INSETS.right, 0, mOutFrames.frame);
}
@Test
@@ -342,9 +344,9 @@ public class WindowLayoutTests {
mAttrs.privateFlags |= PRIVATE_FLAG_LAYOUT_SIZE_EXTENDED_BY_CUTOUT;
computeFrames();
- assertRect(0, 0, DISPLAY_WIDTH, DISPLAY_HEIGHT, mDisplayFrame);
- assertRect(0, 0, DISPLAY_WIDTH, DISPLAY_HEIGHT, mParentFrame);
- assertRect(0, 0, DISPLAY_WIDTH, height + DISPLAY_CUTOUT_HEIGHT, mFrame);
+ assertRect(0, 0, DISPLAY_WIDTH, DISPLAY_HEIGHT, mOutFrames.displayFrame);
+ assertRect(0, 0, DISPLAY_WIDTH, DISPLAY_HEIGHT, mOutFrames.parentFrame);
+ assertRect(0, 0, DISPLAY_WIDTH, height + DISPLAY_CUTOUT_HEIGHT, mOutFrames.frame);
}
@Test
@@ -357,11 +359,11 @@ public class WindowLayoutTests {
computeFrames();
assertInsetBy(WATERFALL_INSETS.left, STATUS_BAR_HEIGHT, WATERFALL_INSETS.right, 0,
- mDisplayFrame);
+ mOutFrames.displayFrame);
assertInsetBy(WATERFALL_INSETS.left, STATUS_BAR_HEIGHT, WATERFALL_INSETS.right, 0,
- mParentFrame);
+ mOutFrames.parentFrame);
assertInsetBy(WATERFALL_INSETS.left, STATUS_BAR_HEIGHT, WATERFALL_INSETS.right, 0,
- mFrame);
+ mOutFrames.frame);
}
@Test
@@ -371,9 +373,9 @@ public class WindowLayoutTests {
mAttrs.setFitInsetsTypes(0);
computeFrames();
- assertInsetBy(WATERFALL_INSETS.left, 0, WATERFALL_INSETS.right, 0, mDisplayFrame);
- assertInsetBy(WATERFALL_INSETS.left, 0, WATERFALL_INSETS.right, 0, mParentFrame);
- assertInsetBy(WATERFALL_INSETS.left, 0, WATERFALL_INSETS.right, 0, mFrame);
+ assertInsetBy(WATERFALL_INSETS.left, 0, WATERFALL_INSETS.right, 0, mOutFrames.displayFrame);
+ assertInsetBy(WATERFALL_INSETS.left, 0, WATERFALL_INSETS.right, 0, mOutFrames.parentFrame);
+ assertInsetBy(WATERFALL_INSETS.left, 0, WATERFALL_INSETS.right, 0, mOutFrames.frame);
}
@Test
@@ -384,11 +386,11 @@ public class WindowLayoutTests {
computeFrames();
assertInsetBy(WATERFALL_INSETS.left, STATUS_BAR_HEIGHT, WATERFALL_INSETS.right, 0,
- mDisplayFrame);
+ mOutFrames.displayFrame);
assertInsetBy(WATERFALL_INSETS.left, STATUS_BAR_HEIGHT, WATERFALL_INSETS.right, 0,
- mParentFrame);
+ mOutFrames.parentFrame);
assertInsetBy(WATERFALL_INSETS.left, STATUS_BAR_HEIGHT, WATERFALL_INSETS.right, 0,
- mFrame);
+ mOutFrames.frame);
}
@Test
@@ -398,8 +400,8 @@ public class WindowLayoutTests {
mAttrs.setFitInsetsTypes(0);
computeFrames();
- assertInsetByTopBottom(0, 0, mDisplayFrame);
- assertInsetByTopBottom(0, 0, mParentFrame);
- assertInsetByTopBottom(0, 0, mFrame);
+ assertInsetByTopBottom(0, 0, mOutFrames.displayFrame);
+ assertInsetByTopBottom(0, 0, mOutFrames.parentFrame);
+ assertInsetByTopBottom(0, 0, mOutFrames.frame);
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
index 68e90e1c00d3..08320f8c423f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
@@ -161,7 +161,7 @@ public class WindowManagerServiceTests extends WindowTestsBase {
@Test
public void testDismissKeyguardCanWakeUp() {
doReturn(true).when(mWm).checkCallingPermission(anyString(), anyString());
- doReturn(true).when(mWm.mAtmService).isDreaming();
+ doReturn(true).when(mWm.mAtmService.mKeyguardController).isShowingDream();
doNothing().when(mWm.mAtmService.mTaskSupervisor).wakeUp(anyString());
mWm.dismissKeyguard(null, "test-dismiss-keyguard");
verify(mWm.mAtmService.mTaskSupervisor).wakeUp(anyString());
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
index 25d7334a529c..b4d305bbe4d0 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
@@ -932,7 +932,7 @@ public class WindowOrganizerTests extends WindowTestsBase {
mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
assertNotNull(o.mChangedInfo);
assertNotNull(o.mChangedInfo.pictureInPictureParams);
- final Rational ratio = o.mChangedInfo.pictureInPictureParams.getAspectRatioRational();
+ final Rational ratio = o.mChangedInfo.pictureInPictureParams.getAspectRatio();
assertEquals(3, ratio.getNumerator());
assertEquals(4, ratio.getDenominator());
}
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 a554fab76c2b..91bde7b31a48 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -29,6 +29,8 @@ import static android.view.Surface.ROTATION_90;
import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+import static android.view.WindowManager.LayoutParams.FLAG_SPLIT_TOUCH;
+import static android.view.WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ABOVE_SUB_PANEL;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
@@ -61,6 +63,7 @@ import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
@@ -80,6 +83,7 @@ import android.graphics.Matrix;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.IBinder;
+import android.os.InputConfig;
import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
import android.util.ArraySet;
@@ -492,6 +496,26 @@ public class WindowStateTests extends WindowTestsBase {
}
@Test
+ public void testApplyWithNextDraw() {
+ final WindowState win = createWindow(null, TYPE_APPLICATION_OVERLAY, "app");
+ final SurfaceControl.Transaction[] handledT = { null };
+ // The normal case that the draw transaction is applied with finishing drawing.
+ 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());
+
+ // If the window is gone before reporting drawn, the sync state should be cleared.
+ win.applyWithNextDraw(t -> handledT[0] = t);
+ win.destroySurfaceUnchecked();
+ assertFalse(win.useBLASTSync());
+ assertNotEquals(drawT, handledT[0]);
+ }
+
+ @Test
public void testSeamlesslyRotateWindow() {
final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
final SurfaceControl.Transaction t = spy(StubTransaction.class);
@@ -669,7 +693,7 @@ public class WindowStateTests extends WindowTestsBase {
doThrow(new RemoteException("test")).when(win.mClient).resized(any() /* frames */,
anyBoolean() /* reportDraw */, any() /* mergedConfig */,
anyBoolean() /* forceLayout */, anyBoolean() /* alwaysConsumeSystemBars */,
- anyInt() /* displayId */);
+ anyInt() /* displayId */, anyInt() /* seqId */, anyInt() /* resizeMode */);
} catch (RemoteException ignored) {
}
win.reportResized();
@@ -733,10 +757,15 @@ public class WindowStateTests extends WindowTestsBase {
assertFalse(win0.canReceiveTouchInput());
}
+ private boolean testFlag(int flags, int test) {
+ return (flags & test) == test;
+ }
+
@Test
public void testUpdateInputWindowHandle() {
final WindowState win = createWindow(null, TYPE_APPLICATION, "win");
win.mAttrs.inputFeatures = WindowManager.LayoutParams.INPUT_FEATURE_DISABLE_USER_ACTIVITY;
+ win.mAttrs.flags = FLAG_WATCH_OUTSIDE_TOUCH | FLAG_SPLIT_TOUCH;
final InputWindowHandle handle = new InputWindowHandle(
win.mInputWindowHandle.getInputApplicationHandle(), win.getDisplayId());
final InputWindowHandleWrapper handleWrapper = new InputWindowHandleWrapper(handle);
@@ -746,13 +775,14 @@ public class WindowStateTests extends WindowTestsBase {
mDisplayContent.getInputMonitor().populateInputWindowHandle(handleWrapper, win);
assertTrue(handleWrapper.isChanged());
+ assertTrue(testFlag(handle.inputConfig, InputConfig.WATCH_OUTSIDE_TOUCH));
+ assertFalse(testFlag(handle.inputConfig, InputConfig.PREVENT_SPLITTING));
+ assertTrue(testFlag(handle.inputConfig, InputConfig.DISABLE_USER_ACTIVITY));
// The window of standard resizable task should not use surface crop as touchable region.
assertFalse(handle.replaceTouchableRegionWithCrop);
assertEquals(inputChannelToken, handle.token);
assertEquals(win.mActivityRecord.getInputApplicationHandle(false /* update */),
handle.inputApplicationHandle);
- assertEquals(win.mAttrs.inputFeatures, handle.inputFeatures);
- assertEquals(win.isVisible(), handle.visible);
final SurfaceControl sc = mock(SurfaceControl.class);
final SurfaceControl.Transaction transaction = mSystemServicesTestRule.mTransaction;
@@ -778,21 +808,18 @@ public class WindowStateTests extends WindowTestsBase {
assertEquals(rotatedBounds, handle.touchableRegion.getBounds());
// Populate as an overlay to disable the input of window.
- InputMonitor.populateOverlayInputInfo(handleWrapper, false /* isVisible */);
+ InputMonitor.populateOverlayInputInfo(handleWrapper);
// The overlay attributes should be set.
assertTrue(handleWrapper.isChanged());
- assertFalse(handle.focusable);
- assertFalse(handle.visible);
+ assertFalse(handleWrapper.isFocusable());
assertNull(handle.token);
assertEquals(0L, handle.dispatchingTimeoutMillis);
- assertEquals(WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL,
- handle.inputFeatures);
+ assertTrue(testFlag(handle.inputConfig, InputConfig.NO_INPUT_CHANNEL));
}
@Test
public void testHasActiveVisibleWindow() {
final int uid = ActivityBuilder.DEFAULT_FAKE_UID;
- mAtm.mActiveUids.onUidActive(uid, 0 /* any proc state */);
final WindowState app = createWindow(null, TYPE_APPLICATION, "app", uid);
app.mActivityRecord.setVisible(false);
@@ -820,6 +847,11 @@ public class WindowStateTests extends WindowTestsBase {
// Make the application overlay window visible. It should be a valid active visible window.
overlay.onSurfaceShownChanged(true);
assertTrue(mAtm.hasActiveVisibleWindow(uid));
+
+ // The number of windows should be independent of the existence of uid state.
+ mAtm.mActiveUids.onUidInactive(uid);
+ mAtm.mActiveUids.onUidActive(uid, 0 /* any proc state */);
+ assertTrue(mAtm.mActiveUids.hasNonAppVisibleWindow(uid));
}
@UseTestDisplay(addWindows = W_ACTIVITY)
@@ -917,6 +949,46 @@ public class WindowStateTests extends WindowTestsBase {
assertFalse(app2.getInsetsState().getSource(ITYPE_IME).isVisible());
}
+ @Test
+ public void testAdjustImeInsetsVisibilityWhenSwitchingApps_toAppInMultiWindowMode() {
+ final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
+ final WindowState app2 = createWindow(null, WINDOWING_MODE_MULTI_WINDOW,
+ ACTIVITY_TYPE_STANDARD, TYPE_APPLICATION, mDisplayContent, "app2");
+ final WindowState imeWindow = createWindow(null, TYPE_APPLICATION, "imeWindow");
+ spyOn(imeWindow);
+ doReturn(true).when(imeWindow).isVisible();
+ mDisplayContent.mInputMethodWindow = imeWindow;
+
+ final InsetsStateController controller = mDisplayContent.getInsetsStateController();
+ controller.getImeSourceProvider().setWindowContainer(imeWindow, null, null);
+
+ // Simulate app2 in multi-window mode is going to background to switch to the fullscreen
+ // app which requests IME with updating all windows Insets State when IME is above app.
+ app2.mActivityRecord.mImeInsetsFrozenUntilStartInput = true;
+ mDisplayContent.setImeLayeringTarget(app);
+ mDisplayContent.setImeInputTarget(app);
+ assertTrue(mDisplayContent.shouldImeAttachedToApp());
+ controller.getImeSourceProvider().scheduleShowImePostLayout(app);
+ controller.getImeSourceProvider().getSource().setVisible(true);
+ controller.updateAboveInsetsState(false);
+
+ // Expect app windows behind IME can receive IME insets visible,
+ // but not for app2 in background.
+ assertTrue(app.getInsetsState().getSource(ITYPE_IME).isVisible());
+ assertFalse(app2.getInsetsState().getSource(ITYPE_IME).isVisible());
+
+ // Simulate app plays closing transition to app2.
+ // And app2 is now IME layering target but not yet to be the IME input target.
+ mDisplayContent.setImeLayeringTarget(app2);
+ app.mActivityRecord.commitVisibility(false, false);
+ assertTrue(app.mActivityRecord.mLastImeShown);
+ assertTrue(app.mActivityRecord.mImeInsetsFrozenUntilStartInput);
+
+ // Verify the IME insets is still visible on app, but not for app2 during task switching.
+ assertTrue(app.getInsetsState().getSource(ITYPE_IME).isVisible());
+ assertFalse(app2.getInsetsState().getSource(ITYPE_IME).isVisible());
+ }
+
@UseTestDisplay(addWindows = {W_ACTIVITY})
@Test
public void testUpdateImeControlTargetWhenLeavingMultiWindow() {
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 eea3f844b40f..0f223ca037ee 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java
@@ -293,8 +293,7 @@ public class ZOrderingTests extends WindowTestsBase {
public void testAssignWindowLayers_ForImeWithAppTargetAndAppAbove() {
final WindowState appBelowImeTarget = createWindow("appBelowImeTarget");
final WindowState imeAppTarget = createWindow("imeAppTarget");
- final WindowState appAboveImeTarget = createWindow(imeAppTarget, TYPE_APPLICATION,
- "appAboveImeTarget");
+ final WindowState appAboveImeTarget = createWindow("appAboveImeTarget");
mDisplayContent.setImeLayeringTarget(imeAppTarget);
mDisplayContent.setImeControlTarget(imeAppTarget);
diff --git a/services/translation/java/com/android/server/translation/TranslationManagerServiceImpl.java b/services/translation/java/com/android/server/translation/TranslationManagerServiceImpl.java
index 364d592d7ce0..3833ceb3122e 100644
--- a/services/translation/java/com/android/server/translation/TranslationManagerServiceImpl.java
+++ b/services/translation/java/com/android/server/translation/TranslationManagerServiceImpl.java
@@ -17,6 +17,7 @@
package com.android.server.translation;
import static android.view.translation.TranslationManager.EXTRA_CAPABILITIES;
+import static android.view.translation.UiTranslationManager.EXTRA_PACKAGE_NAME;
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;
@@ -184,7 +185,7 @@ final class TranslationManagerServiceImpl extends
componentName.getPackageName(), 0, userId).uid;
}
} catch (PackageManager.NameNotFoundException e) {
- Slog.d(TAG, "Cannot find packageManager for" + componentName);
+ Slog.d(TAG, "Cannot find packageManager for" + componentName);
}
return translationActivityUid;
}
@@ -192,19 +193,22 @@ final class TranslationManagerServiceImpl extends
@GuardedBy("mLock")
public void onTranslationFinishedLocked(boolean activityDestroyed, IBinder token,
ComponentName componentName) {
- int translationActivityUid =
+ final int translationActivityUid =
getActivityUidByComponentName(getContext(), componentName, getUserId());
+ final String packageName = componentName.getPackageName();
if (activityDestroyed) {
// In the Activity destroy case, we only calls onTranslationFinished() in
// non-finisTranslation() state. If there is a finisTranslation() calls by apps, we
// should remove the waiting callback to avoid callback twice.
- invokeCallbacks(STATE_UI_TRANSLATION_FINISHED, /* sourceSpec= */
- null, /* targetSpec= */null, translationActivityUid);
+ invokeCallbacks(STATE_UI_TRANSLATION_FINISHED,
+ /* sourceSpec= */ null, /* targetSpec= */ null,
+ packageName, translationActivityUid);
mWaitingFinishedCallbackActivities.remove(token);
} else {
if (mWaitingFinishedCallbackActivities.contains(token)) {
- invokeCallbacks(STATE_UI_TRANSLATION_FINISHED, /* sourceSpec= */
- null, /* targetSpec= */null, translationActivityUid);
+ invokeCallbacks(STATE_UI_TRANSLATION_FINISHED,
+ /* sourceSpec= */ null, /* targetSpec= */ null,
+ packageName, translationActivityUid);
mWaitingFinishedCallbackActivities.remove(token);
}
}
@@ -223,25 +227,25 @@ final class TranslationManagerServiceImpl extends
+ "state for token=" + token + " taskId=" + taskId + " for state= " + state);
return;
}
+ mLastActivityTokens = new WeakReference<>(taskTopActivityTokens);
if (state == STATE_UI_TRANSLATION_FINISHED) {
mWaitingFinishedCallbackActivities.add(token);
}
- int translationActivityUid = -1;
+ IBinder activityToken = taskTopActivityTokens.getActivityToken();
try {
- IBinder activityToken = taskTopActivityTokens.getActivityToken();
taskTopActivityTokens.getApplicationThread().updateUiTranslationState(
activityToken, state, sourceSpec, targetSpec,
viewIds, uiTranslationSpec);
- mLastActivityTokens = new WeakReference<>(taskTopActivityTokens);
- ComponentName componentName =
- mActivityTaskManagerInternal.getActivityName(activityToken);
- translationActivityUid =
- getActivityUidByComponentName(getContext(), componentName, getUserId());
} catch (RemoteException e) {
Slog.w(TAG, "Update UiTranslationState fail: " + e);
}
+
+ ComponentName componentName = mActivityTaskManagerInternal.getActivityName(activityToken);
+ int translationActivityUid =
+ getActivityUidByComponentName(getContext(), componentName, getUserId());
if (state != STATE_UI_TRANSLATION_FINISHED) {
- invokeCallbacks(state, sourceSpec, targetSpec, translationActivityUid);
+ invokeCallbacks(state, sourceSpec, targetSpec, componentName.getPackageName(),
+ translationActivityUid);
}
}
@@ -255,7 +259,7 @@ final class TranslationManagerServiceImpl extends
try (TransferPipe tp = new TransferPipe()) {
activityTokens.getApplicationThread().dumpActivity(tp.getWriteFd(),
activityTokens.getActivityToken(), prefix,
- new String[] {
+ new String[]{
Activity.DUMP_ARG_DUMP_DUMPABLE,
UiTranslationController.DUMPABLE_NAME
});
@@ -266,20 +270,24 @@ final class TranslationManagerServiceImpl extends
pw.println(prefix + "Got a RemoteException while dumping the activity");
}
} else {
- pw.print(prefix); pw.println("No requested UiTranslation Activity.");
+ pw.print(prefix);
+ pw.println("No requested UiTranslation Activity.");
}
final int waitingFinishCallbackSize = mWaitingFinishedCallbackActivities.size();
if (waitingFinishCallbackSize > 0) {
- pw.print(prefix); pw.print("number waiting finish callback activities: ");
+ pw.print(prefix);
+ pw.print("number waiting finish callback activities: ");
pw.println(waitingFinishCallbackSize);
for (IBinder activityToken : mWaitingFinishedCallbackActivities) {
- pw.print(prefix); pw.print("activityToken: "); pw.println(activityToken);
+ pw.print(prefix);
+ pw.print("activityToken: ");
+ pw.println(activityToken);
}
}
}
private void invokeCallbacks(
- int state, TranslationSpec sourceSpec, TranslationSpec targetSpec,
+ int state, TranslationSpec sourceSpec, TranslationSpec targetSpec, String packageName,
int translationActivityUid) {
Bundle res = new Bundle();
res.putInt(EXTRA_STATE, state);
@@ -288,6 +296,7 @@ final class TranslationManagerServiceImpl extends
res.putSerializable(EXTRA_SOURCE_LOCALE, sourceSpec.getLocale());
res.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)
@@ -299,6 +308,7 @@ final class TranslationManagerServiceImpl extends
} catch (RemoteException e) {
Slog.w(TAG, "Failed to invoke UiTranslationStateCallback: " + e);
}
+ return;
}
// Code here is non-optimal since it's temporary..
boolean isIme = false;
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index b9abbf09e74d..366ab0968bb8 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -2015,7 +2015,7 @@ public class UsageStatsService extends SystemService implements
== PackageManager.PERMISSION_GRANTED;
}
- private boolean hasPermissions(String callingPackage, String... permissions) {
+ private boolean hasPermissions(String... permissions) {
final int callingUid = Binder.getCallingUid();
if (callingUid == Process.SYSTEM_UID) {
// Caller is the system, so proceed.
@@ -2578,7 +2578,7 @@ public class UsageStatsService extends SystemService implements
String callingPackage) {
final int callingUid = Binder.getCallingUid();
final DevicePolicyManagerInternal dpmInternal = getDpmInternal();
- if (!hasPermissions(callingPackage,
+ if (!hasPermissions(
Manifest.permission.SUSPEND_APPS, Manifest.permission.OBSERVE_APP_USAGE)
&& (dpmInternal == null || !dpmInternal.isActiveSupervisionApp(callingUid))) {
throw new SecurityException("Caller must be the active supervision app or "
@@ -2605,7 +2605,7 @@ public class UsageStatsService extends SystemService implements
public void unregisterAppUsageLimitObserver(int observerId, String callingPackage) {
final int callingUid = Binder.getCallingUid();
final DevicePolicyManagerInternal dpmInternal = getDpmInternal();
- if (!hasPermissions(callingPackage,
+ if (!hasPermissions(
Manifest.permission.SUSPEND_APPS, Manifest.permission.OBSERVE_APP_USAGE)
&& (dpmInternal == null || !dpmInternal.isActiveSupervisionApp(callingUid))) {
throw new SecurityException("Caller must be the active supervision app or "
@@ -2703,8 +2703,7 @@ public class UsageStatsService extends SystemService implements
@Override
public long getLastTimeAnyComponentUsed(String packageName, String callingPackage) {
- if (!hasPermissions(
- callingPackage, android.Manifest.permission.INTERACT_ACROSS_USERS)) {
+ if (!hasPermissions(android.Manifest.permission.INTERACT_ACROSS_USERS)) {
throw new SecurityException("Caller doesn't have INTERACT_ACROSS_USERS permission");
}
if (!hasPermission(callingPackage)) {
@@ -2731,13 +2730,19 @@ public class UsageStatsService extends SystemService implements
throw new IllegalArgumentException("id needs to be >=0");
}
- final int callingUid = Binder.getCallingUid();
- if (!hasPermission(callingPackage)) {
- throw new SecurityException(
- "Caller does not have the permission needed to call this API; "
- + "callingPackage=" + callingPackage
- + ", callingUid=" + callingUid);
+ final int result = getContext().checkCallingOrSelfPermission(
+ android.Manifest.permission.ACCESS_BROADCAST_RESPONSE_STATS);
+ // STOPSHIP (206518114): Temporarily check for PACKAGE_USAGE_STATS permission as well
+ // until the clients switch to using the new permission.
+ if (result != PackageManager.PERMISSION_GRANTED) {
+ if (!hasPermission(callingPackage)) {
+ throw new SecurityException(
+ "Caller does not have the permission needed to call this API; "
+ + "callingPackage=" + callingPackage
+ + ", callingUid=" + Binder.getCallingUid());
+ }
}
+ final int callingUid = Binder.getCallingUid();
userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), callingUid,
userId, false /* allowAll */, false /* requireFull */,
"queryBroadcastResponseStats" /* name */, callingPackage);
@@ -2757,13 +2762,20 @@ public class UsageStatsService extends SystemService implements
throw new IllegalArgumentException("id needs to be >=0");
}
- final int callingUid = Binder.getCallingUid();
- if (!hasPermission(callingPackage)) {
- throw new SecurityException(
- "Caller does not have the permission needed to call this API; "
- + "callingPackage=" + callingPackage
- + ", callingUid=" + callingUid);
+
+ final int result = getContext().checkCallingOrSelfPermission(
+ android.Manifest.permission.ACCESS_BROADCAST_RESPONSE_STATS);
+ // STOPSHIP (206518114): Temporarily check for PACKAGE_USAGE_STATS permission as well
+ // until the clients switch to using the new permission.
+ if (result != PackageManager.PERMISSION_GRANTED) {
+ if (!hasPermission(callingPackage)) {
+ throw new SecurityException(
+ "Caller does not have the permission needed to call this API; "
+ + "callingPackage=" + callingPackage
+ + ", callingUid=" + Binder.getCallingUid());
+ }
}
+ final int callingUid = Binder.getCallingUid();
userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), callingUid,
userId, false /* allowAll */, false /* requireFull */,
"clearBroadcastResponseStats" /* name */, callingPackage);
@@ -2775,18 +2787,35 @@ public class UsageStatsService extends SystemService implements
public void clearBroadcastEvents(@NonNull String callingPackage, @UserIdInt int userId) {
Objects.requireNonNull(callingPackage);
- final int callingUid = Binder.getCallingUid();
- if (!hasPermission(callingPackage)) {
- throw new SecurityException(
- "Caller does not have the permission needed to call this API; "
- + "callingPackage=" + callingPackage
- + ", callingUid=" + callingUid);
+ final int result = getContext().checkCallingOrSelfPermission(
+ android.Manifest.permission.ACCESS_BROADCAST_RESPONSE_STATS);
+ // STOPSHIP (206518114): Temporarily check for PACKAGE_USAGE_STATS permission as well
+ // until the clients switch to using the new permission.
+ if (result != PackageManager.PERMISSION_GRANTED) {
+ if (!hasPermission(callingPackage)) {
+ throw new SecurityException(
+ "Caller does not have the permission needed to call this API; "
+ + "callingPackage=" + callingPackage
+ + ", callingUid=" + Binder.getCallingUid());
+ }
}
+ final int callingUid = Binder.getCallingUid();
userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), callingUid,
userId, false /* allowAll */, false /* requireFull */,
"clearBroadcastResponseStats" /* name */, callingPackage);
mResponseStatsTracker.clearBroadcastEvents(callingUid, userId);
}
+
+ @Override
+ @Nullable
+ public String getAppStandbyConstant(@NonNull String key) {
+ Objects.requireNonNull(key);
+
+ if (!hasPermissions(Manifest.permission.READ_DEVICE_CONFIG)) {
+ throw new SecurityException("Caller doesn't have READ_DEVICE_CONFIG permission");
+ }
+ return mAppStandby.getAppStandbyConstant(key);
+ }
}
void registerAppUsageObserver(int callingUid, int observerId, String[] packages,
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index 1999cfc706b4..b290669e103e 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -640,7 +640,7 @@ public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObser
Slog.e(TAG, "unknown state " + state);
return;
}
- removeMessages(MSG_UPDATE_STATE);
+ if (configured == 0) removeMessages(MSG_UPDATE_STATE);
if (connected == 1) removeMessages(MSG_FUNCTION_SWITCH_TIMEOUT);
Message msg = Message.obtain(this, MSG_UPDATE_STATE);
msg.arg1 = connected;
diff --git a/services/usb/java/com/android/server/usb/UsbHostManager.java b/services/usb/java/com/android/server/usb/UsbHostManager.java
index a70b033237cf..dd58d3879bb2 100644
--- a/services/usb/java/com/android/server/usb/UsbHostManager.java
+++ b/services/usb/java/com/android/server/usb/UsbHostManager.java
@@ -496,11 +496,13 @@ public class UsbHostManager {
// MIDI
ArrayList<UsbDirectMidiDevice> midiDevices =
mMidiDevices.remove(deviceAddress);
- for (UsbDirectMidiDevice midiDevice : midiDevices) {
- if (midiDevice != null) {
- Slog.i(TAG, "USB MIDI Device Removed: " + deviceAddress);
- IoUtils.closeQuietly(midiDevice);
+ if (midiDevices != null) {
+ for (UsbDirectMidiDevice midiDevice : midiDevices) {
+ if (midiDevice != null) {
+ IoUtils.closeQuietly(midiDevice);
+ }
}
+ Slog.i(TAG, "USB MIDI Devices Removed: " + deviceAddress);
}
getCurrentUserSettings().usbDeviceRemoved(device);
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
index 24ce7e76a49c..c8bcb83cae74 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
@@ -84,6 +84,9 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
private static final int INVALID_VALUE = Integer.MIN_VALUE;
+ /** Maximum time to wait for a model stop confirmation before giving up. */
+ private static final long STOP_TIMEOUT_MS = 5000;
+
/** The {@link ModuleProperties} for the system, or null if none exists. */
final ModuleProperties mModuleProperties;
@@ -831,7 +834,7 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
}
if (!event.recognitionStillActive) {
- model.setStopped();
+ model.setStoppedLocked();
}
try {
@@ -918,7 +921,7 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
MetricsLogger.count(mContext, "sth_recognition_aborted", 1);
ModelData modelData = getModelDataForLocked(event.soundModelHandle);
if (modelData != null && modelData.isModelStarted()) {
- modelData.setStopped();
+ modelData.setStoppedLocked();
try {
modelData.getCallback().onRecognitionPaused();
} catch (DeadObjectException e) {
@@ -972,7 +975,7 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
}
if (!event.recognitionStillActive) {
- modelData.setStopped();
+ modelData.setStoppedLocked();
}
try {
@@ -1200,7 +1203,7 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
if (modelData.isModelStarted()) {
Slog.d(TAG, "Stopping previously started dangling model " + modelData.getHandle());
if (mModule.stopRecognition(modelData.getHandle()) == STATUS_OK) {
- modelData.setStopped();
+ modelData.setStoppedLocked();
modelData.setRequested(false);
} else {
Slog.e(TAG, "Failed to stop model " + modelData.getHandle());
@@ -1249,7 +1252,7 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
private ModelData getOrCreateGenericModelDataLocked(UUID modelId) {
ModelData modelData = mModelDataMap.get(modelId);
if (modelData == null) {
- modelData = ModelData.createGenericModelData(modelId);
+ modelData = createGenericModelData(modelId);
mModelDataMap.put(modelId, modelData);
} else if (!modelData.isGenericModel()) {
Slog.e(TAG, "UUID already used for non-generic model.");
@@ -1281,7 +1284,7 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
mKeyphraseUuidMap.remove(keyphraseId);
mModelDataMap.remove(modelId);
mKeyphraseUuidMap.put(keyphraseId, modelId);
- ModelData modelData = ModelData.createKeyphraseModelData(modelId);
+ ModelData modelData = createKeyphraseModelData(modelId);
mModelDataMap.put(modelId, modelData);
return modelData;
}
@@ -1413,18 +1416,26 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
Slog.w(TAG, "RemoteException in onError", e);
}
}
- } else {
- modelData.setStopped();
- MetricsLogger.count(mContext, "sth_stop_recognition_success", 1);
- // Notify of pause if needed.
- if (notify) {
- try {
- callback.onRecognitionPaused();
- } catch (DeadObjectException e) {
- forceStopAndUnloadModelLocked(modelData, e);
- } catch (RemoteException e) {
- Slog.w(TAG, "RemoteException in onRecognitionPaused", e);
- }
+ return status;
+ }
+
+ // Wait for model to be stopped.
+ try {
+ modelData.waitStoppedLocked(STOP_TIMEOUT_MS);
+ } catch (InterruptedException e) {
+ Slog.e(TAG, "Didn't receive model stop callback");
+ return SoundTrigger.STATUS_ERROR;
+ }
+
+ MetricsLogger.count(mContext, "sth_stop_recognition_success", 1);
+ // Notify of pause if needed.
+ if (notify) {
+ try {
+ callback.onRecognitionPaused();
+ } catch (DeadObjectException e) {
+ forceStopAndUnloadModelLocked(modelData, e);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "RemoteException in onRecognitionPaused", e);
}
}
if (DBG) {
@@ -1459,7 +1470,7 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
// This class encapsulates the callbacks, state, handles and any other information that
// represents a model.
- private static class ModelData {
+ private class ModelData {
// Model not loaded (and hence not started).
static final int MODEL_NOTLOADED = 0;
@@ -1516,17 +1527,9 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
mModelType = modelType;
}
- static ModelData createKeyphraseModelData(UUID modelId) {
- return new ModelData(modelId, SoundModel.TYPE_KEYPHRASE);
- }
-
- static ModelData createGenericModelData(UUID modelId) {
- return new ModelData(modelId, SoundModel.TYPE_GENERIC_SOUND);
- }
-
// Note that most of the functionality in this Java class will not work for
// SoundModel.TYPE_UNKNOWN nevertheless we have it since lower layers support it.
- static ModelData createModelDataOfUnknownType(UUID modelId) {
+ ModelData createModelDataOfUnknownType(UUID modelId) {
return new ModelData(modelId, SoundModel.TYPE_UNKNOWN);
}
@@ -1550,8 +1553,20 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
mModelState = MODEL_STARTED;
}
- synchronized void setStopped() {
+ synchronized void setStoppedLocked() {
mModelState = MODEL_LOADED;
+ mLock.notifyAll();
+ }
+
+ void waitStoppedLocked(long timeoutMs) throws InterruptedException {
+ long deadline = System.currentTimeMillis() + timeoutMs;
+ while (mModelState == MODEL_STARTED) {
+ long waitTime = deadline - System.currentTimeMillis();
+ if (waitTime <= 0) {
+ throw new InterruptedException();
+ }
+ mLock.wait(waitTime);
+ }
}
synchronized void setLoaded() {
@@ -1571,6 +1586,7 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
mRecognitionConfig = null;
mRequested = false;
mCallback = null;
+ notifyAll();
}
synchronized void clearCallback() {
@@ -1675,4 +1691,12 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
return "Model type: " + type + "\n";
}
}
+
+ ModelData createKeyphraseModelData(UUID modelId) {
+ return new ModelData(modelId, SoundModel.TYPE_KEYPHRASE);
+ }
+
+ ModelData createGenericModelData(UUID modelId) {
+ return new ModelData(modelId, SoundModel.TYPE_GENERIC_SOUND);
+ }
}
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
index 84bd98347dab..d527a230a97b 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
@@ -20,9 +20,29 @@ import static android.Manifest.permission.CAPTURE_AUDIO_HOTWORD;
import static android.Manifest.permission.RECORD_AUDIO;
import static android.service.voice.HotwordDetectionService.AUDIO_SOURCE_EXTERNAL;
import static android.service.voice.HotwordDetectionService.AUDIO_SOURCE_MICROPHONE;
+import static android.service.voice.HotwordDetectionService.INITIALIZATION_STATUS_SUCCESS;
import static android.service.voice.HotwordDetectionService.INITIALIZATION_STATUS_UNKNOWN;
import static android.service.voice.HotwordDetectionService.KEY_INITIALIZATION_STATUS;
+import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTION_SERVICE_INIT_RESULT_REPORTED__RESULT__CALLBACK_INIT_STATE_ERROR;
+import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTION_SERVICE_INIT_RESULT_REPORTED__RESULT__CALLBACK_INIT_STATE_SUCCESS;
+import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTION_SERVICE_INIT_RESULT_REPORTED__RESULT__CALLBACK_INIT_STATE_UNKNOWN_NO_VALUE;
+import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTION_SERVICE_INIT_RESULT_REPORTED__RESULT__CALLBACK_INIT_STATE_UNKNOWN_OVER_MAX_CUSTOM_VALUE;
+import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTION_SERVICE_INIT_RESULT_REPORTED__RESULT__CALLBACK_INIT_STATE_UNKNOWN_TIMEOUT;
+import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTION_SERVICE_RESTARTED__REASON__AUDIO_SERVICE_DIED;
+import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTION_SERVICE_RESTARTED__REASON__SCHEDULE;
+import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_EVENTS__EVENT__CALLBACK_UPDATE_STATE_AFTER_TIMEOUT;
+import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_EVENTS__EVENT__ON_CONNECTED;
+import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_EVENTS__EVENT__REQUEST_BIND_SERVICE;
+import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_EVENTS__EVENT__REQUEST_BIND_SERVICE_FAIL;
+import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_EVENTS__EVENT__REQUEST_UPDATE_STATE;
+import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__DETECTOR_TYPE__NORMAL_DETECTOR;
+import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__DETECTOR_TYPE__TRUSTED_DETECTOR_DSP;
+import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__DETECTED;
+import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__DETECT_EXCEPTION;
+import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__DETECT_TIMEOUT;
+import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__KEYPHRASE_TRIGGER;
+import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__REJECTED;
import static com.android.server.voiceinteraction.SoundTriggerSessionPermissionsDecorator.enforcePermissionForPreflight;
import android.annotation.NonNull;
@@ -48,6 +68,7 @@ import android.os.PersistableBundle;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SharedMemory;
+import android.provider.DeviceConfig;
import android.service.voice.HotwordDetectedResult;
import android.service.voice.HotwordDetectionService;
import android.service.voice.HotwordDetector;
@@ -91,32 +112,56 @@ final class HotwordDetectionConnection {
private static final String TAG = "HotwordDetectionConnection";
static final boolean DEBUG = false;
+ private static final String KEY_RESTART_PERIOD_IN_SECONDS = "restart_period_in_seconds";
// TODO: These constants need to be refined.
- private static final long VALIDATION_TIMEOUT_MILLIS = 3000;
+ private static final long VALIDATION_TIMEOUT_MILLIS = 4000;
private static final long MAX_UPDATE_TIMEOUT_MILLIS = 6000;
private static final Duration MAX_UPDATE_TIMEOUT_DURATION =
Duration.ofMillis(MAX_UPDATE_TIMEOUT_MILLIS);
private static final long RESET_DEBUG_HOTWORD_LOGGING_TIMEOUT_MILLIS = 60 * 60 * 1000; // 1 hour
+ /**
+ * Time after which each HotwordDetectionService process is stopped and replaced by a new one.
+ * 0 indicates no restarts.
+ */
+ private static final int RESTART_PERIOD_SECONDS =
+ DeviceConfig.getInt(DeviceConfig.NAMESPACE_VOICE_INTERACTION,
+ KEY_RESTART_PERIOD_IN_SECONDS, 0);
+ private static final int MAX_ISOLATED_PROCESS_NUMBER = 10;
+
+ // Hotword metrics
+ private static final int METRICS_INIT_UNKNOWN_TIMEOUT =
+ HOTWORD_DETECTION_SERVICE_INIT_RESULT_REPORTED__RESULT__CALLBACK_INIT_STATE_UNKNOWN_TIMEOUT;
+ private static final int METRICS_INIT_UNKNOWN_NO_VALUE =
+ HOTWORD_DETECTION_SERVICE_INIT_RESULT_REPORTED__RESULT__CALLBACK_INIT_STATE_UNKNOWN_NO_VALUE;
+ private static final int METRICS_INIT_UNKNOWN_OVER_MAX_CUSTOM_VALUE =
+ HOTWORD_DETECTION_SERVICE_INIT_RESULT_REPORTED__RESULT__CALLBACK_INIT_STATE_UNKNOWN_OVER_MAX_CUSTOM_VALUE;
+ private static final int METRICS_INIT_CALLBACK_STATE_ERROR =
+ HOTWORD_DETECTION_SERVICE_INIT_RESULT_REPORTED__RESULT__CALLBACK_INIT_STATE_ERROR;
+ private static final int METRICS_INIT_CALLBACK_STATE_SUCCESS =
+ HOTWORD_DETECTION_SERVICE_INIT_RESULT_REPORTED__RESULT__CALLBACK_INIT_STATE_SUCCESS;
private final Executor mAudioCopyExecutor = Executors.newCachedThreadPool();
// TODO: This may need to be a Handler(looper)
private final ScheduledExecutorService mScheduledExecutorService =
Executors.newSingleThreadScheduledExecutor();
+ @Nullable private final ScheduledFuture<?> mCancellationTaskFuture;
private final AtomicBoolean mUpdateStateAfterStartFinished = new AtomicBoolean(false);
private final IBinder.DeathRecipient mAudioServerDeathRecipient = this::audioServerDied;
private final @NonNull ServiceConnectionFactory mServiceConnectionFactory;
private final IHotwordRecognitionStatusCallback mCallback;
+ private final int mDetectorType;
final Object mLock;
final int mVoiceInteractionServiceUid;
final ComponentName mDetectionComponentName;
final int mUser;
final Context mContext;
+
volatile HotwordDetectionServiceIdentity mIdentity;
private IMicrophoneHotwordDetectionVoiceInteractionCallback mSoftwareCallback;
private Instant mLastRestartInstant;
- private ScheduledFuture<?> mCancellationTaskFuture;
+ private ScheduledFuture<?> mCancellationKeyPhraseDetectionFuture;
private ScheduledFuture<?> mDebugHotwordLoggingTimeoutFuture = null;
/** Identity used for attributing app ops when delivering data to the Interactor. */
@@ -132,7 +177,6 @@ final class HotwordDetectionConnection {
private @NonNull ServiceConnection mRemoteHotwordDetectionService;
private IBinder mAudioFlinger;
private boolean mDebugHotwordLogging = false;
- private final int mDetectorType;
HotwordDetectionConnection(Object lock, Context context, int voiceInteractionServiceUid,
Identity voiceInteractorIdentity, ComponentName serviceName, int userId,
@@ -162,14 +206,20 @@ final class HotwordDetectionConnection {
mLastRestartInstant = Instant.now();
updateStateAfterProcessStart(options, sharedMemory);
- // TODO(volnov): we need to be smarter here, e.g. schedule it a bit more often, but wait
- // until the current session is closed.
- mCancellationTaskFuture = mScheduledExecutorService.scheduleAtFixedRate(() -> {
- Slog.v(TAG, "Time to restart the process, TTL has passed");
- synchronized (mLock) {
- restartProcessLocked();
- }
- }, 30, 30, TimeUnit.MINUTES);
+ if (RESTART_PERIOD_SECONDS <= 0) {
+ mCancellationTaskFuture = null;
+ } else {
+ // TODO(volnov): we need to be smarter here, e.g. schedule it a bit more often, but wait
+ // until the current session is closed.
+ mCancellationTaskFuture = mScheduledExecutorService.scheduleAtFixedRate(() -> {
+ Slog.v(TAG, "Time to restart the process, TTL has passed");
+ synchronized (mLock) {
+ restartProcessLocked();
+ HotwordMetricsLogger.writeServiceRestartEvent(mDetectorType,
+ HOTWORD_DETECTION_SERVICE_RESTARTED__REASON__SCHEDULE);
+ }
+ }, RESTART_PERIOD_SECONDS, RESTART_PERIOD_SECONDS, TimeUnit.SECONDS);
+ }
}
private void initAudioFlingerLocked() {
@@ -200,6 +250,8 @@ final class HotwordDetectionConnection {
// We restart the process instead of simply sending over the new binder, to avoid race
// conditions with audio reading in the service.
restartProcessLocked();
+ HotwordMetricsLogger.writeServiceRestartEvent(mDetectorType,
+ HOTWORD_DETECTION_SERVICE_RESTARTED__REASON__AUDIO_SERVICE_DIED);
}
}
@@ -219,26 +271,32 @@ final class HotwordDetectionConnection {
future.complete(null);
if (mUpdateStateAfterStartFinished.getAndSet(true)) {
Slog.w(TAG, "call callback after timeout");
+ HotwordMetricsLogger.writeDetectorEvent(mDetectorType,
+ HOTWORD_DETECTOR_EVENTS__EVENT__CALLBACK_UPDATE_STATE_AFTER_TIMEOUT,
+ mVoiceInteractionServiceUid);
return;
}
- int status = bundle != null ? bundle.getInt(
- KEY_INITIALIZATION_STATUS,
- INITIALIZATION_STATUS_UNKNOWN)
- : INITIALIZATION_STATUS_UNKNOWN;
- // Add the protection to avoid unexpected status
- if (status > HotwordDetectionService.getMaxCustomInitializationStatus()
- && status != INITIALIZATION_STATUS_UNKNOWN) {
- status = INITIALIZATION_STATUS_UNKNOWN;
- }
+ Pair<Integer, Integer> statusResultPair = getInitStatusAndMetricsResult(bundle);
+ int status = statusResultPair.first;
+ int initResultMetricsResult = statusResultPair.second;
try {
mCallback.onStatusReported(status);
+ HotwordMetricsLogger.writeServiceInitResultEvent(mDetectorType,
+ initResultMetricsResult);
} catch (RemoteException e) {
+ // TODO: Add a new atom for RemoteException case, the error doesn't very
+ // correct here
Slog.w(TAG, "Failed to report initialization status: " + e);
+ HotwordMetricsLogger.writeServiceInitResultEvent(mDetectorType,
+ METRICS_INIT_CALLBACK_STATE_ERROR);
}
}
};
try {
service.updateState(options, sharedMemory, statusCallback);
+ HotwordMetricsLogger.writeDetectorEvent(mDetectorType,
+ HOTWORD_DETECTOR_EVENTS__EVENT__REQUEST_UPDATE_STATE,
+ mVoiceInteractionServiceUid);
} catch (RemoteException e) {
// TODO: (b/181842909) Report an error to voice interactor
Slog.w(TAG, "Failed to updateState for HotwordDetectionService", e);
@@ -253,8 +311,12 @@ final class HotwordDetectionConnection {
}
try {
mCallback.onStatusReported(INITIALIZATION_STATUS_UNKNOWN);
+ HotwordMetricsLogger.writeServiceInitResultEvent(mDetectorType,
+ METRICS_INIT_UNKNOWN_TIMEOUT);
} catch (RemoteException e) {
Slog.w(TAG, "Failed to report initialization status UNKNOWN", e);
+ HotwordMetricsLogger.writeServiceInitResultEvent(mDetectorType,
+ METRICS_INIT_CALLBACK_STATE_ERROR);
}
} else if (err != null) {
Slog.w(TAG, "Failed to update state: " + err);
@@ -264,6 +326,24 @@ final class HotwordDetectionConnection {
});
}
+ private static Pair<Integer, Integer> getInitStatusAndMetricsResult(Bundle bundle) {
+ if (bundle == null) {
+ return new Pair<>(INITIALIZATION_STATUS_UNKNOWN, METRICS_INIT_UNKNOWN_NO_VALUE);
+ }
+ int status = bundle.getInt(KEY_INITIALIZATION_STATUS, INITIALIZATION_STATUS_UNKNOWN);
+ if (status > HotwordDetectionService.getMaxCustomInitializationStatus()) {
+ return new Pair<>(INITIALIZATION_STATUS_UNKNOWN,
+ status == INITIALIZATION_STATUS_UNKNOWN
+ ? METRICS_INIT_UNKNOWN_NO_VALUE
+ : METRICS_INIT_UNKNOWN_OVER_MAX_CUSTOM_VALUE);
+ }
+ // TODO: should guard against negative here
+ int metricsResult = status == INITIALIZATION_STATUS_SUCCESS
+ ? METRICS_INIT_CALLBACK_STATE_SUCCESS
+ : METRICS_INIT_CALLBACK_STATE_ERROR;
+ return new Pair<>(status, metricsResult);
+ }
+
private boolean isBound() {
synchronized (mLock) {
return mRemoteHotwordDetectionService.isBound();
@@ -281,7 +361,9 @@ final class HotwordDetectionConnection {
removeServiceUidForAudioPolicy(mIdentity.getIsolatedUid());
}
mIdentity = null;
- mCancellationTaskFuture.cancel(/* may interrupt */ true);
+ if (mCancellationTaskFuture != null) {
+ mCancellationTaskFuture.cancel(/* may interrupt */ true);
+ }
if (mAudioFlinger != null) {
mAudioFlinger.unlinkToDeath(mAudioServerDeathRecipient, /* flags= */ 0);
}
@@ -480,12 +562,31 @@ final class HotwordDetectionConnection {
Slog.d(TAG, "onDetected");
}
synchronized (mLock) {
+ // TODO: If the dsp trigger comes in after the timeout, we will log both events.
+ // Because we don't enforce the timeout yet. We should add some synchronizations
+ // within the runnable to prevent the race condition to log both events.
+ if (mCancellationKeyPhraseDetectionFuture != null) {
+ mCancellationKeyPhraseDetectionFuture.cancel(true);
+ }
+ HotwordMetricsLogger.writeKeyphraseTriggerEvent(
+ mDetectorType,
+ HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__DETECTED);
if (!mValidatingDspTrigger) {
Slog.i(TAG, "Ignoring #onDetected due to a process restart");
+ HotwordMetricsLogger.writeKeyphraseTriggerEvent(
+ mDetectorType,
+ HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__DETECT_EXCEPTION);
return;
}
mValidatingDspTrigger = false;
- enforcePermissionsForDataDelivery();
+ try {
+ enforcePermissionsForDataDelivery();
+ } catch (SecurityException e) {
+ HotwordMetricsLogger.writeKeyphraseTriggerEvent(
+ mDetectorType,
+ HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__DETECT_EXCEPTION);
+ throw e;
+ }
externalCallback.onKeyphraseDetected(recognitionEvent, result);
if (result != null) {
Slog.i(TAG, "Egressed " + HotwordDetectedResult.getUsageSize(result)
@@ -503,8 +604,17 @@ final class HotwordDetectionConnection {
Slog.d(TAG, "onRejected");
}
synchronized (mLock) {
+ if (mCancellationKeyPhraseDetectionFuture != null) {
+ mCancellationKeyPhraseDetectionFuture.cancel(true);
+ }
+ HotwordMetricsLogger.writeKeyphraseTriggerEvent(
+ mDetectorType,
+ HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__REJECTED);
if (!mValidatingDspTrigger) {
Slog.i(TAG, "Ignoring #onRejected due to a process restart");
+ HotwordMetricsLogger.writeKeyphraseTriggerEvent(
+ mDetectorType,
+ HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__DETECT_EXCEPTION);
return;
}
mValidatingDspTrigger = false;
@@ -519,11 +629,20 @@ final class HotwordDetectionConnection {
synchronized (mLock) {
mValidatingDspTrigger = true;
mRemoteHotwordDetectionService.run(
- service -> service.detectFromDspSource(
- recognitionEvent,
- recognitionEvent.getCaptureFormat(),
- VALIDATION_TIMEOUT_MILLIS,
- internalCallback));
+ service -> {
+ // TODO: avoid allocate every time
+ mCancellationKeyPhraseDetectionFuture = mScheduledExecutorService.schedule(
+ () -> HotwordMetricsLogger
+ .writeKeyphraseTriggerEvent(mDetectorType,
+ HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__DETECT_TIMEOUT),
+ VALIDATION_TIMEOUT_MILLIS,
+ TimeUnit.MILLISECONDS);
+ service.detectFromDspSource(
+ recognitionEvent,
+ recognitionEvent.getCaptureFormat(),
+ VALIDATION_TIMEOUT_MILLIS,
+ internalCallback);
+ });
}
}
@@ -624,10 +743,16 @@ final class HotwordDetectionConnection {
}
final boolean useHotwordDetectionService = mHotwordDetectionConnection != null;
if (useHotwordDetectionService) {
+ HotwordMetricsLogger.writeKeyphraseTriggerEvent(
+ HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__DETECTOR_TYPE__TRUSTED_DETECTOR_DSP,
+ HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__KEYPHRASE_TRIGGER);
mRecognitionEvent = recognitionEvent;
mHotwordDetectionConnection.detectFromDspSource(
recognitionEvent, mExternalCallback);
} else {
+ HotwordMetricsLogger.writeKeyphraseTriggerEvent(
+ HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__DETECTOR_TYPE__NORMAL_DETECTOR,
+ HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__KEYPHRASE_TRIGGER);
mExternalCallback.onKeyphraseDetected(recognitionEvent, null);
}
}
@@ -656,6 +781,7 @@ final class HotwordDetectionConnection {
}
public void dump(String prefix, PrintWriter pw) {
+ pw.print(prefix); pw.print("RESTART_PERIOD_SECONDS="); pw.println(RESTART_PERIOD_SECONDS);
pw.print(prefix);
pw.print("mBound=" + mRemoteHotwordDetectionService.isBound());
pw.print(", mValidatingDspTrigger=" + mValidatingDspTrigger);
@@ -772,7 +898,8 @@ final class HotwordDetectionConnection {
ServiceConnection createLocked() {
ServiceConnection connection =
new ServiceConnection(mContext, mIntent, mBindingFlags, mUser,
- IHotwordDetectionService.Stub::asInterface, ++mRestartCount);
+ IHotwordDetectionService.Stub::asInterface,
+ mRestartCount++ % MAX_ISOLATED_PROCESS_NUMBER);
connection.connect();
updateAudioFlinger(connection, mAudioFlinger);
@@ -791,6 +918,7 @@ final class HotwordDetectionConnection {
private boolean mRespectServiceConnectionStatusChanged = true;
private boolean mIsBound = false;
+ private boolean mIsLoggedFirstConnect = false;
ServiceConnection(@NonNull Context context,
@NonNull Intent intent, int bindingFlags, int userId,
@@ -814,6 +942,12 @@ final class HotwordDetectionConnection {
return;
}
mIsBound = connected;
+ if (connected && !mIsLoggedFirstConnect) {
+ mIsLoggedFirstConnect = true;
+ HotwordMetricsLogger.writeDetectorEvent(mDetectorType,
+ HOTWORD_DETECTOR_EVENTS__EVENT__ON_CONNECTED,
+ mVoiceInteractionServiceUid);
+ }
}
}
@@ -844,13 +978,25 @@ final class HotwordDetectionConnection {
protected boolean bindService(
@NonNull android.content.ServiceConnection serviceConnection) {
try {
- return mContext.bindIsolatedService(
+ HotwordMetricsLogger.writeDetectorEvent(mDetectorType,
+ HOTWORD_DETECTOR_EVENTS__EVENT__REQUEST_BIND_SERVICE,
+ mVoiceInteractionServiceUid);
+ boolean bindResult = mContext.bindIsolatedService(
mIntent,
Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE | mBindingFlags,
"hotword_detector_" + mInstanceNumber,
mExecutor,
serviceConnection);
+ if (!bindResult) {
+ HotwordMetricsLogger.writeDetectorEvent(mDetectorType,
+ HOTWORD_DETECTOR_EVENTS__EVENT__REQUEST_BIND_SERVICE_FAIL,
+ mVoiceInteractionServiceUid);
+ }
+ return bindResult;
} catch (IllegalArgumentException e) {
+ HotwordMetricsLogger.writeDetectorEvent(mDetectorType,
+ HOTWORD_DETECTOR_EVENTS__EVENT__REQUEST_BIND_SERVICE_FAIL,
+ mVoiceInteractionServiceUid);
Slog.wtf(TAG, "Can't bind to the hotword detection service!", e);
return false;
}
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordMetricsLogger.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordMetricsLogger.java
new file mode 100644
index 000000000000..940aed34b7fb
--- /dev/null
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordMetricsLogger.java
@@ -0,0 +1,154 @@
+/*
+ * 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.voiceinteraction;
+
+import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTION_SERVICE_INIT_RESULT_REPORTED__DETECTOR_TYPE__NORMAL_DETECTOR;
+import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTION_SERVICE_INIT_RESULT_REPORTED__DETECTOR_TYPE__TRUSTED_DETECTOR_DSP;
+import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTION_SERVICE_INIT_RESULT_REPORTED__DETECTOR_TYPE__TRUSTED_DETECTOR_SOFTWARE;
+import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTION_SERVICE_RESTARTED__DETECTOR_TYPE__NORMAL_DETECTOR;
+import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTION_SERVICE_RESTARTED__DETECTOR_TYPE__TRUSTED_DETECTOR_DSP;
+import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTION_SERVICE_RESTARTED__DETECTOR_TYPE__TRUSTED_DETECTOR_SOFTWARE;
+import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_CREATE_REQUESTED__DETECTOR_TYPE__NORMAL_DETECTOR;
+import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_CREATE_REQUESTED__DETECTOR_TYPE__TRUSTED_DETECTOR_DSP;
+import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_CREATE_REQUESTED__DETECTOR_TYPE__TRUSTED_DETECTOR_SOFTWARE;
+import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_EVENTS__DETECTOR_TYPE__NORMAL_DETECTOR;
+import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_EVENTS__DETECTOR_TYPE__TRUSTED_DETECTOR_DSP;
+import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_EVENTS__DETECTOR_TYPE__TRUSTED_DETECTOR_SOFTWARE;
+import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__DETECTOR_TYPE__NORMAL_DETECTOR;
+import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__DETECTOR_TYPE__TRUSTED_DETECTOR_DSP;
+import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__DETECTOR_TYPE__TRUSTED_DETECTOR_SOFTWARE;
+
+import android.service.voice.HotwordDetector;
+
+import com.android.internal.util.FrameworkStatsLog;
+
+/**
+ * A utility class for logging hotword statistics event.
+ */
+public final class HotwordMetricsLogger {
+
+ private static final int METRICS_INIT_DETECTOR_SOFTWARE =
+ HOTWORD_DETECTION_SERVICE_INIT_RESULT_REPORTED__DETECTOR_TYPE__TRUSTED_DETECTOR_SOFTWARE;
+ private static final int METRICS_INIT_DETECTOR_DSP =
+ HOTWORD_DETECTION_SERVICE_INIT_RESULT_REPORTED__DETECTOR_TYPE__TRUSTED_DETECTOR_DSP;
+ private static final int METRICS_INIT_NORMAL_DETECTOR =
+ HOTWORD_DETECTION_SERVICE_INIT_RESULT_REPORTED__DETECTOR_TYPE__NORMAL_DETECTOR;
+
+ private HotwordMetricsLogger() {
+ // Class only contains static utility functions, and should not be instantiated
+ }
+
+ /**
+ * Logs information related to create hotword detector.
+ */
+ public static void writeDetectorCreateEvent(int detectorType, boolean isCreated, int uid) {
+ int metricsDetectorType = getCreateMetricsDetectorType(detectorType);
+ FrameworkStatsLog.write(FrameworkStatsLog.HOTWORD_DETECTOR_CREATE_REQUESTED,
+ metricsDetectorType, isCreated, uid);
+ }
+
+ /**
+ * Logs information related to hotword detection service init result.
+ */
+ public static void writeServiceInitResultEvent(int detectorType, int result) {
+ int metricsDetectorType = getInitMetricsDetectorType(detectorType);
+ FrameworkStatsLog.write(FrameworkStatsLog.HOTWORD_DETECTION_SERVICE_INIT_RESULT_REPORTED,
+ metricsDetectorType, result);
+ }
+
+ /**
+ * Logs information related to hotword detection service restarting.
+ */
+ public static void writeServiceRestartEvent(int detectorType, int reason) {
+ int metricsDetectorType = getRestartMetricsDetectorType(detectorType);
+ FrameworkStatsLog.write(FrameworkStatsLog.HOTWORD_DETECTION_SERVICE_RESTARTED,
+ metricsDetectorType, reason);
+ }
+
+ /**
+ * Logs information related to keyphrase trigger.
+ */
+ public static void writeKeyphraseTriggerEvent(int detectorType, int result) {
+ int metricsDetectorType = getKeyphraseMetricsDetectorType(detectorType);
+ FrameworkStatsLog.write(FrameworkStatsLog.HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED,
+ metricsDetectorType, result);
+ }
+
+ /**
+ * Logs information related to hotword detector events.
+ */
+ public static void writeDetectorEvent(int detectorType, int event, int uid) {
+ int metricsDetectorType = getDetectorMetricsDetectorType(detectorType);
+ FrameworkStatsLog.write(FrameworkStatsLog.HOTWORD_DETECTOR_EVENTS,
+ metricsDetectorType, event, uid);
+ }
+
+ private static int getCreateMetricsDetectorType(int detectorType) {
+ switch (detectorType) {
+ case HotwordDetector.DETECTOR_TYPE_TRUSTED_HOTWORD_SOFTWARE:
+ return HOTWORD_DETECTOR_CREATE_REQUESTED__DETECTOR_TYPE__TRUSTED_DETECTOR_SOFTWARE;
+ case HotwordDetector.DETECTOR_TYPE_TRUSTED_HOTWORD_DSP:
+ return HOTWORD_DETECTOR_CREATE_REQUESTED__DETECTOR_TYPE__TRUSTED_DETECTOR_DSP;
+ default:
+ return HOTWORD_DETECTOR_CREATE_REQUESTED__DETECTOR_TYPE__NORMAL_DETECTOR;
+ }
+ }
+
+ private static int getRestartMetricsDetectorType(int detectorType) {
+ switch (detectorType) {
+ case HotwordDetector.DETECTOR_TYPE_TRUSTED_HOTWORD_SOFTWARE:
+ return HOTWORD_DETECTION_SERVICE_RESTARTED__DETECTOR_TYPE__TRUSTED_DETECTOR_SOFTWARE;
+ case HotwordDetector.DETECTOR_TYPE_TRUSTED_HOTWORD_DSP:
+ return HOTWORD_DETECTION_SERVICE_RESTARTED__DETECTOR_TYPE__TRUSTED_DETECTOR_DSP;
+ default:
+ return HOTWORD_DETECTION_SERVICE_RESTARTED__DETECTOR_TYPE__NORMAL_DETECTOR;
+ }
+ }
+
+ private static int getInitMetricsDetectorType(int detectorType) {
+ switch (detectorType) {
+ case HotwordDetector.DETECTOR_TYPE_TRUSTED_HOTWORD_SOFTWARE:
+ return METRICS_INIT_DETECTOR_SOFTWARE;
+ case HotwordDetector.DETECTOR_TYPE_TRUSTED_HOTWORD_DSP:
+ return METRICS_INIT_DETECTOR_DSP;
+ default:
+ return METRICS_INIT_NORMAL_DETECTOR;
+ }
+ }
+
+ private static int getKeyphraseMetricsDetectorType(int detectorType) {
+ switch (detectorType) {
+ case HotwordDetector.DETECTOR_TYPE_TRUSTED_HOTWORD_SOFTWARE:
+ return HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__DETECTOR_TYPE__TRUSTED_DETECTOR_SOFTWARE;
+ case HotwordDetector.DETECTOR_TYPE_TRUSTED_HOTWORD_DSP:
+ return HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__DETECTOR_TYPE__TRUSTED_DETECTOR_DSP;
+ default:
+ return HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__DETECTOR_TYPE__NORMAL_DETECTOR;
+ }
+ }
+
+ private static int getDetectorMetricsDetectorType(int detectorType) {
+ switch (detectorType) {
+ case HotwordDetector.DETECTOR_TYPE_TRUSTED_HOTWORD_SOFTWARE:
+ return HOTWORD_DETECTOR_EVENTS__DETECTOR_TYPE__TRUSTED_DETECTOR_SOFTWARE;
+ case HotwordDetector.DETECTOR_TYPE_TRUSTED_HOTWORD_DSP:
+ return HOTWORD_DETECTOR_EVENTS__DETECTOR_TYPE__TRUSTED_DETECTOR_DSP;
+ default:
+ return HOTWORD_DETECTOR_EVENTS__DETECTOR_TYPE__NORMAL_DETECTOR;
+ }
+ }
+}
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
index fb4d73cf9d52..0519873810b5 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
@@ -462,24 +462,33 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne
IHotwordRecognitionStatusCallback callback,
int detectorType) {
Slog.v(TAG, "updateStateLocked");
+ int voiceInteractionServiceUid = mInfo.getServiceInfo().applicationInfo.uid;
if (mHotwordDetectionComponentName == null) {
Slog.w(TAG, "Hotword detection service name not found");
+ logDetectorCreateEventIfNeeded(callback, detectorType, false,
+ voiceInteractionServiceUid);
throw new IllegalStateException("Hotword detection service name not found");
}
ServiceInfo hotwordDetectionServiceInfo = getServiceInfoLocked(
mHotwordDetectionComponentName, mUser);
if (hotwordDetectionServiceInfo == null) {
Slog.w(TAG, "Hotword detection service info not found");
+ logDetectorCreateEventIfNeeded(callback, detectorType, false,
+ voiceInteractionServiceUid);
throw new IllegalStateException("Hotword detection service info not found");
}
if (!isIsolatedProcessLocked(hotwordDetectionServiceInfo)) {
Slog.w(TAG, "Hotword detection service not in isolated process");
+ logDetectorCreateEventIfNeeded(callback, detectorType, false,
+ voiceInteractionServiceUid);
throw new IllegalStateException("Hotword detection service not in isolated process");
}
if (!Manifest.permission.BIND_HOTWORD_DETECTION_SERVICE.equals(
hotwordDetectionServiceInfo.permission)) {
Slog.w(TAG, "Hotword detection service does not require permission "
+ Manifest.permission.BIND_HOTWORD_DETECTION_SERVICE);
+ logDetectorCreateEventIfNeeded(callback, detectorType, false,
+ voiceInteractionServiceUid);
throw new SecurityException("Hotword detection service does not require permission "
+ Manifest.permission.BIND_HOTWORD_DETECTION_SERVICE);
}
@@ -488,17 +497,23 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne
mInfo.getServiceInfo().packageName) == PackageManager.PERMISSION_GRANTED) {
Slog.w(TAG, "Voice interaction service should not hold permission "
+ Manifest.permission.BIND_HOTWORD_DETECTION_SERVICE);
+ logDetectorCreateEventIfNeeded(callback, detectorType, false,
+ voiceInteractionServiceUid);
throw new SecurityException("Voice interaction service should not hold permission "
+ Manifest.permission.BIND_HOTWORD_DETECTION_SERVICE);
}
if (sharedMemory != null && !sharedMemory.setProtect(OsConstants.PROT_READ)) {
Slog.w(TAG, "Can't set sharedMemory to be read-only");
+ logDetectorCreateEventIfNeeded(callback, detectorType, false,
+ voiceInteractionServiceUid);
throw new IllegalStateException("Can't set sharedMemory to be read-only");
}
mDetectorType = detectorType;
+ logDetectorCreateEventIfNeeded(callback, detectorType, true,
+ voiceInteractionServiceUid);
if (mHotwordDetectionConnection == null) {
mHotwordDetectionConnection = new HotwordDetectionConnection(mServiceStub, mContext,
mInfo.getServiceInfo().applicationInfo.uid, voiceInteractorIdentity,
@@ -509,6 +524,15 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne
}
}
+ private void logDetectorCreateEventIfNeeded(IHotwordRecognitionStatusCallback callback,
+ int detectorType, boolean isCreated, int voiceInteractionServiceUid) {
+ if (callback != null) {
+ HotwordMetricsLogger.writeDetectorCreateEvent(detectorType, true,
+ voiceInteractionServiceUid);
+ }
+
+ }
+
public void shutdownHotwordDetectionServiceLocked() {
if (DEBUG) {
Slog.d(TAG, "shutdownHotwordDetectionServiceLocked");
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index d94fafc6a5bf..980ea5cd7f8c 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -1476,12 +1476,21 @@ public final class Call {
/**
* Invoked when the RTT session failed to initiate for some reason, including rejection
* by the remote party.
+ * <p>
+ * This callback will ONLY be invoked to report a failure related to a user initiated
+ * session modification request (i.e. {@link Call#sendRttRequest()}).
+ * <p>
+ * If a call is initiated with {@link TelecomManager#EXTRA_START_CALL_WITH_RTT} specified,
+ * the availability of RTT can be determined by checking {@link Details#PROPERTY_RTT}
+ * once the call enters state {@link Details#STATE_ACTIVE}.
+ *
* @param call The call which the RTT initiation failure occurred on.
* @param reason One of the status codes defined in
- * {@link android.telecom.Connection.RttModifyStatus}, with the exception of
- * {@link android.telecom.Connection.RttModifyStatus#SESSION_MODIFY_REQUEST_SUCCESS}.
+ * {@link android.telecom.Connection.RttModifyStatus}, with the exception of
+ * {@link android.telecom.Connection.RttModifyStatus#SESSION_MODIFY_REQUEST_SUCCESS}.
*/
- public void onRttInitiationFailure(Call call, int reason) {}
+ public void onRttInitiationFailure(Call call,
+ @android.telecom.Connection.RttModifyStatus.RttSessionModifyStatus int reason) {}
/**
* Invoked when Call handover from one {@link PhoneAccount} to other {@link PhoneAccount}
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 21a180459978..6a283df5b480 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -1399,6 +1399,18 @@ public abstract class Connection extends Conferenceable {
* Session modify request rejected by remote user.
*/
public static final int SESSION_MODIFY_REQUEST_REJECTED_BY_REMOTE = 5;
+
+
+ /**@hide*/
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = "SESSION_MODIFY_REQUEST_", value = {
+ SESSION_MODIFY_REQUEST_SUCCESS,
+ SESSION_MODIFY_REQUEST_FAIL,
+ SESSION_MODIFY_REQUEST_INVALID,
+ SESSION_MODIFY_REQUEST_TIMED_OUT,
+ SESSION_MODIFY_REQUEST_REJECTED_BY_REMOTE
+ })
+ public @interface RttSessionModifyStatus {}
}
/**
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
index 27d423b3bc1e..bce6809ef32d 100755
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -3171,9 +3171,14 @@ public abstract class ConnectionService extends Service {
*
* {@link TelecomManager#addNewIncomingCall(PhoneAccountHandle, android.os.Bundle)}.
*
+ * @param connectionManagerPhoneAccount The connection manager account to use for managing
+ * this call
+ * @param request Details about the outgoing call
+ * @return The {@code Connection} object to satisfy this call, or the result of an invocation
+ * of {@link Connection#createFailedConnection(DisconnectCause)} to not handle the call
* @hide
*/
- @SystemApi
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
@RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
public @Nullable Connection onCreateUnknownConnection(
@NonNull PhoneAccountHandle connectionManagerPhoneAccount,
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 837cf8b28ff8..dda5ea7aab53 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -504,7 +504,12 @@ public class CarrierConfigManager {
/** Control whether users can choose a network operator. */
public static final String KEY_OPERATOR_SELECTION_EXPAND_BOOL = "operator_selection_expand_bool";
- /** Used in Cellular Network Settings for preferred network type. */
+ /**
+ * Used in the Preferred Network Types menu to determine if the 2G option is displayed.
+ * Value defaults to false as of Android T to discourage the use of insecure 2G protocols.
+ *
+ * @see #KEY_HIDE_ENABLE_2G
+ */
public static final String KEY_PREFER_2G_BOOL = "prefer_2g_bool";
/**
@@ -8488,8 +8493,9 @@ public class CarrierConfigManager {
* <item value="source=GERAN|UTRAN, target:IWLAN, type=disallowed"/>
* <!-- Handover from IWLAN to 3G/4G/5G is not allowed if the device is roaming. -->
* <item value="source=IWLAN, target=UTRAN|EUTRAN|NGRAN, roaming=true, type=disallowed"/>
- * <!-- Handover from 4G to IWLAN is not allowed -->
- * <item value="source=EUTRAN, target=IWLAN, type=disallowed"/>
+ * <!-- Handover from 4G to IWLAN is not allowed if the device has capability in either IMS
+ * or EIMS-->
+ * <item value="source=EUTRAN, target=IWLAN, type=disallowed, capabilities=IMS|EIMS"/>
* <!-- Handover is always allowed in any condition. -->
* <item value="source=GERAN|UTRAN|EUTRAN|NGRAN|IWLAN,
* target=GERAN|UTRAN|EUTRAN|NGRAN|IWLAN, type=allowed"/>
@@ -8594,7 +8600,7 @@ public class CarrierConfigManager {
sDefaults.putBoolean(KEY_IGNORE_SIM_NETWORK_LOCKED_EVENTS_BOOL, false);
sDefaults.putBoolean(KEY_MDN_IS_ADDITIONAL_VOICEMAIL_NUMBER_BOOL, false);
sDefaults.putBoolean(KEY_OPERATOR_SELECTION_EXPAND_BOOL, true);
- sDefaults.putBoolean(KEY_PREFER_2G_BOOL, true);
+ sDefaults.putBoolean(KEY_PREFER_2G_BOOL, false);
sDefaults.putBoolean(KEY_4G_ONLY_BOOL, false);
sDefaults.putBoolean(KEY_SHOW_APN_SETTING_CDMA_BOOL, false);
sDefaults.putBoolean(KEY_SHOW_CDMA_CHOICES_BOOL, false);
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 0aaafef492bf..b6cacaf9f289 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -1976,7 +1976,7 @@ public class SubscriptionManager {
*/
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public void addSubscriptionInfoRecord(@NonNull String uniqueId, @Nullable String displayName,
- int slotIndex, int subscriptionType) {
+ int slotIndex, @SubscriptionType int subscriptionType) {
if (VDBG) {
logd("[addSubscriptionInfoRecord]+ uniqueId:" + uniqueId
+ ", displayName:" + displayName + ", slotIndex:" + slotIndex
@@ -2012,7 +2012,8 @@ public class SubscriptionManager {
* @hide
*/
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
- public void removeSubscriptionInfoRecord(@NonNull String uniqueId, int subscriptionType) {
+ public void removeSubscriptionInfoRecord(@NonNull String uniqueId,
+ @SubscriptionType int subscriptionType) {
if (VDBG) {
logd("[removeSubscriptionInfoRecord]+ uniqueId:" + uniqueId
+ ", subscriptionType: " + subscriptionType);
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 1eb391d60e4d..1b3a29d80bef 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -41,6 +41,7 @@ import android.annotation.SystemService;
import android.annotation.TestApi;
import android.annotation.WorkerThread;
import android.app.PendingIntent;
+import android.app.PropertyInvalidatedCache;
import android.app.role.RoleManager;
import android.compat.Compatibility;
import android.compat.annotation.ChangeId;
@@ -361,6 +362,42 @@ public class TelephonyManager {
@GuardedBy("sCacheLock")
private static final DeathRecipient sServiceDeath = new DeathRecipient();
+ /**
+ * Cache key for a {@link PropertyInvalidatedCache} which maps from {@link PhoneAccountHandle}
+ * to subscription Id. The cache is initialized in {@code PhoneInterfaceManager}'s constructor
+ * when {@link PropertyInvalidatedCache#invalidateCache(String)} is called.
+ * The cache is cleared from {@code TelecomAccountRegistry#tearDown} when all phone accounts are
+ * removed from Telecom.
+ * @hide
+ */
+ public static final String CACHE_KEY_PHONE_ACCOUNT_TO_SUBID =
+ "cache_key.telephony.phone_account_to_subid";
+ private static final int CACHE_MAX_SIZE = 4;
+
+ /**
+ * A {@link PropertyInvalidatedCache} which lives in an app's {@link TelephonyManager} instance.
+ * Caches any queries for a mapping between {@link PhoneAccountHandle} and {@code subscription
+ * id}. The cache may be invalidated from Telephony when phone account re-registration takes
+ * place.
+ */
+ private PropertyInvalidatedCache<PhoneAccountHandle, Integer> mPhoneAccountHandleToSubIdCache =
+ new PropertyInvalidatedCache<PhoneAccountHandle, Integer>(CACHE_MAX_SIZE,
+ CACHE_KEY_PHONE_ACCOUNT_TO_SUBID) {
+ @Override
+ public Integer recompute(PhoneAccountHandle phoneAccountHandle) {
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ return telephony.getSubIdForPhoneAccountHandle(phoneAccountHandle,
+ mContext.getOpPackageName(), mContext.getAttributionTag());
+ }
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+ }
+ };
+
/** Enum indicating multisim variants
* DSDS - Dual SIM Dual Standby
* DSDA - Dual SIM Dual Active
@@ -8352,24 +8389,6 @@ public class TelephonyManager {
}
/**
- * Get P-CSCF address from PCO after data connection is established or modified.
- * @param apnType the apnType, "ims" for IMS APN, "emergency" for EMERGENCY APN
- * @return array of P-CSCF address
- * @hide
- */
- public String[] getPcscfAddress(String apnType) {
- try {
- ITelephony telephony = getITelephony();
- if (telephony == null)
- return new String[0];
- return telephony.getPcscfAddress(apnType, getOpPackageName(), getAttributionTag());
- } catch (RemoteException e) {
- return new String[0];
- }
- }
-
-
- /**
* Resets the {@link android.telephony.ims.ImsService} associated with the specified sim slot.
* Used by diagnostic apps to force the IMS stack to be disabled and re-enabled in an effort to
* recover from scenarios where the {@link android.telephony.ims.ImsService} gets in to a bad
@@ -9833,15 +9852,7 @@ public class TelephonyManager {
@SystemApi
@RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public @Nullable String getCarrierServicePackageName() {
- // TODO(b/205736323) plumb this through to CarrierPrivilegesTracker, which will cache the
- // value instead of re-querying every time.
- List<String> carrierServicePackages =
- getCarrierPackageNamesForIntent(
- new Intent(CarrierService.CARRIER_SERVICE_INTERFACE));
- if (carrierServicePackages != null && !carrierServicePackages.isEmpty()) {
- return carrierServicePackages.get(0);
- }
- return null;
+ return getCarrierServicePackageNameForLogicalSlot(getPhoneId());
}
/**
@@ -9858,13 +9869,15 @@ public class TelephonyManager {
@SystemApi
@RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public @Nullable String getCarrierServicePackageNameForLogicalSlot(int logicalSlotIndex) {
- // TODO(b/205736323) plumb this through to CarrierPrivilegesTracker, which will cache the
- // value instead of re-querying every time.
- List<String> carrierServicePackages =
- getCarrierPackageNamesForIntentAndPhone(
- new Intent(CarrierService.CARRIER_SERVICE_INTERFACE), logicalSlotIndex);
- if (carrierServicePackages != null && !carrierServicePackages.isEmpty()) {
- return carrierServicePackages.get(0);
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ return telephony.getCarrierServicePackageNameForLogicalSlot(logicalSlotIndex);
+ }
+ } catch (RemoteException ex) {
+ Rlog.e(TAG, "getCarrierServicePackageNameForLogicalSlot RemoteException", ex);
+ } catch (NullPointerException ex) {
+ Rlog.e(TAG, "getCarrierServicePackageNameForLogicalSlot NPE", ex);
}
return null;
}
@@ -11904,19 +11917,7 @@ public class TelephonyManager {
@RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
@RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
public int getSubscriptionId(@NonNull PhoneAccountHandle phoneAccountHandle) {
- int retval = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
- try {
- ITelephony service = getITelephony();
- if (service != null) {
- retval = service.getSubIdForPhoneAccountHandle(
- phoneAccountHandle, mContext.getOpPackageName(),
- mContext.getAttributionTag());
- }
- } catch (RemoteException ex) {
- Log.e(TAG, "getSubscriptionId RemoteException", ex);
- ex.rethrowAsRuntimeException();
- }
- return retval;
+ return mPhoneAccountHandleToSubIdCache.query(phoneAccountHandle);
}
/**
@@ -14942,7 +14943,7 @@ public class TelephonyManager {
}
ITelephony service = getITelephony();
if (service != null) {
- return service.isMvnoMatched(getSubId(), mvnoType, mvnoMatchData);
+ return service.isMvnoMatched(getSlotIndex(), mvnoType, mvnoMatchData);
}
} catch (RemoteException ex) {
Rlog.e(TAG, "Telephony#matchesCurrentSimOperator RemoteException" + ex);
@@ -16790,7 +16791,10 @@ public class TelephonyManager {
* Callback to listen for when the set of packages with carrier privileges for a SIM changes.
*
* @hide
+ * @deprecated Use {@link CarrierPrivilegesCallback} instead. This API will be removed soon
+ * prior to API finalization.
*/
+ @Deprecated
@SystemApi
public interface CarrierPrivilegesListener {
/**
@@ -16810,6 +16814,54 @@ public class TelephonyManager {
}
/**
+ * Callbacks to listen for when the set of packages with carrier privileges for a SIM changes.
+ *
+ * <p>Of note, when multiple callbacks are registered, they may be triggered one after another.
+ * The ordering of them is not guaranteed and thus should not be depend on.
+ *
+ * @hide
+ */
+ @SystemApi
+ public interface CarrierPrivilegesCallback {
+ /**
+ * Called when the set of packages with carrier privileges has changed.
+ *
+ * <p>Of note, this callback will <b>not</b> be fired if a carrier triggers a SIM profile
+ * switch and the same set of packages remains privileged after the switch.
+ *
+ * <p>At registration, the callback will receive the current set of privileged packages.
+ *
+ * @param privilegedPackageNames The updated set of package names that have carrier
+ * privileges
+ * @param privilegedUids The updated set of UIDs that have carrier privileges
+ */
+ void onCarrierPrivilegesChanged(
+ @NonNull Set<String> privilegedPackageNames, @NonNull Set<Integer> privilegedUids);
+
+ /**
+ * Called when the {@link CarrierService} for the current user profile has changed.
+ *
+ * <p>This method does nothing by default. Clients that are interested in the carrier
+ * service change should override this method to get package name and UID info.
+ *
+ * <p>At registration, the callback will receive the current carrier service info.
+ *
+ * <p>Of note, this callback will <b>not</b> be fired if a carrier triggers a SIM profile
+ * switch and the same carrier service remains after switch.
+ *
+ * @param carrierServicePackageName package name of the {@link CarrierService}. May be
+ * {@code null} when no carrier service is detected.
+ * @param carrierServiceUid UID of the {@link CarrierService}. May be
+ * {@link android.os.Process#INVALID_UID} if no carrier
+ * service is detected.
+ */
+ default void onCarrierServiceChanged(
+ @Nullable String carrierServicePackageName, int carrierServiceUid) {
+ // do nothing by default
+ }
+ }
+
+ /**
* Registers a {@link CarrierPrivilegesListener} on the given {@code logicalSlotIndex} to
* receive callbacks when the set of packages with carrier privileges changes. The callback will
* immediately be called with the latest state.
@@ -16818,7 +16870,10 @@ public class TelephonyManager {
* @param executor The executor where {@code listener} will be invoked
* @param listener The callback to register
* @hide
+ * @deprecated Use {@link #unregisterCarrierPrivilegesCallback} instead. This API will be
+ * removed prior to API finalization.
*/
+ @Deprecated
@SystemApi
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public void addCarrierPrivilegesListener(
@@ -16842,7 +16897,10 @@ public class TelephonyManager {
* Unregisters an existing {@link CarrierPrivilegesListener}.
*
* @hide
+ * @deprecated Use {@link #unregisterCarrierPrivilegesCallback} instead. This API will be
+ * removed prior to API finalization.
*/
+ @Deprecated
@SystemApi
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public void removeCarrierPrivilegesListener(@NonNull CarrierPrivilegesListener listener) {
@@ -16890,4 +16948,53 @@ public class TelephonyManager {
ex.rethrowAsRuntimeException();
}
}
+
+ /**
+ * Registers a {@link CarrierPrivilegesCallback} on the given {@code logicalSlotIndex} to
+ * receive callbacks when the set of packages with carrier privileges changes. The callback will
+ * immediately be called with the latest state.
+ *
+ * @param logicalSlotIndex The SIM slot to listen on
+ * @param executor The executor where {@code callback} will be invoked
+ * @param callback The callback to register
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ public void registerCarrierPrivilegesCallback(
+ int logicalSlotIndex,
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull CarrierPrivilegesCallback callback) {
+ if (mContext == null) {
+ throw new IllegalStateException("Telephony service is null");
+ } else if (executor == null || callback == null) {
+ throw new IllegalArgumentException(
+ "CarrierPrivilegesCallback and executor must be non-null");
+ }
+ mTelephonyRegistryMgr = mContext.getSystemService(TelephonyRegistryManager.class);
+ if (mTelephonyRegistryMgr == null) {
+ throw new IllegalStateException("Telephony registry service is null");
+ }
+ mTelephonyRegistryMgr.addCarrierPrivilegesCallback(logicalSlotIndex, executor, callback);
+ }
+
+ /**
+ * Unregisters an existing {@link CarrierPrivilegesCallback}.
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ public void unregisterCarrierPrivilegesCallback(@NonNull CarrierPrivilegesCallback callback) {
+ if (mContext == null) {
+ throw new IllegalStateException("Telephony service is null");
+ } else if (callback == null) {
+ throw new IllegalArgumentException("CarrierPrivilegesCallback must be non-null");
+ }
+ mTelephonyRegistryMgr = mContext.getSystemService(TelephonyRegistryManager.class);
+ if (mTelephonyRegistryMgr == null) {
+ throw new IllegalStateException("Telephony registry service is null");
+ }
+ mTelephonyRegistryMgr.removeCarrierPrivilegesCallback(callback);
+ }
}
diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java
index fc94ebf2cc37..8143da5ad431 100644
--- a/telephony/java/android/telephony/data/ApnSetting.java
+++ b/telephony/java/android/telephony/data/ApnSetting.java
@@ -549,7 +549,6 @@ public class ApnSetting implements Parcelable {
* Returns the profile id to which the APN saved in modem.
*
* @return the profile id of the APN
- * @hide
*/
public int getProfileId() {
return mProfileId;
@@ -558,8 +557,7 @@ public class ApnSetting implements Parcelable {
/**
* Returns if the APN setting is persistent on the modem.
*
- * @return is the APN setting to be set in modem
- * @hide
+ * @return {@code true} if the APN setting is persistent on the modem.
*/
public boolean isPersistent() {
return mPersistent;
@@ -1103,8 +1101,10 @@ public class ApnSetting implements Parcelable {
sb.append(", ").append(MVNO_TYPE_INT_MAP.get(mMvnoType));
sb.append(", ").append(mMvnoMatchData);
sb.append(", ").append(mPermanentFailed);
- sb.append(", ").append(mNetworkTypeBitmask);
- sb.append(", ").append(mLingeringNetworkTypeBitmask);
+ sb.append(", ").append(TelephonyManager.convertNetworkTypeBitmaskToString(
+ mNetworkTypeBitmask));
+ sb.append(", ").append(TelephonyManager.convertNetworkTypeBitmaskToString(
+ mLingeringNetworkTypeBitmask));
sb.append(", ").append(mApnSetId);
sb.append(", ").append(mCarrierId);
sb.append(", ").append(mSkip464Xlat);
diff --git a/telephony/java/android/telephony/data/DataService.java b/telephony/java/android/telephony/data/DataService.java
index 892eb2937491..bd346d516a1d 100644
--- a/telephony/java/android/telephony/data/DataService.java
+++ b/telephony/java/android/telephony/data/DataService.java
@@ -31,6 +31,7 @@ import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
+import android.telephony.AccessNetworkConstants.RadioAccessNetworkType;
import android.util.Log;
import android.util.SparseArray;
@@ -166,7 +167,8 @@ public abstract class DataService extends Service {
* link properties of the existing data connection, otherwise null.
* @param callback The result callback for this request.
*/
- public void setupDataCall(int accessNetworkType, @NonNull DataProfile dataProfile,
+ public void setupDataCall(
+ @RadioAccessNetworkType int accessNetworkType, @NonNull DataProfile dataProfile,
boolean isRoaming, boolean allowRoaming,
@SetupDataReason int reason, @Nullable LinkProperties linkProperties,
@NonNull DataServiceCallback callback) {
@@ -214,7 +216,8 @@ public abstract class DataService extends Service {
* for example, a zero-rating slice.
* @param callback The result callback for this request.
*/
- public void setupDataCall(int accessNetworkType, @NonNull DataProfile dataProfile,
+ public void setupDataCall(
+ @RadioAccessNetworkType int accessNetworkType, @NonNull DataProfile dataProfile,
boolean isRoaming, boolean allowRoaming,
@SetupDataReason int reason,
@Nullable LinkProperties linkProperties,
@@ -294,6 +297,9 @@ public abstract class DataService extends Service {
* with reason {@link DataService.REQUEST_REASON_HANDOVER}. The target transport now owns
* the transferred resources and is responsible for releasing them.
*
+ * <p/>
+ * Note that the callback will be executed on binder thread.
+ *
* @param cid The identifier of the data call which is provided in {@link DataCallResponse}
* @param callback The result callback for this request.
*
@@ -322,6 +328,9 @@ public abstract class DataService extends Service {
* </li>
* </ul>
*
+ * <p/>
+ * Note that the callback will be executed on binder thread.
+ *
* @param cid The identifier of the data call which is provided in {@link DataCallResponse}
* @param callback The result callback for this request.
*
diff --git a/telephony/java/android/telephony/data/DataServiceCallback.java b/telephony/java/android/telephony/data/DataServiceCallback.java
index ec734716f6e4..77d4837ccfb6 100644
--- a/telephony/java/android/telephony/data/DataServiceCallback.java
+++ b/telephony/java/android/telephony/data/DataServiceCallback.java
@@ -50,12 +50,13 @@ public class DataServiceCallback {
*/
@Retention(RetentionPolicy.SOURCE)
@IntDef({RESULT_SUCCESS, RESULT_ERROR_UNSUPPORTED, RESULT_ERROR_INVALID_ARG, RESULT_ERROR_BUSY,
- RESULT_ERROR_ILLEGAL_STATE})
+ RESULT_ERROR_ILLEGAL_STATE, RESULT_ERROR_TEMPORARILY_UNAVAILABLE,
+ RESULT_ERROR_INVALID_RESPONSE})
public @interface ResultCode {}
/** Request is completed successfully */
public static final int RESULT_SUCCESS = 0;
- /** Request is not support */
+ /** Request is not supported */
public static final int RESULT_ERROR_UNSUPPORTED = 1;
/** Request contains invalid arguments */
public static final int RESULT_ERROR_INVALID_ARG = 2;
@@ -68,6 +69,11 @@ public class DataServiceCallback {
* @hide
*/
public static final int RESULT_ERROR_TEMPORARILY_UNAVAILABLE = 5;
+ /**
+ * Request failed to complete due to an invalid response.
+ * @hide
+ */
+ public static final int RESULT_ERROR_INVALID_RESPONSE = 6;
private final IDataServiceCallback mCallback;
@@ -255,6 +261,8 @@ public class DataServiceCallback {
return "RESULT_ERROR_ILLEGAL_STATE";
case RESULT_ERROR_TEMPORARILY_UNAVAILABLE:
return "RESULT_ERROR_TEMPORARILY_UNAVAILABLE";
+ case RESULT_ERROR_INVALID_RESPONSE:
+ return "RESULT_ERROR_INVALID_RESPONSE";
default:
return "Unknown(" + resultCode + ")";
}
diff --git a/telephony/java/android/telephony/data/EpsBearerQosSessionAttributes.java b/telephony/java/android/telephony/data/EpsBearerQosSessionAttributes.java
index fe4453081362..5ffee5638cfa 100644
--- a/telephony/java/android/telephony/data/EpsBearerQosSessionAttributes.java
+++ b/telephony/java/android/telephony/data/EpsBearerQosSessionAttributes.java
@@ -32,7 +32,12 @@ import java.util.List;
import java.util.Objects;
/**
- * Provides Qos attributes of an EPS bearer.
+ * Provides QOS attributes of an EPS bearer.
+ *
+ * <p> The dedicated EPS bearer along with QOS is allocated by the LTE network and notified to the
+ * device. The Telephony framework creates the {@link EpsBearerQosSessionAttributes} object which
+ * represents the QOS of the dedicated bearer and notifies the same to applications via
+ * {@link QosCallback}.
*
* {@hide}
*/
diff --git a/telephony/java/android/telephony/data/QualifiedNetworksService.java b/telephony/java/android/telephony/data/QualifiedNetworksService.java
index 4e85d8926f11..a846088cec6c 100644
--- a/telephony/java/android/telephony/data/QualifiedNetworksService.java
+++ b/telephony/java/android/telephony/data/QualifiedNetworksService.java
@@ -129,17 +129,31 @@ public abstract class QualifiedNetworksService extends Service {
}
/**
- * Update the qualified networks list. Network availability provider must invoke this method
- * whenever the qualified networks changes. If this method is never invoked for certain
- * APN types, then frameworks will always use the default (i.e. cellular) data and network
- * service.
+ * Update the suggested qualified networks list. Network availability provider must invoke
+ * this method whenever the suggested qualified networks changes. If this method is never
+ * invoked for certain APN types, then frameworks uses its own logic to determine the
+ * transport to setup the data network.
+ *
+ * For example, QNS can suggest frameworks to setup IMS on IWLAN by specifying
+ * {@link ApnSetting#TYPE_IMS} with a list containing single element
+ * {@link AccessNetworkType#IWLAN}.
+ *
+ * Or if QNS consider multiple access networks are qualified for certain APN type, it can
+ * suggest frameworks by specifying the APN type with multiple elements in the list like
+ * {{@link AccessNetworkType#EUTRAN}, {@link AccessNetworkType#IWLAN}}. Frameworks will then
+ * first attempt to setup data on LTE network. If the device moves from LTE to UMTS, then
+ * frameworks can perform handover the data network to the second preferred access network
+ * if available.
+ *
+ * If the {@code qualifiedNetworkTypes} list is empty, it means QNS has no suggestion to the
+ * frameworks, and frameworks will decide the transport to setup the data network.
*
* @param apnTypes APN types of the qualified networks. This must be a bitmask combination
* of {@link ApnType}.
* @param qualifiedNetworkTypes List of network types which are qualified for data
* connection setup for {@link @apnType} in the preferred order. Each element in the list
- * is a {@link AccessNetworkType}. An empty list indicates no networks are qualified
- * for data setup.
+ * is a {@link AccessNetworkType}. Note that {@link AccessNetworkType#UNKNOWN} is not a
+ * valid input here.
*/
public final void updateQualifiedNetworkTypes(
@ApnType int apnTypes, @NonNull List<Integer> qualifiedNetworkTypes) {
diff --git a/telephony/java/android/telephony/ims/ImsMmTelManager.java b/telephony/java/android/telephony/ims/ImsMmTelManager.java
index bce210fa22a0..5bae1ad72d93 100644
--- a/telephony/java/android/telephony/ims/ImsMmTelManager.java
+++ b/telephony/java/android/telephony/ims/ImsMmTelManager.java
@@ -621,9 +621,9 @@ public class ImsMmTelManager implements RegistrationManager {
ITelephony iTelephony = getITelephony();
if (iTelephony == null) {
- throw new RuntimeException("Could not find Telephony Service.");
+ Log.w("ImsMmTelManager", "Could not find Telephony Service.");
+ return;
}
-
try {
iTelephony.unregisterMmTelCapabilityCallback(mSubId, c.getBinder());
} catch (RemoteException e) {
diff --git a/telephony/java/android/telephony/ims/aidl/SipDelegateAidlWrapper.java b/telephony/java/android/telephony/ims/aidl/SipDelegateAidlWrapper.java
index 493ad5e473a5..1ccb4645a699 100644
--- a/telephony/java/android/telephony/ims/aidl/SipDelegateAidlWrapper.java
+++ b/telephony/java/android/telephony/ims/aidl/SipDelegateAidlWrapper.java
@@ -48,6 +48,9 @@ public class SipDelegateAidlWrapper implements DelegateStateCallback, DelegateMe
@Override
public void sendMessage(SipMessage sipMessage, long configVersion) {
SipDelegate d = mDelegate;
+ if (d == null) {
+ return;
+ }
final long token = Binder.clearCallingIdentity();
try {
mExecutor.execute(() -> d.sendMessage(sipMessage, configVersion));
@@ -59,6 +62,9 @@ public class SipDelegateAidlWrapper implements DelegateStateCallback, DelegateMe
@Override
public void notifyMessageReceived(String viaTransactionId) {
SipDelegate d = mDelegate;
+ if (d == null) {
+ return;
+ }
final long token = Binder.clearCallingIdentity();
try {
mExecutor.execute(() -> d.notifyMessageReceived(viaTransactionId));
@@ -71,6 +77,9 @@ public class SipDelegateAidlWrapper implements DelegateStateCallback, DelegateMe
@Override
public void notifyMessageReceiveError(String viaTransactionId, int reason) {
SipDelegate d = mDelegate;
+ if (d == null) {
+ return;
+ }
final long token = Binder.clearCallingIdentity();
try {
mExecutor.execute(() -> d.notifyMessageReceiveError(viaTransactionId, reason));
@@ -83,6 +92,9 @@ public class SipDelegateAidlWrapper implements DelegateStateCallback, DelegateMe
@Override
public void cleanupSession(String callId) {
SipDelegate d = mDelegate;
+ if (d == null) {
+ return;
+ }
final long token = Binder.clearCallingIdentity();
try {
mExecutor.execute(() -> d.cleanupSession(callId));
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index dc96b3585864..cfd940dac750 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -978,14 +978,6 @@ interface ITelephony {
boolean isManualNetworkSelectionAllowed(int subId);
/**
- * Get P-CSCF address from PCO after data connection is established or modified.
- * @param apnType the apnType, "ims" for IMS APN, "emergency" for EMERGENCY APN
- * @param callingPackage The package making the call.
- * @param callingFeatureId The feature in the package.
- */
- String[] getPcscfAddress(String apnType, String callingPackage, String callingFeatureId);
-
- /**
* Set IMS registration state
*/
void setImsRegistrationState(boolean registered);
@@ -2150,7 +2142,7 @@ interface ITelephony {
List<RadioAccessSpecifier> getSystemSelectionChannels(int subId);
- boolean isMvnoMatched(int subId, int mvnoType, String mvnoMatchData);
+ boolean isMvnoMatched(int slotIndex, int mvnoType, String mvnoMatchData);
/**
* Enqueue a pending sms Consumer, which will answer with the user specified selection for an
@@ -2549,4 +2541,15 @@ interface ITelephony {
* PhoneAccount#CAPABILITY_VOICE_CALLING_AVAILABLE.
*/
void setVoiceServiceStateOverride(int subId, boolean hasService, String callingPackage);
+
+ /**
+ * Returns the package name that provides the {@link CarrierService} implementation for the
+ * specified {@code logicalSlotIndex}, or {@code null} if no package with carrier privileges
+ * declares one.
+ *
+ * @param logicalSlotIndex The slot index to fetch the {@link CarrierService} package for
+ * @return The system-selected package that provides the {@link CarrierService} implementation
+ * for the slot, or {@code null} if none is resolved
+ */
+ String getCarrierServicePackageNameForLogicalSlot(int logicalSlotIndex);
}
diff --git a/telephony/java/com/android/internal/telephony/TelephonyIntents.java b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
index b905212a9100..546d2ce0e115 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyIntents.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
@@ -424,4 +424,24 @@ public class TelephonyIntents {
*/
@Deprecated
public static final String EXTRA_DEFAULT_NETWORK_AVAILABLE = "defaultNetworkAvailable";
+
+ /**
+ * <p>Broadcast sent to show Emergency notification due to Voice Over Wifi availability
+ *
+ * <p class="note">
+ * You can <em>not</em> receive this through components declared
+ * in manifests, only by explicitly registering for it with
+ * {@link android.content.Context#registerReceiver(android.content.BroadcastReceiver,
+ * android.content.IntentFilter) Context.registerReceiver()}.
+ *
+ * <p class="note">
+ * Requires no permission.
+ *
+ * <p class="note">This is a protected intent that can only be sent
+ * by the system.
+ *
+ * @hide
+ */
+ public static final String ACTION_VOWIFI_ENABLED
+ = "com.android.internal.telephony.ACTION_VOWIFI_ENABLED";
}
diff --git a/tests/BandwidthTests/src/com/android/tests/bandwidthenforcement/BandwidthEnforcementTestService.java b/tests/BandwidthTests/src/com/android/tests/bandwidthenforcement/BandwidthEnforcementTestService.java
index 35f1e585931b..644d450a7a88 100644
--- a/tests/BandwidthTests/src/com/android/tests/bandwidthenforcement/BandwidthEnforcementTestService.java
+++ b/tests/BandwidthTests/src/com/android/tests/bandwidthenforcement/BandwidthEnforcementTestService.java
@@ -24,6 +24,8 @@ import android.net.SntpClient;
import android.os.Environment;
import android.util.Log;
+import libcore.io.Streams;
+
import java.io.BufferedWriter;
import java.io.ByteArrayOutputStream;
import java.io.File;
@@ -37,8 +39,6 @@ import java.net.InetAddress;
import java.net.URL;
import java.util.Random;
-import libcore.io.Streams;
-
/*
* Test Service that tries to connect to the web via different methods and outputs the results to
* the log and a output file.
@@ -146,7 +146,7 @@ public class BandwidthEnforcementTestService extends IntentService {
final ConnectivityManager mCM = context.getSystemService(ConnectivityManager.class);
final Network network = mCM.getActiveNetwork();
- if (client.requestTime("0.pool.ntp.org", 10000, network)) {
+ if (client.requestTime("0.pool.ntp.org", SntpClient.STANDARD_NTP_PORT, 10000, network)) {
return true;
}
return false;
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/LaunchAppShowImeAndDialogThemeAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/LaunchAppShowImeAndDialogThemeAppTest.kt
index 71e576a2e5ac..7f4966375b98 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/LaunchAppShowImeAndDialogThemeAppTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/LaunchAppShowImeAndDialogThemeAppTest.kt
@@ -44,7 +44,6 @@ import org.junit.runners.Parameterized
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@FlakyTest(bugId = 219749605)
class LaunchAppShowImeAndDialogThemeAppTest(private val testSpec: FlickerTestParameter) {
private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
private val testApp = ImeAppAutoFocusHelper(instrumentation, testSpec.startRotation)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt
index a9564fdd2332..e7a33543a86b 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt
@@ -46,6 +46,7 @@ import com.android.server.wm.traces.common.FlickerComponentName
import com.android.server.wm.traces.common.WindowManagerConditionsFactory
import org.junit.Assume.assumeFalse
import org.junit.Assume.assumeTrue
+import org.junit.Before
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -61,8 +62,7 @@ import org.junit.runners.Parameterized
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@Group2
-@FlakyTest(bugId = 219757170)
-class ReOpenImeWindowTest(private val testSpec: FlickerTestParameter) {
+open class ReOpenImeWindowTest(private val testSpec: FlickerTestParameter) {
private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
private val testApp = ImeAppAutoFocusHelper(instrumentation, testSpec.startRotation)
@@ -72,6 +72,11 @@ class ReOpenImeWindowTest(private val testSpec: FlickerTestParameter) {
WindowManagerConditionsFactory.isHomeActivityVisible()
))
+ @Before
+ open fun before() {
+ assumeFalse(isShellTransitionsEnabled)
+ }
+
@FlickerBuilderProvider
fun buildFlicker(): FlickerBuilder {
return FlickerBuilder(instrumentation).apply {
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest_ShellTransit.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest_ShellTransit.kt
new file mode 100644
index 000000000000..7ffa51320487
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest_ShellTransit.kt
@@ -0,0 +1,49 @@
+/*
+ * 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.ime
+
+import android.platform.test.annotations.Postsubmit
+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.Group2
+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 IME window opening transitions.
+ * To run this test: `atest FlickerTests:ReOpenImeWindowTest`
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group2
+@FlakyTest(bugId = 221854428)
+class ReOpenImeWindowTest_ShellTransit(private val testSpec: FlickerTestParameter)
+ : ReOpenImeWindowTest(testSpec) {
+ @Before
+ override fun before() {
+ Assume.assumeTrue(isShellTransitionsEnabled)
+ }
+}
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 b0e53e9f85bf..c3a4769bc573 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
@@ -74,7 +74,7 @@ open class OpenAppNonResizeableTest(testSpec: FlickerTestParameter)
* Checks that the nav bar layer starts invisible, becomes visible during unlocking animation
* and remains visible at the end
*/
- @Postsubmit
+ @Presubmit
@Test
fun navBarLayerVisibilityChanges() {
testSpec.assertLayers {
diff --git a/tests/HandwritingIme/src/com/google/android/test/handwritingime/HandwritingIme.java b/tests/HandwritingIme/src/com/google/android/test/handwritingime/HandwritingIme.java
index 18f962398fb8..bf8bd14645a0 100644
--- a/tests/HandwritingIme/src/com/google/android/test/handwritingime/HandwritingIme.java
+++ b/tests/HandwritingIme/src/com/google/android/test/handwritingime/HandwritingIme.java
@@ -18,11 +18,13 @@ package com.google.android.test.handwritingime;
import android.annotation.Nullable;
import android.inputmethodservice.InputMethodService;
import android.util.Log;
+import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.widget.FrameLayout;
+import android.widget.TextView;
import android.widget.Toast;
import java.util.Random;
@@ -79,6 +81,14 @@ public class HandwritingIme extends InputMethodService {
view.setPadding(0, 0, 0, 0);
view.addView(inner, new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT, height));
+ TextView text = new TextView(this);
+ text.setText("Handwriting IME");
+ text.setTextSize(13f);
+ text.setTextColor(getColor(android.R.color.white));
+ text.setGravity(Gravity.CENTER);
+ text.setLayoutParams(new FrameLayout.LayoutParams(
+ FrameLayout.LayoutParams.MATCH_PARENT, height));
+ view.addView(text);
inner.setBackgroundColor(0xff0110fe); // blue
return view;
diff --git a/tests/HandwritingIme/src/com/google/android/test/handwritingime/InkView.java b/tests/HandwritingIme/src/com/google/android/test/handwritingime/InkView.java
index 4ffdc9211f1d..87a5b900cc18 100644
--- a/tests/HandwritingIme/src/com/google/android/test/handwritingime/InkView.java
+++ b/tests/HandwritingIme/src/com/google/android/test/handwritingime/InkView.java
@@ -33,6 +33,7 @@ class InkView extends View {
private static final long FINISH_TIMEOUT = 2500;
private final HandwritingIme.HandwritingFinisher mHwCanceller;
private final HandwritingIme.StylusConsumer mConsumer;
+ private final int mTopInset;
private Paint mPaint;
private Path mPath;
private float mX, mY;
@@ -63,6 +64,7 @@ class InkView extends View {
setLayoutParams(new ViewGroup.LayoutParams(
metrics.getBounds().width() - insets.left - insets.right,
metrics.getBounds().height() - insets.top - insets.bottom));
+ mTopInset = insets.top;
}
@Override
@@ -74,12 +76,14 @@ class InkView extends View {
}
private void stylusStart(float x, float y) {
+ y = y - mTopInset;
mPath.moveTo(x, y);
mX = x;
mY = y;
}
private void stylusMove(float x, float y) {
+ y = y - mTopInset;
float dx = Math.abs(x - mX);
float dy = Math.abs(y - mY);
if (mPath.isEmpty()) {
diff --git a/tests/SoundTriggerTestApp/OWNERS b/tests/SoundTriggerTestApp/OWNERS
index 816bc6bba639..9db19a37812b 100644
--- a/tests/SoundTriggerTestApp/OWNERS
+++ b/tests/SoundTriggerTestApp/OWNERS
@@ -1 +1,2 @@
include /core/java/android/media/soundtrigger/OWNERS
+mdooley@google.com
diff --git a/tests/TrustTests/Android.bp b/tests/TrustTests/Android.bp
index c9c6c5cf193b..77f98e88f1eb 100644
--- a/tests/TrustTests/Android.bp
+++ b/tests/TrustTests/Android.bp
@@ -25,6 +25,8 @@ android_test {
"androidx.test.rules",
"androidx.test.ext.junit",
"androidx.test.uiautomator",
+ "mockito-target-minus-junit4",
+ "servicestests-utils",
"truth-prebuilt",
],
libs: [
diff --git a/tests/TrustTests/AndroidManifest.xml b/tests/TrustTests/AndroidManifest.xml
index c94152da2bf6..8b4cbfd0e44b 100644
--- a/tests/TrustTests/AndroidManifest.xml
+++ b/tests/TrustTests/AndroidManifest.xml
@@ -23,7 +23,9 @@
<uses-permission android:name="android.permission.BIND_DEVICE_ADMIN" />
<uses-permission android:name="android.permission.CONTROL_KEYGUARD" />
<uses-permission android:name="android.permission.DEVICE_POWER" />
+ <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
+ <uses-permission android:name="android.permission.MANAGE_USERS" />
<uses-permission android:name="android.permission.PROVIDE_TRUST_AGENT" />
<uses-permission android:name="android.permission.TRUST_LISTENER" />
@@ -66,6 +68,16 @@
<action android:name="android.service.trust.TrustAgentService" />
</intent-filter>
</service>
+
+ <service
+ android:name=".TemporaryAndRenewableTrustAgent"
+ android:exported="true"
+ android:label="Test Agent"
+ android:permission="android.permission.BIND_TRUST_AGENT">
+ <intent-filter>
+ <action android:name="android.service.trust.TrustAgentService" />
+ </intent-filter>
+ </service>
</application>
<!-- self-instrumenting test package. -->
diff --git a/tests/TrustTests/TEST_MAPPING b/tests/TrustTests/TEST_MAPPING
new file mode 100644
index 000000000000..b9c46bfbba8c
--- /dev/null
+++ b/tests/TrustTests/TEST_MAPPING
@@ -0,0 +1,15 @@
+{
+ "presubmit": [
+ {
+ "name": "TrustTests",
+ "options": [
+ {
+ "include-filter": "android.trust.test"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ }
+ ]
+ }
+ ]
+} \ No newline at end of file
diff --git a/tests/TrustTests/src/android/trust/test/GrantAndRevokeTrustTest.kt b/tests/TrustTests/src/android/trust/test/GrantAndRevokeTrustTest.kt
index 790afd389152..f864fedf4e62 100644
--- a/tests/TrustTests/src/android/trust/test/GrantAndRevokeTrustTest.kt
+++ b/tests/TrustTests/src/android/trust/test/GrantAndRevokeTrustTest.kt
@@ -16,6 +16,7 @@
package android.trust.test
+import android.service.trust.GrantTrustResult
import android.trust.BaseTrustAgentService
import android.trust.TrustTestActivity
import android.trust.test.lib.LockStateTrackingRule
@@ -25,11 +26,13 @@ import androidx.test.ext.junit.rules.ActivityScenarioRule
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
import androidx.test.uiautomator.UiDevice
+import com.android.server.testutils.mock
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.rules.RuleChain
import org.junit.runner.RunWith
+import org.mockito.Mockito.verifyZeroInteractions
/**
* Test for testing revokeTrust & grantTrust for non-renewable trust.
@@ -60,31 +63,37 @@ class GrantAndRevokeTrustTest {
@Test
fun sleepingDeviceWithoutGrantLocksDevice() {
uiDevice.sleep()
- await()
lockStateTrackingRule.assertLocked()
}
@Test
fun grantKeepsDeviceUnlocked() {
- trustAgentRule.agent.grantTrust(GRANT_MESSAGE, 10000, 0)
+ trustAgentRule.agent.grantTrust(GRANT_MESSAGE, 10000, 0) {}
uiDevice.sleep()
- await()
lockStateTrackingRule.assertUnlocked()
}
@Test
fun grantKeepsDeviceUnlocked_untilRevoked() {
- trustAgentRule.agent.grantTrust(GRANT_MESSAGE, 0, 0)
+ trustAgentRule.agent.grantTrust(GRANT_MESSAGE, 0, 0) {}
await()
uiDevice.sleep()
trustAgentRule.agent.revokeTrust()
- await()
lockStateTrackingRule.assertLocked()
}
+ @Test
+ fun grantDoesNotCallBack() {
+ val callback = mock<(GrantTrustResult) -> Unit>()
+ trustAgentRule.agent.grantTrust(GRANT_MESSAGE, 0, 0, callback)
+ await()
+
+ verifyZeroInteractions(callback)
+ }
+
companion object {
private const val TAG = "GrantAndRevokeTrustTest"
private const val GRANT_MESSAGE = "granted by test"
diff --git a/tests/TrustTests/src/android/trust/test/LockUserTest.kt b/tests/TrustTests/src/android/trust/test/LockUserTest.kt
index 83fc28fee818..a7dd41ad2e98 100644
--- a/tests/TrustTests/src/android/trust/test/LockUserTest.kt
+++ b/tests/TrustTests/src/android/trust/test/LockUserTest.kt
@@ -24,8 +24,6 @@ import android.trust.test.lib.TrustAgentRule
import android.util.Log
import androidx.test.ext.junit.rules.ActivityScenarioRule
import androidx.test.ext.junit.runners.AndroidJUnit4
-import com.google.common.truth.Truth.assertThat
-import org.junit.Ignore
import org.junit.Rule
import org.junit.Test
import org.junit.rules.RuleChain
@@ -49,14 +47,12 @@ class LockUserTest {
.around(lockStateTrackingRule)
.around(trustAgentRule)
- @Ignore("Causes issues with subsequent tests") // TODO: Enable test
@Test
fun lockUser_locksTheDevice() {
Log.i(TAG, "Locking user")
trustAgentRule.agent.lockUser()
- await()
- assertThat(lockStateTrackingRule.lockState.locked).isTrue()
+ lockStateTrackingRule.assertLocked()
}
companion object {
diff --git a/tests/TrustTests/src/android/trust/test/TemporaryAndRenewableTrustTest.kt b/tests/TrustTests/src/android/trust/test/TemporaryAndRenewableTrustTest.kt
new file mode 100644
index 000000000000..3c6d54d24291
--- /dev/null
+++ b/tests/TrustTests/src/android/trust/test/TemporaryAndRenewableTrustTest.kt
@@ -0,0 +1,159 @@
+/*
+ * 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.trust.test
+
+import android.service.trust.GrantTrustResult
+import android.service.trust.GrantTrustResult.STATUS_UNLOCKED_BY_GRANT
+import android.service.trust.TrustAgentService.FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE
+import android.trust.BaseTrustAgentService
+import android.trust.TrustTestActivity
+import android.trust.test.lib.LockStateTrackingRule
+import android.trust.test.lib.ScreenLockRule
+import android.trust.test.lib.TrustAgentRule
+import android.util.Log
+import androidx.test.ext.junit.rules.ActivityScenarioRule
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
+import androidx.test.uiautomator.UiDevice
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.rules.RuleChain
+import org.junit.runner.RunWith
+
+/**
+ * Test for testing revokeTrust & grantTrust for renewable trust.
+ *
+ * atest TrustTests:TemporaryAndRenewableTrustTest
+ */
+@RunWith(AndroidJUnit4::class)
+class TemporaryAndRenewableTrustTest {
+ private val uiDevice = UiDevice.getInstance(getInstrumentation())
+ private val activityScenarioRule = ActivityScenarioRule(TrustTestActivity::class.java)
+ private val lockStateTrackingRule = LockStateTrackingRule()
+ private val trustAgentRule = TrustAgentRule<TemporaryAndRenewableTrustAgent>()
+
+ @get:Rule
+ val rule: RuleChain = RuleChain
+ .outerRule(activityScenarioRule)
+ .around(ScreenLockRule())
+ .around(lockStateTrackingRule)
+ .around(trustAgentRule)
+
+ @Before
+ fun manageTrust() {
+ trustAgentRule.agent.setManagingTrust(true)
+ }
+
+ // This test serves a baseline for Grant tests, verifying that the default behavior of the
+ // device is to lock when put to sleep
+ @Test
+ fun sleepingDeviceWithoutGrantLocksDevice() {
+ uiDevice.sleep()
+
+ lockStateTrackingRule.assertLocked()
+ }
+
+ @Test
+ fun grantTrustLockedDevice_deviceStaysLocked() {
+ uiDevice.sleep()
+ lockStateTrackingRule.assertLocked()
+
+ trustAgentRule.agent.grantTrust(
+ GRANT_MESSAGE, 0, FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE) {}
+ uiDevice.wakeUp()
+
+ lockStateTrackingRule.assertLocked()
+ }
+
+ @Test
+ fun grantTrustUnlockedDevice_deviceLocksOnScreenOff() {
+ trustAgentRule.agent.grantTrust(
+ GRANT_MESSAGE, 0, FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE) {}
+ uiDevice.sleep()
+
+ lockStateTrackingRule.assertLocked()
+ }
+
+ @Test
+ fun grantTrustLockedDevice_grantTrustOnLockedDeviceUnlocksDevice() {
+ trustAgentRule.agent.grantTrust(
+ GRANT_MESSAGE, 0, FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE) {}
+ uiDevice.sleep()
+
+ lockStateTrackingRule.assertLocked()
+
+ trustAgentRule.agent.grantTrust(
+ GRANT_MESSAGE, 0, FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE) {}
+ uiDevice.wakeUp()
+
+ lockStateTrackingRule.assertUnlocked()
+ }
+
+ @Test
+ fun grantTrustLockedDevice_callsBackWhenUnlocked() {
+ Log.i(TAG, "Granting renewable trust while unlocked")
+ trustAgentRule.agent.grantTrust(
+ GRANT_MESSAGE, 0, FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE) {}
+ await(1000)
+
+ Log.i(TAG, "Locking device")
+ uiDevice.sleep()
+
+ lockStateTrackingRule.assertLocked()
+
+ Log.i(TAG, "Renewing trust and unlocking")
+ var result: GrantTrustResult? = null
+ trustAgentRule.agent.grantTrust(
+ GRANT_MESSAGE, 0, FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE) {
+ Log.i(TAG, "Callback received; status=${it.status}")
+ result = it
+ }
+ uiDevice.wakeUp()
+ lockStateTrackingRule.assertUnlocked()
+
+ assertThat(result?.status).isEqualTo(STATUS_UNLOCKED_BY_GRANT)
+ }
+
+ @Test
+ fun grantTrustLockedDevice_revokeTrustPreventsSubsequentUnlock() {
+ trustAgentRule.agent.grantTrust(
+ GRANT_MESSAGE, 0, FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE) {}
+ uiDevice.sleep()
+
+ lockStateTrackingRule.assertLocked()
+
+ trustAgentRule.agent.revokeTrust()
+ await(500)
+ uiDevice.wakeUp()
+ await(500)
+
+ trustAgentRule.agent.grantTrust(
+ GRANT_MESSAGE, 0, FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE) {}
+
+ lockStateTrackingRule.assertLocked()
+ }
+
+ companion object {
+ private const val TAG = "TemporaryAndRenewableTrustTest"
+ private const val GRANT_MESSAGE = "granted by test"
+ private fun await(millis: Long) = Thread.sleep(millis)
+ }
+}
+
+class TemporaryAndRenewableTrustAgent : BaseTrustAgentService()
diff --git a/tests/TrustTests/src/android/trust/test/UserUnlockRequestTest.kt b/tests/TrustTests/src/android/trust/test/UserUnlockRequestTest.kt
index f8783fbaf121..8bd8340a04b1 100644
--- a/tests/TrustTests/src/android/trust/test/UserUnlockRequestTest.kt
+++ b/tests/TrustTests/src/android/trust/test/UserUnlockRequestTest.kt
@@ -32,7 +32,7 @@ import org.junit.rules.RuleChain
import org.junit.runner.RunWith
/**
- * Test for testing the user unlock trigger.
+ * Test for the user unlock triggers.
*
* atest TrustTests:UserUnlockRequestTest
*/
@@ -53,13 +53,32 @@ class UserUnlockRequestTest {
@Test
fun reportUserRequestedUnlock_propagatesToAgent() {
val oldCount = trustAgentRule.agent.onUserRequestedUnlockCallCount
- trustManager.reportUserRequestedUnlock(userId)
+ trustManager.reportUserRequestedUnlock(userId, false)
await()
assertThat(trustAgentRule.agent.onUserRequestedUnlockCallCount)
.isEqualTo(oldCount + 1)
}
+ @Test
+ fun reportUserRequestedUnlock_propagatesToAgentWithDismissKeyguard() {
+ trustManager.reportUserRequestedUnlock(userId, true)
+ await()
+
+ assertThat(trustAgentRule.agent.lastCallDismissKeyguard)
+ .isTrue()
+ }
+
+ @Test
+ fun reportUserMayRequestUnlock_propagatesToAgent() {
+ val oldCount = trustAgentRule.agent.onUserMayRequestUnlockCallCount
+ trustManager.reportUserMayRequestUnlock(userId)
+ await()
+
+ assertThat(trustAgentRule.agent.onUserMayRequestUnlockCallCount)
+ .isEqualTo(oldCount + 1)
+ }
+
companion object {
private const val TAG = "UserUnlockRequestTest"
private fun await() = Thread.sleep(250)
@@ -69,10 +88,20 @@ class UserUnlockRequestTest {
class UserUnlockRequestTrustAgent : BaseTrustAgentService() {
var onUserRequestedUnlockCallCount: Long = 0
private set
+ var onUserMayRequestUnlockCallCount: Long = 0
+ private set
+ var lastCallDismissKeyguard: Boolean = false
+ private set
- override fun onUserRequestedUnlock() {
- Log.i(TAG, "onUserRequestedUnlock")
+ override fun onUserRequestedUnlock(dismissKeyguard: Boolean) {
+ Log.i(TAG, "onUserRequestedUnlock($dismissKeyguard)")
onUserRequestedUnlockCallCount++
+ lastCallDismissKeyguard = dismissKeyguard
+ }
+
+ override fun onUserMayRequestUnlock() {
+ Log.i(TAG, "onUserMayRequestUnlock")
+ onUserMayRequestUnlockCallCount++
}
companion object {
diff --git a/tests/TrustTests/src/android/trust/test/lib/LockStateTrackingRule.kt b/tests/TrustTests/src/android/trust/test/lib/LockStateTrackingRule.kt
index 0023af8893e2..00f457b5328a 100644
--- a/tests/TrustTests/src/android/trust/test/lib/LockStateTrackingRule.kt
+++ b/tests/TrustTests/src/android/trust/test/lib/LockStateTrackingRule.kt
@@ -52,8 +52,39 @@ class LockStateTrackingRule : TestRule {
}
}
- fun assertLocked() = assertThat(lockState.locked).isTrue()
- fun assertUnlocked() = assertThat(lockState.locked).isFalse()
+ fun assertLocked() {
+ val maxWaits = 50
+ var waitCount = 0
+
+ // First verify we get the call in LockState via TrustListener
+ while ((lockState.locked == false) && waitCount < maxWaits) {
+ Log.i(TAG, "phone still unlocked (TrustListener), wait 50ms more ($waitCount)")
+ Thread.sleep(50)
+ waitCount++
+ }
+ assertThat(lockState.locked).isTrue()
+
+ // TODO(b/225231929): refactor checks into one loop and re-use for assertUnlocked
+ // Then verify we get the window manager locked
+ while (!windowManager.isKeyguardLocked && waitCount < maxWaits) {
+ Log.i(TAG, "phone still unlocked (WindowManager), wait 50ms more ($waitCount)")
+ Thread.sleep(50)
+ waitCount++
+ }
+ assertThat(windowManager.isKeyguardLocked).isTrue()
+ }
+
+ fun assertUnlocked() {
+ val maxWaits = 50
+ var waitCount = 0
+
+ while ((lockState.locked == true) && waitCount < maxWaits) {
+ Log.i(TAG, "phone still unlocked, wait 50ms more ($waitCount)")
+ Thread.sleep(50)
+ waitCount++
+ }
+ assertThat(lockState.locked).isFalse()
+ }
inner class Listener : TrustListener {
override fun onTrustChanged(
diff --git a/tests/TrustTests/src/android/trust/test/lib/ScreenLockRule.kt b/tests/TrustTests/src/android/trust/test/lib/ScreenLockRule.kt
index bc100ba03639..127653d13b10 100644
--- a/tests/TrustTests/src/android/trust/test/lib/ScreenLockRule.kt
+++ b/tests/TrustTests/src/android/trust/test/lib/ScreenLockRule.kt
@@ -20,6 +20,8 @@ import android.content.Context
import android.util.Log
import android.view.WindowManagerGlobal
import androidx.test.core.app.ApplicationProvider.getApplicationContext
+import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
+import androidx.test.uiautomator.UiDevice
import com.android.internal.widget.LockPatternUtils
import com.android.internal.widget.LockscreenCredential
import com.google.common.truth.Truth.assertWithMessage
@@ -32,6 +34,7 @@ import org.junit.runners.model.Statement
*/
class ScreenLockRule : TestRule {
private val context: Context = getApplicationContext()
+ private val uiDevice = UiDevice.getInstance(getInstrumentation())
private val windowManager = WindowManagerGlobal.getWindowManagerService()
private val lockPatternUtils = LockPatternUtils(context)
private var instantLockSavedValue = false
@@ -48,39 +51,52 @@ class ScreenLockRule : TestRule {
} finally {
removeScreenLock()
revertLockOnPowerButton()
+ verifyKeyguardDismissed()
}
}
}
private fun verifyNoScreenLockAlreadySet() {
assertWithMessage("Screen Lock must not already be set on device")
- .that(lockPatternUtils.isSecure(context.userId))
- .isFalse()
+ .that(lockPatternUtils.isSecure(context.userId))
+ .isFalse()
}
private fun verifyKeyguardDismissed() {
val maxWaits = 30
var waitCount = 0
+
while (windowManager.isKeyguardLocked && waitCount < maxWaits) {
Log.i(TAG, "Keyguard still showing; attempting to dismiss and wait 50ms ($waitCount)")
windowManager.dismissKeyguard(null, null)
+
+ // Sometimes, bouncer gets shown due to a race, so we have to put display to sleep
+ // and wake it back up to get it to go away
+ if (waitCount >= 10 && waitCount % 5 == 0) {
+ Log.i(TAG, "Escalation: attempting screen off/on to get rid of bouncer (+500ms)")
+ uiDevice.sleep()
+ Thread.sleep(250)
+ uiDevice.wakeUp()
+ Thread.sleep(250)
+ }
+
Thread.sleep(50)
waitCount++
}
assertWithMessage("Keyguard should be unlocked")
- .that(windowManager.isKeyguardLocked)
- .isFalse()
+ .that(windowManager.isKeyguardLocked)
+ .isFalse()
}
private fun setScreenLock() {
lockPatternUtils.setLockCredential(
- LockscreenCredential.createPin(PIN),
- LockscreenCredential.createNone(),
- context.userId
+ LockscreenCredential.createPin(PIN),
+ LockscreenCredential.createNone(),
+ context.userId
)
assertWithMessage("Screen Lock should now be set")
- .that(lockPatternUtils.isSecure(context.userId))
- .isTrue()
+ .that(lockPatternUtils.isSecure(context.userId))
+ .isTrue()
Log.i(TAG, "Device PIN set to $PIN")
}
@@ -90,14 +106,25 @@ class ScreenLockRule : TestRule {
}
private fun removeScreenLock() {
- lockPatternUtils.setLockCredential(
- LockscreenCredential.createNone(),
- LockscreenCredential.createPin(PIN),
- context.userId
- )
- Log.i(TAG, "Device PIN cleared; waiting 50 ms then dismissing Keyguard")
- Thread.sleep(50)
- windowManager.dismissKeyguard(null, null)
+ var lockCredentialUnset = lockPatternUtils.setLockCredential(
+ LockscreenCredential.createNone(),
+ LockscreenCredential.createPin(PIN),
+ context.userId)
+ Thread.sleep(100)
+ assertWithMessage("Lock screen credential should be unset")
+ .that(lockCredentialUnset)
+ .isTrue()
+
+ lockPatternUtils.setLockScreenDisabled(true, context.userId)
+ Thread.sleep(100)
+ assertWithMessage("Lockscreen needs to be disabled")
+ .that(lockPatternUtils.isLockScreenDisabled(context.userId))
+ .isTrue()
+
+ // this is here because somehow it helps the keyguard not get stuck
+ uiDevice.sleep()
+ Thread.sleep(500) // delay added to avoid initiating camera by double clicking power
+ uiDevice.wakeUp()
}
private fun revertLockOnPowerButton() {
diff --git a/tests/componentalias/src/android/content/componentalias/tests/BaseComponentAliasTest.java b/tests/componentalias/src/android/content/componentalias/tests/BaseComponentAliasTest.java
index 9658d6f6a698..164f61c4c630 100644
--- a/tests/componentalias/src/android/content/componentalias/tests/BaseComponentAliasTest.java
+++ b/tests/componentalias/src/android/content/componentalias/tests/BaseComponentAliasTest.java
@@ -37,7 +37,7 @@ public class BaseComponentAliasTest {
protected static final Context sContext = InstrumentationRegistry.getTargetContext();
protected static final DeviceConfigStateHelper sDeviceConfig = new DeviceConfigStateHelper(
- DeviceConfig.NAMESPACE_ACTIVITY_MANAGER);
+ DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_COMPONENT_ALIAS);
@Before
public void enableComponentAliasWithCompatFlag() throws Exception {
Assume.assumeTrue(Build.isDebuggable());
diff --git a/tests/componentalias/src/android/content/componentalias/tests/ComponentAliasEnableWithDeviceConfigTest.java b/tests/componentalias/src/android/content/componentalias/tests/ComponentAliasEnableWithDeviceConfigTest.java
index 52c6d5b8ae12..ee20379d971a 100644
--- a/tests/componentalias/src/android/content/componentalias/tests/ComponentAliasEnableWithDeviceConfigTest.java
+++ b/tests/componentalias/src/android/content/componentalias/tests/ComponentAliasEnableWithDeviceConfigTest.java
@@ -28,7 +28,7 @@ import org.junit.Test;
public class ComponentAliasEnableWithDeviceConfigTest {
protected static final DeviceConfigStateHelper sDeviceConfig = new DeviceConfigStateHelper(
- DeviceConfig.NAMESPACE_ACTIVITY_MANAGER);
+ DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_COMPONENT_ALIAS);
@AfterClass
public static void restoreDeviceConfig() throws Exception {
diff --git a/tests/componentalias/src/android/content/componentalias/tests/ComponentAliasNotSupportedOnUserBuildTest.java b/tests/componentalias/src/android/content/componentalias/tests/ComponentAliasNotSupportedOnUserBuildTest.java
index 7935476d6156..0899886fe951 100644
--- a/tests/componentalias/src/android/content/componentalias/tests/ComponentAliasNotSupportedOnUserBuildTest.java
+++ b/tests/componentalias/src/android/content/componentalias/tests/ComponentAliasNotSupportedOnUserBuildTest.java
@@ -32,7 +32,7 @@ import org.junit.Test;
*/
public class ComponentAliasNotSupportedOnUserBuildTest {
protected static final DeviceConfigStateHelper sDeviceConfig = new DeviceConfigStateHelper(
- DeviceConfig.NAMESPACE_ACTIVITY_MANAGER);
+ DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_COMPONENT_ALIAS);
@AfterClass
public static void restoreDeviceConfig() throws Exception {
diff --git a/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java b/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java
index 7b1f7a599519..b67395735426 100644
--- a/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java
+++ b/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java
@@ -60,7 +60,7 @@ import android.telephony.SubscriptionManager;
import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
import android.telephony.TelephonyCallback;
import android.telephony.TelephonyManager;
-import android.telephony.TelephonyManager.CarrierPrivilegesListener;
+import android.telephony.TelephonyManager.CarrierPrivilegesCallback;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -187,11 +187,11 @@ public class TelephonySubscriptionTrackerTest {
return captor.getValue();
}
- private List<CarrierPrivilegesListener> getCarrierPrivilegesListeners() {
- final ArgumentCaptor<CarrierPrivilegesListener> captor =
- ArgumentCaptor.forClass(CarrierPrivilegesListener.class);
+ private List<CarrierPrivilegesCallback> getCarrierPrivilegesCallbacks() {
+ final ArgumentCaptor<CarrierPrivilegesCallback> captor =
+ ArgumentCaptor.forClass(CarrierPrivilegesCallback.class);
verify(mTelephonyManager, atLeastOnce())
- .addCarrierPrivilegesListener(anyInt(), any(), captor.capture());
+ .registerCarrierPrivilegesCallback(anyInt(), any(), captor.capture());
return captor.getAllValues();
}
@@ -270,12 +270,12 @@ public class TelephonySubscriptionTrackerTest {
assertNotNull(getOnSubscriptionsChangedListener());
verify(mTelephonyManager, times(2))
- .addCarrierPrivilegesListener(anyInt(), any(HandlerExecutor.class), any());
+ .registerCarrierPrivilegesCallback(anyInt(), any(HandlerExecutor.class), any());
verify(mTelephonyManager)
- .addCarrierPrivilegesListener(eq(0), any(HandlerExecutor.class), any());
+ .registerCarrierPrivilegesCallback(eq(0), any(HandlerExecutor.class), any());
verify(mTelephonyManager)
- .addCarrierPrivilegesListener(eq(1), any(HandlerExecutor.class), any());
- assertEquals(2, getCarrierPrivilegesListeners().size());
+ .registerCarrierPrivilegesCallback(eq(1), any(HandlerExecutor.class), any());
+ assertEquals(2, getCarrierPrivilegesCallbacks().size());
}
@Test
@@ -287,10 +287,10 @@ public class TelephonySubscriptionTrackerTest {
final OnSubscriptionsChangedListener listener = getOnSubscriptionsChangedListener();
verify(mSubscriptionManager).removeOnSubscriptionsChangedListener(eq(listener));
- for (CarrierPrivilegesListener carrierPrivilegesListener :
- getCarrierPrivilegesListeners()) {
+ for (CarrierPrivilegesCallback carrierPrivilegesCallback :
+ getCarrierPrivilegesCallbacks()) {
verify(mTelephonyManager)
- .removeCarrierPrivilegesListener(eq(carrierPrivilegesListener));
+ .unregisterCarrierPrivilegesCallback(eq(carrierPrivilegesCallback));
}
}
@@ -303,15 +303,15 @@ public class TelephonySubscriptionTrackerTest {
mTelephonySubscriptionTracker.setReadySubIdsBySlotId(readySubIdsBySlotId);
doReturn(1).when(mTelephonyManager).getActiveModemCount();
- List<CarrierPrivilegesListener> carrierPrivilegesListeners =
- getCarrierPrivilegesListeners();
+ List<CarrierPrivilegesCallback> carrierPrivilegesCallbacks =
+ getCarrierPrivilegesCallbacks();
mTelephonySubscriptionTracker.onReceive(mContext, buildTestMultiSimConfigBroadcastIntent());
mTestLooper.dispatchAll();
- for (CarrierPrivilegesListener carrierPrivilegesListener : carrierPrivilegesListeners) {
+ for (CarrierPrivilegesCallback carrierPrivilegesCallback : carrierPrivilegesCallbacks) {
verify(mTelephonyManager)
- .removeCarrierPrivilegesListener(eq(carrierPrivilegesListener));
+ .unregisterCarrierPrivilegesCallback(eq(carrierPrivilegesCallback));
}
// Expect cache cleared for inactive slots.
@@ -323,9 +323,9 @@ public class TelephonySubscriptionTrackerTest {
// Expect a new CarrierPrivilegesListener to have been registered for slot 0, and none other
// (2 previously registered during startup, for slots 0 & 1)
verify(mTelephonyManager, times(3))
- .addCarrierPrivilegesListener(anyInt(), any(HandlerExecutor.class), any());
+ .registerCarrierPrivilegesCallback(anyInt(), any(HandlerExecutor.class), any());
verify(mTelephonyManager, times(2))
- .addCarrierPrivilegesListener(eq(0), any(HandlerExecutor.class), any());
+ .registerCarrierPrivilegesCallback(eq(0), any(HandlerExecutor.class), any());
// Verify that this triggers a re-evaluation
verify(mCallback).onNewSnapshot(eq(buildExpectedSnapshot(TEST_PRIVILEGED_PACKAGES)));
@@ -391,8 +391,8 @@ public class TelephonySubscriptionTrackerTest {
public void testOnCarrierPrivilegesChanged() throws Exception {
setupReadySubIds();
- final CarrierPrivilegesListener listener = getCarrierPrivilegesListeners().get(0);
- listener.onCarrierPrivilegesChanged(Collections.emptyList(), new int[] {});
+ final CarrierPrivilegesCallback callback = getCarrierPrivilegesCallbacks().get(0);
+ callback.onCarrierPrivilegesChanged(Collections.emptySet(), Collections.emptySet());
mTestLooper.dispatchAll();
verify(mCallback).onNewSnapshot(eq(buildExpectedSnapshot(TEST_PRIVILEGED_PACKAGES)));
diff --git a/tools/aapt2/ResourceParser.cpp b/tools/aapt2/ResourceParser.cpp
index 42715f9c3592..8d35eeec2a93 100644
--- a/tools/aapt2/ResourceParser.cpp
+++ b/tools/aapt2/ResourceParser.cpp
@@ -1038,6 +1038,13 @@ bool static ParseGroupImpl(xml::XmlPullParser* parser, ParsedResource* out_resou
continue;
}
+ if (maybe_name.value().substr(0, std::strlen("removed_")) == "removed_") {
+ // Skip resources that have been removed from the framework, but leave a hole so that
+ // other staged resources don't shift and break apps previously compiled against them
+ next_id.id++;
+ continue;
+ }
+
ParsedResource& entry_res = out_resource->child_resources.emplace_back(ParsedResource{
.name = ResourceName{{}, *parsed_type, maybe_name.value().to_string()},
.source = item_source,
diff --git a/tools/aapt2/tools/finalize_res.py b/tools/aapt2/tools/finalize_res.py
new file mode 100755
index 000000000000..0e4d865bc890
--- /dev/null
+++ b/tools/aapt2/tools/finalize_res.py
@@ -0,0 +1,141 @@
+#!/usr/bin/env python3
+# -*- coding: 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.
+#
+# 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.
+
+"""
+Finalize resource values in <staging-public-group> tags
+and convert those to <staging-public-group-final>
+
+Usage: $ANDROID_BUILD_TOP/frameworks/base/tools/aapt2/tools/finalize_res.py \
+ $ANDROID_BUILD_TOP/frameworks/base/core/res/res/values/public-staging.xml \
+ $ANDROID_BUILD_TOP/frameworks/base/core/res/res/values/public-final.xml
+"""
+
+import re
+import sys
+
+resTypes = ["attr", "id", "style", "string", "dimen", "color", "array", "drawable", "layout",
+ "anim", "animator", "interpolator", "mipmap", "integer", "transition", "raw", "bool",
+ "fraction"]
+
+_type_ids = {}
+_type = ""
+
+_lowest_staging_first_id = 0x01FFFFFF
+
+"""
+ Created finalized <public> declarations for staging resources, ignoring them if they've been
+ prefixed with removed_. The IDs are assigned without holes starting from the last ID for that
+ type currently finalized in public-final.xml.
+"""
+def finalize_item(raw):
+ name = raw.group(1)
+ if re.match(r'_*removed.+', name):
+ return ""
+ id = _type_ids[_type]
+ _type_ids[_type] += 1
+ return ' <public type="%s" name="%s" id="%s" />\n' % (_type, name, '0x{0:0{1}x}'.format(id, 8))
+
+
+"""
+ Finalizes staging-public-groups if they have any entries in them. Also keeps track of the
+ lowest first-id of the non-empty groups so that the next release's staging-public-groups can
+ be assigned the next down shifted first-id.
+"""
+def finalize_group(raw):
+ global _type, _lowest_staging_first_id
+ _type = raw.group(1)
+ id = int(raw.group(2), 16)
+ _type_ids[_type] = _type_ids.get(_type, id)
+ (res, count) = re.subn(' {0,4}<public name="(.+?)" */>\n', finalize_item, raw.group(3))
+ if count > 0:
+ res = raw.group(0).replace("staging-public-group",
+ "staging-public-group-final") + '\n' + res
+ _lowest_staging_first_id = min(id, _lowest_staging_first_id)
+ return res
+
+"""
+ Collects the max ID for each resType so that the new IDs can be assigned afterwards
+"""
+def collect_ids(raw):
+ for m in re.finditer(r'<public type="(.+?)" name=".+?" id="(.+?)" />', raw):
+ type = m.group(1)
+ id = int(m.group(2), 16)
+ _type_ids[type] = max(id + 1, _type_ids.get(type, 0))
+
+
+with open(sys.argv[1], "r+") as stagingFile:
+ with open(sys.argv[2], "r+") as finalFile:
+ existing = finalFile.read()
+ # Cut out the closing resources tag so that it can be concatenated easily later
+ existing = "\n".join(existing.rsplit("</resources>", 1))
+
+ # Collect the IDs from the existing already finalized resources
+ collect_ids(existing)
+
+ staging = stagingFile.read()
+ stagingSplit = staging.rsplit("<resources>")
+ staging = stagingSplit[1]
+ staging = re.sub(
+ r'<staging-public-group type="(.+?)" first-id="(.+?)">(.+?)</staging-public-group>',
+ finalize_group, staging, flags=re.DOTALL)
+ staging = re.sub(r' *\n', '\n', staging)
+ staging = re.sub(r'\n{3,}', '\n\n', staging)
+
+ # First write the existing finalized declarations and then append the new stuff
+ finalFile.seek(0)
+ finalFile.write(existing.strip("\n"))
+ finalFile.write("\n\n")
+ finalFile.write(staging.strip("\n"))
+ finalFile.write("\n")
+ finalFile.truncate()
+
+ stagingFile.seek(0)
+ # Include the documentation from public-staging.xml that was previously split out
+ stagingFile.write(stagingSplit[0])
+ # Write the next platform header
+ stagingFile.write("<resources>\n\n")
+ stagingFile.write(" <!-- ===============================================================\n")
+ stagingFile.write(" Resources added in version NEXT of the platform\n\n")
+ stagingFile.write(" NOTE: After this version of the platform is forked, changes cannot be made to the root\n")
+ stagingFile.write(" branch's groups for that release. Only merge changes to the forked platform branch.\n")
+ stagingFile.write(" =============================================================== -->\n")
+ stagingFile.write(" <eat-comment/>\n\n")
+
+ # Seed the next release's staging-public-groups as empty declarations,
+ # so its easy for another developer to expose a new public resource
+ nextId = _lowest_staging_first_id - 0x00010000
+ for resType in resTypes:
+ stagingFile.write(' <staging-public-group type="%s" first-id="%s">\n'
+ ' </staging-public-group>\n\n' %
+ (resType, '0x{0:0{1}x}'.format(nextId, 8)))
+ nextId -= 0x00010000
+
+ # Close the resources tag and truncate, since the file will be shorter than the previous
+ stagingFile.write("</resources>\n")
+ stagingFile.truncate()
diff --git a/tools/finalize_res/finalize_res.py b/tools/finalize_res/finalize_res.py
deleted file mode 100755
index aaf01875024e..000000000000
--- a/tools/finalize_res/finalize_res.py
+++ /dev/null
@@ -1,41 +0,0 @@
-#!/usr/bin/env python3
-#-*- coding: utf-8 -*-
-
-# Copyright (C) 2021 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the 'License');
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an 'AS IS' BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-"""
-Finalize resource values in <staging-public-group> tags
-
-Usage: finalize_res.py core/res/res/values/public.xml public_finalized.xml
-"""
-
-import re, sys, codecs
-
-def finalize_item(raw):
- global _type, _id
- _id += 1
- return '<public type="%s" name="%s" id="%s" />' % (_type, raw.group(1), '0x{0:0{1}x}'.format(_id-1,8))
-
-def finalize_group(raw):
- global _type, _id
- _type = raw.group(1)
- _id = int(raw.group(2), 16)
- return re.sub(r'<public name="(.+?)" */>', finalize_item, raw.group(3))
-
-with open(sys.argv[1]) as f:
- raw = f.read()
- raw = re.sub(r'<staging-public-group type="(.+?)" first-id="(.+?)">(.+?)</staging-public-group>', finalize_group, raw, flags=re.DOTALL)
- with open(sys.argv[2], "w") as f:
- f.write(raw)
diff --git a/tools/processors/staledataclass/src/android/processor/staledataclass/StaleDataclassProcessor.kt b/tools/processors/staledataclass/src/android/processor/staledataclass/StaleDataclassProcessor.kt
index 1aec9b812e61..2e60f64b21e8 100644
--- a/tools/processors/staledataclass/src/android/processor/staledataclass/StaleDataclassProcessor.kt
+++ b/tools/processors/staledataclass/src/android/processor/staledataclass/StaleDataclassProcessor.kt
@@ -21,8 +21,6 @@ import com.android.codegen.BASE_BUILDER_CLASS
import com.android.codegen.CANONICAL_BUILDER_CLASS
import com.android.codegen.CODEGEN_NAME
import com.android.codegen.CODEGEN_VERSION
-import com.sun.tools.javac.code.Symbol
-import com.sun.tools.javac.code.Type
import java.io.File
import java.io.FileNotFoundException
import javax.annotation.processing.AbstractProcessor
@@ -33,6 +31,7 @@ import javax.lang.model.element.AnnotationMirror
import javax.lang.model.element.Element
import javax.lang.model.element.ElementKind
import javax.lang.model.element.TypeElement
+import javax.lang.model.type.ExecutableType
import javax.tools.Diagnostic
private const val STALE_FILE_THRESHOLD_MS = 1000
@@ -102,14 +101,13 @@ class StaleDataclassProcessor: AbstractProcessor() {
append(" ")
append(elem.annotationMirrors.joinToString(" ", transform = { annotationToString(it) }))
append(" ")
- if (elem is Symbol) {
- if (elem.type is Type.MethodType) {
- append((elem.type as Type.MethodType).returnType)
- } else {
- append(elem.type)
- }
- append(" ")
+ val type = elem.asType()
+ if (type is ExecutableType) {
+ append(type.returnType)
+ } else {
+ append(type)
}
+ append(" ")
append(elem)
}
}
@@ -234,4 +232,4 @@ class StaleDataclassProcessor: AbstractProcessor() {
override fun getSupportedSourceVersion(): SourceVersion {
return SourceVersion.latest()
}
-} \ No newline at end of file
+}
diff --git a/tools/traceinjection/Android.bp b/tools/traceinjection/Android.bp
new file mode 100644
index 000000000000..1395c5f2e635
--- /dev/null
+++ b/tools/traceinjection/Android.bp
@@ -0,0 +1,49 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+java_binary_host {
+ name: "traceinjection",
+ manifest: "manifest.txt",
+ srcs: ["src/**/*.java"],
+ static_libs: [
+ "asm-7.0",
+ "asm-commons-7.0",
+ "asm-tree-7.0",
+ "asm-analysis-7.0",
+ "guava-21.0",
+ ],
+}
+
+java_library_host {
+ name: "TraceInjectionTests-Uninjected",
+ srcs: ["test/**/*.java"],
+ static_libs: [
+ "junit",
+ ],
+}
+
+java_genrule_host {
+ name: "TraceInjectionTests-Injected",
+ srcs: [":TraceInjectionTests-Uninjected"],
+ tools: ["traceinjection"],
+ cmd: "$(location traceinjection) " +
+ " --annotation \"com/android/traceinjection/Trace\"" +
+ " --start \"com/android/traceinjection/InjectionTests.traceStart\"" +
+ " --end \"com/android/traceinjection/InjectionTests.traceEnd\"" +
+ " -o $(out) " +
+ " -i $(in)",
+ out: ["TraceInjectionTests-Injected.jar"],
+}
+
+java_test_host {
+ name: "TraceInjectionTests",
+ static_libs: [
+ "TraceInjectionTests-Injected",
+ ],
+}
diff --git a/tools/traceinjection/manifest.txt b/tools/traceinjection/manifest.txt
new file mode 100644
index 000000000000..7f4ee1d617fa
--- /dev/null
+++ b/tools/traceinjection/manifest.txt
@@ -0,0 +1 @@
+Main-Class: com.android.traceinjection.Main
diff --git a/tools/traceinjection/src/com/android/traceinjection/Main.java b/tools/traceinjection/src/com/android/traceinjection/Main.java
new file mode 100644
index 000000000000..190df819dd64
--- /dev/null
+++ b/tools/traceinjection/src/com/android/traceinjection/Main.java
@@ -0,0 +1,121 @@
+/*
+ * 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.traceinjection;
+
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassWriter;
+
+import java.io.BufferedInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Enumeration;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+import java.util.zip.ZipOutputStream;
+
+public class Main {
+ public static void main(String[] args) throws IOException {
+ String inJar = null;
+ String outJar = null;
+ String annotation = null;
+ String traceStart = null;
+ String traceEnd = null;
+
+ // All arguments require a value currently, so just make sure we have an even number and
+ // then process them all two at a time.
+ if (args.length % 2 != 0) {
+ throw new IllegalArgumentException("Argument is missing corresponding value");
+ }
+ for (int i = 0; i < args.length - 1; i += 2) {
+ final String arg = args[i].trim();
+ final String argValue = args[i + 1].trim();
+ if ("-i".equals(arg)) {
+ inJar = argValue;
+ } else if ("-o".equals(arg)) {
+ outJar = argValue;
+ } else if ("--annotation".equals(arg)) {
+ annotation = argValue;
+ } else if ("--start".equals(arg)) {
+ traceStart = argValue;
+ } else if ("--end".equals(arg)) {
+ traceEnd = argValue;
+ } else {
+ throw new IllegalArgumentException("Unknown argument: " + arg);
+ }
+ }
+
+ if (inJar == null) {
+ throw new IllegalArgumentException("input jar is required");
+ }
+
+ if (outJar == null) {
+ throw new IllegalArgumentException("output jar is required");
+ }
+
+ if (annotation == null) {
+ throw new IllegalArgumentException("trace annotation is required");
+ }
+
+ if (traceStart == null) {
+ throw new IllegalArgumentException("start trace method is required");
+ }
+
+ if (traceEnd == null) {
+ throw new IllegalArgumentException("end trace method is required");
+ }
+
+ TraceInjectionConfiguration params =
+ new TraceInjectionConfiguration(annotation, traceStart, traceEnd);
+
+ try (
+ ZipFile zipSrc = new ZipFile(inJar);
+ ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(outJar));
+ ) {
+ Enumeration<? extends ZipEntry> srcEntries = zipSrc.entries();
+ while (srcEntries.hasMoreElements()) {
+ ZipEntry entry = srcEntries.nextElement();
+ ZipEntry newEntry = new ZipEntry(entry.getName());
+ newEntry.setTime(entry.getTime());
+ zos.putNextEntry(newEntry);
+ BufferedInputStream bis = new BufferedInputStream(zipSrc.getInputStream(entry));
+
+ if (entry.getName().endsWith(".class")) {
+ convert(bis, zos, params);
+ } else {
+ while (bis.available() > 0) {
+ zos.write(bis.read());
+ }
+ zos.closeEntry();
+ bis.close();
+ }
+ }
+ zos.finish();
+ }
+ }
+
+ private static void convert(InputStream in, OutputStream out,
+ TraceInjectionConfiguration params) throws IOException {
+ ClassReader cr = new ClassReader(in);
+ ClassWriter cw = new ClassWriter(0);
+ TraceInjectionClassVisitor cv = new TraceInjectionClassVisitor(cw, params);
+ cr.accept(cv, ClassReader.EXPAND_FRAMES);
+ byte[] data = cw.toByteArray();
+ out.write(data);
+ }
+}
diff --git a/tools/traceinjection/src/com/android/traceinjection/TraceInjectionClassVisitor.java b/tools/traceinjection/src/com/android/traceinjection/TraceInjectionClassVisitor.java
new file mode 100644
index 000000000000..863f976b8aff
--- /dev/null
+++ b/tools/traceinjection/src/com/android/traceinjection/TraceInjectionClassVisitor.java
@@ -0,0 +1,41 @@
+/*
+ * 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.traceinjection;
+
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+
+/**
+ * {@link ClassVisitor} that injects tracing code to methods annotated with the configured
+ * annotation.
+ */
+public class TraceInjectionClassVisitor extends ClassVisitor {
+ private final TraceInjectionConfiguration mParams;
+ public TraceInjectionClassVisitor(ClassVisitor classVisitor,
+ TraceInjectionConfiguration params) {
+ super(Opcodes.ASM7, classVisitor);
+ mParams = params;
+ }
+
+ @Override
+ public MethodVisitor visitMethod(int access, String name, String desc, String signature,
+ String[] exceptions) {
+ MethodVisitor chain = super.visitMethod(access, name, desc, signature, exceptions);
+ return new TraceInjectionMethodAdapter(chain, access, name, desc, mParams);
+ }
+}
diff --git a/tools/traceinjection/src/com/android/traceinjection/TraceInjectionConfiguration.java b/tools/traceinjection/src/com/android/traceinjection/TraceInjectionConfiguration.java
new file mode 100644
index 000000000000..f9595bdad9cf
--- /dev/null
+++ b/tools/traceinjection/src/com/android/traceinjection/TraceInjectionConfiguration.java
@@ -0,0 +1,52 @@
+/*
+ * 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.traceinjection;
+
+/**
+ * Configuration data for trace method injection.
+ */
+public class TraceInjectionConfiguration {
+ public final String annotation;
+ public final String startMethodClass;
+ public final String startMethodName;
+ public final String endMethodClass;
+ public final String endMethodName;
+
+ public TraceInjectionConfiguration(String annotation, String startMethod, String endMethod) {
+ this.annotation = annotation;
+ String[] startMethodComponents = parseMethod(startMethod);
+ String[] endMethodComponents = parseMethod(endMethod);
+ startMethodClass = startMethodComponents[0];
+ startMethodName = startMethodComponents[1];
+ endMethodClass = endMethodComponents[0];
+ endMethodName = endMethodComponents[1];
+ }
+
+ public String toString() {
+ return "TraceInjectionParams{annotation=" + annotation
+ + ", startMethod=" + startMethodClass + "." + startMethodName
+ + ", endMethod=" + endMethodClass + "." + endMethodName + "}";
+ }
+
+ private static String[] parseMethod(String method) {
+ String[] methodComponents = method.split("\\.");
+ if (methodComponents.length != 2) {
+ throw new IllegalArgumentException("Invalid method descriptor: " + method);
+ }
+ return methodComponents;
+ }
+}
diff --git a/tools/traceinjection/src/com/android/traceinjection/TraceInjectionMethodAdapter.java b/tools/traceinjection/src/com/android/traceinjection/TraceInjectionMethodAdapter.java
new file mode 100644
index 000000000000..c2bbddcb5668
--- /dev/null
+++ b/tools/traceinjection/src/com/android/traceinjection/TraceInjectionMethodAdapter.java
@@ -0,0 +1,183 @@
+/*
+ * 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.traceinjection;
+
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+import org.objectweb.asm.commons.AdviceAdapter;
+import org.objectweb.asm.commons.Method;
+
+/**
+ * Adapter that injects tracing code to methods annotated with the configured annotation.
+ *
+ * Assuming the configured annotation is {@code @Trace} and the configured methods are
+ * {@code Tracing.begin()} and {@code Tracing.end()}, it effectively transforms:
+ *
+ * <pre>{@code
+ * @Trace
+ * void method() {
+ * doStuff();
+ * }
+ * }</pre>
+ *
+ * into:
+ * <pre>{@code
+ * @Trace
+ * void method() {
+ * Tracing.begin();
+ * try {
+ * doStuff();
+ * } finally {
+ * Tracing.end();
+ * }
+ * }
+ * }</pre>
+ */
+public class TraceInjectionMethodAdapter extends AdviceAdapter {
+ private final TraceInjectionConfiguration mParams;
+ private final Label mStartFinally = newLabel();
+ private final boolean mIsConstructor;
+
+ private boolean mShouldTrace;
+ private long mTraceId;
+ private String mTraceLabel;
+
+ public TraceInjectionMethodAdapter(MethodVisitor methodVisitor, int access,
+ String name, String descriptor, TraceInjectionConfiguration params) {
+ super(Opcodes.ASM7, methodVisitor, access, name, descriptor);
+ mParams = params;
+ mIsConstructor = "<init>".equals(name);
+ }
+
+ @Override
+ public void visitCode() {
+ super.visitCode();
+ if (mShouldTrace) {
+ visitLabel(mStartFinally);
+ }
+ }
+
+ @Override
+ protected void onMethodEnter() {
+ if (!mShouldTrace) {
+ return;
+ }
+ Type type = Type.getType(toJavaSpecifier(mParams.startMethodClass));
+ Method trace = Method.getMethod("void " + mParams.startMethodName + " (long, String)");
+ push(mTraceId);
+ push(getTraceLabel());
+ invokeStatic(type, trace);
+ }
+
+ private String getTraceLabel() {
+ return !isEmpty(mTraceLabel) ? mTraceLabel : getName();
+ }
+
+ @Override
+ protected void onMethodExit(int opCode) {
+ // Any ATHROW exits will be caught as part of our exception-handling block, so putting it
+ // here would cause us to call the end trace method multiple times.
+ if (opCode != ATHROW) {
+ onFinally();
+ }
+ }
+
+ private void onFinally() {
+ if (!mShouldTrace) {
+ return;
+ }
+ Type type = Type.getType(toJavaSpecifier(mParams.endMethodClass));
+ Method trace = Method.getMethod("void " + mParams.endMethodName + " (long)");
+ push(mTraceId);
+ invokeStatic(type, trace);
+ }
+
+ @Override
+ public void visitMaxs(int maxStack, int maxLocals) {
+ final int minStackSize;
+ if (mShouldTrace) {
+ Label endFinally = newLabel();
+ visitLabel(endFinally);
+ catchException(mStartFinally, endFinally, null);
+ // The stack will always contain exactly one element: the exception we caught
+ final Object[] stack = new Object[]{ "java/lang/Throwable"};
+ // Because we use EXPAND_FRAMES, the frame type must always be F_NEW.
+ visitFrame(F_NEW, /* numLocal= */ 0, /* local= */ null, stack.length, stack);
+ onFinally();
+ // Rethrow the exception that we caught in the finally block.
+ throwException();
+
+ // Make sure we have at least enough stack space to push the trace arguments
+ // (long, String)
+ minStackSize = Type.LONG_TYPE.getSize() + Type.getType(String.class).getSize();
+ } else {
+ // We didn't inject anything, so no need for additional stack space.
+ minStackSize = 0;
+ }
+
+ super.visitMaxs(Math.max(minStackSize, maxStack), maxLocals);
+ }
+
+ @Override
+ public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
+ AnnotationVisitor av = super.visitAnnotation(descriptor, visible);
+ if (descriptor.equals(toJavaSpecifier(mParams.annotation))) {
+ if (mIsConstructor) {
+ // TODO: Support constructor tracing. At the moment, constructors aren't supported
+ // because you can't put an exception handler around a super() call within the
+ // constructor itself.
+ throw new IllegalStateException("Cannot trace constructors");
+ }
+ av = new TracingAnnotationVisitor(av);
+ }
+ return av;
+ }
+
+ /**
+ * An AnnotationVisitor that pulls the trace ID and label information from the configured
+ * annotation.
+ */
+ class TracingAnnotationVisitor extends AnnotationVisitor {
+
+ TracingAnnotationVisitor(AnnotationVisitor annotationVisitor) {
+ super(Opcodes.ASM7, annotationVisitor);
+ }
+
+ @Override
+ public void visit(String name, Object value) {
+ if ("tag".equals(name)) {
+ mTraceId = (long) value;
+ // If we have a trace annotation and ID, then we have everything we need to trace
+ mShouldTrace = true;
+ } else if ("label".equals(name)) {
+ mTraceLabel = (String) value;
+ }
+ super.visit(name, value);
+ }
+ }
+
+ private static String toJavaSpecifier(String klass) {
+ return "L" + klass + ";";
+ }
+
+ private static boolean isEmpty(String str) {
+ return str == null || "".equals(str);
+ }
+}
diff --git a/tools/traceinjection/test/com/android/traceinjection/InjectionTests.java b/tools/traceinjection/test/com/android/traceinjection/InjectionTests.java
new file mode 100644
index 000000000000..81bf235fe0a6
--- /dev/null
+++ b/tools/traceinjection/test/com/android/traceinjection/InjectionTests.java
@@ -0,0 +1,246 @@
+/*
+ * 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.traceinjection;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThrows;
+
+import org.junit.After;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@RunWith(JUnit4.class)
+public class InjectionTests {
+ public static final int TRACE_TAG = 42;
+ public static final String CUSTOM_TRACE_NAME = "Custom";
+
+ public static final TraceTracker TRACKER = new TraceTracker();
+
+ @After
+ public void tearDown() {
+ TRACKER.reset();
+ }
+
+ @Test
+ public void testDefaultLabel() {
+ assertTraces(this::tracedMethod, "tracedMethod");
+ tracedMethodThrowsAndCatches();
+ }
+
+ @Test
+ public void testCustomLabel() {
+ assertTraces(this::tracedMethodHasCustomName, CUSTOM_TRACE_NAME);
+ }
+
+ @Test
+ public void testTracedMethodsStillThrow() {
+ assertTraces(() -> assertThrows(IllegalArgumentException.class, this::tracedMethodThrows),
+ "tracedMethodThrows");
+ // Also test that we rethrow exceptions from method calls. This is slightly different from
+ // the previous case because the ATHROW instruction is not actually present at all in the
+ // bytecode of the instrumented method.
+ TRACKER.reset();
+ assertTraces(() -> assertThrows(NullPointerException.class,
+ this::tracedMethodCallsThrowingMethod),
+ "tracedMethodCallsThrowingMethod");
+ }
+
+ @Test
+ public void testNestedTracedMethods() {
+ assertTraces(this::outerTracedMethod, "outerTracedMethod", "innerTracedMethod");
+ }
+
+ @Test
+ public void testTracedMethodWithCatchBlock() {
+ assertTraces(this::tracedMethodThrowsAndCatches, "tracedMethodThrowsAndCatches");
+ }
+
+ @Test
+ public void testTracedMethodWithFinallyBlock() {
+ assertTraces(() -> assertThrows(IllegalArgumentException.class,
+ this::tracedMethodThrowWithFinally), "tracedMethodThrowWithFinally");
+ }
+
+ @Test
+ public void testNonVoidMethod() {
+ assertTraces(this::tracedNonVoidMethod, "tracedNonVoidMethod");
+ }
+
+ @Test
+ public void testNonVoidMethodReturnsWithinCatches() {
+ assertTraces(this::tracedNonVoidMethodReturnsWithinCatches,
+ "tracedNonVoidMethodReturnsWithinCatches");
+ }
+
+ @Test
+ public void testNonVoidMethodReturnsWithinFinally() {
+ assertTraces(this::tracedNonVoidMethodReturnsWithinFinally,
+ "tracedNonVoidMethodReturnsWithinFinally");
+ }
+
+ @Test
+ public void testTracedStaticMethod() {
+ assertTraces(InjectionTests::tracedStaticMethod, "tracedStaticMethod");
+ }
+
+ @Trace(tag = TRACE_TAG)
+ public void tracedMethod() {
+ assertEquals(1, TRACKER.getTraceCount(TRACE_TAG));
+ }
+
+ @Trace(tag = TRACE_TAG)
+ public void tracedMethodThrows() {
+ throw new IllegalArgumentException();
+ }
+
+ @Trace(tag = TRACE_TAG)
+ public void tracedMethodCallsThrowingMethod() {
+ throwingMethod();
+ }
+
+ private void throwingMethod() {
+ throw new NullPointerException();
+ }
+
+
+ @Trace(tag = TRACE_TAG)
+ public void tracedMethodThrowsAndCatches() {
+ try {
+ throw new IllegalArgumentException();
+ } catch (IllegalArgumentException ignored) {
+ assertEquals(1, TRACKER.getTraceCount(TRACE_TAG));
+ }
+ }
+
+ @Trace(tag = TRACE_TAG)
+ public void tracedMethodThrowWithFinally() {
+ try {
+ throw new IllegalArgumentException();
+ } finally {
+ assertEquals(1, TRACKER.getTraceCount(TRACE_TAG));
+ }
+ }
+
+ @Trace(tag = TRACE_TAG, label = CUSTOM_TRACE_NAME)
+ public void tracedMethodHasCustomName() {
+ }
+
+ @Trace(tag = TRACE_TAG)
+ public void outerTracedMethod() {
+ innerTracedMethod();
+ assertEquals(1, TRACKER.getTraceCount(TRACE_TAG));
+ }
+
+ @Trace(tag = TRACE_TAG)
+ public void innerTracedMethod() {
+ assertEquals(2, TRACKER.getTraceCount(TRACE_TAG));
+ }
+
+ @Trace(tag = TRACE_TAG)
+ public int tracedNonVoidMethod() {
+ assertEquals(1, TRACKER.getTraceCount(TRACE_TAG));
+ return 0;
+ }
+
+ @Trace(tag = TRACE_TAG)
+ public int tracedNonVoidMethodReturnsWithinCatches() {
+ try {
+ throw new IllegalArgumentException();
+ } catch (IllegalArgumentException ignored) {
+ assertEquals(1, TRACKER.getTraceCount(TRACE_TAG));
+ return 0;
+ }
+ }
+
+ @Trace(tag = TRACE_TAG)
+ public int tracedNonVoidMethodReturnsWithinFinally() {
+ try {
+ throw new IllegalArgumentException();
+ } finally {
+ assertEquals(1, TRACKER.getTraceCount(TRACE_TAG));
+ return 0;
+ }
+ }
+
+ @Trace(tag = TRACE_TAG)
+ public static void tracedStaticMethod() {
+ assertEquals(1, TRACKER.getTraceCount(TRACE_TAG));
+ }
+
+ public void assertTraces(Runnable r, String... traceLabels) {
+ r.run();
+ assertEquals(Arrays.asList(traceLabels), TRACKER.getTraceLabels(TRACE_TAG));
+ TRACKER.assertAllTracesClosed();
+ }
+
+ public static void traceStart(long tag, String name) {
+ TRACKER.onTraceStart(tag, name);
+ }
+
+ public static void traceEnd(long tag) {
+ TRACKER.onTraceEnd(tag);
+ }
+
+ static class TraceTracker {
+ private final Map<Long, List<String>> mTraceLabelsByTag = new HashMap<>();
+ private final Map<Long, Integer> mTraceCountsByTag = new HashMap<>();
+
+ public void onTraceStart(long tag, String name) {
+ getTraceLabels(tag).add(name);
+ mTraceCountsByTag.put(tag, mTraceCountsByTag.getOrDefault(tag, 0) + 1);
+ }
+
+ public void onTraceEnd(long tag) {
+ final int newCount = getTraceCount(tag) - 1;
+ if (newCount < 0) {
+ throw new IllegalStateException("Trace count has gone negative for tag " + tag);
+ }
+ mTraceCountsByTag.put(tag, newCount);
+ }
+
+ public void reset() {
+ mTraceLabelsByTag.clear();
+ mTraceCountsByTag.clear();
+ }
+
+ public List<String> getTraceLabels(long tag) {
+ if (!mTraceLabelsByTag.containsKey(tag)) {
+ mTraceLabelsByTag.put(tag, new ArrayList<>());
+ }
+ return mTraceLabelsByTag.get(tag);
+ }
+
+ public int getTraceCount(long tag) {
+ return mTraceCountsByTag.getOrDefault(tag, 0);
+ }
+
+ public void assertAllTracesClosed() {
+ for (Map.Entry<Long, Integer> count: mTraceCountsByTag.entrySet()) {
+ final String errorMsg = "Tag " + count.getKey() + " is not fully closed (count="
+ + count.getValue() + ")";
+ assertEquals(errorMsg, 0, (int) count.getValue());
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/WMModule.java b/tools/traceinjection/test/com/android/traceinjection/Trace.java
index 2894780e04b8..9e1c545673e8 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/WMModule.java
+++ b/tools/traceinjection/test/com/android/traceinjection/Trace.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 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.
@@ -14,13 +14,9 @@
* limitations under the License.
*/
-package com.android.systemui.dagger;
+package com.android.traceinjection;
-import dagger.Module;
-
-/**
- * Dagger module for including the WMComponent.
- */
-@Module(subcomponents = {WMComponent.class})
-public abstract class WMModule {
+public @interface Trace {
+ long tag();
+ String label() default "";
}
diff --git a/tools/validatekeymaps/Android.bp b/tools/validatekeymaps/Android.bp
index 0423b7abd685..ff24d160b917 100644
--- a/tools/validatekeymaps/Android.bp
+++ b/tools/validatekeymaps/Android.bp
@@ -32,7 +32,7 @@ cc_binary_host {
"libui-types",
],
target: {
- linux_glibc: {
+ host_linux: {
static_libs: [
// libbinder is only available for linux
"libbinder",
diff --git a/wifi/java/src/android/net/wifi/nl80211/WifiNl80211Manager.java b/wifi/java/src/android/net/wifi/nl80211/WifiNl80211Manager.java
index 960447504d15..d85a5bdc3e66 100644
--- a/wifi/java/src/android/net/wifi/nl80211/WifiNl80211Manager.java
+++ b/wifi/java/src/android/net/wifi/nl80211/WifiNl80211Manager.java
@@ -963,6 +963,25 @@ public class WifiNl80211Manager {
}
/**
+ * Get the max number of SSIDs that the driver supports per scan.
+ *
+ * @param ifaceName Name of the interface.
+ */
+ public int getMaxSsidsPerScan(@NonNull String ifaceName) {
+ IWifiScannerImpl scannerImpl = getScannerImpl(ifaceName);
+ if (scannerImpl == null) {
+ Log.e(TAG, "No valid wificond scanner interface handler for iface=" + ifaceName);
+ return 0;
+ }
+ try {
+ return scannerImpl.getMaxSsidsPerScan();
+ } catch (RemoteException e1) {
+ Log.e(TAG, "Failed to getMaxSsidsPerScan");
+ }
+ return 0;
+ }
+
+ /**
* Return scan type for the parcelable {@link SingleScanSettings}
*/
private static int getScanType(@WifiAnnotations.ScanType int scanType) {